@asteby/storefront-react 0.19.0 → 0.21.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.
Files changed (51) hide show
  1. package/README.md +41 -0
  2. package/dist/account-server.cjs +405 -7
  3. package/dist/account-server.cjs.map +1 -1
  4. package/dist/account-server.d.cts +41 -1
  5. package/dist/account-server.d.ts +41 -1
  6. package/dist/account-server.js +73 -3
  7. package/dist/account-server.js.map +1 -1
  8. package/dist/account.cjs +1663 -4
  9. package/dist/account.cjs.map +1 -1
  10. package/dist/account.css +362 -0
  11. package/dist/account.d.cts +499 -3
  12. package/dist/account.d.ts +499 -3
  13. package/dist/account.js +1102 -2
  14. package/dist/account.js.map +1 -1
  15. package/dist/cart.cjs +125 -2
  16. package/dist/cart.cjs.map +1 -1
  17. package/dist/cart.css +145 -2
  18. package/dist/cart.js +4 -2
  19. package/dist/cart.js.map +1 -1
  20. package/dist/checkout.cjs +129 -1
  21. package/dist/checkout.cjs.map +1 -1
  22. package/dist/checkout.css +142 -0
  23. package/dist/checkout.d.cts +3 -1
  24. package/dist/checkout.d.ts +3 -1
  25. package/dist/checkout.js +10 -3
  26. package/dist/checkout.js.map +1 -1
  27. package/dist/chunk-PPQEUTXJ.js +260 -0
  28. package/dist/chunk-PPQEUTXJ.js.map +1 -0
  29. package/dist/chunk-TXEYBDFG.js +182 -0
  30. package/dist/chunk-TXEYBDFG.js.map +1 -0
  31. package/dist/chunk-VHEY5AU3.js +152 -0
  32. package/dist/chunk-VHEY5AU3.js.map +1 -0
  33. package/dist/fiscal.d.cts +34 -34
  34. package/dist/fiscal.d.ts +34 -34
  35. package/dist/fiscal.js +4 -258
  36. package/dist/fiscal.js.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/payments.css +15 -14
  39. package/dist/payments.js +2 -2
  40. package/dist/product-preview-DRtLWGLS.d.cts +85 -0
  41. package/dist/product-preview-DaICr4f2.d.ts +85 -0
  42. package/dist/ui.cjs +202 -0
  43. package/dist/ui.cjs.map +1 -1
  44. package/dist/ui.css +142 -0
  45. package/dist/ui.d.cts +3 -0
  46. package/dist/ui.d.ts +3 -0
  47. package/dist/ui.js +3 -1
  48. package/dist/ui.js.map +1 -1
  49. package/dist/voucher-document-SFWJCLTN.js +124 -0
  50. package/dist/voucher-document-SFWJCLTN.js.map +1 -0
  51. package/package.json +2 -2
