@getmicdrop/venue-calendar 4.1.47 → 4.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CartView-CbImzM52.js → CartView-B0-njiyN.js} +9 -9
- package/dist/{CartView-CbImzM52.js.map → CartView-B0-njiyN.js.map} +1 -1
- package/dist/{Checkout-CBFw6GZN.js → Checkout-8UfJfjXs.js} +7 -7
- package/dist/{Checkout-CBFw6GZN.js.map → Checkout-8UfJfjXs.js.map} +1 -1
- package/dist/{Checkout-mumN8wST.js → Checkout-CPE71a3G.js} +9 -9
- package/dist/{Checkout-mumN8wST.js.map → Checkout-CPE71a3G.js.map} +1 -1
- package/dist/{CheckoutTimer-BhsNhhBa.js → CheckoutTimer-C434YHXL.js} +5 -5
- package/dist/{CheckoutTimer-BhsNhhBa.js.map → CheckoutTimer-C434YHXL.js.map} +1 -1
- package/dist/{ClockIcon-D3j6Gx1p.js → ClockIcon-1EWOmMft.js} +2 -2
- package/dist/{ClockIcon-D3j6Gx1p.js.map → ClockIcon-1EWOmMft.js.map} +1 -1
- package/dist/{CollectionView-BmQ9gyF5.js → CollectionView-B3tIkbHY.js} +5 -5
- package/dist/{CollectionView-BmQ9gyF5.js.map → CollectionView-B3tIkbHY.js.map} +1 -1
- package/dist/{Event-CcCutqWI.js → Event-jo9PKuvP.js} +9 -9
- package/dist/{Event-CcCutqWI.js.map → Event-jo9PKuvP.js.map} +1 -1
- package/dist/{EventPage-CGLlJmJH.js → EventPage-DMQlqhx8.js} +8 -8
- package/dist/{EventPage-CGLlJmJH.js.map → EventPage-DMQlqhx8.js.map} +1 -1
- package/dist/{Heading-BhUb8Qlt.js → Heading-D4rbiqn7.js} +2 -2
- package/dist/{Heading-BhUb8Qlt.js.map → Heading-D4rbiqn7.js.map} +1 -1
- package/dist/{ScarcityBadge-CNl2iC42.js → ScarcityBadge-FcNYnsd-.js} +2 -2
- package/dist/{ScarcityBadge-CNl2iC42.js.map → ScarcityBadge-FcNYnsd-.js.map} +1 -1
- package/dist/{SeriesPage-B2Atn3ez.js → SeriesPage-J1gRV4q-.js} +5 -5
- package/dist/{SeriesPage-B2Atn3ez.js.map → SeriesPage-J1gRV4q-.js.map} +1 -1
- package/dist/{Spinner-D0a8MRGw.js → Spinner-ByX__SQ_.js} +2 -2
- package/dist/{Spinner-D0a8MRGw.js.map → Spinner-ByX__SQ_.js.map} +1 -1
- package/dist/{Success-FKjtAZ1r.js → Success-CpSK7Ci6.js} +9 -9
- package/dist/{Success-FKjtAZ1r.js.map → Success-CpSK7Ci6.js.map} +1 -1
- package/dist/{Text-GVslpRl8.js → Text-B4v9UASh.js} +2 -2
- package/dist/{Text-GVslpRl8.js.map → Text-B4v9UASh.js.map} +1 -1
- package/dist/{VenueCalendar-IEGPsGSM.js → VenueCalendar-_2IxPPd9.js} +13 -13
- package/dist/{VenueCalendar-IEGPsGSM.js.map → VenueCalendar-_2IxPPd9.js.map} +1 -1
- package/dist/{ViewTicketsEmbed-I8NO3tD_.js → ViewTicketsEmbed-mij4jtve.js} +5 -5
- package/dist/{ViewTicketsEmbed-I8NO3tD_.js.map → ViewTicketsEmbed-mij4jtve.js.map} +1 -1
- package/dist/{index-DKCSB6tL.js → index-BZir8DjN.js} +3 -3
- package/dist/{index-DKCSB6tL.js.map → index-BZir8DjN.js.map} +1 -1
- package/dist/{modalManager.svelte-BhC7KM1O.js → modalManager.svelte-DMr2h-BU.js} +2 -2
- package/dist/{modalManager.svelte-BhC7KM1O.js.map → modalManager.svelte-DMr2h-BU.js.map} +1 -1
- package/dist/{promo-DaPaF6A0.js → promo-BJhqO4xY.js} +2 -2
- package/dist/{promo-DaPaF6A0.js.map → promo-BJhqO4xY.js.map} +1 -1
- package/dist/{serverTotals-XG4zmsqL.js → serverTotals-BfNBGnwC.js} +2 -2
- package/dist/{serverTotals-XG4zmsqL.js.map → serverTotals-BfNBGnwC.js.map} +1 -1
- package/dist/{shareCopyFeedback.svelte-DPdedQSM.js → shareCopyFeedback.svelte-BIBn5Euu.js} +2 -2
- package/dist/{shareCopyFeedback.svelte-DPdedQSM.js.map → shareCopyFeedback.svelte-BIBn5Euu.js.map} +1 -1
- package/dist/{showcase-state-options-B9mGAmsO.js → showcase-state-options-xLL5PImR.js} +2 -2
- package/dist/{showcase-state-options-B9mGAmsO.js.map → showcase-state-options-xLL5PImR.js.map} +1 -1
- package/dist/{transform-B8WJuYbl.js → transform-e3UmqOFQ.js} +2 -2
- package/dist/{transform-B8WJuYbl.js.map → transform-e3UmqOFQ.js.map} +1 -1
- package/dist/{utm-BBbGSW1u.js → utm-Bl3wrnTZ.js} +2 -2
- package/dist/{utm-BBbGSW1u.js.map → utm-Bl3wrnTZ.js.map} +1 -1
- package/dist/venue-calendar.es.js +1 -1
- package/dist/venue-calendar.iife.js +1 -1
- package/dist/venue-calendar.umd.js +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Text-GVslpRl8.js","sources":["../node_modules/@getmicdrop/svelte-components/dist/primitives/Image/Image.svelte","../node_modules/@getmicdrop/svelte-components/dist/components/Text.svelte"],"sourcesContent":["<!--\r\n Image.svelte\r\n\r\n The canonical image primitive for Micdrop. Variable-aspect, user-uploaded\r\n sources (event posters, performer headshots, venue photos) where we do NOT\r\n control the aspect ratio. This component is now the single home for the\r\n whole image family — `Avatar` composes it, and `BlurBackdropImage` is a\r\n thin `@deprecated` shim.\r\n\r\n Premium contract (Atlas brief 04 — perf 5 / completeness 5):\r\n\r\n 1. ZERO CLS — pass `width`/`height` (intrinsic px) or `aspectRatio`\r\n (e.g. `'2/3'`, `'16/9'`, `'1'`). The component reserves that space\r\n BEFORE the image loads so the page never reflows when it arrives.\r\n A height-only sizing class (`h-8`, `size-10`, `aspect-video`) counts\r\n too — see `DEFINITE_BOX_CLASS` below for exactly which spellings.\r\n Dev-only `console.warn` if you provide neither dimensions nor one of\r\n those classes (we can't reserve space and CLS can creep back in).\r\n\r\n The width is still free: in normal block flow it fills the parent,\r\n and in a shrink-to-fit context (flex item, grid item, inline-block,\r\n absolutely positioned) it takes the width the bitmap's own ratio\r\n gives it at that height. `<Image class=\"h-8 w-auto\" />` inside a\r\n flex row is the auth-page wordmark and it renders at its natural\r\n ratio. That was NOT true before pad-endgame x162: the wrapper was a\r\n `container-type: inline-size` size container, which makes an element\r\n compute its inline size as if it had no contents, so every one of\r\n those shrink-to-fit contexts collapsed it — to ZERO as a flex item or\r\n absolutely positioned, to a 3.9px sliver as an inline-block — and\r\n `overflow: hidden` clipped the image away. The size container now lives on the\r\n absolutely-positioned blur layer, which contributes nothing to the\r\n wrapper's width by construction.\r\n\r\n 2. BLUR-UP LOADING — the main image starts slightly blurred and SHARPENS\r\n (blur → 0) once the real bitmap has decoded (`img.decode()` +\r\n `decoding=\"async\"`). In blur-backdrop framing a blurred copy of the\r\n SAME already-fetched bitmap fills the letterbox gaps — no second\r\n network fetch, no LQIP asset to ship. Fade timing reads the motion\r\n tokens, so `prefers-reduced-motion` collapses it automatically.\r\n\r\n 3. BLUR-BACKDROP IS THE DEFAULT FRAMING — `fit` defaults to\r\n `'blur-backdrop'`: the image is `object-fit: contain` (never cropped)\r\n and a blurred copy of itself fills the letterbox gaps. This handles\r\n BOTH tall posters and wide photos with no cropping and no flat-gray\r\n bars. `'cover'` / `'contain'` / `'fill'` / `'scale-down'` / `'none'`\r\n remain as escape hatches and render the plain single-`<img>` path\r\n (identical DOM to the pre-premium component).\r\n\r\n 4. BRANDED FALLBACK — when `src` (and `fallback`) are missing or both\r\n error, we render a branded placeholder (the Micdrop mark on a tint)\r\n instead of a flat gray div. Override the asset with `fallback`, or\r\n suppress the mark with `branded={false}`.\r\n\r\n Passthrough props for raw-<img> parity (so consumers can migrate\r\n existing `<img>` sites to `<Image>`):\r\n - `draggable` — forwarded to the underlying `<img draggable>`.\r\n - `onload` — forwarded to the `<img>` load event.\r\n - `fetchpriority` — forwarded to `<img fetchpriority>` (resource hint).\r\n - `onError` — fires ONCE, only after the internal fallback chain is\r\n exhausted (i.e. the branded placeholder takes over). It does NOT fire\r\n on the first error while a distinct `fallback` is still going to be\r\n tried. The raw `onerror` handler stays owned internally to drive the\r\n src→fallback→placeholder degradation; `onError` composes with it\r\n rather than replacing it.\r\n Deliberately NOT exposed (closed-interface rulings, sc#682):\r\n - `srcset`/`sizes` — zero consumer demand.\r\n - `onclick` — interactive semantics belong on an interactive WRAPPER\r\n (`<a>` for navigation, `<button type=\"button\">` otherwise) around\r\n `<Image>`, never on the img itself. A clickable img is a keyboard trap\r\n that only compiles behind a11y suppressions; the wrapper gets focus +\r\n key handling for free and nothing in this interface blocks it.\r\n - `aria-hidden` — redundant. `alt=\"\"` (the default) maps the img to role\r\n none/presentation per HTML-AAM, removing it from the accessibility\r\n tree already. Decorative icons: `alt=\"\"` + `fit=\"contain\"` +\r\n `blurUp={false}` (plain single-<img> DOM).\r\n - an errored-element `onError(event)` — the src-swap-on-error use case IS\r\n the `fallback` prop (src → fallback → branded placeholder, loop-safe).\r\n Consumers never need the raw element.\r\n\r\n Example:\r\n <Image src={event.posterUrl} alt={event.name} aspectRatio=\"2/3\" class=\"w-full rounded-xl\" />\r\n <Image src={user.avatarUrl} alt={user.name} width={80} height={80} fit=\"cover\" class=\"rounded-xl\" />\r\n <Image src={banner.url} alt=\"\" aspectRatio=\"16/9\" class=\"w-full\" loading=\"eager\" fetchpriority=\"high\" />\r\n-->\r\n<script lang=\"ts\">\r\n import { DEV } from 'esm-env';\r\n import { cn } from '../../utils/classNames.js';\r\n import { createLogger } from '../../utils/logger.js';\r\n\r\n const log = createLogger('Image');\r\n\r\n // Silence the dev CLS nudge under the test runner (the suite intentionally\r\n // renders without dimensions to exercise other behaviour). Reads the Node\r\n // env var Vitest sets — bundler-agnostic.\r\n const IS_TEST =\r\n typeof process !== 'undefined' && !!process.env?.VITEST;\r\n\r\n interface Props {\r\n /** Image source URL. When empty/missing, falls back to `fallback`. */\r\n src?: string;\r\n /** Alt text. Empty string marks decorative images per WCAG. */\r\n alt?: string;\r\n /** Additional CSS classes (sizing, shape, rounded corners). Wins last. */\r\n class?: string;\r\n /** Fallback URL used when src is empty or errors (before the branded mark). */\r\n fallback?: string;\r\n /** Loading strategy. Default 'lazy'; pass 'eager' for above-fold. */\r\n loading?: 'eager' | 'lazy';\r\n /**\r\n * Framing mode. Default `'blur-backdrop'` — `object-fit: contain` over a\r\n * blurred copy of the same image so tall AND wide sources are never\r\n * cropped and never letterboxed with flat gray. The remaining values are\r\n * escape hatches that render a plain single `<img object-fit:…>`.\r\n */\r\n fit?: 'blur-backdrop' | 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\r\n /**\r\n * Intrinsic width in CSS px — reserves space before load (zero CLS) and\r\n * sets the `<img width>` attribute. Pair with `height` for a fixed box.\r\n */\r\n width?: number;\r\n /**\r\n * Intrinsic height in CSS px — reserves space before load (zero CLS) and\r\n * sets the `<img height>` attribute. Pair with `width` for a fixed box.\r\n */\r\n height?: number;\r\n /**\r\n * CSS `aspect-ratio` string (e.g. `'2/3'` posters, `'16/9'` banners,\r\n * `'1'` square). Reserves space before load when you size by one axis\r\n * (`w-full`) — the zero-CLS path for fluid layouts.\r\n */\r\n aspectRatio?: string;\r\n /**\r\n * Blur-up loading: render blurred, then sharpen once the real bitmap\r\n * decodes. Default true. Set false to skip the effect (e.g. tiny icons\r\n * where the blur is imperceptible but the extra work isn't worth it).\r\n */\r\n blurUp?: boolean;\r\n /**\r\n * When the fallback chain is exhausted, show the branded Micdrop mark on\r\n * a tint. Default true. Set false for a plain tinted placeholder.\r\n */\r\n branded?: boolean;\r\n /** Forwarded to `<img draggable>`. Omitted when undefined. */\r\n draggable?: boolean;\r\n /** Forwarded to the `<img>` load event. */\r\n // eslint-disable-next-line no-unused-vars -- intentionally retained (prop/slot/forward-compat or Svelte-5 reactive binding eslint cannot see)\r\n onload?: (e: Event) => void;\r\n /** Forwarded to `<img fetchpriority>` (fetch-priority resource hint). */\r\n fetchpriority?: 'high' | 'low' | 'auto';\r\n /**\r\n * Fires once when the fallback chain is exhausted and the branded\r\n * placeholder takes over — NOT on the first error if a distinct\r\n * `fallback` is still going to be tried. Composes with the internal\r\n * `onerror` machine.\r\n */\r\n onError?: () => void;\r\n }\r\n\r\n let {\r\n src = '',\r\n alt = '',\r\n class: className = '',\r\n fallback = '',\r\n loading = 'lazy',\r\n fit = 'blur-backdrop',\r\n width,\r\n height,\r\n aspectRatio,\r\n blurUp = true,\r\n branded = true,\r\n draggable,\r\n onload,\r\n fetchpriority,\r\n onError,\r\n }: Props = $props();\r\n\r\n // Track loading attempts: which URL we're showing right now.\r\n // When the current URL errors, drop to 'failed' and render the placeholder.\r\n // Distinct from src/fallback inputs because we need to remember which\r\n // candidate we already tried. Reset whenever inputs change.\r\n let attempt: 'src' | 'fallback' | 'failed' = $state(\r\n // eslint-disable-next-line svelte/valid-compile -- known Svelte compiler note, accepted for this primitive\r\n src ? 'src' : fallback ? 'fallback' : 'failed'\r\n );\r\n\r\n // Guard so `onError` fires at most once per input set, even if a stale\r\n // <img> re-emits a duplicate final `error`. Reset when inputs change so a\r\n // fresh src/fallback can legitimately fail-and-notify again.\r\n let notifiedError = $state(false);\r\n\r\n // Blur-up: starts blurred, sharpens once the real bitmap decodes. Reset on\r\n // every new candidate URL so each swap re-runs the blur-up reveal.\r\n let decoded = $state(false);\r\n\r\n // The rendered main <img>, so we can detect an already-decoded bitmap that\r\n // won't fire `load` again (a cached src re-assigned, or a re-mount onto a\r\n // cached URL). Without this, `decoded` sticks at false and the image stays\r\n // blurred forever — the \"avatar goes blurry after save\" bug.\r\n let mainImg: HTMLImageElement | undefined = $state();\r\n\r\n $effect(() => {\r\n // Re-derive when inputs change. (Read both to register dependencies.)\r\n const _s = src;\r\n const _f = fallback;\r\n attempt = _s ? 'src' : _f ? 'fallback' : 'failed';\r\n notifiedError = false;\r\n decoded = false;\r\n });\r\n\r\n let activeSrc = $derived(\r\n attempt === 'src' ? src : attempt === 'fallback' ? fallback : ''\r\n );\r\n\r\n // Cached-bitmap reveal: after the shown URL settles, a browser that already\r\n // has the image marks the <img> `complete` WITHOUT re-firing `load` (cache\r\n // hit, or a mount whose load event landed before the handler attached). Reveal\r\n // it immediately so it never sticks blurred; a genuinely-loading image is\r\n // `complete: false` here and still waits for `handleLoad`. Depends on the SAME\r\n // inputs as the reset effect (src/fallback) — plus activeSrc — so it always\r\n // re-runs right after the reset (declaration order) and reads the post-update\r\n // <img>, even when the resolved URL is unchanged.\r\n $effect(() => {\r\n void src;\r\n void fallback;\r\n void activeSrc;\r\n if (mainImg?.complete && mainImg.naturalWidth > 0) decoded = true;\r\n });\r\n let showImg = $derived(attempt !== 'failed' && !!activeSrc);\r\n\r\n // blur-backdrop is the only framing mode that wraps; everything else is a\r\n // plain single <img object-fit:…> (identical DOM to the legacy component).\r\n let backdrop = $derived(fit === 'blur-backdrop');\r\n let objectFit = $derived(backdrop ? 'contain' : fit);\r\n\r\n // Does the consumer reserve a DEFINITE box — one that fixes the rendered\r\n // HEIGHT before the bitmap's intrinsic dimensions are known? Only these\r\n // prevent vertical CLS:\r\n // - aspectRatio (height derives from width via the ratio), OR\r\n // - both width AND height (a fully fixed box), OR\r\n // - a `size-*` utility (sets width AND height together), OR\r\n // - a definite height / aspect-ratio class (`h-*`, `aspect-*`).\r\n // Deliberately NOT counted: width alone, `w-full`, `max-h-*`, `h-auto`,\r\n // AND `min-h-*` — min-h only reserves a FLOOR, so a taller bitmap still\r\n // grows the box and shifts the page. None of these reserve the actual\r\n // vertical extent before metadata, so CLS can still creep in. (`max-h-*`\r\n // and `min-h-*` are excluded by the leading `(?:^|\\s)` — the `h-` in them\r\n // is preceded by `-`, never by whitespace.)\r\n //\r\n // KNOWN LIMIT, stated because the reserved-box rules drive layout and not\r\n // just the warning: the same leading `(?:^|\\s)` means a VARIANT-PREFIXED\r\n // class does not match either — `md:h-8`, `sm:size-8`, `dark:aspect-video`\r\n // all read as NO reserved box. Such a consumer gets the dev CLS warning at\r\n // every width, and above the breakpoint the wrapper has a definite height\r\n // while the main image is still on the `height:auto` path, so a tall bitmap\r\n // is clipped by the wrapper instead of contained inside it. No live\r\n // consumer sizes an Image that way today (checked across micdrop-frontend\r\n // 2026-08-01), which is why this is recorded rather than widened here:\r\n // matching them means matching `h-` after `:` too, and that also matches\r\n // arbitrary values like `[&>img]:h-8`, so it is its own change with its own\r\n // test, not a regex tweak smuggled into a sizing fix.\r\n const DEFINITE_BOX_CLASS = /(?:^|\\s)(?:aspect-|size-|h-(?!auto\\b))/;\r\n let hasReservedBox = $derived(\r\n !!aspectRatio ||\r\n (width != null && height != null) ||\r\n DEFINITE_BOX_CLASS.test(className)\r\n );\r\n\r\n // Dev-only nudge: without a definite box we cannot reserve VERTICAL space,\r\n // so CLS can creep back in. Warn, never throw.\r\n $effect(() => {\r\n // Dev-only (tree-shaken from prod via esm-env DEV) and never under test.\r\n if (DEV && !IS_TEST && !hasReservedBox) {\r\n log.warn(\r\n 'No aspectRatio, no width+height pair, and no definite height/aspect ' +\r\n 'sizing class — vertical layout space cannot be reserved and the ' +\r\n 'page may shift when the image loads (CLS). Pass aspectRatio=\"2/3\", ' +\r\n 'both width and height, or an h-*/aspect-* class. (width alone or ' +\r\n 'w-full does not reserve vertical space.)'\r\n );\r\n }\r\n });\r\n\r\n // Reserve intrinsic space on the box that owns layout. For blur-backdrop\r\n // that's the wrapper; for the plain path it's the <img> itself.\r\n let reserveStyle = $derived(\r\n [\r\n width != null ? `width:${width}px` : '',\r\n height != null ? `height:${height}px` : '',\r\n aspectRatio ? `aspect-ratio:${aspectRatio}` : '',\r\n ]\r\n .filter(Boolean)\r\n .join(';')\r\n );\r\n\r\n // mark the real bitmap as decoded → triggers the blur→sharp fade.\r\n async function handleLoad(e: Event) {\r\n const img = e.currentTarget as HTMLImageElement;\r\n // Capture which URL this load is FOR. If `src` swaps mid-decode (the\r\n // active candidate changes), this stale resolution must NOT sharpen — or\r\n // fire onload for — the new image. Compare against the live activeSrc\r\n // after the await and bail if it moved on.\r\n const loadedSrc = activeSrc;\r\n try {\r\n // decode() resolves once the bitmap is paint-ready; avoids revealing a\r\n // half-painted image. Falls through if unsupported / aborted.\r\n await img.decode?.();\r\n } catch {\r\n // decode can reject on detached/aborted images — reveal anyway.\r\n }\r\n // Src swapped while we awaited decode() → this is a stale load. Drop it;\r\n // the new candidate's own load event will drive the reveal.\r\n if (activeSrc !== loadedSrc) return;\r\n decoded = true;\r\n onload?.(e);\r\n }\r\n\r\n function handleError() {\r\n // If we were on src and have a distinct fallback to try, advance.\r\n if (attempt === 'src' && fallback && fallback !== src) {\r\n attempt = 'fallback';\r\n return;\r\n }\r\n // Either fallback already attempted, or no distinct fallback exists.\r\n // The chain is exhausted — the branded placeholder takes over. Notify the\r\n // consumer exactly here (final failure only), never on the transient\r\n // src→fallback hop, and at most once per input set.\r\n attempt = 'failed';\r\n if (!notifiedError) {\r\n notifiedError = true;\r\n onError?.();\r\n }\r\n }\r\n</script>\r\n\r\n{#if showImg && backdrop}\r\n <!-- blur-backdrop framing (default): contain + same-image blurred fill.\r\n The wrapper owns layout + reserves space; the blur layer is a second\r\n cheap reuse of the already-fetched bitmap (no extra network fetch). -->\r\n <div\r\n class={cn('sc-image sc-image--backdrop', className)}\r\n class:sc-image--backdrop-reserved={hasReservedBox}\r\n style={reserveStyle || undefined}\r\n >\r\n <div class=\"sc-image__blur-layer\">\r\n <img\r\n src={activeSrc}\r\n alt=\"\"\r\n class=\"sc-image__blur\"\r\n aria-hidden=\"true\"\r\n decoding=\"async\"\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n />\r\n </div>\r\n <img\r\n bind:this={mainImg}\r\n src={activeSrc}\r\n {alt}\r\n class=\"sc-image__main\"\r\n class:sc-image__main--reserved={hasReservedBox}\r\n class:sc-image__main--loading={blurUp && !decoded}\r\n style:object-fit={objectFit}\r\n {width}\r\n {height}\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n decoding=\"async\"\r\n onerror={handleError}\r\n onload={handleLoad}\r\n />\r\n </div>\r\n{:else if showImg}\r\n <!-- escape-hatch framing (cover/contain/fill/none/scale-down): plain single\r\n <img>, identical DOM to the legacy component, plus blur-up + dims. -->\r\n <img\r\n bind:this={mainImg}\r\n src={activeSrc}\r\n {alt}\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n {width}\r\n {height}\r\n class={cn(\r\n 'sc-image image',\r\n blurUp && !decoded && 'sc-image--loading',\r\n className\r\n )}\r\n style:object-fit={objectFit}\r\n style:aspect-ratio={aspectRatio || undefined}\r\n decoding=\"async\"\r\n onerror={handleError}\r\n onload={handleLoad}\r\n />\r\n{:else}\r\n <!-- No usable src — branded placeholder (Micdrop mark on a tint), or a plain\r\n tinted box when branded={false}. Empty alt marks decorative images (per\r\n WCAG); hide from assistive tech via aria-hidden + no role. -->\r\n {#if alt}\r\n <div\r\n class={cn(\r\n 'sc-image image sc-image-placeholder image-placeholder',\r\n branded && 'sc-image-placeholder--branded',\r\n className\r\n )}\r\n style={reserveStyle || undefined}\r\n role=\"img\"\r\n aria-label={alt}\r\n ></div>\r\n {:else}\r\n <div\r\n class={cn(\r\n 'sc-image image sc-image-placeholder image-placeholder',\r\n branded && 'sc-image-placeholder--branded',\r\n className\r\n )}\r\n style={reserveStyle || undefined}\r\n aria-hidden=\"true\"\r\n ></div>\r\n {/if}\r\n{/if}\r\n\r\n<style>\r\n /* `.image` is a legacy back-compat alias of `.sc-image` on the plain\r\n escape-hatch <img> + placeholder (consumer CSS / tests may target it). */\r\n .sc-image,\r\n .image {\r\n display: block;\r\n max-width: 100%;\r\n }\r\n\r\n /* --- blur-backdrop framing ---\r\n THE WRAPPER IS NOT A SIZE CONTAINER, AND MUST NOT BECOME ONE AGAIN (x162).\r\n It used to carry `container-type: inline-size` for the small-container blur\r\n rule below. Inline-size containment makes an element compute its inline size\r\n AS IF IT HAD NO CONTENTS — so in every shrink-to-fit context (flex item,\r\n inline-block, absolutely positioned) `width: auto` collapsed, the main image\r\n at `width: 100%` collapsed with it, and `overflow: hidden` clipped the whole\r\n thing away. Measured in Chromium at 104x30 natural size: as a flex item and\r\n absolutely positioned it is exactly 0 (wrapper 0x32, main image 0x32); as an\r\n inline-block it is a 3.9px sliver. Every wordmark on the auth pages\r\n rendered as nothing. Normal block flow was unaffected (the parent's width is\r\n definite there), which is why it survived so long. */\r\n .sc-image--backdrop {\r\n position: relative;\r\n overflow: hidden;\r\n background: hsl(var(--bg-quaternary));\r\n }\r\n\r\n /* The size container lives HERE instead. This layer is absolutely positioned,\r\n so it contributes nothing to the wrapper's intrinsic width BY CONSTRUCTION —\r\n containment on it can never collapse the box the way it did on the wrapper.\r\n\r\n ONE MEASUREMENT CHANGED WITH IT, deliberately: the query below now reads the\r\n wrapper's PADDING box (this layer's own box) where the old wrapper container\r\n read its CONTENT box. On a padded wrapper those differ. The padding box is\r\n the right one — the rule exists so the blur's opaque area still reaches the\r\n visible edge after the halo grows, and the blur fills the padding box, not\r\n the content box. No consumer pads an Image today either way. */\r\n .sc-image__blur-layer {\r\n position: absolute;\r\n inset: 0;\r\n container-type: inline-size;\r\n /* decorative; never take a hit that belongs to the wrapper */\r\n pointer-events: none;\r\n }\r\n\r\n .sc-image__blur {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n max-width: none;\r\n object-fit: cover;\r\n transform: scale(1.15);\r\n filter: blur(16px) saturate(1.2);\r\n /* purely decorative fill; the absolutely-positioned blur layer paints first\r\n and the in-flow main layer (position:relative) stacks above it by source\r\n order — no explicit z-index needed. */\r\n }\r\n\r\n /* Small containers (<=80px): blur() applies before scale() in the render\r\n pipeline, so the blur halo gets scaled too. Need enough scale that the\r\n opaque image extends past the container edge even after the halo grows.\r\n Measured unchanged by the containment move (Chromium): a 40px avatar box\r\n still resolves to scale(2), a 160px box still resolves to scale(1.15). */\r\n @container (max-width: 5rem) {\r\n .sc-image__blur {\r\n transform: scale(2);\r\n filter: blur(6px) saturate(1.2);\r\n }\r\n }\r\n\r\n .sc-image__main {\r\n position: relative;\r\n display: block;\r\n width: 100%;\r\n /* No reserved box (legacy / no-fit default): the in-flow main image\r\n DRIVES the wrapper height and sizes ITSELF to the consumer's sizing\r\n classes — which land on the wrapper. `max-height: inherit` /\r\n `max-width: inherit` pull the wrapper's `max-h-*` / `max-w-*` onto the\r\n image so object-fit:contain shrinks it to fit (image height == wrapper\r\n height). The image therefore NEVER exceeds the wrapper, so the wrapper's\r\n overflow:hidden (which clips the decorative blur fill) cannot clip the\r\n MAIN image — it renders exactly as the pre-premium single <img> did,\r\n constrained by max-h-* / h-auto, no reflow. Only force the image to fill\r\n a fixed box when the consumer reserved a DEFINITE one (explicit height /\r\n aspectRatio / size-* / h-* / aspect-*) — there the wrapper owns layout\r\n and the image fills it (true zero-CLS letterbox). */\r\n height: auto;\r\n max-width: inherit;\r\n max-height: inherit;\r\n object-fit: contain;\r\n }\r\n\r\n .sc-image--backdrop-reserved .sc-image__main--reserved {\r\n height: 100%;\r\n max-width: none;\r\n max-height: none;\r\n }\r\n\r\n /* --- blur-up reveal (CSS-only; reduced-motion gated via motion tokens) ---\r\n The main image / plain image starts slightly blurred + scaled and\r\n sharpens on decode. Durations read from --motion-* so\r\n prefers-reduced-motion collapses them. */\r\n .sc-image--loading,\r\n .sc-image__main {\r\n transition:\r\n filter var(--motion-normal) var(--ease-smooth),\r\n transform var(--motion-normal) var(--ease-smooth);\r\n }\r\n\r\n .sc-image--loading,\r\n .sc-image__main--loading {\r\n filter: blur(12px);\r\n transform: scale(1.02);\r\n }\r\n\r\n /* --- placeholder --- */\r\n .sc-image-placeholder {\r\n background: hsl(var(--bg-quaternary));\r\n }\r\n\r\n /* DARK ONLY. `--bg-quaternary` is the deepest surface token, and in dark that is\r\n literally `0 0% 0%` (tokens.css) against a card at 10% lightness — so an empty\r\n image slot painted pure black reads as a hole punched in the card, not as an empty\r\n box. `--muted` is 16.9% in dark, a 6.9-point step ABOVE the card, which is what\r\n an empty box is supposed to look like. Peet ruled the no-artwork state must be a\r\n grey box (2026-07-29, on the x48 deck); this is the half of that ruling the dark\r\n theme was failing.\r\n LIGHT IS DELIBERATELY UNTOUCHED: `--bg-quaternary` is 91% there and reads correctly\r\n on a white card, and `--muted` at 95.9% would fade the box Peet just approved. One\r\n token per theme, both already in the palette — no new token minted for this. */\r\n :global([data-theme='dark']) .sc-image-placeholder {\r\n background: hsl(var(--muted));\r\n }\r\n\r\n .sc-image-placeholder--branded {\r\n background-color: hsl(var(--bg-tertiary));\r\n background-image: url('../../assets/images/micdrop-logo.png');\r\n background-repeat: no-repeat;\r\n background-position: center;\r\n /* keep the mark a small, calm watermark — never edge-to-edge */\r\n background-size: min(48%, 96px) auto;\r\n opacity: 0.92;\r\n }\r\n</style>\r\n","<script lang=\"ts\">\n import type { Snippet } from 'svelte';\n import type { TypographyRole, TypographyTone } from '../tokens/typography.js';\n\n interface Props {\n /** Text role — the closed type system. Sets size+weight+line-height+tracking. Preferred. */\n variant?: TypographyRole;\n /** Tone (color) — orthogonal to variant. */\n tone?: TypographyTone;\n as?: 'span' | 'p' | 'label' | 'div';\n truncate?: boolean;\n class?: string;\n /** @deprecated use `variant` */ size?: 'xs' | 'sm' | 'base' | 'md' | 'lg' | 'xl' | '2xl';\n /** @deprecated set via `variant` */ leading?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose';\n /** @deprecated use `tone` */ color?: 'default' | 'muted' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'none';\n /** @deprecated set via `variant` */ weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n children: Snippet;\n }\n\n let {\n variant,\n tone,\n as = 'span',\n truncate = false,\n class: className = '',\n size,\n leading,\n color = 'default',\n weight,\n children,\n }: Props = $props();\n\n // ── New role API ──\n const toneClass: Record<string, string> = {\n primary: 'tone-primary', secondary: 'tone-secondary', muted: 'tone-muted',\n brand: 'tone-brand', success: 'tone-success', warning: 'tone-warning', danger: 'tone-danger',\n };\n\n // ── Deprecated prop maps (back-compat until consumers migrate to `variant`) ──\n const sizeClasses: Record<string, string> = {\n xs: 'type-caption', sm: 'type-body', base: 'type-bodyLarge', md: 'type-bodyLarge',\n lg: 'text-lg', xl: 'text-xl', '2xl': 'text-2xl',\n };\n const legacyColorClasses: Record<string, string> = {\n default: 'tone-primary', muted: 'tone-muted', primary: 'text-brand-primary',\n secondary: 'tone-secondary', success: 'text-accent-success', warning: 'text-accent-warning',\n error: 'text-accent-danger', none: '',\n };\n const leadingClasses: Record<string, string> = {\n none: 'leading-none', tight: 'leading-tight', snug: 'leading-snug',\n normal: 'leading-normal', relaxed: 'leading-relaxed', loose: 'leading-loose',\n };\n const weightClasses: Record<string, string> = {\n normal: 'font-normal', medium: 'font-medium', semibold: 'font-semibold', bold: 'font-bold',\n };\n\n let classes = $derived(\n (variant\n ? [`type-${variant}`, tone ? toneClass[tone] : '']\n : [\n sizeClasses[size ?? 'md'] || 'type-bodyLarge',\n leading ? leadingClasses[leading] : '',\n tone ? toneClass[tone] : legacyColorClasses[color] || '',\n weight ? weightClasses[weight] : 'font-normal',\n ])\n .concat(truncate ? 'truncate' : '', className)\n .filter(Boolean)\n .join(' '),\n );\n</script>\n\n<svelte:element this={as} class={classes}>{@render children()}</svelte:element>\n"],"names":["createLogger","src","$","$$props","alt","className","fallback","loading","fit","blurUp","branded","attempt","notifiedError","decoded","mainImg","_s","_f","activeSrc","showImg","backdrop","objectFit","DEFINITE_BOX_CLASS","hasReservedBox","reserveStyle","handleLoad","e","img","loadedSrc","handleError","div","root","div_1","img_1","img_2","$$value","classes","classes_1","styles","cn","img_3","root_1","$0","styles_1","div_2","root_2","div_3","root_3","$$render","consequent_2","alternate","consequent","consequent_1","alternate_1","as","truncate","color","toneClass","sizeClasses","legacyColorClasses","leadingClasses","weightClasses","$$element","$$anchor"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"Text-B4v9UASh.js","sources":["../node_modules/@getmicdrop/svelte-components/dist/primitives/Image/Image.svelte","../node_modules/@getmicdrop/svelte-components/dist/components/Text.svelte"],"sourcesContent":["<!--\r\n Image.svelte\r\n\r\n The canonical image primitive for Micdrop. Variable-aspect, user-uploaded\r\n sources (event posters, performer headshots, venue photos) where we do NOT\r\n control the aspect ratio. This component is now the single home for the\r\n whole image family — `Avatar` composes it, and `BlurBackdropImage` is a\r\n thin `@deprecated` shim.\r\n\r\n Premium contract (Atlas brief 04 — perf 5 / completeness 5):\r\n\r\n 1. ZERO CLS — pass `width`/`height` (intrinsic px) or `aspectRatio`\r\n (e.g. `'2/3'`, `'16/9'`, `'1'`). The component reserves that space\r\n BEFORE the image loads so the page never reflows when it arrives.\r\n A height-only sizing class (`h-8`, `size-10`, `aspect-video`) counts\r\n too — see `DEFINITE_BOX_CLASS` below for exactly which spellings.\r\n Dev-only `console.warn` if you provide neither dimensions nor one of\r\n those classes (we can't reserve space and CLS can creep back in).\r\n\r\n The width is still free: in normal block flow it fills the parent,\r\n and in a shrink-to-fit context (flex item, grid item, inline-block,\r\n absolutely positioned) it takes the width the bitmap's own ratio\r\n gives it at that height. `<Image class=\"h-8 w-auto\" />` inside a\r\n flex row is the auth-page wordmark and it renders at its natural\r\n ratio. That was NOT true before pad-endgame x162: the wrapper was a\r\n `container-type: inline-size` size container, which makes an element\r\n compute its inline size as if it had no contents, so every one of\r\n those shrink-to-fit contexts collapsed it — to ZERO as a flex item or\r\n absolutely positioned, to a 3.9px sliver as an inline-block — and\r\n `overflow: hidden` clipped the image away. The size container now lives on the\r\n absolutely-positioned blur layer, which contributes nothing to the\r\n wrapper's width by construction.\r\n\r\n 2. BLUR-UP LOADING — the main image starts slightly blurred and SHARPENS\r\n (blur → 0) once the real bitmap has decoded (`img.decode()` +\r\n `decoding=\"async\"`). In blur-backdrop framing a blurred copy of the\r\n SAME already-fetched bitmap fills the letterbox gaps — no second\r\n network fetch, no LQIP asset to ship. Fade timing reads the motion\r\n tokens, so `prefers-reduced-motion` collapses it automatically.\r\n\r\n 3. BLUR-BACKDROP IS THE DEFAULT FRAMING — `fit` defaults to\r\n `'blur-backdrop'`: the image is `object-fit: contain` (never cropped)\r\n and a blurred copy of itself fills the letterbox gaps. This handles\r\n BOTH tall posters and wide photos with no cropping and no flat-gray\r\n bars. `'cover'` / `'contain'` / `'fill'` / `'scale-down'` / `'none'`\r\n remain as escape hatches and render the plain single-`<img>` path\r\n (identical DOM to the pre-premium component).\r\n\r\n 4. BRANDED FALLBACK — when `src` (and `fallback`) are missing or both\r\n error, we render a branded placeholder (the Micdrop mark on a tint)\r\n instead of a flat gray div. Override the asset with `fallback`, or\r\n suppress the mark with `branded={false}`.\r\n\r\n Passthrough props for raw-<img> parity (so consumers can migrate\r\n existing `<img>` sites to `<Image>`):\r\n - `draggable` — forwarded to the underlying `<img draggable>`.\r\n - `onload` — forwarded to the `<img>` load event.\r\n - `fetchpriority` — forwarded to `<img fetchpriority>` (resource hint).\r\n - `onError` — fires ONCE, only after the internal fallback chain is\r\n exhausted (i.e. the branded placeholder takes over). It does NOT fire\r\n on the first error while a distinct `fallback` is still going to be\r\n tried. The raw `onerror` handler stays owned internally to drive the\r\n src→fallback→placeholder degradation; `onError` composes with it\r\n rather than replacing it.\r\n Deliberately NOT exposed (closed-interface rulings, sc#682):\r\n - `srcset`/`sizes` — zero consumer demand.\r\n - `onclick` — interactive semantics belong on an interactive WRAPPER\r\n (`<a>` for navigation, `<button type=\"button\">` otherwise) around\r\n `<Image>`, never on the img itself. A clickable img is a keyboard trap\r\n that only compiles behind a11y suppressions; the wrapper gets focus +\r\n key handling for free and nothing in this interface blocks it.\r\n - `aria-hidden` — redundant. `alt=\"\"` (the default) maps the img to role\r\n none/presentation per HTML-AAM, removing it from the accessibility\r\n tree already. Decorative icons: `alt=\"\"` + `fit=\"contain\"` +\r\n `blurUp={false}` (plain single-<img> DOM).\r\n - an errored-element `onError(event)` — the src-swap-on-error use case IS\r\n the `fallback` prop (src → fallback → branded placeholder, loop-safe).\r\n Consumers never need the raw element.\r\n\r\n Example:\r\n <Image src={event.posterUrl} alt={event.name} aspectRatio=\"2/3\" class=\"w-full rounded-xl\" />\r\n <Image src={user.avatarUrl} alt={user.name} width={80} height={80} fit=\"cover\" class=\"rounded-xl\" />\r\n <Image src={banner.url} alt=\"\" aspectRatio=\"16/9\" class=\"w-full\" loading=\"eager\" fetchpriority=\"high\" />\r\n-->\r\n<script lang=\"ts\">\r\n import { DEV } from 'esm-env';\r\n import { cn } from '../../utils/classNames.js';\r\n import { createLogger } from '../../utils/logger.js';\r\n\r\n const log = createLogger('Image');\r\n\r\n // Silence the dev CLS nudge under the test runner (the suite intentionally\r\n // renders without dimensions to exercise other behaviour). Reads the Node\r\n // env var Vitest sets — bundler-agnostic.\r\n const IS_TEST =\r\n typeof process !== 'undefined' && !!process.env?.VITEST;\r\n\r\n interface Props {\r\n /** Image source URL. When empty/missing, falls back to `fallback`. */\r\n src?: string;\r\n /** Alt text. Empty string marks decorative images per WCAG. */\r\n alt?: string;\r\n /** Additional CSS classes (sizing, shape, rounded corners). Wins last. */\r\n class?: string;\r\n /** Fallback URL used when src is empty or errors (before the branded mark). */\r\n fallback?: string;\r\n /** Loading strategy. Default 'lazy'; pass 'eager' for above-fold. */\r\n loading?: 'eager' | 'lazy';\r\n /**\r\n * Framing mode. Default `'blur-backdrop'` — `object-fit: contain` over a\r\n * blurred copy of the same image so tall AND wide sources are never\r\n * cropped and never letterboxed with flat gray. The remaining values are\r\n * escape hatches that render a plain single `<img object-fit:…>`.\r\n */\r\n fit?: 'blur-backdrop' | 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\r\n /**\r\n * Intrinsic width in CSS px — reserves space before load (zero CLS) and\r\n * sets the `<img width>` attribute. Pair with `height` for a fixed box.\r\n */\r\n width?: number;\r\n /**\r\n * Intrinsic height in CSS px — reserves space before load (zero CLS) and\r\n * sets the `<img height>` attribute. Pair with `width` for a fixed box.\r\n */\r\n height?: number;\r\n /**\r\n * CSS `aspect-ratio` string (e.g. `'2/3'` posters, `'16/9'` banners,\r\n * `'1'` square). Reserves space before load when you size by one axis\r\n * (`w-full`) — the zero-CLS path for fluid layouts.\r\n */\r\n aspectRatio?: string;\r\n /**\r\n * Blur-up loading: render blurred, then sharpen once the real bitmap\r\n * decodes. Default true. Set false to skip the effect (e.g. tiny icons\r\n * where the blur is imperceptible but the extra work isn't worth it).\r\n */\r\n blurUp?: boolean;\r\n /**\r\n * When the fallback chain is exhausted, show the branded Micdrop mark on\r\n * a tint. Default true. Set false for a plain tinted placeholder.\r\n */\r\n branded?: boolean;\r\n /** Forwarded to `<img draggable>`. Omitted when undefined. */\r\n draggable?: boolean;\r\n /** Forwarded to the `<img>` load event. */\r\n // eslint-disable-next-line no-unused-vars -- intentionally retained (prop/slot/forward-compat or Svelte-5 reactive binding eslint cannot see)\r\n onload?: (e: Event) => void;\r\n /** Forwarded to `<img fetchpriority>` (fetch-priority resource hint). */\r\n fetchpriority?: 'high' | 'low' | 'auto';\r\n /**\r\n * Fires once when the fallback chain is exhausted and the branded\r\n * placeholder takes over — NOT on the first error if a distinct\r\n * `fallback` is still going to be tried. Composes with the internal\r\n * `onerror` machine.\r\n */\r\n onError?: () => void;\r\n }\r\n\r\n let {\r\n src = '',\r\n alt = '',\r\n class: className = '',\r\n fallback = '',\r\n loading = 'lazy',\r\n fit = 'blur-backdrop',\r\n width,\r\n height,\r\n aspectRatio,\r\n blurUp = true,\r\n branded = true,\r\n draggable,\r\n onload,\r\n fetchpriority,\r\n onError,\r\n }: Props = $props();\r\n\r\n // Track loading attempts: which URL we're showing right now.\r\n // When the current URL errors, drop to 'failed' and render the placeholder.\r\n // Distinct from src/fallback inputs because we need to remember which\r\n // candidate we already tried. Reset whenever inputs change.\r\n let attempt: 'src' | 'fallback' | 'failed' = $state(\r\n // eslint-disable-next-line svelte/valid-compile -- known Svelte compiler note, accepted for this primitive\r\n src ? 'src' : fallback ? 'fallback' : 'failed'\r\n );\r\n\r\n // Guard so `onError` fires at most once per input set, even if a stale\r\n // <img> re-emits a duplicate final `error`. Reset when inputs change so a\r\n // fresh src/fallback can legitimately fail-and-notify again.\r\n let notifiedError = $state(false);\r\n\r\n // Blur-up: starts blurred, sharpens once the real bitmap decodes. Reset on\r\n // every new candidate URL so each swap re-runs the blur-up reveal.\r\n let decoded = $state(false);\r\n\r\n // The rendered main <img>, so we can detect an already-decoded bitmap that\r\n // won't fire `load` again (a cached src re-assigned, or a re-mount onto a\r\n // cached URL). Without this, `decoded` sticks at false and the image stays\r\n // blurred forever — the \"avatar goes blurry after save\" bug.\r\n let mainImg: HTMLImageElement | undefined = $state();\r\n\r\n $effect(() => {\r\n // Re-derive when inputs change. (Read both to register dependencies.)\r\n const _s = src;\r\n const _f = fallback;\r\n attempt = _s ? 'src' : _f ? 'fallback' : 'failed';\r\n notifiedError = false;\r\n decoded = false;\r\n });\r\n\r\n let activeSrc = $derived(\r\n attempt === 'src' ? src : attempt === 'fallback' ? fallback : ''\r\n );\r\n\r\n // Cached-bitmap reveal: after the shown URL settles, a browser that already\r\n // has the image marks the <img> `complete` WITHOUT re-firing `load` (cache\r\n // hit, or a mount whose load event landed before the handler attached). Reveal\r\n // it immediately so it never sticks blurred; a genuinely-loading image is\r\n // `complete: false` here and still waits for `handleLoad`. Depends on the SAME\r\n // inputs as the reset effect (src/fallback) — plus activeSrc — so it always\r\n // re-runs right after the reset (declaration order) and reads the post-update\r\n // <img>, even when the resolved URL is unchanged.\r\n $effect(() => {\r\n void src;\r\n void fallback;\r\n void activeSrc;\r\n if (mainImg?.complete && mainImg.naturalWidth > 0) decoded = true;\r\n });\r\n let showImg = $derived(attempt !== 'failed' && !!activeSrc);\r\n\r\n // blur-backdrop is the only framing mode that wraps; everything else is a\r\n // plain single <img object-fit:…> (identical DOM to the legacy component).\r\n let backdrop = $derived(fit === 'blur-backdrop');\r\n let objectFit = $derived(backdrop ? 'contain' : fit);\r\n\r\n // Does the consumer reserve a DEFINITE box — one that fixes the rendered\r\n // HEIGHT before the bitmap's intrinsic dimensions are known? Only these\r\n // prevent vertical CLS:\r\n // - aspectRatio (height derives from width via the ratio), OR\r\n // - both width AND height (a fully fixed box), OR\r\n // - a `size-*` utility (sets width AND height together), OR\r\n // - a definite height / aspect-ratio class (`h-*`, `aspect-*`).\r\n // Deliberately NOT counted: width alone, `w-full`, `max-h-*`, `h-auto`,\r\n // AND `min-h-*` — min-h only reserves a FLOOR, so a taller bitmap still\r\n // grows the box and shifts the page. None of these reserve the actual\r\n // vertical extent before metadata, so CLS can still creep in. (`max-h-*`\r\n // and `min-h-*` are excluded by the leading `(?:^|\\s)` — the `h-` in them\r\n // is preceded by `-`, never by whitespace.)\r\n //\r\n // KNOWN LIMIT, stated because the reserved-box rules drive layout and not\r\n // just the warning: the same leading `(?:^|\\s)` means a VARIANT-PREFIXED\r\n // class does not match either — `md:h-8`, `sm:size-8`, `dark:aspect-video`\r\n // all read as NO reserved box. Such a consumer gets the dev CLS warning at\r\n // every width, and above the breakpoint the wrapper has a definite height\r\n // while the main image is still on the `height:auto` path, so a tall bitmap\r\n // is clipped by the wrapper instead of contained inside it. No live\r\n // consumer sizes an Image that way today (checked across micdrop-frontend\r\n // 2026-08-01), which is why this is recorded rather than widened here:\r\n // matching them means matching `h-` after `:` too, and that also matches\r\n // arbitrary values like `[&>img]:h-8`, so it is its own change with its own\r\n // test, not a regex tweak smuggled into a sizing fix.\r\n const DEFINITE_BOX_CLASS = /(?:^|\\s)(?:aspect-|size-|h-(?!auto\\b))/;\r\n let hasReservedBox = $derived(\r\n !!aspectRatio ||\r\n (width != null && height != null) ||\r\n DEFINITE_BOX_CLASS.test(className)\r\n );\r\n\r\n // Dev-only nudge: without a definite box we cannot reserve VERTICAL space,\r\n // so CLS can creep back in. Warn, never throw.\r\n $effect(() => {\r\n // Dev-only (tree-shaken from prod via esm-env DEV) and never under test.\r\n if (DEV && !IS_TEST && !hasReservedBox) {\r\n log.warn(\r\n 'No aspectRatio, no width+height pair, and no definite height/aspect ' +\r\n 'sizing class — vertical layout space cannot be reserved and the ' +\r\n 'page may shift when the image loads (CLS). Pass aspectRatio=\"2/3\", ' +\r\n 'both width and height, or an h-*/aspect-* class. (width alone or ' +\r\n 'w-full does not reserve vertical space.)'\r\n );\r\n }\r\n });\r\n\r\n // Reserve intrinsic space on the box that owns layout. For blur-backdrop\r\n // that's the wrapper; for the plain path it's the <img> itself.\r\n let reserveStyle = $derived(\r\n [\r\n width != null ? `width:${width}px` : '',\r\n height != null ? `height:${height}px` : '',\r\n aspectRatio ? `aspect-ratio:${aspectRatio}` : '',\r\n ]\r\n .filter(Boolean)\r\n .join(';')\r\n );\r\n\r\n // mark the real bitmap as decoded → triggers the blur→sharp fade.\r\n async function handleLoad(e: Event) {\r\n const img = e.currentTarget as HTMLImageElement;\r\n // Capture which URL this load is FOR. If `src` swaps mid-decode (the\r\n // active candidate changes), this stale resolution must NOT sharpen — or\r\n // fire onload for — the new image. Compare against the live activeSrc\r\n // after the await and bail if it moved on.\r\n const loadedSrc = activeSrc;\r\n try {\r\n // decode() resolves once the bitmap is paint-ready; avoids revealing a\r\n // half-painted image. Falls through if unsupported / aborted.\r\n await img.decode?.();\r\n } catch {\r\n // decode can reject on detached/aborted images — reveal anyway.\r\n }\r\n // Src swapped while we awaited decode() → this is a stale load. Drop it;\r\n // the new candidate's own load event will drive the reveal.\r\n if (activeSrc !== loadedSrc) return;\r\n decoded = true;\r\n onload?.(e);\r\n }\r\n\r\n function handleError() {\r\n // If we were on src and have a distinct fallback to try, advance.\r\n if (attempt === 'src' && fallback && fallback !== src) {\r\n attempt = 'fallback';\r\n return;\r\n }\r\n // Either fallback already attempted, or no distinct fallback exists.\r\n // The chain is exhausted — the branded placeholder takes over. Notify the\r\n // consumer exactly here (final failure only), never on the transient\r\n // src→fallback hop, and at most once per input set.\r\n attempt = 'failed';\r\n if (!notifiedError) {\r\n notifiedError = true;\r\n onError?.();\r\n }\r\n }\r\n</script>\r\n\r\n{#if showImg && backdrop}\r\n <!-- blur-backdrop framing (default): contain + same-image blurred fill.\r\n The wrapper owns layout + reserves space; the blur layer is a second\r\n cheap reuse of the already-fetched bitmap (no extra network fetch). -->\r\n <div\r\n class={cn('sc-image sc-image--backdrop', className)}\r\n class:sc-image--backdrop-reserved={hasReservedBox}\r\n style={reserveStyle || undefined}\r\n >\r\n <div class=\"sc-image__blur-layer\">\r\n <img\r\n src={activeSrc}\r\n alt=\"\"\r\n class=\"sc-image__blur\"\r\n aria-hidden=\"true\"\r\n decoding=\"async\"\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n />\r\n </div>\r\n <img\r\n bind:this={mainImg}\r\n src={activeSrc}\r\n {alt}\r\n class=\"sc-image__main\"\r\n class:sc-image__main--reserved={hasReservedBox}\r\n class:sc-image__main--loading={blurUp && !decoded}\r\n style:object-fit={objectFit}\r\n {width}\r\n {height}\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n decoding=\"async\"\r\n onerror={handleError}\r\n onload={handleLoad}\r\n />\r\n </div>\r\n{:else if showImg}\r\n <!-- escape-hatch framing (cover/contain/fill/none/scale-down): plain single\r\n <img>, identical DOM to the legacy component, plus blur-up + dims. -->\r\n <img\r\n bind:this={mainImg}\r\n src={activeSrc}\r\n {alt}\r\n {loading}\r\n {draggable}\r\n {fetchpriority}\r\n {width}\r\n {height}\r\n class={cn(\r\n 'sc-image image',\r\n blurUp && !decoded && 'sc-image--loading',\r\n className\r\n )}\r\n style:object-fit={objectFit}\r\n style:aspect-ratio={aspectRatio || undefined}\r\n decoding=\"async\"\r\n onerror={handleError}\r\n onload={handleLoad}\r\n />\r\n{:else}\r\n <!-- No usable src — branded placeholder (Micdrop mark on a tint), or a plain\r\n tinted box when branded={false}. Empty alt marks decorative images (per\r\n WCAG); hide from assistive tech via aria-hidden + no role. -->\r\n {#if alt}\r\n <div\r\n class={cn(\r\n 'sc-image image sc-image-placeholder image-placeholder',\r\n branded && 'sc-image-placeholder--branded',\r\n className\r\n )}\r\n style={reserveStyle || undefined}\r\n role=\"img\"\r\n aria-label={alt}\r\n ></div>\r\n {:else}\r\n <div\r\n class={cn(\r\n 'sc-image image sc-image-placeholder image-placeholder',\r\n branded && 'sc-image-placeholder--branded',\r\n className\r\n )}\r\n style={reserveStyle || undefined}\r\n aria-hidden=\"true\"\r\n ></div>\r\n {/if}\r\n{/if}\r\n\r\n<style>\r\n /* `.image` is a legacy back-compat alias of `.sc-image` on the plain\r\n escape-hatch <img> + placeholder (consumer CSS / tests may target it). */\r\n .sc-image,\r\n .image {\r\n display: block;\r\n max-width: 100%;\r\n }\r\n\r\n /* --- blur-backdrop framing ---\r\n THE WRAPPER IS NOT A SIZE CONTAINER, AND MUST NOT BECOME ONE AGAIN (x162).\r\n It used to carry `container-type: inline-size` for the small-container blur\r\n rule below. Inline-size containment makes an element compute its inline size\r\n AS IF IT HAD NO CONTENTS — so in every shrink-to-fit context (flex item,\r\n inline-block, absolutely positioned) `width: auto` collapsed, the main image\r\n at `width: 100%` collapsed with it, and `overflow: hidden` clipped the whole\r\n thing away. Measured in Chromium at 104x30 natural size: as a flex item and\r\n absolutely positioned it is exactly 0 (wrapper 0x32, main image 0x32); as an\r\n inline-block it is a 3.9px sliver. Every wordmark on the auth pages\r\n rendered as nothing. Normal block flow was unaffected (the parent's width is\r\n definite there), which is why it survived so long. */\r\n .sc-image--backdrop {\r\n position: relative;\r\n overflow: hidden;\r\n background: hsl(var(--bg-quaternary));\r\n }\r\n\r\n /* The size container lives HERE instead. This layer is absolutely positioned,\r\n so it contributes nothing to the wrapper's intrinsic width BY CONSTRUCTION —\r\n containment on it can never collapse the box the way it did on the wrapper.\r\n\r\n ONE MEASUREMENT CHANGED WITH IT, deliberately: the query below now reads the\r\n wrapper's PADDING box (this layer's own box) where the old wrapper container\r\n read its CONTENT box. On a padded wrapper those differ. The padding box is\r\n the right one — the rule exists so the blur's opaque area still reaches the\r\n visible edge after the halo grows, and the blur fills the padding box, not\r\n the content box. No consumer pads an Image today either way. */\r\n .sc-image__blur-layer {\r\n position: absolute;\r\n inset: 0;\r\n container-type: inline-size;\r\n /* decorative; never take a hit that belongs to the wrapper */\r\n pointer-events: none;\r\n }\r\n\r\n .sc-image__blur {\r\n display: block;\r\n width: 100%;\r\n height: 100%;\r\n max-width: none;\r\n object-fit: cover;\r\n transform: scale(1.15);\r\n filter: blur(16px) saturate(1.2);\r\n /* purely decorative fill; the absolutely-positioned blur layer paints first\r\n and the in-flow main layer (position:relative) stacks above it by source\r\n order — no explicit z-index needed. */\r\n }\r\n\r\n /* Small containers (<=80px): blur() applies before scale() in the render\r\n pipeline, so the blur halo gets scaled too. Need enough scale that the\r\n opaque image extends past the container edge even after the halo grows.\r\n Measured unchanged by the containment move (Chromium): a 40px avatar box\r\n still resolves to scale(2), a 160px box still resolves to scale(1.15). */\r\n @container (max-width: 5rem) {\r\n .sc-image__blur {\r\n transform: scale(2);\r\n filter: blur(6px) saturate(1.2);\r\n }\r\n }\r\n\r\n .sc-image__main {\r\n position: relative;\r\n display: block;\r\n width: 100%;\r\n /* No reserved box (legacy / no-fit default): the in-flow main image\r\n DRIVES the wrapper height and sizes ITSELF to the consumer's sizing\r\n classes — which land on the wrapper. `max-height: inherit` /\r\n `max-width: inherit` pull the wrapper's `max-h-*` / `max-w-*` onto the\r\n image so object-fit:contain shrinks it to fit (image height == wrapper\r\n height). The image therefore NEVER exceeds the wrapper, so the wrapper's\r\n overflow:hidden (which clips the decorative blur fill) cannot clip the\r\n MAIN image — it renders exactly as the pre-premium single <img> did,\r\n constrained by max-h-* / h-auto, no reflow. Only force the image to fill\r\n a fixed box when the consumer reserved a DEFINITE one (explicit height /\r\n aspectRatio / size-* / h-* / aspect-*) — there the wrapper owns layout\r\n and the image fills it (true zero-CLS letterbox). */\r\n height: auto;\r\n max-width: inherit;\r\n max-height: inherit;\r\n object-fit: contain;\r\n }\r\n\r\n .sc-image--backdrop-reserved .sc-image__main--reserved {\r\n height: 100%;\r\n max-width: none;\r\n max-height: none;\r\n }\r\n\r\n /* --- blur-up reveal (CSS-only; reduced-motion gated via motion tokens) ---\r\n The main image / plain image starts slightly blurred + scaled and\r\n sharpens on decode. Durations read from --motion-* so\r\n prefers-reduced-motion collapses them. */\r\n .sc-image--loading,\r\n .sc-image__main {\r\n transition:\r\n filter var(--motion-normal) var(--ease-smooth),\r\n transform var(--motion-normal) var(--ease-smooth);\r\n }\r\n\r\n .sc-image--loading,\r\n .sc-image__main--loading {\r\n filter: blur(12px);\r\n transform: scale(1.02);\r\n }\r\n\r\n /* --- placeholder --- */\r\n .sc-image-placeholder {\r\n background: hsl(var(--bg-quaternary));\r\n }\r\n\r\n /* DARK ONLY. `--bg-quaternary` is the deepest surface token, and in dark that is\r\n literally `0 0% 0%` (tokens.css) against a card at 10% lightness — so an empty\r\n image slot painted pure black reads as a hole punched in the card, not as an empty\r\n box. `--muted` is 16.9% in dark, a 6.9-point step ABOVE the card, which is what\r\n an empty box is supposed to look like. Peet ruled the no-artwork state must be a\r\n grey box (2026-07-29, on the x48 deck); this is the half of that ruling the dark\r\n theme was failing.\r\n LIGHT IS DELIBERATELY UNTOUCHED: `--bg-quaternary` is 91% there and reads correctly\r\n on a white card, and `--muted` at 95.9% would fade the box Peet just approved. One\r\n token per theme, both already in the palette — no new token minted for this. */\r\n :global([data-theme='dark']) .sc-image-placeholder {\r\n background: hsl(var(--muted));\r\n }\r\n\r\n .sc-image-placeholder--branded {\r\n background-color: hsl(var(--bg-tertiary));\r\n background-image: url('../../assets/images/micdrop-logo.png');\r\n background-repeat: no-repeat;\r\n background-position: center;\r\n /* keep the mark a small, calm watermark — never edge-to-edge */\r\n background-size: min(48%, 96px) auto;\r\n opacity: 0.92;\r\n }\r\n</style>\r\n","<script lang=\"ts\">\n import type { Snippet } from 'svelte';\n import type { TypographyRole, TypographyTone } from '../tokens/typography.js';\n\n interface Props {\n /** Text role — the closed type system. Sets size+weight+line-height+tracking. Preferred. */\n variant?: TypographyRole;\n /** Tone (color) — orthogonal to variant. */\n tone?: TypographyTone;\n as?: 'span' | 'p' | 'label' | 'div';\n truncate?: boolean;\n class?: string;\n /** @deprecated use `variant` */ size?: 'xs' | 'sm' | 'base' | 'md' | 'lg' | 'xl' | '2xl';\n /** @deprecated set via `variant` */ leading?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose';\n /** @deprecated use `tone` */ color?: 'default' | 'muted' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'none';\n /** @deprecated set via `variant` */ weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n children: Snippet;\n }\n\n let {\n variant,\n tone,\n as = 'span',\n truncate = false,\n class: className = '',\n size,\n leading,\n color = 'default',\n weight,\n children,\n }: Props = $props();\n\n // ── New role API ──\n const toneClass: Record<string, string> = {\n primary: 'tone-primary', secondary: 'tone-secondary', muted: 'tone-muted',\n brand: 'tone-brand', success: 'tone-success', warning: 'tone-warning', danger: 'tone-danger',\n };\n\n // ── Deprecated prop maps (back-compat until consumers migrate to `variant`) ──\n const sizeClasses: Record<string, string> = {\n xs: 'type-caption', sm: 'type-body', base: 'type-bodyLarge', md: 'type-bodyLarge',\n lg: 'text-lg', xl: 'text-xl', '2xl': 'text-2xl',\n };\n const legacyColorClasses: Record<string, string> = {\n default: 'tone-primary', muted: 'tone-muted', primary: 'text-brand-primary',\n secondary: 'tone-secondary', success: 'text-accent-success', warning: 'text-accent-warning',\n error: 'text-accent-danger', none: '',\n };\n const leadingClasses: Record<string, string> = {\n none: 'leading-none', tight: 'leading-tight', snug: 'leading-snug',\n normal: 'leading-normal', relaxed: 'leading-relaxed', loose: 'leading-loose',\n };\n const weightClasses: Record<string, string> = {\n normal: 'font-normal', medium: 'font-medium', semibold: 'font-semibold', bold: 'font-bold',\n };\n\n let classes = $derived(\n (variant\n ? [`type-${variant}`, tone ? toneClass[tone] : '']\n : [\n sizeClasses[size ?? 'md'] || 'type-bodyLarge',\n leading ? leadingClasses[leading] : '',\n tone ? toneClass[tone] : legacyColorClasses[color] || '',\n weight ? weightClasses[weight] : 'font-normal',\n ])\n .concat(truncate ? 'truncate' : '', className)\n .filter(Boolean)\n .join(' '),\n );\n</script>\n\n<svelte:element this={as} class={classes}>{@render children()}</svelte:element>\n"],"names":["createLogger","src","$","$$props","alt","className","fallback","loading","fit","blurUp","branded","attempt","notifiedError","decoded","mainImg","_s","_f","activeSrc","showImg","backdrop","objectFit","DEFINITE_BOX_CLASS","hasReservedBox","reserveStyle","handleLoad","e","img","loadedSrc","handleError","div","root","div_1","img_1","img_2","$$value","classes","classes_1","styles","cn","img_3","root_1","$0","styles_1","div_2","root_2","div_3","root_3","$$render","consequent_2","alternate","consequent","consequent_1","alternate_1","as","truncate","color","toneClass","sizeClasses","legacyColorClasses","leadingClasses","weightClasses","$$element","$$anchor"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -16216,7 +16216,7 @@ function Po(e, t) {
|
|
|
16216
16216
|
}
|
|
16217
16217
|
}
|
|
16218
16218
|
async function _u(C) {
|
|
16219
|
-
C === "series" ? n.get(We) || n.set(We, (await import("./SeriesPage-
|
|
16219
|
+
C === "series" ? n.get(We) || n.set(We, (await import("./SeriesPage-J1gRV4q-.js")).default, !0) : C === "collection" ? n.get(bt) || n.set(bt, (await import("./CollectionView-B3tIkbHY.js")).default, !0) : n.get(Me) || n.set(Me, (await import("./EventPage-DMQlqhx8.js")).default, !0);
|
|
16220
16220
|
}
|
|
16221
16221
|
async function un({
|
|
16222
16222
|
type: C,
|
|
@@ -16281,12 +16281,12 @@ function Po(e, t) {
|
|
|
16281
16281
|
contentName: R?.name || R?.title || n.get(B)?.data?.name || n.get(B)?.data?.title || ""
|
|
16282
16282
|
}), typeof window < "u" && requestAnimationFrame(() => {
|
|
16283
16283
|
document.querySelector(".micdrop-calendar-container")?.scrollIntoView?.({ block: "start", behavior: "auto" });
|
|
16284
|
-
}), n.get(Fe) || n.set(Fe, (await import("./Checkout-
|
|
16284
|
+
}), n.get(Fe) || n.set(Fe, (await import("./Checkout-8UfJfjXs.js")).default, !0);
|
|
16285
16285
|
}
|
|
16286
16286
|
async function Cu(C) {
|
|
16287
16287
|
Ne++, n.set(ue, C || {}, !0), n.set(te, "success"), typeof window < "u" && requestAnimationFrame(() => {
|
|
16288
16288
|
document.querySelector(".micdrop-calendar-container")?.scrollIntoView?.({ block: "start", behavior: "auto" });
|
|
16289
|
-
}), n.get(ft) || n.set(ft, (await import("./Success-
|
|
16289
|
+
}), n.get(ft) || n.set(ft, (await import("./Success-CpSK7Ci6.js")).default, !0);
|
|
16290
16290
|
}
|
|
16291
16291
|
function Su() {
|
|
16292
16292
|
n.get(B) ? un({
|
|
@@ -17820,7 +17820,7 @@ if (typeof window < "u" && typeof HTMLElement < "u") {
|
|
|
17820
17820
|
}
|
|
17821
17821
|
}, customElements.get("micdrop-calendar") || customElements.define("micdrop-calendar", Vl);
|
|
17822
17822
|
}
|
|
17823
|
-
const y9 = "4.1.
|
|
17823
|
+
const y9 = "4.1.48", dn = tt("VenueCalendar");
|
|
17824
17824
|
let Gi = null;
|
|
17825
17825
|
function uu(e = {}) {
|
|
17826
17826
|
typeof e.onError == "function" && (Gi = e.onError, Jr({
|
|
@@ -17865,35 +17865,35 @@ const Re = {
|
|
|
17865
17865
|
// duplicate) has been deleted; everything uses EventPage.
|
|
17866
17866
|
EventPage: () => tn(
|
|
17867
17867
|
"EventPage",
|
|
17868
|
-
() => import("./EventPage-
|
|
17868
|
+
() => import("./EventPage-DMQlqhx8.js").then((e) => e.default)
|
|
17869
17869
|
),
|
|
17870
17870
|
Checkout: () => tn(
|
|
17871
17871
|
"Checkout",
|
|
17872
|
-
() => import("./Checkout-
|
|
17872
|
+
() => import("./Checkout-8UfJfjXs.js").then((e) => e.default)
|
|
17873
17873
|
),
|
|
17874
17874
|
Success: () => tn(
|
|
17875
17875
|
"Success",
|
|
17876
|
-
() => import("./Success-
|
|
17876
|
+
() => import("./Success-CpSK7Ci6.js").then((e) => e.default)
|
|
17877
17877
|
),
|
|
17878
17878
|
CartView: () => tn(
|
|
17879
17879
|
"CartView",
|
|
17880
|
-
() => import("./CartView-
|
|
17880
|
+
() => import("./CartView-B0-njiyN.js").then((e) => e.default)
|
|
17881
17881
|
),
|
|
17882
17882
|
ViewTicketsEmbed: () => tn(
|
|
17883
17883
|
"ViewTicketsEmbed",
|
|
17884
|
-
() => import("./ViewTicketsEmbed-
|
|
17884
|
+
() => import("./ViewTicketsEmbed-mij4jtve.js").then((e) => e.default)
|
|
17885
17885
|
),
|
|
17886
17886
|
CheckoutMain: () => tn(
|
|
17887
17887
|
"CheckoutMain",
|
|
17888
|
-
() => import("./Checkout-
|
|
17888
|
+
() => import("./Checkout-CPE71a3G.js").then((e) => e.b).then((e) => e.default)
|
|
17889
17889
|
),
|
|
17890
17890
|
SeriesPage: () => tn(
|
|
17891
17891
|
"SeriesPage",
|
|
17892
|
-
() => import("./SeriesPage-
|
|
17892
|
+
() => import("./SeriesPage-J1gRV4q-.js").then((e) => e.default)
|
|
17893
17893
|
),
|
|
17894
17894
|
CollectionView: () => tn(
|
|
17895
17895
|
"CollectionView",
|
|
17896
|
-
() => import("./CollectionView-
|
|
17896
|
+
() => import("./CollectionView-B3tIkbHY.js").then((e) => e.default)
|
|
17897
17897
|
)
|
|
17898
17898
|
};
|
|
17899
17899
|
function zr(e, t) {
|
|
@@ -18427,4 +18427,4 @@ export {
|
|
|
18427
18427
|
R4 as y,
|
|
18428
18428
|
N8 as z
|
|
18429
18429
|
};
|
|
18430
|
-
//# sourceMappingURL=VenueCalendar-
|
|
18430
|
+
//# sourceMappingURL=VenueCalendar-_2IxPPd9.js.map
|