package/dist/ui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ui/select.tsx","../src/ui/swatch-colors.ts","../src/ui/swatch.tsx","../src/ui/theme-toggle.tsx","../src/ui/pwa.tsx"],"names":["current","style","jsx","useState","useEffect","jsxs"],"mappings":"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","file":"ui.js","sourcesContent":["import { useEffect, useId, useRef, useState } from 'react'\n\nexport type SelectOption = { value: string; label: string }\n\nconst Chevron = ({ open = false, floating = false }: { open?: boolean; floating?: boolean }) => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" data-select-chevron={floating ? 'floating' : ''} data-open={open || undefined}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n)\nconst Check = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n)\n\nexport type SelectProps = {\n id: string\n name: string\n options: SelectOption[]\n defaultValue?: string\n /** Etiqueta accesible (la visible la pone el llamador con <label htmlFor={id}>). */\n label: string\n className?: string\n}\n\n/**\n * Selector con mejora progresiva. Sin JavaScript (o antes de hidratar) es un <select> nativo dentro de un formulario;\n * con JavaScript se reemplaza por un listbox propio (teclado completo, objetivo táctil de 44 px, tema claro/oscuro).\n * El <select> nativo sigue en el DOM como fuente de verdad: al elegir se cambia su valor y se emite \"change\", así un\n * formulario con onChange → submit (filtros por URL) no nota la diferencia.\n * Estilos: clases `select` (ver ui.css) y los tokens --background, --foreground, --border, --tint, --primary.\n */\nexport function Select({ id, name, options, defaultValue, label, className = '' }: SelectProps) {\n const native = useRef<HTMLSelectElement>(null)\n const root = useRef<HTMLDivElement>(null)\n const [enhanced, setEnhanced] = useState(false)\n const [open, setOpen] = useState(false)\n const [value, setValue] = useState(defaultValue ?? options[0]?.value ?? '')\n const [active, setActive] = useState(0)\n const listId = useId()\n const current = options.find((o) => o.value === value) ?? options[0]\n\n useEffect(() => setEnhanced(true), [])\n // El valor lo puede cambiar la URL (atrás/adelante): se sincroniza.\n useEffect(() => {\n if (defaultValue != null) setValue(defaultValue)\n }, [defaultValue])\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: PointerEvent) => {\n if (!root.current?.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('pointerdown', onDown)\n return () => document.removeEventListener('pointerdown', onDown)\n }, [open])\n\n const openList = () => {\n setActive(Math.max(0, options.findIndex((o) => o.value === value)))\n setOpen(true)\n }\n\n const choose = (next: string) => {\n setOpen(false)\n setValue(next)\n const el = native.current\n if (el && el.value !== next) {\n el.value = next\n el.dispatchEvent(new Event('change', { bubbles: true }))\n }\n root.current?.querySelector<HTMLButtonElement>('button')?.focus()\n }\n\n const onKeyDown = (e: React.KeyboardEvent) => {\n const last = options.length - 1\n if (!open) {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {\n e.preventDefault()\n openList()\n }\n return\n }\n const go = (i: number) => {\n e.preventDefault()\n setActive(i)\n }\n if (e.key === 'Escape') {\n e.preventDefault()\n setOpen(false)\n } else if (e.key === 'ArrowDown') go(Math.min(last, active + 1))\n else if (e.key === 'ArrowUp') go(Math.max(0, active - 1))\n else if (e.key === 'Home') go(0)\n else if (e.key === 'End') go(last)\n else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n const picked = options[active]\n if (picked) choose(picked.value)\n } else if (e.key === 'Tab') setOpen(false)\n }\n\n return (\n <div ref={root} data-select=\"\" className={className || undefined}>\n <div data-select-native={enhanced ? 'hidden' : ''}>\n <select\n ref={native}\n id={enhanced ? undefined : id}\n name={name}\n defaultValue={defaultValue}\n tabIndex={enhanced ? -1 : undefined}\n aria-hidden={enhanced || undefined}\n aria-label={enhanced ? label : undefined}\n className=\"select\"\n >\n {options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n {!enhanced ? <Chevron floating /> : null}\n </div>\n\n {enhanced ? (\n <>\n <button\n type=\"button\"\n id={id}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-label={`${label}: ${current?.label}`}\n onClick={() => (open ? setOpen(false) : openList())}\n onKeyDown={onKeyDown}\n className=\"select\" data-select-trigger=\"\"\n >\n <span data-select-value=\"\">{current?.label}</span>\n <Chevron open={open} />\n </button>\n {open ? (\n <ul id={listId} role=\"listbox\" aria-label={label} tabIndex={-1} data-select-list=\"\">\n {options.map((o, i) => (\n <li\n key={o.value}\n role=\"option\"\n aria-selected={o.value === value}\n data-active={i === active || undefined}\n onPointerEnter={() => setActive(i)}\n onClick={() => choose(o.value)}\n >\n {o.label}\n {o.value === value ? <Check /> : null}\n </li>\n ))}\n </ul>\n ) : null}\n </>\n ) : null}\n </div>\n )\n}\n","/**\n * Muestras de variante (color, combinación o emoji), pura y sin DOM: sirve en servidor y cliente.\n *\n * El MOTOR es genérico; los DICCIONARIOS no. El SDK solo trae colores básicos (ropa, acabados). Los sabores, emojis y cualquier\n * vocabulario de un giro (suplementos, café, moda…) los inyecta la tienda con `createSwatchResolver`, o llegan del catálogo\n * como atributo (`parseSwatchAttribute`), que siempre manda sobre cualquier diccionario.\n */\n\n/**\n * Lo que dibuja una muestra: colores planos, emoji, o AMBOS (una píldora pastel con la mezcla de colores y los emoji encima).\n * Al menos uno de los dos viene lleno.\n */\nexport type SwatchSpec = { colors?: string[]; emoji?: string }\n\n/** [frase normalizada (minúsculas, sin acentos), un color hex o varios] */\nexport type ColorEntry = [phrase: string, color: string | string[]]\n/** [frase normalizada, emoji o varios emoji] */\nexport type EmojiEntry = [phrase: string, emoji: string]\n\n/** Qué dibujar primero cuando hay color y emoji para el mismo nombre. */\nexport type SwatchPrefer = 'auto' | 'color' | 'emoji' | 'both'\n\nconst HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i\nconst HEX_IN_TEXT = /#(?:[0-9a-f]{6}|[0-9a-f]{3})\\b/gi\nconst MAX = 4\n\n/** Minúsculas, sin acentos, sin puntuación suelta. \"Piña\" → \"pina\". */\nexport function normalize(value: string): string {\n return value.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim()\n}\n\n/** Colores básicos (es/en) para ropa y acabados. Sin vocabulario de ningún giro en particular. */\nexport const defaultColors: ColorEntry[] = [\n ['azul marino', '#14213d'], ['navy', '#14213d'], ['azul rey', '#2447d6'], ['azul cielo', '#6ec1f0'], ['celeste', '#8fd0f5'],\n ['verde militar', '#4b5320'], ['verde oliva', '#6b7a2a'], ['verde limon', '#b8e03a'], ['verde menta', '#8fe0b5'],\n ['rosa mexicano', '#e4007c'], ['gris oscuro', '#4a4f57'], ['gris claro', '#cfd3d8'],\n ['rojo', '#e0262d'], ['red', '#e0262d'], ['vino', '#6d1a36'], ['guinda', '#7a1f3d'], ['burgundy', '#6d1a36'],\n ['azul', '#2f5bea'], ['blue', '#2f5bea'], ['verde', '#2fa84f'], ['green', '#2fa84f'],\n ['amarillo', '#ffd21f'], ['yellow', '#ffd21f'], ['naranja', '#ff8a1f'], ['orange', '#ff8a1f'],\n ['morado', '#7b3fc4'], ['purpura', '#7b3fc4'], ['purple', '#7b3fc4'], ['violeta', '#8a4fd6'], ['lila', '#c4a5f0'],\n ['rosa', '#ff7eb6'], ['pink', '#ff7eb6'], ['fucsia', '#e4007c'], ['magenta', '#d4119e'],\n ['negro', '#111111'], ['black', '#111111'], ['blanco', '#ffffff'], ['white', '#ffffff'],\n ['gris', '#9aa0a8'], ['gray', '#9aa0a8'], ['grey', '#9aa0a8'], ['plata', '#c0c4cc'], ['plateado', '#c0c4cc'], ['silver', '#c0c4cc'],\n ['dorado', '#d4a72c'], ['oro', '#d4a72c'], ['gold', '#d4a72c'], ['cafe', '#7a4a2b'], ['marron', '#7a4a2b'], ['brown', '#7a4a2b'],\n ['beige', '#e6d3b3'], ['crema', '#f4ead2'], ['hueso', '#f1ecde'], ['arena', '#d9c39a'], ['khaki', '#b8a77a'], ['camel', '#b9824a'],\n ['turquesa', '#1fc8c8'], ['aqua', '#34d3d3'], ['coral', '#ff6f61'], ['salmon', '#ff8f7a'], ['mostaza', '#d9a521'], ['terracota', '#c4623f'],\n ['transparente', '#e8edf2'],\n]\n\n/**\n * Busca en el texto COMPLETO las frases del diccionario como palabras (plural con \"s\" opcional), la más larga primero, y las\n * devuelve en el orden en que se leen. Se tacha lo encontrado: \"azul\" no vuelve a salir dentro de \"azul marino\". Al no partir\n * el texto por \"y\"/\"and\", las frases con conectores (\"cookies and cream\") se resuelven como frase.\n */\nfunction scan<T>(text: string, entries: [string, T][]): T[] {\n const found: { index: number; value: T }[] = []\n let rest = text\n for (const [phrase, value] of [...entries].sort((a, b) => b[0].length - a[0].length)) {\n const m = new RegExp(`(^|[^a-z])${phrase}s?(?![a-z])`).exec(rest)\n if (!m) continue\n const start = m.index + (m[1]?.length ?? 0)\n found.push({ index: start, value })\n rest = rest.slice(0, start) + ' '.repeat(phrase.length + 1) + rest.slice(start + phrase.length + 1)\n }\n return found.sort((a, b) => a.index - b.index).map((f) => f.value)\n}\n\nfunction graphemes(text: string): string[] {\n return [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text)].map((g) => g.segment)\n}\n\nexport type SwatchResolverOptions = {\n /** Diccionario de colores. Default: `defaultColors`. Para sumar vocabulario: `[...defaultColors, ...tusColores]`. */\n colors?: ColorEntry[]\n /** Diccionario de emoji (sin default: es vocabulario del giro). */\n emojis?: EmojiEntry[]\n /** Qué dibujar si hay color y emoji: `auto`/`color` = color primero, `emoji` = emoji primero, `both` = píldora pastel con colores y emoji. */\n prefer?: SwatchPrefer\n}\n\nexport type SwatchResolver = {\n /** Colores del nombre (\"Rojo / Negro\", \"#ff8800\"), en orden de lectura, o `null`. */\n colors(value: string): string[] | null\n /** Emoji(s) del nombre (hasta 3, sin repetir), o `null`. */\n emoji(value: string): string | null\n /** Muestra de una variante: primero el atributo del catálogo, luego el nombre según `prefer`. */\n resolve(value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null\n /** ¿Todos los valores de una opción tienen muestra? */\n hasSwatches(values: string[], attribute?: Map<string, SwatchSpec>): boolean\n}\n\nexport function createSwatchResolver({ colors: colorTable = defaultColors, emojis = [], prefer = 'auto' }: SwatchResolverOptions = {}): SwatchResolver {\n const colors = (value: string): string[] | null => {\n const text = normalize(value)\n if (!text) return null\n const hex = (text.match(HEX_IN_TEXT) ?? []).filter((h) => HEX.test(h))\n const found = [...hex, ...scan(text, colorTable).flat()]\n const unique = found.filter((c, i) => found.indexOf(c) === i).slice(0, MAX)\n return unique.length > 0 ? unique : null\n }\n const emoji = (value: string): string | null => {\n const parts = scan(normalize(value), emojis).flatMap(graphemes)\n const unique = parts.filter((e, i) => parts.indexOf(e) === i).slice(0, 3)\n return unique.length > 0 ? unique.join('') : null\n }\n const resolve = (value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null => {\n const fromCatalog = attribute?.get(normalize(value))\n if (fromCatalog) return fromCatalog\n const c = colors(value)\n const e = emoji(value)\n if (prefer === 'both' && c && e) return { colors: c, emoji: e }\n if (prefer === 'emoji') return e ? { emoji: e } : c ? { colors: c } : null\n if (prefer === 'color') return c ? { colors: c } : e ? { emoji: e } : null\n return c ? { colors: c } : e ? { emoji: e } : null\n }\n return { colors, emoji, resolve, hasSwatches: (values, attribute) => values.length > 0 && values.every((v) => resolve(v, attribute) !== null) }\n}\n\nconst basic = createSwatchResolver()\n\n/** Colores básicos del nombre (sin vocabulario de giro). Para uno propio: `createSwatchResolver`. */\nexport const resolveSwatch = basic.colors\n/** Muestra de una variante con solo colores básicos. Para uno propio: `createSwatchResolver`. */\nexport const resolveSwatchSpec = (value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null => basic.resolve(value, attribute)\nexport const optionHasSwatches = basic.hasSwatches\n\n/**\n * Atributo del producto con el color o emoji de cada variante, como lo siembra el catálogo (OPS):\n * `\"Mora Azul:#3d4fd6|Fresa Kiwi:#ff4d6d+#8bc34a 🍓🥝|Natural:🥛\"`. Cada valor es un hex, varios hex con \"+\" (combinación), emoji, o colores y emoji juntos.\n * Es la fuente de verdad: manda sobre cualquier diccionario.\n */\nexport function parseSwatchAttribute(raw: unknown): Map<string, SwatchSpec> {\n const map = new Map<string, SwatchSpec>()\n if (typeof raw !== 'string') return map\n for (const part of raw.split('|')) {\n const i = part.lastIndexOf(':')\n if (i <= 0) continue\n const name = normalize(part.slice(0, i))\n const value = part.slice(i + 1).trim()\n const colors = (value.match(HEX_IN_TEXT) ?? []).filter((c) => HEX.test(c)).slice(0, MAX)\n const emoji = value.replace(HEX_IN_TEXT, '').replace(/[+\\s]/g, '')\n const hasEmoji = emoji.length > 0 && /\\p{Extended_Pictographic}/u.test(emoji)\n if (colors.length > 0 || hasEmoji) map.set(name, { ...(colors.length > 0 ? { colors } : {}), ...(hasEmoji ? { emoji } : {}) })\n }\n return map\n}\n\n/** Fondo CSS plano: un color liso, dos mitades, o sectores iguales (hasta 4). */\nexport function swatchBackground(colors: string[]): string {\n const [first = 'transparent', second] = colors\n if (second === undefined) return first\n if (colors.length === 2) return `linear-gradient(90deg, ${first} 50%, ${second} 50%)`\n const step = 360 / colors.length\n return `conic-gradient(${colors.map((c, i) => `${c} ${i * step}deg ${(i + 1) * step}deg`).join(', ')})`\n}\n\n/** Luminancia relativa (0 negro – 1 blanco) de un color hex, para decidir si hace falta un aro. */\nexport function luminance(hex: string): number {\n const h = hex.replace('#', '')\n const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h\n const channel = (i: number): number => {\n const v = parseInt(full.slice(i, i + 2), 16) / 255\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4\n }\n return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4)\n}\n\n/**\n * Fondo pastel de una píldora: cada color mezclado con blanco (queda claro y suave en claro y oscuro), un degradado suave entre\n * ellos si son varios. Con ese fondo el emoji siempre contrasta.\n */\nexport function pastelBackground(colors: string[]): string {\n const soft = colors.map((c) => `color-mix(in srgb, ${c} 26%, white)`)\n const [first = 'transparent', second] = soft\n if (second === undefined) return first\n return `linear-gradient(100deg, ${soft.join(', ')})`\n}\n","import type { CSSProperties } from 'react'\nimport { luminance, pastelBackground, resolveSwatchSpec, swatchBackground, type SwatchSpec } from './swatch-colors'\n\nexport type SwatchProps = {\n /** Nombre de la variante; se resuelve con los colores básicos del SDK. Para vocabulario propio resuelve tú con `createSwatchResolver` y pasa `spec`. */\n value?: string\n /** Lo que se dibuja (color(es) o emoji), ya resuelto: del catálogo (`parseSwatchAttribute`) o de tu `createSwatchResolver`. Manda sobre `value`. */\n spec?: SwatchSpec | null\n size?: number\n shape?: 'circle' | 'square'\n className?: string\n}\n\n/**\n * Muestra de color 2D para variantes: plana, sin sombras ni brillos y sin borde, salvo un aro mínimo cuando el color\n * se perdería contra el fondo (blanco en tema claro, negro en tema oscuro). Las combinaciones se dibujan en partes iguales.\n * Es decorativa (aria-hidden): el nombre de la variante debe ir siempre como texto junto a ella.\n * Con `spec.emoji` dibuja el emoji. Devuelve null si no reconoce nada, para que el llamador muestre solo el texto.\n */\nexport function Swatch({ value = '', spec, size = 20, shape = 'circle', className = '' }: SwatchProps) {\n const resolved = spec ?? resolveSwatchSpec(value)\n if (!resolved) return null\n const colors = resolved.colors ?? []\n if (resolved.emoji) {\n // Badge: círculo (un emoji) o píldora (mezcla) con fondo pastel de los colores del sabor y el emoji encima; sin colores, fondo\n // neutro de superficie. En la mezcla los emoji se montan un poco, el primero arriba. Así se ve qué emoji forman cada grupo.\n const parts = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(resolved.emoji)].map((g) => g.segment)\n const mixed = parts.length > 1\n const style: CSSProperties = {\n minWidth: size,\n height: size,\n fontSize: Math.round(size * (mixed ? 0.56 : 0.6)),\n ...(colors.length > 0 ? { background: pastelBackground(colors), ['--sw-ring' as string]: colors[0] } : {}),\n }\n return (\n <span aria-hidden=\"true\" data-swatch=\"\" data-kind=\"emoji\" data-mixed={mixed || undefined} data-colored={colors.length > 0 || undefined} data-shape={shape} className={className || undefined} style={style}>\n {parts.map((emoji, i) => (\n <span key={`${emoji}-${i}`} style={i > 0 ? { marginInlineStart: '-0.3em', zIndex: parts.length - i } : { zIndex: parts.length }}>\n {emoji}\n </span>\n ))}\n </span>\n )\n }\n if (colors.length === 0) return null\n const lums = colors.map(luminance)\n const edge = lums.some((l) => l > 0.82) ? 'light' : lums.some((l) => l < 0.04) ? 'dark' : undefined\n const style: CSSProperties = { width: size, height: size, background: swatchBackground(colors) }\n return <span aria-hidden=\"true\" data-swatch=\"\" data-edge={edge} data-shape={shape} className={className || undefined} style={style} />\n}\n","import { useEffect, useState } from 'react'\n\ntype Theme = 'light' | 'dark'\n\n/** Script de cabecera: aplica el tema guardado antes de pintar (sin parpadeo). Sin preferencia guardada manda el sistema. */\nexport const THEME_INIT_SCRIPT = `try{var t=localStorage.getItem(\"theme\");if(t===\"light\"||t===\"dark\")document.documentElement.setAttribute(\"data-theme\",t)}catch(e){}`\n\nfunction current(): Theme {\n const attr = document.documentElement.getAttribute('data-theme')\n if (attr === 'light' || attr === 'dark') return attr\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\n/**\n * Botón claro/oscuro. El estado real se lee del DOM tras hidratar (el servidor no sabe la preferencia).\n * Guarda la elección en localStorage (\"theme\") y fija `html[data-theme]`; los tokens de la tienda reaccionan a eso.\n */\nexport function ThemeToggle({ className = '', themeColors = { light: '#ffffff', dark: '#000000' } }: { className?: string; themeColors?: { light: string; dark: string } }) {\n const [theme, setTheme] = useState<Theme | null>(null)\n useEffect(() => setTheme(current()), [])\n\n const toggle = () => {\n const next: Theme = current() === 'dark' ? 'light' : 'dark'\n document.documentElement.setAttribute('data-theme', next)\n try {\n localStorage.setItem('theme', next)\n } catch {\n /* modo privado: el cambio dura la sesión */\n }\n document.querySelector('meta[name=\"theme-color\"][data-dynamic]')?.setAttribute('content', themeColors[next])\n setTheme(next)\n }\n\n const dark = theme === 'dark'\n return (\n <button type=\"button\" onClick={toggle} className={className} aria-label={dark ? 'Cambiar a tema claro' : 'Cambiar a tema oscuro'} aria-pressed={theme === null ? undefined : dark}>\n {dark ? (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </svg>\n ) : (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\" />\n </svg>\n )}\n </button>\n )\n}\n","import { useEffect, useState } from 'react'\n\ntype InstallEvent = Event & { prompt: () => Promise<void>; userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }> }\n\n/** Registra el service worker (solo si `enabled`, normalmente producción; requiere HTTPS o localhost). */\nexport function useServiceWorker({ enabled, url = '/sw.js', scope = '/' }: { enabled: boolean; url?: string; scope?: string }) {\n useEffect(() => {\n if (!enabled || !('serviceWorker' in navigator)) return\n const register = () => navigator.serviceWorker.register(url, { scope }).catch(() => undefined)\n if (document.readyState === 'complete') register()\n else window.addEventListener('load', register, { once: true })\n }, [enabled, url, scope])\n}\n\n/**\n * Botón \"Instalar app\": aparece solo cuando el navegador ofrece la instalación (Chrome, Edge, Android).\n * En iPhone/iPad no existe ese evento: muestra la instrucción de Compartir → Agregar a pantalla de inicio.\n */\nexport function InstallApp({ className = '', label = 'Instalar app', iosHint = 'Para instalar: toca Compartir y luego «Agregar a pantalla de inicio».' }: { className?: string; label?: string; iosHint?: string }) {\n const [event, setEvent] = useState<InstallEvent | null>(null)\n const [ios, setIos] = useState(false)\n const [installed, setInstalled] = useState(true)\n\n useEffect(() => {\n const standalone = window.matchMedia('(display-mode: standalone)').matches || (navigator as Navigator & { standalone?: boolean }).standalone === true\n setInstalled(standalone)\n setIos(/iphone|ipad|ipod/i.test(navigator.userAgent) && !standalone)\n const onPrompt = (e: Event) => {\n e.preventDefault()\n setEvent(e as InstallEvent)\n }\n const onInstalled = () => setInstalled(true)\n window.addEventListener('beforeinstallprompt', onPrompt)\n window.addEventListener('appinstalled', onInstalled)\n return () => {\n window.removeEventListener('beforeinstallprompt', onPrompt)\n window.removeEventListener('appinstalled', onInstalled)\n }\n }, [])\n\n if (installed) return null\n if (event) {\n return (\n <button\n type=\"button\"\n className={className}\n onClick={async () => {\n await event.prompt()\n await event.userChoice\n setEvent(null)\n }}\n >\n {label}\n </button>\n )\n }\n return ios ? <p className={className}>{iosHint}</p> : null\n}\n"]}
1
+ {"version":3,"sources":["../src/ui/select.tsx","../src/ui/swatch-colors.ts","../src/ui/swatch.tsx","../src/ui/theme-toggle.tsx","../src/ui/pwa.tsx"],"names":["current","style","jsx","useState","useEffect","jsxs"],"mappings":";;;;;;AAIA,IAAM,UAAU,CAAC,EAAE,IAAA,GAAO,KAAA,EAAO,WAAW,KAAA,EAAM,qBAChD,GAAA,CAAC,KAAA,EAAA,EAAI,OAAM,IAAA,EAAK,MAAA,EAAO,MAAK,OAAA,EAAQ,WAAA,EAAY,MAAK,MAAA,EAAO,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,KAAI,aAAA,EAAc,OAAA,EAAQ,gBAAe,OAAA,EAAQ,aAAA,EAAY,QAAO,qBAAA,EAAqB,QAAA,GAAW,UAAA,GAAa,EAAA,EAAI,aAAW,IAAA,IAAQ,MAAA,EACpO,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,gBAAe,CAAA,EACzB,CAAA;AAEF,IAAM,KAAA,GAAQ,sBACZ,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,gBAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,aAAA,EAAY,MAAA,EAC3J,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,iBAAA,EAAkB,CAAA,EAC5B,CAAA;AAoBK,SAAS,MAAA,CAAO,EAAE,EAAA,EAAI,IAAA,EAAM,SAAS,YAAA,EAAc,KAAA,EAAO,SAAA,GAAY,EAAA,EAAG,EAAgB;AAC9F,EAAA,MAAM,MAAA,GAAS,OAA0B,IAAI,CAAA;AAC7C,EAAA,MAAM,IAAA,GAAO,OAAuB,IAAI,CAAA;AACxC,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA,CAAS,gBAAgB,OAAA,CAAQ,CAAC,CAAA,EAAG,KAAA,IAAS,EAAE,CAAA;AAC1E,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,CAAC,CAAA;AACtC,EAAA,MAAM,SAAS,KAAA,EAAM;AACrB,EAAA,MAAMA,QAAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,KAAA,KAAU,KAAK,CAAA,IAAK,OAAA,CAAQ,CAAC,CAAA;AAEnE,EAAA,SAAA,CAAU,MAAM,WAAA,CAAY,IAAI,CAAA,EAAG,EAAE,CAAA;AAErC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAA,IAAgB,IAAA,EAAM,QAAA,CAAS,YAAY,CAAA;AAAA,EACjD,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAoB;AAClC,MAAA,IAAI,CAAC,KAAK,OAAA,EAAS,QAAA,CAAS,EAAE,MAAc,CAAA,UAAW,KAAK,CAAA;AAAA,IAC9D,CAAA;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,eAAe,MAAM,CAAA;AAC/C,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,aAAA,EAAe,MAAM,CAAA;AAAA,EACjE,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,WAAW,MAAM;AACrB,IAAA,SAAA,CAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,KAAU,KAAK,CAAC,CAAC,CAAA;AAClE,IAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,EACd,CAAA;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,KAAiB;AAC/B,IAAA,OAAA,CAAQ,KAAK,CAAA;AACb,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,MAAM,KAAK,MAAA,CAAO,OAAA;AAClB,IAAA,IAAI,EAAA,IAAM,EAAA,CAAG,KAAA,KAAU,IAAA,EAAM;AAC3B,MAAA,EAAA,CAAG,KAAA,GAAQ,IAAA;AACX,MAAA,EAAA,CAAG,aAAA,CAAc,IAAI,KAAA,CAAM,QAAA,EAAU,EAAE,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AAAA,IACzD;AACA,IAAA,IAAA,CAAK,OAAA,EAAS,aAAA,CAAiC,QAAQ,CAAA,EAAG,KAAA,EAAM;AAAA,EAClE,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAA2B;AAC5C,IAAA,MAAM,IAAA,GAAO,QAAQ,MAAA,GAAS,CAAA;AAC9B,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAI,CAAC,aAAa,SAAA,EAAW,OAAA,EAAS,GAAG,CAAA,CAAE,QAAA,CAAS,CAAA,CAAE,GAAG,CAAA,EAAG;AAC1D,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,QAAA,EAAS;AAAA,MACX;AACA,MAAA;AAAA,IACF;AACA,IAAA,MAAM,EAAA,GAAK,CAAC,CAAA,KAAc;AACxB,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,SAAA,CAAU,CAAC,CAAA;AAAA,IACb,CAAA;AACA,IAAA,IAAI,CAAA,CAAE,QAAQ,QAAA,EAAU;AACtB,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,IACf,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,WAAA,EAAa,EAAA,CAAG,KAAK,GAAA,CAAI,IAAA,EAAM,MAAA,GAAS,CAAC,CAAC,CAAA;AAAA,SAAA,IACtD,CAAA,CAAE,QAAQ,SAAA,EAAW,EAAA,CAAG,KAAK,GAAA,CAAI,CAAA,EAAG,MAAA,GAAS,CAAC,CAAC,CAAA;AAAA,SAAA,IAC/C,CAAA,CAAE,GAAA,KAAQ,MAAA,EAAQ,EAAA,CAAG,CAAC,CAAA;AAAA,SAAA,IACtB,CAAA,CAAE,GAAA,KAAQ,KAAA,EAAO,EAAA,CAAG,IAAI,CAAA;AAAA,SAAA,IACxB,CAAA,CAAE,GAAA,KAAQ,OAAA,IAAW,CAAA,CAAE,QAAQ,GAAA,EAAK;AAC3C,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,MAAM,MAAA,GAAS,QAAQ,MAAM,CAAA;AAC7B,MAAA,IAAI,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAAA,IACjC,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,KAAA,UAAe,KAAK,CAAA;AAAA,EAC3C,CAAA;AAEA,EAAA,uBACE,IAAA,CAAC,SAAI,GAAA,EAAK,IAAA,EAAM,eAAY,EAAA,EAAG,SAAA,EAAW,aAAa,MAAA,EACrD,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,oBAAA,EAAoB,QAAA,GAAW,QAAA,GAAW,EAAA,EAC7C,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,MAAA;AAAA,UACL,EAAA,EAAI,WAAW,MAAA,GAAY,EAAA;AAAA,UAC3B,IAAA;AAAA,UACA,YAAA;AAAA,UACA,QAAA,EAAU,WAAW,EAAA,GAAK,MAAA;AAAA,UAC1B,eAAa,QAAA,IAAY,MAAA;AAAA,UACzB,YAAA,EAAY,WAAW,KAAA,GAAQ,MAAA;AAAA,UAC/B,SAAA,EAAU,QAAA;AAAA,UAET,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,qBACZ,GAAA,CAAC,QAAA,EAAA,EAAqB,KAAA,EAAO,CAAA,CAAE,KAAA,EAC5B,QAAA,EAAA,CAAA,CAAE,KAAA,EAAA,EADQ,CAAA,CAAE,KAEf,CACD;AAAA;AAAA,OACH;AAAA,MACC,CAAC,QAAA,mBAAW,GAAA,CAAC,OAAA,EAAA,EAAQ,QAAA,EAAQ,MAAC,CAAA,GAAK;AAAA,KAAA,EACtC,CAAA;AAAA,IAEC,2BACC,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,EAAA;AAAA,UACA,IAAA,EAAK,UAAA;AAAA,UACL,eAAA,EAAc,SAAA;AAAA,UACd,eAAA,EAAe,IAAA;AAAA,UACf,eAAA,EAAe,MAAA;AAAA,UACf,YAAA,EAAY,CAAA,EAAG,KAAK,CAAA,EAAA,EAAKA,UAAS,KAAK,CAAA,CAAA;AAAA,UACvC,SAAS,MAAO,IAAA,GAAO,OAAA,CAAQ,KAAK,IAAI,QAAA,EAAS;AAAA,UACjD,SAAA;AAAA,UACA,SAAA,EAAU,QAAA;AAAA,UAAS,qBAAA,EAAoB,EAAA;AAAA,UAEvC,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,mBAAA,EAAkB,EAAA,EAAI,QAAA,EAAAA,UAAS,KAAA,EAAM,CAAA;AAAA,4BAC3C,GAAA,CAAC,WAAQ,IAAA,EAAY;AAAA;AAAA;AAAA,OACvB;AAAA,MACC,uBACC,GAAA,CAAC,IAAA,EAAA,EAAG,EAAA,EAAI,MAAA,EAAQ,MAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAAO,QAAA,EAAU,IAAI,kBAAA,EAAiB,EAAA,EAC9E,kBAAQ,GAAA,CAAI,CAAC,GAAG,CAAA,qBACf,IAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,IAAA,EAAK,QAAA;AAAA,UACL,eAAA,EAAe,EAAE,KAAA,KAAU,KAAA;AAAA,UAC3B,aAAA,EAAa,MAAM,MAAA,IAAU,MAAA;AAAA,UAC7B,cAAA,EAAgB,MAAM,SAAA,CAAU,CAAC,CAAA;AAAA,UACjC,OAAA,EAAS,MAAM,MAAA,CAAO,CAAA,CAAE,KAAK,CAAA;AAAA,UAE5B,QAAA,EAAA;AAAA,YAAA,CAAA,CAAE,KAAA;AAAA,YACF,CAAA,CAAE,KAAA,KAAU,KAAA,mBAAQ,GAAA,CAAC,SAAM,CAAA,GAAK;AAAA;AAAA,SAAA;AAAA,QAR5B,CAAA,CAAE;AAAA,OAUV,GACH,CAAA,GACE;AAAA,KAAA,EACN,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;;;AC1IA,IAAM,GAAA,GAAM,iCAAA;AACZ,IAAM,WAAA,GAAc,kCAAA;AACpB,IAAM,GAAA,GAAM,CAAA;AAGL,SAAS,UAAU,KAAA,EAAuB;AAC/C,EAAA,OAAO,KAAA,CAAM,SAAA,CAAU,KAAK,CAAA,CAAE,OAAA,CAAQ,UAAU,EAAE,CAAA,CAAE,WAAA,EAAY,CAAE,IAAA,EAAK;AACzE;AAGO,IAAM,aAAA,GAA8B;AAAA,EACzC,CAAC,eAAe,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,YAAY,SAAS,CAAA;AAAA,EAAG,CAAC,cAAc,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EAC1H,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAAG,CAAC,eAAe,SAAS,CAAA;AAAA,EAAG,CAAC,eAAe,SAAS,CAAA;AAAA,EAAG,CAAC,eAAe,SAAS,CAAA;AAAA,EAC/G,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAAG,CAAC,eAAe,SAAS,CAAA;AAAA,EAAG,CAAC,cAAc,SAAS,CAAA;AAAA,EAClF,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,OAAO,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,YAAY,SAAS,CAAA;AAAA,EAC3G,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EACnF,CAAC,YAAY,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAC5F,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAChH,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EACtF,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EACtF,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,YAAY,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAClI,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,OAAO,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAC/H,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EACjI,CAAC,YAAY,SAAS,CAAA;AAAA,EAAG,CAAC,QAAQ,SAAS,CAAA;AAAA,EAAG,CAAC,SAAS,SAAS,CAAA;AAAA,EAAG,CAAC,UAAU,SAAS,CAAA;AAAA,EAAG,CAAC,WAAW,SAAS,CAAA;AAAA,EAAG,CAAC,aAAa,SAAS,CAAA;AAAA,EAC1I,CAAC,gBAAgB,SAAS;AAC5B;AAOA,SAAS,IAAA,CAAQ,MAAc,OAAA,EAA6B;AAC1D,EAAA,MAAM,QAAuC,EAAC;AAC9C,EAAA,IAAI,IAAA,GAAO,IAAA;AACX,EAAA,KAAA,MAAW,CAAC,QAAQ,KAAK,CAAA,IAAK,CAAC,GAAG,OAAO,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA,GAAS,EAAE,CAAC,CAAA,CAAE,MAAM,CAAA,EAAG;AACpF,IAAA,MAAM,CAAA,GAAI,IAAI,MAAA,CAAO,CAAA,UAAA,EAAa,MAAM,CAAA,WAAA,CAAa,CAAA,CAAE,KAAK,IAAI,CAAA;AAChE,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,MAAM,QAAQ,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,CAAC,GAAG,MAAA,IAAU,CAAA,CAAA;AACzC,IAAA,KAAA,CAAM,IAAA,CAAK,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA;AAClC,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,IAAI,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,IAAI,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,MAAA,CAAO,SAAS,CAAC,CAAA;AAAA,EACpG;AACA,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AACnE;AAEA,SAAS,UAAU,IAAA,EAAwB;AACzC,EAAA,OAAO,CAAC,GAAG,IAAI,KAAK,SAAA,CAAU,MAAA,EAAW,EAAE,WAAA,EAAa,UAAA,EAAY,CAAA,CAAE,OAAA,CAAQ,IAAI,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,EAAE,OAAO,CAAA;AAC3G;AAsBO,SAAS,oBAAA,CAAqB,EAAE,MAAA,EAAQ,UAAA,GAAa,aAAA,EAAe,MAAA,GAAS,EAAC,EAAG,MAAA,GAAS,MAAA,EAAO,GAA2B,EAAC,EAAmB;AACrJ,EAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KAAmC;AACjD,IAAA,MAAM,IAAA,GAAO,UAAU,KAAK,CAAA;AAC5B,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,IAAA,MAAM,GAAA,GAAA,CAAO,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA,IAAK,EAAC,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,GAAA,CAAI,IAAA,CAAK,CAAC,CAAC,CAAA;AACrE,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,GAAA,EAAK,GAAG,KAAK,IAAA,EAAM,UAAU,CAAA,CAAE,IAAA,EAAM,CAAA;AACvD,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AAC1E,IAAA,OAAO,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,MAAA,GAAS,IAAA;AAAA,EACtC,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,KAAiC;AAC9C,IAAA,MAAM,KAAA,GAAQ,KAAK,SAAA,CAAU,KAAK,GAAG,MAAM,CAAA,CAAE,QAAQ,SAAS,CAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA;AACxE,IAAA,OAAO,OAAO,MAAA,GAAS,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA,GAAI,IAAA;AAAA,EAC/C,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAe,SAAA,KAA2D;AACzF,IAAA,MAAM,WAAA,GAAc,SAAA,EAAW,GAAA,CAAI,SAAA,CAAU,KAAK,CAAC,CAAA;AACnD,IAAA,IAAI,aAAa,OAAO,WAAA;AACxB,IAAA,MAAM,CAAA,GAAI,OAAO,KAAK,CAAA;AACtB,IAAA,MAAM,CAAA,GAAI,MAAM,KAAK,CAAA;AACrB,IAAA,IAAI,MAAA,KAAW,UAAU,CAAA,IAAK,CAAA,SAAU,EAAE,MAAA,EAAQ,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE;AAC9D,IAAA,IAAI,MAAA,KAAW,OAAA,EAAS,OAAO,CAAA,GAAI,EAAE,KAAA,EAAO,CAAA,EAAE,GAAI,CAAA,GAAI,EAAE,MAAA,EAAQ,CAAA,EAAE,GAAI,IAAA;AACtE,IAAA,IAAI,MAAA,KAAW,OAAA,EAAS,OAAO,CAAA,GAAI,EAAE,MAAA,EAAQ,CAAA,EAAE,GAAI,CAAA,GAAI,EAAE,KAAA,EAAO,CAAA,EAAE,GAAI,IAAA;AACtE,IAAA,OAAO,CAAA,GAAI,EAAE,MAAA,EAAQ,CAAA,KAAM,CAAA,GAAI,EAAE,KAAA,EAAO,CAAA,EAAE,GAAI,IAAA;AAAA,EAChD,CAAA;AACA,EAAA,OAAO,EAAE,QAAQ,KAAA,EAAO,OAAA,EAAS,aAAa,CAAC,MAAA,EAAQ,cAAc,MAAA,CAAO,MAAA,GAAS,KAAK,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAG,SAAS,CAAA,KAAM,IAAI,CAAA,EAAE;AAChJ;AAEA,IAAM,QAAQ,oBAAA,EAAqB;AAG5B,IAAM,gBAAgB,KAAA,CAAM;AAE5B,IAAM,oBAAoB,CAAC,KAAA,EAAe,cAA2D,KAAA,CAAM,OAAA,CAAQ,OAAO,SAAS;AACnI,IAAM,oBAAoB,KAAA,CAAM;AAOhC,SAAS,qBAAqB,GAAA,EAAuC;AAC1E,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAwB;AACxC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,EAAA,KAAA,MAAW,IAAA,IAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAC9B,IAAA,IAAI,KAAK,CAAA,EAAG;AACZ,IAAA,MAAM,OAAO,SAAA,CAAU,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA;AACvC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,CAAC,EAAE,IAAA,EAAK;AACrC,IAAA,MAAM,UAAU,KAAA,CAAM,KAAA,CAAM,WAAW,CAAA,IAAK,EAAC,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,IAAI,IAAA,CAAK,CAAC,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AACvF,IAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA,CAAE,OAAA,CAAQ,UAAU,EAAE,CAAA;AACjE,IAAA,MAAM,WAAW,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,4BAAA,CAA6B,KAAK,KAAK,CAAA;AAC5E,IAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,IAAK,QAAA,EAAU,GAAA,CAAI,IAAI,IAAA,EAAM,EAAE,GAAI,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,EAAE,MAAA,EAAO,GAAI,EAAC,EAAI,GAAI,QAAA,GAAW,EAAE,KAAA,EAAM,GAAI,EAAC,EAAI,CAAA;AAAA,EAC/H;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,iBAAiB,MAAA,EAA0B;AACzD,EAAA,MAAM,CAAC,KAAA,GAAQ,aAAA,EAAe,MAAM,CAAA,GAAI,MAAA;AACxC,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,KAAA;AACjC,EAAA,IAAI,OAAO,MAAA,KAAW,CAAA,SAAU,CAAA,uBAAA,EAA0B,KAAK,SAAS,MAAM,CAAA,KAAA,CAAA;AAC9E,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,MAAA;AAC1B,EAAA,OAAO,kBAAkB,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,KAAM,GAAG,CAAC,CAAA,CAAA,EAAI,IAAI,IAAI,CAAA,IAAA,EAAA,CAAQ,IAAI,CAAA,IAAK,IAAI,KAAK,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AACtG;AAGO,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,EAAE,CAAA;AAC7B,EAAA,MAAM,OAAO,CAAA,CAAE,MAAA,KAAW,CAAA,GAAI,CAAA,CAAE,MAAM,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,MAAM,CAAA,GAAI,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAAI,CAAA;AACvE,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAsB;AACrC,IAAA,MAAM,CAAA,GAAI,SAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA,GAAI,GAAA;AAC/C,IAAA,OAAO,KAAK,OAAA,GAAU,CAAA,GAAI,KAAA,GAAA,CAAA,CAAU,CAAA,GAAI,SAAS,KAAA,KAAU,GAAA;AAAA,EAC7D,CAAA;AACA,EAAA,OAAO,MAAA,GAAS,OAAA,CAAQ,CAAC,CAAA,GAAI,MAAA,GAAS,QAAQ,CAAC,CAAA,GAAI,MAAA,GAAS,OAAA,CAAQ,CAAC,CAAA;AACvE;AAMO,SAAS,iBAAiB,MAAA,EAA0B;AACzD,EAAA,MAAM,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,mBAAA,EAAsB,CAAC,CAAA,YAAA,CAAc,CAAA;AACpE,EAAA,MAAM,CAAC,KAAA,GAAQ,aAAA,EAAe,MAAM,CAAA,GAAI,IAAA;AACxC,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,KAAA;AACjC,EAAA,OAAO,CAAA,wBAAA,EAA2B,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AACnD;AC7JO,SAAS,MAAA,CAAO,EAAE,KAAA,GAAQ,EAAA,EAAI,IAAA,EAAM,IAAA,GAAO,EAAA,EAAI,KAAA,GAAQ,QAAA,EAAU,SAAA,GAAY,EAAA,EAAG,EAAgB;AACrG,EAAA,MAAM,QAAA,GAAW,IAAA,IAAQ,iBAAA,CAAkB,KAAK,CAAA;AAChD,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,MAAA,IAAU,EAAC;AACnC,EAAA,IAAI,SAAS,KAAA,EAAO;AAGlB,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAI,KAAK,SAAA,CAAU,MAAA,EAAW,EAAE,WAAA,EAAa,UAAA,EAAY,CAAA,CAAE,OAAA,CAAQ,SAAS,KAAK,CAAC,EAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA;AAC1H,IAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,GAAS,CAAA;AAC7B,IAAA,MAAMC,MAAAA,GAAuB;AAAA,MAC3B,QAAA,EAAU,IAAA;AAAA,MACV,MAAA,EAAQ,IAAA;AAAA,MACR,UAAU,IAAA,CAAK,KAAA,CAAM,IAAA,IAAQ,KAAA,GAAQ,OAAO,GAAA,CAAI,CAAA;AAAA,MAChD,GAAI,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,EAAE,YAAY,gBAAA,CAAiB,MAAM,CAAA,EAAG,CAAC,WAAqB,GAAG,MAAA,CAAO,CAAC,CAAA,KAAM;AAAC,KAC1G;AACA,IAAA,uBACEC,GAAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,MAAA,EAAO,eAAY,EAAA,EAAG,WAAA,EAAU,OAAA,EAAQ,YAAA,EAAY,KAAA,IAAS,MAAA,EAAW,gBAAc,MAAA,CAAO,MAAA,GAAS,CAAA,IAAK,MAAA,EAAW,YAAA,EAAY,KAAA,EAAO,SAAA,EAAW,SAAA,IAAa,MAAA,EAAW,KAAA,EAAOD,MAAAA,EAClM,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,OAAO,CAAA,qBACjBC,GAAAA,CAAC,MAAA,EAAA,EAA2B,KAAA,EAAO,CAAA,GAAI,CAAA,GAAI,EAAE,iBAAA,EAAmB,QAAA,EAAU,MAAA,EAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,KAAM,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,EAC3H,QAAA,EAAA,KAAA,EAAA,EADQ,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAExB,CACD,CAAA,EACH,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AACjC,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,IAAI,IAAI,CAAA,GAAI,OAAA,GAAU,IAAA,CAAK,KAAK,CAAC,CAAA,KAAM,CAAA,GAAI,IAAI,IAAI,MAAA,GAAS,MAAA;AAC1F,EAAA,MAAM,KAAA,GAAuB,EAAE,KAAA,EAAO,IAAA,EAAM,QAAQ,IAAA,EAAM,UAAA,EAAY,gBAAA,CAAiB,MAAM,CAAA,EAAE;AAC/F,EAAA,uBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,QAAO,aAAA,EAAY,EAAA,EAAG,WAAA,EAAW,IAAA,EAAM,YAAA,EAAY,KAAA,EAAO,SAAA,EAAW,SAAA,IAAa,QAAW,KAAA,EAAc,CAAA;AACtI;AC5CO,IAAM,iBAAA,GAAoB,CAAA,mIAAA;AAEjC,SAAS,OAAA,GAAiB;AACxB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,eAAA,CAAgB,YAAA,CAAa,YAAY,CAAA;AAC/D,EAAA,IAAI,IAAA,KAAS,OAAA,IAAW,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AAChD,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,CAAE,UAAU,MAAA,GAAS,OAAA;AAC9E;AAMO,SAAS,WAAA,CAAY,EAAE,SAAA,GAAY,EAAA,EAAI,WAAA,GAAc,EAAE,KAAA,EAAO,SAAA,EAAW,IAAA,EAAM,SAAA,EAAU,EAAE,EAA0E;AAC1K,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,SAAuB,IAAI,CAAA;AACrD,EAAAC,UAAU,MAAM,QAAA,CAAS,SAAS,CAAA,EAAG,EAAE,CAAA;AAEvC,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,IAAA,GAAc,OAAA,EAAQ,KAAM,MAAA,GAAS,OAAA,GAAU,MAAA;AACrD,IAAA,QAAA,CAAS,eAAA,CAAgB,YAAA,CAAa,YAAA,EAAc,IAAI,CAAA;AACxD,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,SAAS,IAAI,CAAA;AAAA,IACpC,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,QAAA,CAAS,cAAc,wCAAwC,CAAA,EAAG,aAAa,SAAA,EAAW,WAAA,CAAY,IAAI,CAAC,CAAA;AAC3G,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf,CAAA;AAEA,EAAA,MAAM,OAAO,KAAA,KAAU,MAAA;AACvB,EAAA,uBACEF,GAAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,SAAS,MAAA,EAAQ,SAAA,EAAsB,YAAA,EAAY,IAAA,GAAO,yBAAyB,uBAAA,EAAyB,cAAA,EAAc,KAAA,KAAU,IAAA,GAAO,SAAY,IAAA,EAC1K,QAAA,EAAA,IAAA,mBACCG,IAAAA,CAAC,SAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,SAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,gBAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,OAAA,EAAQ,eAAY,MAAA,EACpI,QAAA,EAAA;AAAA,oBAAAH,IAAC,QAAA,EAAA,EAAO,EAAA,EAAG,MAAK,EAAA,EAAG,IAAA,EAAK,GAAE,GAAA,EAAI,CAAA;AAAA,oBAC9BA,GAAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,oGAAA,EAAqG;AAAA,GAAA,EAC/G,CAAA,mBAEAA,GAAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,aAAA,EAAY,MAAA,EAC3J,QAAA,kBAAAA,GAAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,8CAAA,EAA+C,CAAA,EACzD,CAAA,EAEJ,CAAA;AAEJ;AC3CO,SAAS,iBAAiB,EAAE,OAAA,EAAS,MAAM,QAAA,EAAU,KAAA,GAAQ,KAAI,EAAuD;AAC7H,EAAAE,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,EAAE,eAAA,IAAmB,SAAA,CAAA,EAAY;AACjD,IAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,aAAA,CAAc,QAAA,CAAS,GAAA,EAAK,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAC7F,IAAA,IAAI,QAAA,CAAS,UAAA,KAAe,UAAA,EAAY,QAAA,EAAS;AAAA,gBACrC,gBAAA,CAAiB,MAAA,EAAQ,UAAU,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC/D,CAAA,EAAG,CAAC,OAAA,EAAS,GAAA,EAAK,KAAK,CAAC,CAAA;AAC1B;AAMO,SAAS,UAAA,CAAW,EAAE,SAAA,GAAY,EAAA,EAAI,QAAQ,cAAA,EAAgB,OAAA,GAAU,+EAAwE,EAA6D;AAClN,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAID,SAA8B,IAAI,CAAA;AAC5D,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAIA,SAAS,KAAK,CAAA;AACpC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,IAAI,CAAA;AAE/C,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,aAAa,MAAA,CAAO,UAAA,CAAW,4BAA4B,CAAA,CAAE,OAAA,IAAY,UAAmD,UAAA,KAAe,IAAA;AACjJ,IAAA,YAAA,CAAa,UAAU,CAAA;AACvB,IAAA,MAAA,CAAO,oBAAoB,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA,IAAK,CAAC,UAAU,CAAA;AACnE,IAAA,MAAM,QAAA,GAAW,CAAC,CAAA,KAAa;AAC7B,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,QAAA,CAAS,CAAiB,CAAA;AAAA,IAC5B,CAAA;AACA,IAAA,MAAM,WAAA,GAAc,MAAM,YAAA,CAAa,IAAI,CAAA;AAC3C,IAAA,MAAA,CAAO,gBAAA,CAAiB,uBAAuB,QAAQ,CAAA;AACvD,IAAA,MAAA,CAAO,gBAAA,CAAiB,gBAAgB,WAAW,CAAA;AACnD,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,mBAAA,CAAoB,uBAAuB,QAAQ,CAAA;AAC1D,MAAA,MAAA,CAAO,mBAAA,CAAoB,gBAAgB,WAAW,CAAA;AAAA,IACxD,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,IAAI,WAAW,OAAO,IAAA;AACtB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,uBACEF,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,SAAA;AAAA,QACA,SAAS,YAAY;AACnB,UAAA,MAAM,MAAM,MAAA,EAAO;AACnB,UAAA,MAAM,KAAA,CAAM,UAAA;AACZ,UAAA,QAAA,CAAS,IAAI,CAAA;AAAA,QACf,CAAA;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AACA,EAAA,OAAO,sBAAMA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAuB,mBAAQ,CAAA,GAAO,IAAA;AACxD","file":"ui.js","sourcesContent":["import { useEffect, useId, useRef, useState } from 'react'\n\nexport type SelectOption = { value: string; label: string }\n\nconst Chevron = ({ open = false, floating = false }: { open?: boolean; floating?: boolean }) => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" data-select-chevron={floating ? 'floating' : ''} data-open={open || undefined}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n)\nconst Check = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n)\n\nexport type SelectProps = {\n id: string\n name: string\n options: SelectOption[]\n defaultValue?: string\n /** Etiqueta accesible (la visible la pone el llamador con <label htmlFor={id}>). */\n label: string\n className?: string\n}\n\n/**\n * Selector con mejora progresiva. Sin JavaScript (o antes de hidratar) es un <select> nativo dentro de un formulario;\n * con JavaScript se reemplaza por un listbox propio (teclado completo, objetivo táctil de 44 px, tema claro/oscuro).\n * El <select> nativo sigue en el DOM como fuente de verdad: al elegir se cambia su valor y se emite \"change\", así un\n * formulario con onChange → submit (filtros por URL) no nota la diferencia.\n * Estilos: clases `select` (ver ui.css) y los tokens --background, --foreground, --border, --tint, --primary.\n */\nexport function Select({ id, name, options, defaultValue, label, className = '' }: SelectProps) {\n const native = useRef<HTMLSelectElement>(null)\n const root = useRef<HTMLDivElement>(null)\n const [enhanced, setEnhanced] = useState(false)\n const [open, setOpen] = useState(false)\n const [value, setValue] = useState(defaultValue ?? options[0]?.value ?? '')\n const [active, setActive] = useState(0)\n const listId = useId()\n const current = options.find((o) => o.value === value) ?? options[0]\n\n useEffect(() => setEnhanced(true), [])\n // El valor lo puede cambiar la URL (atrás/adelante): se sincroniza.\n useEffect(() => {\n if (defaultValue != null) setValue(defaultValue)\n }, [defaultValue])\n\n useEffect(() => {\n if (!open) return\n const onDown = (e: PointerEvent) => {\n if (!root.current?.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('pointerdown', onDown)\n return () => document.removeEventListener('pointerdown', onDown)\n }, [open])\n\n const openList = () => {\n setActive(Math.max(0, options.findIndex((o) => o.value === value)))\n setOpen(true)\n }\n\n const choose = (next: string) => {\n setOpen(false)\n setValue(next)\n const el = native.current\n if (el && el.value !== next) {\n el.value = next\n el.dispatchEvent(new Event('change', { bubbles: true }))\n }\n root.current?.querySelector<HTMLButtonElement>('button')?.focus()\n }\n\n const onKeyDown = (e: React.KeyboardEvent) => {\n const last = options.length - 1\n if (!open) {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(e.key)) {\n e.preventDefault()\n openList()\n }\n return\n }\n const go = (i: number) => {\n e.preventDefault()\n setActive(i)\n }\n if (e.key === 'Escape') {\n e.preventDefault()\n setOpen(false)\n } else if (e.key === 'ArrowDown') go(Math.min(last, active + 1))\n else if (e.key === 'ArrowUp') go(Math.max(0, active - 1))\n else if (e.key === 'Home') go(0)\n else if (e.key === 'End') go(last)\n else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n const picked = options[active]\n if (picked) choose(picked.value)\n } else if (e.key === 'Tab') setOpen(false)\n }\n\n return (\n <div ref={root} data-select=\"\" className={className || undefined}>\n <div data-select-native={enhanced ? 'hidden' : ''}>\n <select\n ref={native}\n id={enhanced ? undefined : id}\n name={name}\n defaultValue={defaultValue}\n tabIndex={enhanced ? -1 : undefined}\n aria-hidden={enhanced || undefined}\n aria-label={enhanced ? label : undefined}\n className=\"select\"\n >\n {options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n {!enhanced ? <Chevron floating /> : null}\n </div>\n\n {enhanced ? (\n <>\n <button\n type=\"button\"\n id={id}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-label={`${label}: ${current?.label}`}\n onClick={() => (open ? setOpen(false) : openList())}\n onKeyDown={onKeyDown}\n className=\"select\" data-select-trigger=\"\"\n >\n <span data-select-value=\"\">{current?.label}</span>\n <Chevron open={open} />\n </button>\n {open ? (\n <ul id={listId} role=\"listbox\" aria-label={label} tabIndex={-1} data-select-list=\"\">\n {options.map((o, i) => (\n <li\n key={o.value}\n role=\"option\"\n aria-selected={o.value === value}\n data-active={i === active || undefined}\n onPointerEnter={() => setActive(i)}\n onClick={() => choose(o.value)}\n >\n {o.label}\n {o.value === value ? <Check /> : null}\n </li>\n ))}\n </ul>\n ) : null}\n </>\n ) : null}\n </div>\n )\n}\n","/**\n * Muestras de variante (color, combinación o emoji), pura y sin DOM: sirve en servidor y cliente.\n *\n * El MOTOR es genérico; los DICCIONARIOS no. El SDK solo trae colores básicos (ropa, acabados). Los sabores, emojis y cualquier\n * vocabulario de un giro (suplementos, café, moda…) los inyecta la tienda con `createSwatchResolver`, o llegan del catálogo\n * como atributo (`parseSwatchAttribute`), que siempre manda sobre cualquier diccionario.\n */\n\n/**\n * Lo que dibuja una muestra: colores planos, emoji, o AMBOS (una píldora pastel con la mezcla de colores y los emoji encima).\n * Al menos uno de los dos viene lleno.\n */\nexport type SwatchSpec = { colors?: string[]; emoji?: string }\n\n/** [frase normalizada (minúsculas, sin acentos), un color hex o varios] */\nexport type ColorEntry = [phrase: string, color: string | string[]]\n/** [frase normalizada, emoji o varios emoji] */\nexport type EmojiEntry = [phrase: string, emoji: string]\n\n/** Qué dibujar primero cuando hay color y emoji para el mismo nombre. */\nexport type SwatchPrefer = 'auto' | 'color' | 'emoji' | 'both'\n\nconst HEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i\nconst HEX_IN_TEXT = /#(?:[0-9a-f]{6}|[0-9a-f]{3})\\b/gi\nconst MAX = 4\n\n/** Minúsculas, sin acentos, sin puntuación suelta. \"Piña\" → \"pina\". */\nexport function normalize(value: string): string {\n return value.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim()\n}\n\n/** Colores básicos (es/en) para ropa y acabados. Sin vocabulario de ningún giro en particular. */\nexport const defaultColors: ColorEntry[] = [\n ['azul marino', '#14213d'], ['navy', '#14213d'], ['azul rey', '#2447d6'], ['azul cielo', '#6ec1f0'], ['celeste', '#8fd0f5'],\n ['verde militar', '#4b5320'], ['verde oliva', '#6b7a2a'], ['verde limon', '#b8e03a'], ['verde menta', '#8fe0b5'],\n ['rosa mexicano', '#e4007c'], ['gris oscuro', '#4a4f57'], ['gris claro', '#cfd3d8'],\n ['rojo', '#e0262d'], ['red', '#e0262d'], ['vino', '#6d1a36'], ['guinda', '#7a1f3d'], ['burgundy', '#6d1a36'],\n ['azul', '#2f5bea'], ['blue', '#2f5bea'], ['verde', '#2fa84f'], ['green', '#2fa84f'],\n ['amarillo', '#ffd21f'], ['yellow', '#ffd21f'], ['naranja', '#ff8a1f'], ['orange', '#ff8a1f'],\n ['morado', '#7b3fc4'], ['purpura', '#7b3fc4'], ['purple', '#7b3fc4'], ['violeta', '#8a4fd6'], ['lila', '#c4a5f0'],\n ['rosa', '#ff7eb6'], ['pink', '#ff7eb6'], ['fucsia', '#e4007c'], ['magenta', '#d4119e'],\n ['negro', '#111111'], ['black', '#111111'], ['blanco', '#ffffff'], ['white', '#ffffff'],\n ['gris', '#9aa0a8'], ['gray', '#9aa0a8'], ['grey', '#9aa0a8'], ['plata', '#c0c4cc'], ['plateado', '#c0c4cc'], ['silver', '#c0c4cc'],\n ['dorado', '#d4a72c'], ['oro', '#d4a72c'], ['gold', '#d4a72c'], ['cafe', '#7a4a2b'], ['marron', '#7a4a2b'], ['brown', '#7a4a2b'],\n ['beige', '#e6d3b3'], ['crema', '#f4ead2'], ['hueso', '#f1ecde'], ['arena', '#d9c39a'], ['khaki', '#b8a77a'], ['camel', '#b9824a'],\n ['turquesa', '#1fc8c8'], ['aqua', '#34d3d3'], ['coral', '#ff6f61'], ['salmon', '#ff8f7a'], ['mostaza', '#d9a521'], ['terracota', '#c4623f'],\n ['transparente', '#e8edf2'],\n]\n\n/**\n * Busca en el texto COMPLETO las frases del diccionario como palabras (plural con \"s\" opcional), la más larga primero, y las\n * devuelve en el orden en que se leen. Se tacha lo encontrado: \"azul\" no vuelve a salir dentro de \"azul marino\". Al no partir\n * el texto por \"y\"/\"and\", las frases con conectores (\"cookies and cream\") se resuelven como frase.\n */\nfunction scan<T>(text: string, entries: [string, T][]): T[] {\n const found: { index: number; value: T }[] = []\n let rest = text\n for (const [phrase, value] of [...entries].sort((a, b) => b[0].length - a[0].length)) {\n const m = new RegExp(`(^|[^a-z])${phrase}s?(?![a-z])`).exec(rest)\n if (!m) continue\n const start = m.index + (m[1]?.length ?? 0)\n found.push({ index: start, value })\n rest = rest.slice(0, start) + ' '.repeat(phrase.length + 1) + rest.slice(start + phrase.length + 1)\n }\n return found.sort((a, b) => a.index - b.index).map((f) => f.value)\n}\n\nfunction graphemes(text: string): string[] {\n return [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text)].map((g) => g.segment)\n}\n\nexport type SwatchResolverOptions = {\n /** Diccionario de colores. Default: `defaultColors`. Para sumar vocabulario: `[...defaultColors, ...tusColores]`. */\n colors?: ColorEntry[]\n /** Diccionario de emoji (sin default: es vocabulario del giro). */\n emojis?: EmojiEntry[]\n /** Qué dibujar si hay color y emoji: `auto`/`color` = color primero, `emoji` = emoji primero, `both` = píldora pastel con colores y emoji. */\n prefer?: SwatchPrefer\n}\n\nexport type SwatchResolver = {\n /** Colores del nombre (\"Rojo / Negro\", \"#ff8800\"), en orden de lectura, o `null`. */\n colors(value: string): string[] | null\n /** Emoji(s) del nombre (hasta 3, sin repetir), o `null`. */\n emoji(value: string): string | null\n /** Muestra de una variante: primero el atributo del catálogo, luego el nombre según `prefer`. */\n resolve(value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null\n /** ¿Todos los valores de una opción tienen muestra? */\n hasSwatches(values: string[], attribute?: Map<string, SwatchSpec>): boolean\n}\n\nexport function createSwatchResolver({ colors: colorTable = defaultColors, emojis = [], prefer = 'auto' }: SwatchResolverOptions = {}): SwatchResolver {\n const colors = (value: string): string[] | null => {\n const text = normalize(value)\n if (!text) return null\n const hex = (text.match(HEX_IN_TEXT) ?? []).filter((h) => HEX.test(h))\n const found = [...hex, ...scan(text, colorTable).flat()]\n const unique = found.filter((c, i) => found.indexOf(c) === i).slice(0, MAX)\n return unique.length > 0 ? unique : null\n }\n const emoji = (value: string): string | null => {\n const parts = scan(normalize(value), emojis).flatMap(graphemes)\n const unique = parts.filter((e, i) => parts.indexOf(e) === i).slice(0, 3)\n return unique.length > 0 ? unique.join('') : null\n }\n const resolve = (value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null => {\n const fromCatalog = attribute?.get(normalize(value))\n if (fromCatalog) return fromCatalog\n const c = colors(value)\n const e = emoji(value)\n if (prefer === 'both' && c && e) return { colors: c, emoji: e }\n if (prefer === 'emoji') return e ? { emoji: e } : c ? { colors: c } : null\n if (prefer === 'color') return c ? { colors: c } : e ? { emoji: e } : null\n return c ? { colors: c } : e ? { emoji: e } : null\n }\n return { colors, emoji, resolve, hasSwatches: (values, attribute) => values.length > 0 && values.every((v) => resolve(v, attribute) !== null) }\n}\n\nconst basic = createSwatchResolver()\n\n/** Colores básicos del nombre (sin vocabulario de giro). Para uno propio: `createSwatchResolver`. */\nexport const resolveSwatch = basic.colors\n/** Muestra de una variante con solo colores básicos. Para uno propio: `createSwatchResolver`. */\nexport const resolveSwatchSpec = (value: string, attribute?: Map<string, SwatchSpec>): SwatchSpec | null => basic.resolve(value, attribute)\nexport const optionHasSwatches = basic.hasSwatches\n\n/**\n * Atributo del producto con el color o emoji de cada variante, como lo siembra el catálogo (OPS):\n * `\"Mora Azul:#3d4fd6|Fresa Kiwi:#ff4d6d+#8bc34a 🍓🥝|Natural:🥛\"`. Cada valor es un hex, varios hex con \"+\" (combinación), emoji, o colores y emoji juntos.\n * Es la fuente de verdad: manda sobre cualquier diccionario.\n */\nexport function parseSwatchAttribute(raw: unknown): Map<string, SwatchSpec> {\n const map = new Map<string, SwatchSpec>()\n if (typeof raw !== 'string') return map\n for (const part of raw.split('|')) {\n const i = part.lastIndexOf(':')\n if (i <= 0) continue\n const name = normalize(part.slice(0, i))\n const value = part.slice(i + 1).trim()\n const colors = (value.match(HEX_IN_TEXT) ?? []).filter((c) => HEX.test(c)).slice(0, MAX)\n const emoji = value.replace(HEX_IN_TEXT, '').replace(/[+\\s]/g, '')\n const hasEmoji = emoji.length > 0 && /\\p{Extended_Pictographic}/u.test(emoji)\n if (colors.length > 0 || hasEmoji) map.set(name, { ...(colors.length > 0 ? { colors } : {}), ...(hasEmoji ? { emoji } : {}) })\n }\n return map\n}\n\n/** Fondo CSS plano: un color liso, dos mitades, o sectores iguales (hasta 4). */\nexport function swatchBackground(colors: string[]): string {\n const [first = 'transparent', second] = colors\n if (second === undefined) return first\n if (colors.length === 2) return `linear-gradient(90deg, ${first} 50%, ${second} 50%)`\n const step = 360 / colors.length\n return `conic-gradient(${colors.map((c, i) => `${c} ${i * step}deg ${(i + 1) * step}deg`).join(', ')})`\n}\n\n/** Luminancia relativa (0 negro – 1 blanco) de un color hex, para decidir si hace falta un aro. */\nexport function luminance(hex: string): number {\n const h = hex.replace('#', '')\n const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h\n const channel = (i: number): number => {\n const v = parseInt(full.slice(i, i + 2), 16) / 255\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4\n }\n return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4)\n}\n\n/**\n * Fondo pastel de una píldora: cada color mezclado con blanco (queda claro y suave en claro y oscuro), un degradado suave entre\n * ellos si son varios. Con ese fondo el emoji siempre contrasta.\n */\nexport function pastelBackground(colors: string[]): string {\n const soft = colors.map((c) => `color-mix(in srgb, ${c} 26%, white)`)\n const [first = 'transparent', second] = soft\n if (second === undefined) return first\n return `linear-gradient(100deg, ${soft.join(', ')})`\n}\n","import type { CSSProperties } from 'react'\nimport { luminance, pastelBackground, resolveSwatchSpec, swatchBackground, type SwatchSpec } from './swatch-colors'\n\nexport type SwatchProps = {\n /** Nombre de la variante; se resuelve con los colores básicos del SDK. Para vocabulario propio resuelve tú con `createSwatchResolver` y pasa `spec`. */\n value?: string\n /** Lo que se dibuja (color(es) o emoji), ya resuelto: del catálogo (`parseSwatchAttribute`) o de tu `createSwatchResolver`. Manda sobre `value`. */\n spec?: SwatchSpec | null\n size?: number\n shape?: 'circle' | 'square'\n className?: string\n}\n\n/**\n * Muestra de color 2D para variantes: plana, sin sombras ni brillos y sin borde, salvo un aro mínimo cuando el color\n * se perdería contra el fondo (blanco en tema claro, negro en tema oscuro). Las combinaciones se dibujan en partes iguales.\n * Es decorativa (aria-hidden): el nombre de la variante debe ir siempre como texto junto a ella.\n * Con `spec.emoji` dibuja el emoji. Devuelve null si no reconoce nada, para que el llamador muestre solo el texto.\n */\nexport function Swatch({ value = '', spec, size = 20, shape = 'circle', className = '' }: SwatchProps) {\n const resolved = spec ?? resolveSwatchSpec(value)\n if (!resolved) return null\n const colors = resolved.colors ?? []\n if (resolved.emoji) {\n // Badge: círculo (un emoji) o píldora (mezcla) con fondo pastel de los colores del sabor y el emoji encima; sin colores, fondo\n // neutro de superficie. En la mezcla los emoji se montan un poco, el primero arriba. Así se ve qué emoji forman cada grupo.\n const parts = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(resolved.emoji)].map((g) => g.segment)\n const mixed = parts.length > 1\n const style: CSSProperties = {\n minWidth: size,\n height: size,\n fontSize: Math.round(size * (mixed ? 0.56 : 0.6)),\n ...(colors.length > 0 ? { background: pastelBackground(colors), ['--sw-ring' as string]: colors[0] } : {}),\n }\n return (\n <span aria-hidden=\"true\" data-swatch=\"\" data-kind=\"emoji\" data-mixed={mixed || undefined} data-colored={colors.length > 0 || undefined} data-shape={shape} className={className || undefined} style={style}>\n {parts.map((emoji, i) => (\n <span key={`${emoji}-${i}`} style={i > 0 ? { marginInlineStart: '-0.3em', zIndex: parts.length - i } : { zIndex: parts.length }}>\n {emoji}\n </span>\n ))}\n </span>\n )\n }\n if (colors.length === 0) return null\n const lums = colors.map(luminance)\n const edge = lums.some((l) => l > 0.82) ? 'light' : lums.some((l) => l < 0.04) ? 'dark' : undefined\n const style: CSSProperties = { width: size, height: size, background: swatchBackground(colors) }\n return <span aria-hidden=\"true\" data-swatch=\"\" data-edge={edge} data-shape={shape} className={className || undefined} style={style} />\n}\n","import { useEffect, useState } from 'react'\n\ntype Theme = 'light' | 'dark'\n\n/** Script de cabecera: aplica el tema guardado antes de pintar (sin parpadeo). Sin preferencia guardada manda el sistema. */\nexport const THEME_INIT_SCRIPT = `try{var t=localStorage.getItem(\"theme\");if(t===\"light\"||t===\"dark\")document.documentElement.setAttribute(\"data-theme\",t)}catch(e){}`\n\nfunction current(): Theme {\n const attr = document.documentElement.getAttribute('data-theme')\n if (attr === 'light' || attr === 'dark') return attr\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\n/**\n * Botón claro/oscuro. El estado real se lee del DOM tras hidratar (el servidor no sabe la preferencia).\n * Guarda la elección en localStorage (\"theme\") y fija `html[data-theme]`; los tokens de la tienda reaccionan a eso.\n */\nexport function ThemeToggle({ className = '', themeColors = { light: '#ffffff', dark: '#000000' } }: { className?: string; themeColors?: { light: string; dark: string } }) {\n const [theme, setTheme] = useState<Theme | null>(null)\n useEffect(() => setTheme(current()), [])\n\n const toggle = () => {\n const next: Theme = current() === 'dark' ? 'light' : 'dark'\n document.documentElement.setAttribute('data-theme', next)\n try {\n localStorage.setItem('theme', next)\n } catch {\n /* modo privado: el cambio dura la sesión */\n }\n document.querySelector('meta[name=\"theme-color\"][data-dynamic]')?.setAttribute('content', themeColors[next])\n setTheme(next)\n }\n\n const dark = theme === 'dark'\n return (\n <button type=\"button\" onClick={toggle} className={className} aria-label={dark ? 'Cambiar a tema claro' : 'Cambiar a tema oscuro'} aria-pressed={theme === null ? undefined : dark}>\n {dark ? (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </svg>\n ) : (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\" />\n </svg>\n )}\n </button>\n )\n}\n","import { useEffect, useState } from 'react'\n\ntype InstallEvent = Event & { prompt: () => Promise<void>; userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }> }\n\n/** Registra el service worker (solo si `enabled`, normalmente producción; requiere HTTPS o localhost). */\nexport function useServiceWorker({ enabled, url = '/sw.js', scope = '/' }: { enabled: boolean; url?: string; scope?: string }) {\n useEffect(() => {\n if (!enabled || !('serviceWorker' in navigator)) return\n const register = () => navigator.serviceWorker.register(url, { scope }).catch(() => undefined)\n if (document.readyState === 'complete') register()\n else window.addEventListener('load', register, { once: true })\n }, [enabled, url, scope])\n}\n\n/**\n * Botón \"Instalar app\": aparece solo cuando el navegador ofrece la instalación (Chrome, Edge, Android).\n * En iPhone/iPad no existe ese evento: muestra la instrucción de Compartir → Agregar a pantalla de inicio.\n */\nexport function InstallApp({ className = '', label = 'Instalar app', iosHint = 'Para instalar: toca Compartir y luego «Agregar a pantalla de inicio».' }: { className?: string; label?: string; iosHint?: string }) {\n const [event, setEvent] = useState<InstallEvent | null>(null)\n const [ios, setIos] = useState(false)\n const [installed, setInstalled] = useState(true)\n\n useEffect(() => {\n const standalone = window.matchMedia('(display-mode: standalone)').matches || (navigator as Navigator & { standalone?: boolean }).standalone === true\n setInstalled(standalone)\n setIos(/iphone|ipad|ipod/i.test(navigator.userAgent) && !standalone)\n const onPrompt = (e: Event) => {\n e.preventDefault()\n setEvent(e as InstallEvent)\n }\n const onInstalled = () => setInstalled(true)\n window.addEventListener('beforeinstallprompt', onPrompt)\n window.addEventListener('appinstalled', onInstalled)\n return () => {\n window.removeEventListener('beforeinstallprompt', onPrompt)\n window.removeEventListener('appinstalled', onInstalled)\n }\n }, [])\n\n if (installed) return null\n if (event) {\n return (\n <button\n type=\"button\"\n className={className}\n onClick={async () => {\n await event.prompt()\n await event.userChoice\n setEvent(null)\n }}\n >\n {label}\n </button>\n )\n }\n return ios ? <p className={className}>{iosHint}</p> : null\n}\n"]}
@@ -0,0 +1,124 @@
1
+ import { barcodeValue, barcodeGeometry } from './chunk-TXEYBDFG.js';
2
+
3
+ // src/account/voucher-document.ts
4
+ function esc(s) {
5
+ return s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
6
+ }
7
+ var ES = {
8
+ title: "Ficha de pago",
9
+ total: "Total a pagar",
10
+ reference: "Referencia",
11
+ clabe: "CLABE",
12
+ expires: "Vence",
13
+ expiresNote: "Pasada esa fecha la ficha deja de ser v\xE1lida.",
14
+ order: "Pedido",
15
+ barcode: "C\xF3digo de barras",
16
+ print: "Imprimir ficha",
17
+ footer: "Tu pedido se genera cuando se confirma el pago. Esta ficha es de un solo uso; no la compartas.",
18
+ stepsCash: [
19
+ "Acude a la tienda OXXO (o el comercio indicado) y di que vas a hacer un pago de servicio en efectivo.",
20
+ "Muestra el c\xF3digo de barras o dicta la referencia y paga el monto exacto.",
21
+ "Conserva tu comprobante: confirmaremos tu pago autom\xE1ticamente."
22
+ ],
23
+ stepsSpei: ["Entra a la banca en l\xEDnea o app de tu banco.", "Haz una transferencia SPEI a la CLABE indicada por el monto exacto.", "Conserva tu comprobante: confirmaremos tu pago autom\xE1ticamente."],
24
+ methods: { oxxo: "OXXO", spei: "Transferencia SPEI", bank_transfer: "Transferencia bancaria", bank_deposit: "Dep\xF3sito bancario", cash: "Pago en efectivo" },
25
+ cash: "Pago en efectivo"
26
+ };
27
+ var EN = {
28
+ title: "Payment voucher",
29
+ total: "Amount to pay",
30
+ reference: "Reference",
31
+ clabe: "CLABE",
32
+ expires: "Expires",
33
+ expiresNote: "After that date the voucher is no longer valid.",
34
+ order: "Order",
35
+ barcode: "Barcode",
36
+ print: "Print voucher",
37
+ footer: "Your order is created when the payment is confirmed. This voucher is single-use; do not share it.",
38
+ stepsCash: [
39
+ "Go to an OXXO store (or the store indicated) and say you want to make a cash service payment.",
40
+ "Show the barcode or read out the reference and pay the exact amount.",
41
+ "Keep your receipt: we will confirm your payment automatically."
42
+ ],
43
+ stepsSpei: ["Open your bank online or app.", "Make a SPEI transfer to the CLABE below for the exact amount.", "Keep your receipt: we will confirm your payment automatically."],
44
+ methods: { oxxo: "OXXO", spei: "SPEI transfer", bank_transfer: "Bank transfer", bank_deposit: "Bank deposit", cash: "Cash payment" },
45
+ cash: "Cash payment"
46
+ };
47
+ var CSS = `
48
+ @page { size: A4; margin: 18mm; }
49
+ * { box-sizing: border-box; }
50
+ body { margin: 0; font: 14px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: #111; background: #fff; }
51
+ main { max-width: 174mm; margin: 0 auto; padding: 24px 16px; }
52
+ h1 { font-size: 22px; margin: 0; }
53
+ .muted { color: #555; }
54
+ .head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; border-bottom: 3px solid #111; padding-bottom: 12px; }
55
+ .amount { font-size: 28px; font-weight: 700; text-align: right; }
56
+ .box { border: 1px solid #111; padding: 14px 16px; margin-top: 18px; }
57
+ .label { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: #555; }
58
+ .value { font: 700 22px/1.3 ui-monospace, "SF Mono", Menlo, Consolas, monospace; word-break: break-all; letter-spacing: .04em; }
59
+ .bar { margin-top: 18px; text-align: center; }
60
+ .bar svg { max-width: 100%; height: auto; }
61
+ .steps { margin: 18px 0 0; padding-left: 20px; }
62
+ .note { margin-top: 18px; font-size: 12px; }
63
+ .pre { white-space: pre-line; }
64
+ .actions { margin-top: 24px; display: flex; gap: 12px; }
65
+ .actions button { font: inherit; padding: 10px 18px; border: 1px solid #111; background: #111; color: #fff; cursor: pointer; }
66
+ @media print { .actions { display: none; } main { padding: 0; } }
67
+ `;
68
+ function formatMoney(m, locale) {
69
+ if (!m) return "";
70
+ try {
71
+ return new Intl.NumberFormat(locale, { style: "currency", currency: m.currency_code }).format(Number(m.amount));
72
+ } catch {
73
+ return `${m.amount} ${m.currency_code}`;
74
+ }
75
+ }
76
+ function formatDate(iso, locale, timeZone) {
77
+ if (!iso) return "";
78
+ const d = new Date(iso);
79
+ if (Number.isNaN(d.getTime())) return "";
80
+ try {
81
+ return d.toLocaleString(locale, { dateStyle: "long", timeStyle: "short", ...timeZone ? { timeZone } : {} });
82
+ } catch {
83
+ return d.toISOString();
84
+ }
85
+ }
86
+ function barcodeSvg(value, label) {
87
+ const g = barcodeGeometry(value);
88
+ if (!g) return null;
89
+ const rects = g.rects.map((r) => `<rect x="${r.x}" y="0" width="${r.w}" height="${g.height}"/>`).join("");
90
+ return `<svg viewBox="0 0 ${g.width} ${g.height}" width="${g.width}" height="${g.height}" role="img" aria-label="${esc(label)} ${esc(value)}" shape-rendering="crispEdges" fill="#000">${rects}</svg>`;
91
+ }
92
+ function renderVoucherDocument(v, opts = {}) {
93
+ const locale = opts.locale ?? "es-MX";
94
+ const t = locale.toLowerCase().startsWith("en") ? EN : ES;
95
+ const shop = opts.shopName || "";
96
+ const method = v.method ? Object.prototype.hasOwnProperty.call(t.methods, v.method.toLowerCase()) ? t.methods[v.method.toLowerCase()] : v.method : t.cash;
97
+ const isSpei = !!v.clabe && !v.reference;
98
+ const code = barcodeValue(v);
99
+ const svg = code ? barcodeSvg(code, t.barcode) : null;
100
+ const expires = formatDate(v.expires_at, locale, opts.timeZone);
101
+ const field = (label, value) => value ? `<div class="box"><div class="label">${esc(label)}</div><div class="value">${esc(value)}</div></div>` : "";
102
+ const steps = isSpei ? t.stepsSpei : t.stepsCash;
103
+ const subtitle = [shop, method, opts.number ? `${t.order} ${opts.number}` : ""].filter(Boolean).map(esc).join(" \xB7 ");
104
+ return `<!doctype html>
105
+ <html lang="${esc(locale)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
106
+ <meta name="robots" content="noindex"><title>${esc(t.title)}${shop ? ` - ${esc(shop)}` : ""}</title><style>${CSS}</style></head>
107
+ <body><main>
108
+ <div class="head"><div><h1>${esc(t.title)}</h1><div class="muted">${subtitle}</div></div>
109
+ ${v.amount ? `<div><div class="label" style="text-align:right">${esc(t.total)}</div><div class="amount">${esc(formatMoney(v.amount, locale))}</div></div>` : ""}</div>
110
+ ${field(t.reference, v.reference)}${field(t.clabe, v.clabe)}
111
+ ${svg ? `<div class="bar">${svg}<div class="muted" style="font-family:ui-monospace,monospace">${esc(code)}</div></div>` : ""}
112
+ ${expires ? `<p><strong>${esc(t.expires)}:</strong> ${esc(expires)}. ${esc(t.expiresNote)}</p>` : ""}
113
+ <ol class="steps">${steps.map((s) => `<li>${esc(s)}</li>`).join("")}</ol>
114
+ ${v.instructions ? `<p class="note pre muted">${esc(v.instructions)}</p>` : ""}
115
+ <p class="note muted">${esc(t.footer)}</p>
116
+ ${opts.printButton ? `<div class="actions"><button type="button" id="print">${esc(t.print)}</button></div>` : ""}
117
+ </main>
118
+ ${opts.printButton || opts.autoPrint ? `<script${opts.nonce ? ` nonce="${esc(opts.nonce)}"` : ""}>(function(){var b=document.getElementById("print");if(b)b.addEventListener("click",function(){window.print()});${opts.autoPrint ? 'window.addEventListener("load",function(){setTimeout(function(){window.print()},300)});' : ""}})();</script>` : ""}
119
+ </body></html>`;
120
+ }
121
+
122
+ export { esc, renderVoucherDocument };
123
+ //# sourceMappingURL=voucher-document-SFWJCLTN.js.map
124
+ //# sourceMappingURL=voucher-document-SFWJCLTN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/account/voucher-document.ts"],"names":[],"mappings":"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","file":"voucher-document-SFWJCLTN.js","sourcesContent":["/**\n * Printable voucher (A4 HTML) that does not depend on any payment gateway: built only from the voucher data OPS keeps.\n * Loaded on demand (the buyer taps print/download) or by `pendingVoucherResponse` on the server; plain text, no React.\n * Everything external passes through `esc` before it enters the HTML.\n */\nimport type { Money } from '@asteby/storefront'\nimport { barcodeGeometry, barcodeValue, type VoucherView } from './voucher.js'\n\nexport function esc(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c] as string)\n}\n\ntype DocText = {\n title: string\n total: string\n reference: string\n clabe: string\n expires: string\n expiresNote: string\n order: string\n barcode: string\n print: string\n footer: string\n stepsCash: string[]\n stepsSpei: string[]\n methods: Record<string, string>\n cash: string\n}\n\nconst ES: DocText = {\n title: 'Ficha de pago',\n total: 'Total a pagar',\n reference: 'Referencia',\n clabe: 'CLABE',\n expires: 'Vence',\n expiresNote: 'Pasada esa fecha la ficha deja de ser válida.',\n order: 'Pedido',\n barcode: 'Código de barras',\n print: 'Imprimir ficha',\n footer: 'Tu pedido se genera cuando se confirma el pago. Esta ficha es de un solo uso; no la compartas.',\n stepsCash: [\n 'Acude a la tienda OXXO (o el comercio indicado) y di que vas a hacer un pago de servicio en efectivo.',\n 'Muestra el código de barras o dicta la referencia y paga el monto exacto.',\n 'Conserva tu comprobante: confirmaremos tu pago automáticamente.',\n ],\n stepsSpei: ['Entra a la banca en línea o app de tu banco.', 'Haz una transferencia SPEI a la CLABE indicada por el monto exacto.', 'Conserva tu comprobante: confirmaremos tu pago automáticamente.'],\n methods: { oxxo: 'OXXO', spei: 'Transferencia SPEI', bank_transfer: 'Transferencia bancaria', bank_deposit: 'Depósito bancario', cash: 'Pago en efectivo' },\n cash: 'Pago en efectivo',\n}\n\nconst EN: DocText = {\n title: 'Payment voucher',\n total: 'Amount to pay',\n reference: 'Reference',\n clabe: 'CLABE',\n expires: 'Expires',\n expiresNote: 'After that date the voucher is no longer valid.',\n order: 'Order',\n barcode: 'Barcode',\n print: 'Print voucher',\n footer: 'Your order is created when the payment is confirmed. This voucher is single-use; do not share it.',\n stepsCash: [\n 'Go to an OXXO store (or the store indicated) and say you want to make a cash service payment.',\n 'Show the barcode or read out the reference and pay the exact amount.',\n 'Keep your receipt: we will confirm your payment automatically.',\n ],\n stepsSpei: ['Open your bank online or app.', 'Make a SPEI transfer to the CLABE below for the exact amount.', 'Keep your receipt: we will confirm your payment automatically.'],\n methods: { oxxo: 'OXXO', spei: 'SPEI transfer', bank_transfer: 'Bank transfer', bank_deposit: 'Bank deposit', cash: 'Cash payment' },\n cash: 'Cash payment',\n}\n\nexport type VoucherDocumentOptions = {\n shopName?: string\n /** Order number, if there is one yet. */\n number?: string | null\n locale?: string\n /** IANA zone the expiry is printed in (default: the runtime's). */\n timeZone?: string\n /** Print button on screen (hidden when printing). */\n printButton?: boolean\n /** Opens the print dialog on load. */\n autoPrint?: boolean\n /** `<script>` nonce when the one serving the voucher sends a CSP with `script-src 'nonce-…'`. */\n nonce?: string\n}\n\nconst CSS = `\n@page { size: A4; margin: 18mm; }\n* { box-sizing: border-box; }\nbody { margin: 0; font: 14px/1.5 system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif; color: #111; background: #fff; }\nmain { max-width: 174mm; margin: 0 auto; padding: 24px 16px; }\nh1 { font-size: 22px; margin: 0; }\n.muted { color: #555; }\n.head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; border-bottom: 3px solid #111; padding-bottom: 12px; }\n.amount { font-size: 28px; font-weight: 700; text-align: right; }\n.box { border: 1px solid #111; padding: 14px 16px; margin-top: 18px; }\n.label { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: #555; }\n.value { font: 700 22px/1.3 ui-monospace, \"SF Mono\", Menlo, Consolas, monospace; word-break: break-all; letter-spacing: .04em; }\n.bar { margin-top: 18px; text-align: center; }\n.bar svg { max-width: 100%; height: auto; }\n.steps { margin: 18px 0 0; padding-left: 20px; }\n.note { margin-top: 18px; font-size: 12px; }\n.pre { white-space: pre-line; }\n.actions { margin-top: 24px; display: flex; gap: 12px; }\n.actions button { font: inherit; padding: 10px 18px; border: 1px solid #111; background: #111; color: #fff; cursor: pointer; }\n@media print { .actions { display: none; } main { padding: 0; } }\n`\n\nfunction formatMoney(m: Money | null, locale: string): string {\n if (!m) return ''\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: m.currency_code }).format(Number(m.amount))\n } catch {\n return `${m.amount} ${m.currency_code}`\n }\n}\n\nfunction formatDate(iso: string | null, locale: string, timeZone?: string): string {\n if (!iso) return ''\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return ''\n try {\n return d.toLocaleString(locale, { dateStyle: 'long', timeStyle: 'short', ...(timeZone ? { timeZone } : {}) })\n } catch {\n return d.toISOString()\n }\n}\n\nfunction barcodeSvg(value: string, label: string): string | null {\n const g = barcodeGeometry(value)\n if (!g) return null\n const rects = g.rects.map((r) => `<rect x=\"${r.x}\" y=\"0\" width=\"${r.w}\" height=\"${g.height}\"/>`).join('')\n return `<svg viewBox=\"0 0 ${g.width} ${g.height}\" width=\"${g.width}\" height=\"${g.height}\" role=\"img\" aria-label=\"${esc(label)} ${esc(value)}\" shape-rendering=\"crispEdges\" fill=\"#000\">${rects}</svg>`\n}\n\n/** Complete HTML document of the voucher. Missing data is simply not drawn. */\nexport function renderVoucherDocument(v: VoucherView, opts: VoucherDocumentOptions = {}): string {\n const locale = opts.locale ?? 'es-MX'\n const t = locale.toLowerCase().startsWith('en') ? EN : ES\n const shop = opts.shopName || ''\n // Own keys only: a gateway method named `constructor` or `__proto__` must print as itself, not as Object internals.\n const method = v.method ? (Object.prototype.hasOwnProperty.call(t.methods, v.method.toLowerCase()) ? t.methods[v.method.toLowerCase()]! : v.method) : t.cash\n const isSpei = !!v.clabe && !v.reference\n const code = barcodeValue(v)\n const svg = code ? barcodeSvg(code, t.barcode) : null\n const expires = formatDate(v.expires_at, locale, opts.timeZone)\n const field = (label: string, value: string | null) => (value ? `<div class=\"box\"><div class=\"label\">${esc(label)}</div><div class=\"value\">${esc(value)}</div></div>` : '')\n const steps = isSpei ? t.stepsSpei : t.stepsCash\n const subtitle = [shop, method, opts.number ? `${t.order} ${opts.number}` : ''].filter(Boolean).map(esc).join(' · ')\n return `<!doctype html>\n<html lang=\"${esc(locale)}\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"robots\" content=\"noindex\"><title>${esc(t.title)}${shop ? ` - ${esc(shop)}` : ''}</title><style>${CSS}</style></head>\n<body><main>\n<div class=\"head\"><div><h1>${esc(t.title)}</h1><div class=\"muted\">${subtitle}</div></div>\n${v.amount ? `<div><div class=\"label\" style=\"text-align:right\">${esc(t.total)}</div><div class=\"amount\">${esc(formatMoney(v.amount, locale))}</div></div>` : ''}</div>\n${field(t.reference, v.reference)}${field(t.clabe, v.clabe)}\n${svg ? `<div class=\"bar\">${svg}<div class=\"muted\" style=\"font-family:ui-monospace,monospace\">${esc(code as string)}</div></div>` : ''}\n${expires ? `<p><strong>${esc(t.expires)}:</strong> ${esc(expires)}. ${esc(t.expiresNote)}</p>` : ''}\n<ol class=\"steps\">${steps.map((s) => `<li>${esc(s)}</li>`).join('')}</ol>\n${v.instructions ? `<p class=\"note pre muted\">${esc(v.instructions)}</p>` : ''}\n<p class=\"note muted\">${esc(t.footer)}</p>\n${opts.printButton ? `<div class=\"actions\"><button type=\"button\" id=\"print\">${esc(t.print)}</button></div>` : ''}\n</main>\n${opts.printButton || opts.autoPrint ? `<script${opts.nonce ? ` nonce=\"${esc(opts.nonce)}\"` : ''}>(function(){var b=document.getElementById(\"print\");if(b)b.addEventListener(\"click\",function(){window.print()});${opts.autoPrint ? 'window.addEventListener(\"load\",function(){setTimeout(function(){window.print()},300)});' : ''}})();</script>` : ''}\n</body></html>`\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/storefront-react",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "React bindings for @asteby/storefront — SSR-safe provider, optimistic cart, Money, responsive Image, prices, variant selection, SEO meta and JSON-LD, section registry and server-rendered theme CSS.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -163,7 +163,7 @@
163
163
  "react": "^19.0.0"
164
164
  },
165
165
  "dependencies": {
166
- "@asteby/storefront": "0.13.0"
166
+ "@asteby/storefront": "0.14.0"
167
167
  },
168
168
  "devDependencies": {
169
169
  "@testing-library/react": "^16.3.2",