@nymbalhq/web-components 1.1.0 → 1.2.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 (187) hide show
  1. package/astro/NymbalElement.astro +19 -0
  2. package/dist/base-element-CPMgAdyQ.d.ts +91 -0
  3. package/dist/chunk-2TPQNQYO.js +155 -0
  4. package/dist/chunk-2TPQNQYO.js.map +1 -0
  5. package/dist/chunk-2XXBQPDB.js +113 -0
  6. package/dist/chunk-2XXBQPDB.js.map +1 -0
  7. package/dist/chunk-42SSME5H.js +84 -0
  8. package/dist/chunk-42SSME5H.js.map +1 -0
  9. package/dist/chunk-4COVK727.js +204 -0
  10. package/dist/chunk-4COVK727.js.map +1 -0
  11. package/dist/chunk-5VWZ2U5K.js +149 -0
  12. package/dist/chunk-5VWZ2U5K.js.map +1 -0
  13. package/dist/chunk-6XCCAAMF.js +656 -0
  14. package/dist/chunk-6XCCAAMF.js.map +1 -0
  15. package/dist/chunk-7JAAOVCE.js +114 -0
  16. package/dist/chunk-7JAAOVCE.js.map +1 -0
  17. package/dist/chunk-B73QVSA5.js +206 -0
  18. package/dist/chunk-B73QVSA5.js.map +1 -0
  19. package/dist/chunk-DR5QB5VN.js +17 -0
  20. package/dist/chunk-DR5QB5VN.js.map +1 -0
  21. package/dist/chunk-DXWMNB5F.js +70 -0
  22. package/dist/chunk-DXWMNB5F.js.map +1 -0
  23. package/dist/chunk-EBMA7JGV.js +130 -0
  24. package/dist/chunk-EBMA7JGV.js.map +1 -0
  25. package/dist/chunk-EYDMJNNK.js +176 -0
  26. package/dist/chunk-EYDMJNNK.js.map +1 -0
  27. package/dist/chunk-FIF6GQ6U.js +141 -0
  28. package/dist/chunk-FIF6GQ6U.js.map +1 -0
  29. package/dist/chunk-GHXTJ2CF.js +109 -0
  30. package/dist/chunk-GHXTJ2CF.js.map +1 -0
  31. package/dist/chunk-H3ZBYNHV.js +153 -0
  32. package/dist/chunk-H3ZBYNHV.js.map +1 -0
  33. package/dist/chunk-HPBC3OG7.js +174 -0
  34. package/dist/chunk-HPBC3OG7.js.map +1 -0
  35. package/dist/chunk-IYT7VXFS.js +105 -0
  36. package/dist/chunk-IYT7VXFS.js.map +1 -0
  37. package/dist/chunk-LHYXNQWY.js +105 -0
  38. package/dist/chunk-LHYXNQWY.js.map +1 -0
  39. package/dist/chunk-LO2EW5YP.js +25 -0
  40. package/dist/chunk-LO2EW5YP.js.map +1 -0
  41. package/dist/chunk-LSQPUZK6.js +291 -0
  42. package/dist/chunk-LSQPUZK6.js.map +1 -0
  43. package/dist/chunk-N4Y5DI4X.js +82 -0
  44. package/dist/chunk-N4Y5DI4X.js.map +1 -0
  45. package/dist/chunk-NE6UHTOT.js +148 -0
  46. package/dist/chunk-NE6UHTOT.js.map +1 -0
  47. package/dist/chunk-NW47OJVN.js +138 -0
  48. package/dist/chunk-NW47OJVN.js.map +1 -0
  49. package/dist/chunk-O2YKCDR2.js +77 -0
  50. package/dist/chunk-O2YKCDR2.js.map +1 -0
  51. package/dist/chunk-PN6QKYE4.js +71 -0
  52. package/dist/chunk-PN6QKYE4.js.map +1 -0
  53. package/dist/chunk-RAOGZH3Z.js +188 -0
  54. package/dist/chunk-RAOGZH3Z.js.map +1 -0
  55. package/dist/chunk-RVSKX2RX.js +11 -0
  56. package/dist/chunk-RVSKX2RX.js.map +1 -0
  57. package/dist/chunk-RZVFA3N5.js +154 -0
  58. package/dist/chunk-RZVFA3N5.js.map +1 -0
  59. package/dist/chunk-SM7TASEW.js +135 -0
  60. package/dist/chunk-SM7TASEW.js.map +1 -0
  61. package/dist/chunk-U2PU4CWB.js +124 -0
  62. package/dist/chunk-U2PU4CWB.js.map +1 -0
  63. package/dist/chunk-UCEVCLQ7.js +5 -0
  64. package/dist/chunk-UCEVCLQ7.js.map +1 -0
  65. package/dist/chunk-UYSZOEOA.js +32 -0
  66. package/dist/chunk-UYSZOEOA.js.map +1 -0
  67. package/dist/chunk-V55K2CS5.js +126 -0
  68. package/dist/chunk-V55K2CS5.js.map +1 -0
  69. package/dist/chunk-VTQVGNVC.js +346 -0
  70. package/dist/chunk-VTQVGNVC.js.map +1 -0
  71. package/dist/chunk-W23P7SI4.js +239 -0
  72. package/dist/chunk-W23P7SI4.js.map +1 -0
  73. package/dist/chunk-W7D3STJH.js +279 -0
  74. package/dist/chunk-W7D3STJH.js.map +1 -0
  75. package/dist/chunk-WEEHXWM3.js +172 -0
  76. package/dist/chunk-WEEHXWM3.js.map +1 -0
  77. package/dist/chunk-WTEVTCIL.js +128 -0
  78. package/dist/chunk-WTEVTCIL.js.map +1 -0
  79. package/dist/chunk-XE6IWISA.js +137 -0
  80. package/dist/chunk-XE6IWISA.js.map +1 -0
  81. package/dist/elements/nymbal-add-to-cart.d.ts +14 -0
  82. package/dist/elements/nymbal-add-to-cart.js +10 -0
  83. package/dist/elements/nymbal-add-to-cart.js.map +1 -0
  84. package/dist/elements/nymbal-address-book.d.ts +30 -0
  85. package/dist/elements/nymbal-address-book.js +13 -0
  86. package/dist/elements/nymbal-address-book.js.map +1 -0
  87. package/dist/elements/nymbal-address-form.d.ts +29 -0
  88. package/dist/elements/nymbal-address-form.js +12 -0
  89. package/dist/elements/nymbal-address-form.js.map +1 -0
  90. package/dist/elements/nymbal-breadcrumb.d.ts +15 -0
  91. package/dist/elements/nymbal-breadcrumb.js +11 -0
  92. package/dist/elements/nymbal-breadcrumb.js.map +1 -0
  93. package/dist/elements/nymbal-cart-drawer.d.ts +24 -0
  94. package/dist/elements/nymbal-cart-drawer.js +11 -0
  95. package/dist/elements/nymbal-cart-drawer.js.map +1 -0
  96. package/dist/elements/nymbal-cart-page.d.ts +20 -0
  97. package/dist/elements/nymbal-cart-page.js +14 -0
  98. package/dist/elements/nymbal-cart-page.js.map +1 -0
  99. package/dist/elements/nymbal-category-nav.d.ts +15 -0
  100. package/dist/elements/nymbal-category-nav.js +11 -0
  101. package/dist/elements/nymbal-category-nav.js.map +1 -0
  102. package/dist/elements/nymbal-checkout.d.ts +77 -0
  103. package/dist/elements/nymbal-checkout.js +15 -0
  104. package/dist/elements/nymbal-checkout.js.map +1 -0
  105. package/dist/elements/nymbal-image-gallery.d.ts +19 -0
  106. package/dist/elements/nymbal-image-gallery.js +10 -0
  107. package/dist/elements/nymbal-image-gallery.js.map +1 -0
  108. package/dist/elements/nymbal-login-form.d.ts +17 -0
  109. package/dist/elements/nymbal-login-form.js +12 -0
  110. package/dist/elements/nymbal-login-form.js.map +1 -0
  111. package/dist/elements/nymbal-mini-cart.d.ts +17 -0
  112. package/dist/elements/nymbal-mini-cart.js +10 -0
  113. package/dist/elements/nymbal-mini-cart.js.map +1 -0
  114. package/dist/elements/nymbal-order-summary.d.ts +20 -0
  115. package/dist/elements/nymbal-order-summary.js +11 -0
  116. package/dist/elements/nymbal-order-summary.js.map +1 -0
  117. package/dist/elements/nymbal-payment-element.d.ts +4 -0
  118. package/dist/elements/nymbal-payment-element.js +10 -0
  119. package/dist/elements/nymbal-payment-element.js.map +1 -0
  120. package/dist/elements/nymbal-product-card.d.ts +4 -0
  121. package/dist/elements/nymbal-product-card.js +12 -0
  122. package/dist/elements/nymbal-product-card.js.map +1 -0
  123. package/dist/elements/nymbal-product-filter.d.ts +32 -0
  124. package/dist/elements/nymbal-product-filter.js +10 -0
  125. package/dist/elements/nymbal-product-filter.js.map +1 -0
  126. package/dist/elements/nymbal-product-grid.d.ts +24 -0
  127. package/dist/elements/nymbal-product-grid.js +14 -0
  128. package/dist/elements/nymbal-product-grid.js.map +1 -0
  129. package/dist/elements/nymbal-product-price.d.ts +18 -0
  130. package/dist/elements/nymbal-product-price.js +12 -0
  131. package/dist/elements/nymbal-product-price.js.map +1 -0
  132. package/dist/elements/nymbal-profile-form.d.ts +19 -0
  133. package/dist/elements/nymbal-profile-form.js +12 -0
  134. package/dist/elements/nymbal-profile-form.js.map +1 -0
  135. package/dist/elements/nymbal-quantity-selector.d.ts +20 -0
  136. package/dist/elements/nymbal-quantity-selector.js +10 -0
  137. package/dist/elements/nymbal-quantity-selector.js.map +1 -0
  138. package/dist/elements/nymbal-register-form.d.ts +17 -0
  139. package/dist/elements/nymbal-register-form.js +12 -0
  140. package/dist/elements/nymbal-register-form.js.map +1 -0
  141. package/dist/elements/nymbal-review-form.d.ts +17 -0
  142. package/dist/elements/nymbal-review-form.js +12 -0
  143. package/dist/elements/nymbal-review-form.js.map +1 -0
  144. package/dist/elements/nymbal-review-list.d.ts +14 -0
  145. package/dist/elements/nymbal-review-list.js +10 -0
  146. package/dist/elements/nymbal-review-list.js.map +1 -0
  147. package/dist/elements/nymbal-search-bar.d.ts +19 -0
  148. package/dist/elements/nymbal-search-bar.js +10 -0
  149. package/dist/elements/nymbal-search-bar.js.map +1 -0
  150. package/dist/elements/nymbal-search-results.d.ts +29 -0
  151. package/dist/elements/nymbal-search-results.js +14 -0
  152. package/dist/elements/nymbal-search-results.js.map +1 -0
  153. package/dist/elements/nymbal-site-footer.d.ts +15 -0
  154. package/dist/elements/nymbal-site-footer.js +11 -0
  155. package/dist/elements/nymbal-site-footer.js.map +1 -0
  156. package/dist/elements/nymbal-site-header.d.ts +19 -0
  157. package/dist/elements/nymbal-site-header.js +11 -0
  158. package/dist/elements/nymbal-site-header.js.map +1 -0
  159. package/dist/elements/nymbal-sort-dropdown.d.ts +28 -0
  160. package/dist/elements/nymbal-sort-dropdown.js +10 -0
  161. package/dist/elements/nymbal-sort-dropdown.js.map +1 -0
  162. package/dist/elements/nymbal-stock-badge.d.ts +16 -0
  163. package/dist/elements/nymbal-stock-badge.js +11 -0
  164. package/dist/elements/nymbal-stock-badge.js.map +1 -0
  165. package/dist/elements/nymbal-toast.d.ts +18 -0
  166. package/dist/elements/nymbal-toast.js +10 -0
  167. package/dist/elements/nymbal-toast.js.map +1 -0
  168. package/dist/elements/nymbal-variant-selector.d.ts +16 -0
  169. package/dist/elements/nymbal-variant-selector.js +10 -0
  170. package/dist/elements/nymbal-variant-selector.js.map +1 -0
  171. package/dist/form-element-C-qo3gpD.d.ts +25 -0
  172. package/dist/hydrate-support.d.ts +2 -0
  173. package/dist/hydrate-support.js +3 -0
  174. package/dist/hydrate-support.js.map +1 -0
  175. package/dist/index.d.ts +38 -157
  176. package/dist/index.js +127 -1407
  177. package/dist/index.js.map +1 -1
  178. package/dist/nymbal-payment-element-Bt8EF42T.d.ts +51 -0
  179. package/dist/nymbal-product-card-C8HkE_rG.d.ts +47 -0
  180. package/dist/register-components.d.ts +46 -0
  181. package/dist/register-components.js +48 -0
  182. package/dist/register-components.js.map +1 -0
  183. package/dist/selected-variant-Dym0shlJ.d.ts +23 -0
  184. package/dist/ssr/index.d.ts +30 -0
  185. package/dist/ssr/index.js +143 -0
  186. package/dist/ssr/index.js.map +1 -0
  187. package/package.json +33 -6
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/registry.ts","../src/base-element.ts","../src/styles.ts","../src/components/add-to-cart.ts","../src/components/cart-drawer.ts","../src/components/mini-cart.ts","../src/components/variant-selector.ts","../src/components/quantity-selector.ts","../src/components/search-bar.ts","../src/components/product-filter.ts","../src/components/toast.ts","../src/components/payment-element.ts","../src/components/sort-dropdown.ts","../src/index.ts","../src/payment-drivers/test-mode.ts","../src/payment-drivers/stripe.ts"],"sourcesContent":["import type { NymbalClient } from '@nymbalhq/sdk'\n\nconst CLIENT_KEY = Symbol.for('nymbal.client')\n\nexport function registerClient(client: NymbalClient): void {\n (globalThis as Record<symbol, unknown>)[CLIENT_KEY] = client\n}\n\nexport function getClient(): NymbalClient {\n const client = (globalThis as Record<symbol, unknown>)[CLIENT_KEY] as NymbalClient | undefined\n if (!client) {\n throw new Error('NymbalClient not registered. Call registerClient() before using components.')\n }\n return client\n}\n","import type { NymbalClient } from '@nymbalhq/sdk'\nimport { getClient } from './registry.js'\n\n/** `HTMLElement`, or a stand-in on a server, where the module is imported but no element is ever made. */\nexport const HTMLElementBase =\n typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement)\n\nexport abstract class NymbalElement extends HTMLElementBase {\n private _unsubs: Array<() => void> = []\n private _renderQueued = false\n\n protected get client(): NymbalClient {\n return getClient()\n }\n\n protected subscribeToStore(store: { subscribe(fn: () => void): () => void }): void {\n this._unsubs.push(store.subscribe(() => this.requestRender()))\n }\n\n protected requestRender(): void {\n if (this._renderQueued) return\n this._renderQueued = true\n queueMicrotask(() => {\n this._renderQueued = false\n this.render()\n })\n }\n\n connectedCallback(): void {\n this.setup()\n this.render()\n }\n\n disconnectedCallback(): void {\n for (const fn of this._unsubs) fn()\n this._unsubs = []\n }\n\n protected abstract setup(): void\n protected abstract render(): void\n}\n","const injected = new Set<string>()\n\nexport function injectStyles(tagName: string, css: string): void {\n if (injected.has(tagName)) return\n if (typeof document === 'undefined') return\n const style = document.createElement('style')\n style.setAttribute('data-nymbal', tagName)\n style.textContent = css\n document.head.appendChild(style)\n injected.add(tagName)\n}\n","import { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-add-to-cart {\n display: inline-block;\n}\nnymbal-add-to-cart button {\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-base);\n font-weight: var(--nymbal-font-weight-medium);\n background: var(--nymbal-color-primary);\n color: var(--nymbal-color-text-inverse);\n border: none;\n border-radius: var(--nymbal-radius-md);\n padding: var(--nymbal-spacing-sm) var(--nymbal-spacing-lg);\n cursor: pointer;\n transition: background var(--nymbal-transition-fast);\n min-width: 140px;\n}\nnymbal-add-to-cart button:hover:not(:disabled) {\n background: var(--nymbal-color-primary-hover);\n}\nnymbal-add-to-cart button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n`\n\nconst MIN_QTY = 1\nconst MAX_QTY = 99\n\n/** The `qty` attribute as a whole number of units: a non-integer is 1, and the result is clamped to 1-99. */\nfunction quantityOf(attr: string | null): number {\n const n = attr === null || attr.trim() === '' ? Number.NaN : Number(attr)\n const whole = Number.isInteger(n) ? n : MIN_QTY\n return Math.min(MAX_QTY, Math.max(MIN_QTY, whole))\n}\n\nexport class NymbalAddToCart extends NymbalElement {\n static get observedAttributes(): string[] {\n return ['variant-id', 'qty', 'disabled']\n }\n\n private button!: HTMLButtonElement\n\n protected setup(): void {\n injectStyles('nymbal-add-to-cart', STYLES)\n this.subscribeToStore(this.client.cart)\n }\n\n protected render(): void {\n const variantId = this.getAttribute('variant-id')\n const isDisabled = this.hasAttribute('disabled')\n const cartState = this.client.cart.getState()\n\n if (!this.button) {\n this.button = document.createElement('button')\n this.button.setAttribute('type', 'button')\n this.button.setAttribute('data-testid', 'add-to-cart')\n this.button.addEventListener('click', this.handleClick)\n this.innerHTML = ''\n this.appendChild(this.button)\n }\n\n this.button.disabled = isDisabled || cartState.loading || !variantId\n this.button.setAttribute('aria-busy', String(cartState.loading))\n this.button.textContent = cartState.loading ? 'Adding...' : 'Add to Cart'\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.requestRender()\n }\n\n private handleClick = async (): Promise<void> => {\n const variantId = this.getAttribute('variant-id')\n if (!variantId) return\n const qty = quantityOf(this.getAttribute('qty'))\n try {\n await this.client.cart.addItem(variantId, qty)\n this.dispatchEvent(\n new CustomEvent('nymbal:cart:item-added', {\n bubbles: true,\n composed: true,\n detail: { variantId, qty },\n }),\n )\n } catch {\n // error is stored in cart state\n }\n }\n}\n","import { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-cart-drawer {\n display: block;\n}\nnymbal-cart-drawer .nymbal-drawer-overlay {\n position: fixed;\n inset: 0;\n background: var(--nymbal-color-overlay);\n z-index: var(--nymbal-z-drawer);\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--nymbal-transition-normal), visibility var(--nymbal-transition-normal);\n}\nnymbal-cart-drawer[open] .nymbal-drawer-overlay {\n opacity: 1;\n visibility: visible;\n}\nnymbal-cart-drawer .nymbal-drawer-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(400px, 90vw);\n background: var(--nymbal-color-surface);\n z-index: var(--nymbal-z-drawer);\n transform: translateX(100%);\n transition: transform var(--nymbal-transition-normal);\n display: flex;\n flex-direction: column;\n font-family: var(--nymbal-font-family);\n}\nnymbal-cart-drawer[open] .nymbal-drawer-panel {\n transform: translateX(0);\n}\nnymbal-cart-drawer .nymbal-drawer-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: var(--nymbal-spacing-md) var(--nymbal-spacing-lg);\n border-bottom: 1px solid var(--nymbal-color-border);\n}\nnymbal-cart-drawer .nymbal-drawer-header h2 {\n margin: 0;\n font-size: var(--nymbal-font-size-lg);\n font-weight: var(--nymbal-font-weight-bold);\n}\nnymbal-cart-drawer .nymbal-drawer-close {\n background: none;\n border: none;\n font-size: var(--nymbal-font-size-xl);\n cursor: pointer;\n padding: var(--nymbal-spacing-xs);\n color: var(--nymbal-color-text-muted);\n}\nnymbal-cart-drawer .nymbal-drawer-items {\n flex: 1;\n overflow-y: auto;\n padding: var(--nymbal-spacing-md) var(--nymbal-spacing-lg);\n}\nnymbal-cart-drawer .nymbal-cart-item {\n display: flex;\n gap: var(--nymbal-spacing-md);\n padding: var(--nymbal-spacing-md) 0;\n border-bottom: 1px solid var(--nymbal-color-border);\n}\nnymbal-cart-drawer .nymbal-cart-item-info {\n flex: 1;\n}\nnymbal-cart-drawer .nymbal-cart-item-name {\n font-weight: var(--nymbal-font-weight-medium);\n margin-bottom: var(--nymbal-spacing-xs);\n}\nnymbal-cart-drawer .nymbal-cart-item-variant {\n font-size: var(--nymbal-font-size-sm);\n color: var(--nymbal-color-text-muted);\n}\nnymbal-cart-drawer .nymbal-cart-item-actions {\n display: flex;\n align-items: center;\n gap: var(--nymbal-spacing-sm);\n}\nnymbal-cart-drawer .nymbal-cart-item-remove {\n background: none;\n border: none;\n color: var(--nymbal-color-error);\n cursor: pointer;\n font-size: var(--nymbal-font-size-sm);\n padding: var(--nymbal-spacing-xs);\n}\nnymbal-cart-drawer .nymbal-drawer-footer {\n padding: var(--nymbal-spacing-md) var(--nymbal-spacing-lg);\n border-top: 1px solid var(--nymbal-color-border);\n}\nnymbal-cart-drawer .nymbal-cart-subtotal {\n display: flex;\n justify-content: space-between;\n font-weight: var(--nymbal-font-weight-bold);\n margin-bottom: var(--nymbal-spacing-md);\n}\nnymbal-cart-drawer .nymbal-checkout-btn {\n width: 100%;\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-base);\n font-weight: var(--nymbal-font-weight-medium);\n background: var(--nymbal-color-primary);\n color: var(--nymbal-color-text-inverse);\n border: none;\n border-radius: var(--nymbal-radius-md);\n padding: var(--nymbal-spacing-sm) var(--nymbal-spacing-lg);\n cursor: pointer;\n transition: background var(--nymbal-transition-fast);\n}\nnymbal-cart-drawer .nymbal-checkout-btn:hover {\n background: var(--nymbal-color-primary-hover);\n}\nnymbal-cart-drawer .nymbal-drawer-empty {\n text-align: center;\n color: var(--nymbal-color-text-muted);\n padding: var(--nymbal-spacing-xl) 0;\n}\n`\n\nexport class NymbalCartDrawer extends NymbalElement {\n static get observedAttributes(): string[] {\n return ['open']\n }\n\n private readonly handleItemAdded = (): void => {\n this.open()\n }\n\n private readonly handleMiniCartClicked = (): void => {\n this.toggle()\n }\n\n protected setup(): void {\n injectStyles('nymbal-cart-drawer', STYLES)\n this.subscribeToStore(this.client.cart)\n document.addEventListener('nymbal:cart:item-added', this.handleItemAdded)\n document.addEventListener('nymbal:mini-cart:clicked', this.handleMiniCartClicked)\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback()\n document.removeEventListener('nymbal:cart:item-added', this.handleItemAdded)\n document.removeEventListener('nymbal:mini-cart:clicked', this.handleMiniCartClicked)\n }\n\n open(): void {\n this.setAttribute('open', '')\n window.dispatchEvent(new CustomEvent('nymbal:cart:open'))\n }\n\n close(): void {\n this.removeAttribute('open')\n window.dispatchEvent(new CustomEvent('nymbal:cart:close'))\n }\n\n toggle(): void {\n if (this.hasAttribute('open')) {\n this.close()\n } else {\n this.open()\n }\n }\n\n protected render(): void {\n const state = this.client.cart.getState()\n const currency = state.currency\n\n const itemsHtml = state.items.length === 0\n ? `<div class=\"nymbal-drawer-empty\">Your cart is empty</div>`\n : state.items.map((item) => `\n <div class=\"nymbal-cart-item\" data-testid=\"cart-item-${item.variantId}\">\n <div class=\"nymbal-cart-item-info\">\n <div class=\"nymbal-cart-item-name\">${this.esc(item.productName)}</div>\n <div class=\"nymbal-cart-item-variant\">${this.esc(item.variantName)}</div>\n <div class=\"nymbal-cart-item-qty\">Qty: ${item.qty}</div>\n </div>\n <div class=\"nymbal-cart-item-actions\">\n <span>${this.formatPrice(item.priceMinor * item.qty, currency)}</span>\n <button type=\"button\" class=\"nymbal-cart-item-remove\" data-testid=\"remove-item-${item.variantId}\" data-variant-id=\"${item.variantId}\">Remove</button>\n </div>\n </div>\n `).join('')\n\n this.innerHTML = `\n <div class=\"nymbal-drawer-overlay\" data-testid=\"cart-drawer-overlay\"></div>\n <div class=\"nymbal-drawer-panel\" role=\"dialog\" aria-label=\"Shopping cart\" aria-modal=\"true\" data-testid=\"cart-drawer\">\n <div class=\"nymbal-drawer-header\">\n <h2>Cart (${state.itemCount})</h2>\n <button type=\"button\" class=\"nymbal-drawer-close\" data-testid=\"cart-drawer-close\" aria-label=\"Close cart\">&times;</button>\n </div>\n <div class=\"nymbal-drawer-items\">${itemsHtml}</div>\n ${state.items.length > 0 ? `\n <div class=\"nymbal-drawer-footer\">\n <div class=\"nymbal-cart-subtotal\">\n <span>Subtotal</span>\n <span>${this.formatPrice(state.subtotalMinor, currency)}</span>\n </div>\n <button type=\"button\" class=\"nymbal-checkout-btn\" data-testid=\"cart-checkout-btn\">Checkout</button>\n </div>\n ` : ''}\n </div>\n `\n\n this.querySelector('.nymbal-drawer-overlay')?.addEventListener('click', () => this.close())\n this.querySelector('.nymbal-drawer-close')?.addEventListener('click', () => this.close())\n this.querySelector('.nymbal-checkout-btn')?.addEventListener('click', () => {\n this.dispatchEvent(new CustomEvent('nymbal:cart:checkout-clicked', { bubbles: true, composed: true }))\n })\n this.querySelectorAll('.nymbal-cart-item-remove').forEach((btn) => {\n btn.addEventListener('click', () => {\n const variantId = (btn as HTMLElement).dataset['variantId']\n if (variantId) this.client.cart.removeItem(variantId)\n })\n })\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.requestRender()\n }\n\n private esc(str: string): string {\n const div = document.createElement('div')\n div.textContent = str\n return div.innerHTML\n }\n\n private formatPrice(minor: number, currency: string): string {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n }).format(minor / 100)\n }\n}\n","import { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-mini-cart {\n display: inline-block;\n position: relative;\n}\nnymbal-mini-cart button {\n background: none;\n border: none;\n cursor: pointer;\n position: relative;\n padding: var(--nymbal-spacing-sm);\n font-family: var(--nymbal-font-family);\n color: var(--nymbal-color-text);\n}\nnymbal-mini-cart .nymbal-mini-cart-icon {\n width: 24px;\n height: 24px;\n}\nnymbal-mini-cart .nymbal-mini-cart-badge {\n position: absolute;\n top: 0;\n right: 0;\n background: var(--nymbal-color-accent);\n color: var(--nymbal-color-text-inverse);\n font-size: var(--nymbal-font-size-xs);\n font-weight: var(--nymbal-font-weight-bold);\n min-width: 18px;\n height: 18px;\n border-radius: var(--nymbal-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\nnymbal-mini-cart .nymbal-mini-cart-badge:empty {\n display: none;\n}\n`\n\nconst CART_SVG = `<svg class=\"nymbal-mini-cart-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"9\" cy=\"21\" r=\"1\"/><circle cx=\"20\" cy=\"21\" r=\"1\"/><path d=\"M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6\"/></svg>`\n\nexport class NymbalMiniCart extends NymbalElement {\n protected setup(): void {\n injectStyles('nymbal-mini-cart', STYLES)\n this.subscribeToStore(this.client.cart)\n }\n\n protected render(): void {\n const { itemCount } = this.client.cart.getState()\n\n this.innerHTML = `\n <button type=\"button\" data-testid=\"mini-cart\" aria-label=\"Cart (${itemCount} items)\">\n ${CART_SVG}\n <span class=\"nymbal-mini-cart-badge\" data-testid=\"mini-cart-badge\">${itemCount > 0 ? itemCount : ''}</span>\n </button>\n `\n\n this.querySelector('button')?.addEventListener('click', () => {\n this.dispatchEvent(new CustomEvent('nymbal:mini-cart:clicked', { bubbles: true, composed: true }))\n })\n }\n}\n","import type { DenormalisedVariant, DenormalisedProduct } from '@nymbalhq/sdk'\nimport type { VariantOption } from '@nymbalhq/types'\nimport { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-variant-selector {\n display: block;\n font-family: var(--nymbal-font-family);\n}\nnymbal-variant-selector .nymbal-option-group {\n margin-bottom: var(--nymbal-spacing-md);\n}\nnymbal-variant-selector .nymbal-option-label {\n display: block;\n font-size: var(--nymbal-font-size-sm);\n font-weight: var(--nymbal-font-weight-medium);\n margin-bottom: var(--nymbal-spacing-sm);\n color: var(--nymbal-color-text);\n}\nnymbal-variant-selector .nymbal-option-buttons {\n display: flex;\n flex-wrap: wrap;\n gap: var(--nymbal-spacing-sm);\n}\nnymbal-variant-selector .nymbal-option-btn {\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-sm);\n background: var(--nymbal-color-surface);\n color: var(--nymbal-color-text);\n border: 1px solid var(--nymbal-color-border);\n border-radius: var(--nymbal-radius-md);\n padding: var(--nymbal-spacing-xs) var(--nymbal-spacing-md);\n cursor: pointer;\n transition: border-color var(--nymbal-transition-fast), background var(--nymbal-transition-fast);\n}\nnymbal-variant-selector .nymbal-option-btn:hover {\n border-color: var(--nymbal-color-primary);\n}\nnymbal-variant-selector .nymbal-option-btn[aria-pressed=\"true\"] {\n background: var(--nymbal-color-primary);\n color: var(--nymbal-color-text-inverse);\n border-color: var(--nymbal-color-primary);\n}\nnymbal-variant-selector .nymbal-option-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n`\n\ninterface OptionGroup {\n name: string\n values: string[]\n}\n\n/** A variant's options when they are the `VariantOption[]` the read model serves; any other shape offers none. */\nfunction optionsOf(variant: DenormalisedVariant): VariantOption[] {\n return Array.isArray(variant.options) ? variant.options : []\n}\n\nexport class NymbalVariantSelector extends NymbalElement {\n protected setup(): void {\n injectStyles('nymbal-variant-selector', STYLES)\n this.subscribeToStore(this.client.product)\n }\n\n protected render(): void {\n const state = this.client.product.getState()\n const product = state.product\n if (!product) {\n this.innerHTML = ''\n return\n }\n\n const optionGroups = this.getOptionGroups(product)\n const selected = state.selectedVariant\n\n this.innerHTML = optionGroups.map((group) => `\n <div class=\"nymbal-option-group\">\n <span class=\"nymbal-option-label\">${this.esc(group.name)}</span>\n <div class=\"nymbal-option-buttons\">\n ${group.values.map((value) => {\n const isSelected =\n selected !== null &&\n optionsOf(selected).some((o) => o.name === group.name && o.value === value)\n return `<button\n class=\"nymbal-option-btn\"\n data-testid=\"variant-option-${this.esc(group.name)}-${this.esc(value)}\"\n data-option-name=\"${this.esc(group.name)}\"\n data-option-value=\"${this.esc(value)}\"\n aria-pressed=\"${isSelected}\"\n >${this.esc(value)}</button>`\n }).join('')}\n </div>\n </div>\n `).join('')\n\n this.querySelectorAll('.nymbal-option-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const el = btn as HTMLElement\n const optionName = el.dataset['optionName']\n const optionValue = el.dataset['optionValue']\n if (!optionName || !optionValue || !product) return\n\n const currentSelections = new Map<string, string>()\n if (selected) {\n for (const opt of optionsOf(selected)) {\n currentSelections.set(opt.name, opt.value)\n }\n }\n currentSelections.set(optionName, optionValue)\n\n const match = product.variants.find((v: DenormalisedVariant) =>\n optionsOf(v).every((o) => currentSelections.get(o.name) === o.value),\n )\n\n if (match) {\n this.client.product.selectVariant(match)\n this.dispatchEvent(\n new CustomEvent('nymbal:variant:selected', {\n bubbles: true,\n composed: true,\n detail: { variant: match },\n }),\n )\n }\n })\n })\n }\n\n private getOptionGroups(product: DenormalisedProduct): OptionGroup[] {\n const groups = new Map<string, Set<string>>()\n for (const variant of product.variants) {\n for (const opt of optionsOf(variant)) {\n let values = groups.get(opt.name)\n if (!values) {\n values = new Set()\n groups.set(opt.name, values)\n }\n values.add(opt.value)\n }\n }\n return Array.from(groups.entries()).map(([name, values]) => ({\n name,\n values: Array.from(values),\n }))\n }\n\n private esc(str: string): string {\n const div = document.createElement('div')\n div.textContent = str\n return div.innerHTML\n }\n}\n","import { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-quantity-selector {\n display: inline-flex;\n align-items: center;\n font-family: var(--nymbal-font-family);\n}\nnymbal-quantity-selector button {\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-base);\n background: var(--nymbal-color-surface);\n color: var(--nymbal-color-text);\n border: 1px solid var(--nymbal-color-border);\n width: 36px;\n height: 36px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background var(--nymbal-transition-fast);\n}\nnymbal-quantity-selector button:hover:not(:disabled) {\n background: var(--nymbal-color-secondary, #f4f4f5);\n}\nnymbal-quantity-selector button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\nnymbal-quantity-selector button:first-child {\n border-radius: var(--nymbal-radius-md) 0 0 var(--nymbal-radius-md);\n}\nnymbal-quantity-selector button:last-child {\n border-radius: 0 var(--nymbal-radius-md) var(--nymbal-radius-md) 0;\n}\nnymbal-quantity-selector input {\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-base);\n width: 48px;\n height: 36px;\n text-align: center;\n border: 1px solid var(--nymbal-color-border);\n border-left: none;\n border-right: none;\n -moz-appearance: textfield;\n}\nnymbal-quantity-selector input::-webkit-outer-spin-button,\nnymbal-quantity-selector input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n`\n\n/**\n * A quantity as a whole number of units in `min`-`max`: a number is truncated toward zero and clamped, anything else is\n * `min`. Add-to-cart takes only integers, so the selector shows and emits the same integer.\n */\nfunction wholeQuantity(raw: string | null, min: number, max: number): number {\n const n = raw === null || raw.trim() === '' ? Number.NaN : Number(raw)\n if (Number.isNaN(n)) return min\n return Math.min(max, Math.max(min, Math.trunc(n)))\n}\n\nexport class NymbalQuantitySelector extends NymbalElement {\n static get observedAttributes(): string[] {\n return ['value', 'min', 'max']\n }\n\n private _value = 1\n\n protected setup(): void {\n injectStyles('nymbal-quantity-selector', STYLES)\n this._value = wholeQuantity(this.getAttribute('value'), ...this.bounds())\n }\n\n private bounds(): [number, number] {\n return [Number(this.getAttribute('min')) || 1, Number(this.getAttribute('max')) || 99]\n }\n\n protected render(): void {\n const [min, max] = this.bounds()\n\n this.innerHTML = `\n <button data-testid=\"qty-decrement\" aria-label=\"Decrease quantity\" ${this._value <= min ? 'disabled' : ''}>&#8722;</button>\n <input data-testid=\"qty-input\" type=\"number\" value=\"${this._value}\" min=\"${min}\" max=\"${max}\" aria-label=\"Quantity\">\n <button data-testid=\"qty-increment\" aria-label=\"Increase quantity\" ${this._value >= max ? 'disabled' : ''}>&#43;</button>\n `\n\n this.querySelector('[data-testid=\"qty-decrement\"]')?.addEventListener('click', () => {\n if (this._value > min) {\n this._value--\n this.emitChange()\n this.render()\n }\n })\n\n this.querySelector('[data-testid=\"qty-increment\"]')?.addEventListener('click', () => {\n if (this._value < max) {\n this._value++\n this.emitChange()\n this.render()\n }\n })\n\n const input = this.querySelector('input')\n input?.addEventListener('change', () => {\n this._value = wholeQuantity(input.value, min, max)\n this.emitChange()\n this.render()\n })\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'value') {\n this._value = wholeQuantity(this.getAttribute('value'), ...this.bounds())\n }\n if (this.isConnected) this.requestRender()\n }\n\n private emitChange(): void {\n this.dispatchEvent(\n new CustomEvent('nymbal:quantity:changed', {\n bubbles: true,\n composed: true,\n detail: { value: this._value },\n }),\n )\n }\n}\n","import { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\nimport type { DenormalisedProduct } from '@nymbalhq/sdk'\n\nconst STYLES = `\nnymbal-search-bar {\n display: block;\n position: relative;\n font-family: var(--nymbal-font-family);\n}\nnymbal-search-bar input {\n font-family: var(--nymbal-font-family);\n font-size: var(--nymbal-font-size-base);\n width: 100%;\n padding: var(--nymbal-spacing-sm) var(--nymbal-spacing-md);\n border: 1px solid var(--nymbal-color-border);\n border-radius: var(--nymbal-radius-md);\n outline: none;\n transition: border-color var(--nymbal-transition-fast);\n box-sizing: border-box;\n}\nnymbal-search-bar input:focus {\n border-color: var(--nymbal-color-accent);\n}\nnymbal-search-bar .nymbal-search-results {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n background: var(--nymbal-color-surface);\n border: 1px solid var(--nymbal-color-border);\n border-top: none;\n border-radius: 0 0 var(--nymbal-radius-md) var(--nymbal-radius-md);\n box-shadow: var(--nymbal-shadow-md);\n z-index: var(--nymbal-z-dropdown);\n max-height: 300px;\n overflow-y: auto;\n}\nnymbal-search-bar .nymbal-search-result-item {\n padding: var(--nymbal-spacing-sm) var(--nymbal-spacing-md);\n cursor: pointer;\n transition: background var(--nymbal-transition-fast);\n}\nnymbal-search-bar .nymbal-search-result-item:hover,\nnymbal-search-bar .nymbal-search-result-item[aria-selected=\"true\"] {\n background: var(--nymbal-color-secondary, #f4f4f5);\n}\nnymbal-search-bar .nymbal-search-result-name {\n font-weight: var(--nymbal-font-weight-medium);\n}\nnymbal-search-bar .nymbal-search-result-price {\n font-size: var(--nymbal-font-size-sm);\n color: var(--nymbal-color-text-muted);\n}\nnymbal-search-bar .nymbal-search-loading {\n padding: var(--nymbal-spacing-md);\n text-align: center;\n color: var(--nymbal-color-text-muted);\n font-size: var(--nymbal-font-size-sm);\n}\n`\n\nexport class NymbalSearchBar extends NymbalElement {\n static get observedAttributes(): string[] {\n return ['placeholder', 'debounce-ms']\n }\n\n private debounceTimer: ReturnType<typeof setTimeout> | null = null\n private selectedIndex = -1\n\n protected setup(): void {\n injectStyles('nymbal-search-bar', STYLES)\n this.subscribeToStore(this.client.search)\n }\n\n protected render(): void {\n const state = this.client.search.getState()\n const placeholder = this.getAttribute('placeholder') ?? 'Search products...'\n\n let resultsHtml = ''\n if (state.query) {\n if (state.loading) {\n resultsHtml = `<div class=\"nymbal-search-results\" data-testid=\"search-results\"><div class=\"nymbal-search-loading\">Searching...</div></div>`\n } else if (state.results.length > 0) {\n resultsHtml = `<div class=\"nymbal-search-results\" data-testid=\"search-results\">\n ${state.results\n .map(\n (product, i) => `\n <div class=\"nymbal-search-result-item\" data-testid=\"search-result-${this.esc(product.slug)}\" data-slug=\"${this.esc(product.slug)}\" aria-selected=\"${i === this.selectedIndex}\">\n <div class=\"nymbal-search-result-name\">${this.esc(product.name)}</div>\n ${product.priceMinor !== null ? `<div class=\"nymbal-search-result-price\">${this.formatPrice(product.priceMinor, product.currency ?? 'USD')}</div>` : ''}\n </div>\n `,\n )\n .join('')}\n </div>`\n }\n }\n\n this.innerHTML = `\n <input data-testid=\"search-input\" type=\"search\" placeholder=\"${this.esc(placeholder)}\" value=\"${this.esc(state.query)}\" autocomplete=\"off\" role=\"combobox\" aria-expanded=\"${state.results.length > 0}\" aria-haspopup=\"listbox\">\n ${resultsHtml}\n `\n\n this.querySelectorAll<HTMLElement>('.nymbal-search-result-item').forEach((item, i) => {\n item.addEventListener('click', () => {\n const product = state.results[i]\n if (product) this.select(product)\n })\n })\n\n const input = this.querySelector('input')!\n input.addEventListener('input', () => {\n const query = input.value\n const debounceMs = Number(this.getAttribute('debounce-ms')) || 300\n if (this.debounceTimer !== null) clearTimeout(this.debounceTimer)\n this.debounceTimer = setTimeout(() => {\n this.selectedIndex = -1\n if (query.trim()) {\n this.client.search.search(query)\n } else {\n this.client.search.clearSearch()\n }\n }, debounceMs)\n })\n\n input.addEventListener('keydown', (e) => {\n const results = state.results\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n this.selectedIndex = Math.min(this.selectedIndex + 1, results.length - 1)\n this.render()\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n this.selectedIndex = Math.max(this.selectedIndex - 1, -1)\n this.render()\n } else if (e.key === 'Enter') {\n e.preventDefault()\n const selected = this.selectedIndex >= 0 ? results[this.selectedIndex] : undefined\n if (selected) {\n this.select(selected)\n } else {\n const query = input.value.trim()\n if (query) {\n window.location.href = `/search?q=${encodeURIComponent(query)}`\n }\n }\n } else if (e.key === 'Escape') {\n this.client.search.clearSearch()\n this.selectedIndex = -1\n }\n })\n }\n\n private select(product: DenormalisedProduct): void {\n this.dispatchEvent(\n new CustomEvent('nymbal:search:selected', {\n bubbles: true,\n composed: true,\n detail: { product, query: product.name },\n }),\n )\n this.client.search.clearSearch()\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.requestRender()\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback()\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer)\n this.debounceTimer = null\n }\n }\n\n /** Escapes a value for both text and quoted-attribute contexts. */\n private esc(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n }\n\n private formatPrice(minor: number, currency: string): string {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(minor / 100)\n }\n}\n","import type { Facet } from '@nymbalhq/types'\nimport { NymbalElement } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-product-filter {\n display: block;\n font-family: var(--nymbal-font-family);\n}\nnymbal-product-filter .nymbal-filter-group {\n margin-bottom: var(--nymbal-spacing-lg);\n}\nnymbal-product-filter .nymbal-filter-label {\n display: block;\n font-size: var(--nymbal-font-size-sm);\n font-weight: var(--nymbal-font-weight-bold);\n margin-bottom: var(--nymbal-spacing-sm);\n color: var(--nymbal-color-text);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\nnymbal-product-filter .nymbal-filter-option {\n display: flex;\n align-items: center;\n gap: var(--nymbal-spacing-sm);\n padding: var(--nymbal-spacing-xs) 0;\n cursor: pointer;\n font-size: var(--nymbal-font-size-sm);\n color: var(--nymbal-color-text);\n}\nnymbal-product-filter .nymbal-filter-option input[type=\"checkbox\"] {\n accent-color: var(--nymbal-color-primary);\n}\nnymbal-product-filter .nymbal-filter-count {\n color: var(--nymbal-color-text-muted);\n font-size: var(--nymbal-font-size-xs);\n}\n`\n\n\n/**\n * The facet filter. By default it reads the `facets` attribute and filters the product list. With `source=\"search\"`\n * it renders the search's own facets and narrows the search to one category: choosing an option selects it, choosing\n * the selected option again clears it.\n */\nexport class NymbalProductFilter extends NymbalElement {\n static get observedAttributes(): string[] {\n return ['facets', 'source']\n }\n\n protected setup(): void {\n injectStyles('nymbal-product-filter', STYLES)\n // Both: a wrapper may set `source` after the element has connected.\n this.subscribeToStore(this.client.productList)\n this.subscribeToStore(this.client.search)\n }\n\n protected render(): void {\n if (this.isSearch()) {\n this.renderSearch()\n return\n }\n const state = this.client.productList.getState()\n const facets = this.getFacets()\n\n if (facets.length === 0) {\n this.innerHTML = ''\n return\n }\n\n this.innerHTML = facets.map((facet) => {\n const activeFilter = state.filters[facet.field]\n const activeValues = Array.isArray(activeFilter)\n ? activeFilter\n : (activeFilter ? [activeFilter] : [])\n\n return `\n <div class=\"nymbal-filter-group\" data-testid=\"filter-group-${facet.field}\">\n <span class=\"nymbal-filter-label\">${this.esc(facet.label)}</span>\n ${facet.values.map((v) => {\n const checked = activeValues.includes(v.value)\n return `\n <label class=\"nymbal-filter-option\" data-testid=\"filter-option-${v.value}\">\n <input type=\"checkbox\" data-filter-name=\"${facet.field}\" data-filter-value=\"${v.value}\" ${checked ? 'checked' : ''}>\n <span>${this.esc(v.label ?? v.value)}</span>\n ${v.count !== undefined ? `<span class=\"nymbal-filter-count\">(${v.count})</span>` : ''}\n </label>\n `\n }).join('')}\n </div>\n `\n }).join('')\n\n this.querySelectorAll('input[type=\"checkbox\"]').forEach((input) => {\n input.addEventListener('change', () => {\n const el = input as HTMLInputElement\n const name = el.dataset['filterName']!\n const value = el.dataset['filterValue']!\n if (el.checked) {\n const current = state.filters[name]\n const values = Array.isArray(current) ? [...current, value] : (current ? [current, value] : value)\n this.client.productList.applyFilter(name, values)\n } else {\n const current = state.filters[name]\n if (Array.isArray(current)) {\n const remaining = current.filter((v) => v !== value)\n if (remaining.length > 0) {\n this.client.productList.applyFilter(name, remaining)\n } else {\n this.client.productList.removeFilter(name)\n }\n } else {\n this.client.productList.removeFilter(name)\n }\n }\n this.dispatchEvent(\n new CustomEvent('nymbal:filter:changed', { bubbles: true, composed: true, detail: { name, value } }),\n )\n })\n })\n }\n\n private renderSearch(): void {\n const { facets, category } = this.client.search.getState()\n const shown = facets.filter((f) => f.field === 'category')\n this.innerHTML = shown\n .map(\n (facet) => `\n <div class=\"nymbal-filter-group\" data-testid=\"filter-group-${this.esc(facet.field)}\">\n <span class=\"nymbal-filter-label\">${this.esc(facet.label)}</span>\n ${facet.values\n .map(\n (v) => `\n <label class=\"nymbal-filter-option\" data-testid=\"filter-option-${this.esc(v.value)}\">\n <input type=\"checkbox\" data-filter-value=\"${this.esc(v.value)}\" ${v.value === category ? 'checked' : ''}>\n <span>${this.esc(v.label ?? v.value)}</span>\n ${v.count !== undefined ? `<span class=\"nymbal-filter-count\">(${v.count})</span>` : ''}\n </label>\n `,\n )\n .join('')}\n </div>\n `,\n )\n .join('')\n\n this.querySelectorAll<HTMLInputElement>('input[type=\"checkbox\"]').forEach((input) => {\n input.addEventListener('change', () => {\n const value = input.dataset['filterValue']!\n void this.client.search.setCategory(input.checked ? value : null)\n this.dispatchEvent(\n new CustomEvent('nymbal:filter:changed', {\n bubbles: true,\n composed: true,\n detail: { name: 'category', value: input.checked ? value : '' },\n }),\n )\n })\n })\n }\n\n private isSearch(): boolean {\n return this.getAttribute('source') === 'search'\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.requestRender()\n }\n\n private getFacets(): Facet[] {\n const attr = this.getAttribute('facets')\n if (!attr) return []\n try {\n return JSON.parse(attr) as Facet[]\n } catch (err) {\n console.error('[nymbal-product-filter] failed to parse facets attribute', err)\n return []\n }\n }\n\n private esc(str: string): string {\n const div = document.createElement('div')\n div.textContent = str\n return div.innerHTML\n }\n}\n","import { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-toast {\n position: fixed;\n z-index: var(--nymbal-z-toast);\n display: flex;\n flex-direction: column;\n gap: var(--nymbal-spacing-sm);\n pointer-events: none;\n font-family: var(--nymbal-font-family);\n}\nnymbal-toast[position=\"top-right\"],\nnymbal-toast:not([position]) {\n top: var(--nymbal-spacing-lg);\n right: var(--nymbal-spacing-lg);\n}\nnymbal-toast[position=\"top-left\"] {\n top: var(--nymbal-spacing-lg);\n left: var(--nymbal-spacing-lg);\n}\nnymbal-toast[position=\"bottom-right\"] {\n bottom: var(--nymbal-spacing-lg);\n right: var(--nymbal-spacing-lg);\n}\nnymbal-toast[position=\"bottom-left\"] {\n bottom: var(--nymbal-spacing-lg);\n left: var(--nymbal-spacing-lg);\n}\nnymbal-toast .nymbal-toast-item {\n pointer-events: auto;\n display: flex;\n align-items: center;\n gap: var(--nymbal-spacing-sm);\n padding: var(--nymbal-spacing-sm) var(--nymbal-spacing-md);\n border-radius: var(--nymbal-radius-md);\n box-shadow: var(--nymbal-shadow-lg);\n font-size: var(--nymbal-font-size-sm);\n background: var(--nymbal-color-surface);\n color: var(--nymbal-color-text);\n border: 1px solid var(--nymbal-color-border);\n animation: nymbal-toast-in var(--nymbal-transition-normal) forwards;\n max-width: 360px;\n}\nnymbal-toast .nymbal-toast-item[data-type=\"success\"] {\n border-left: 3px solid var(--nymbal-color-success);\n}\nnymbal-toast .nymbal-toast-item[data-type=\"error\"] {\n border-left: 3px solid var(--nymbal-color-error);\n}\nnymbal-toast .nymbal-toast-item[data-type=\"warning\"] {\n border-left: 3px solid var(--nymbal-color-warning);\n}\nnymbal-toast .nymbal-toast-item[data-type=\"info\"] {\n border-left: 3px solid var(--nymbal-color-accent);\n}\nnymbal-toast .nymbal-toast-close {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--nymbal-color-text-muted);\n font-size: var(--nymbal-font-size-base);\n padding: 0;\n margin-left: auto;\n}\n@keyframes nymbal-toast-in {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n`\n\nconst HTMLElementBase =\n typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement)\n\nexport class NymbalToast extends HTMLElementBase {\n static get observedAttributes(): string[] {\n return ['position', 'duration-ms']\n }\n\n connectedCallback(): void {\n injectStyles('nymbal-toast', STYLES)\n this.setAttribute('data-testid', 'toast')\n }\n\n show(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n const durationMs = Number(this.getAttribute('duration-ms')) || 4000\n\n const item = document.createElement('div')\n item.className = 'nymbal-toast-item'\n item.setAttribute('data-type', type)\n item.setAttribute('role', 'alert')\n\n const text = document.createElement('span')\n text.textContent = message\n\n const close = document.createElement('button')\n close.className = 'nymbal-toast-close'\n close.setAttribute('aria-label', 'Dismiss')\n close.textContent = '×'\n close.addEventListener('click', () => this.dismiss(item))\n\n item.appendChild(text)\n item.appendChild(close)\n this.appendChild(item)\n\n setTimeout(() => this.dismiss(item), durationMs)\n }\n\n private dismiss(item: HTMLElement): void {\n if (item.parentNode === this) {\n this.removeChild(item)\n }\n }\n\n static showGlobal(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n let toastEl = document.querySelector('nymbal-toast') as NymbalToast | null\n if (!toastEl) {\n toastEl = document.createElement('nymbal-toast') as NymbalToast\n document.body.appendChild(toastEl)\n }\n toastEl.show(message, type)\n }\n}\n","import {\n getPaymentDriver,\n type PaymentConfirmContext,\n type PaymentConfirmation,\n type PaymentDriver,\n} from '@nymbalhq/sdk'\nimport type { PaymentClient } from '@nymbalhq/types'\nimport { HTMLElementBase } from '../base-element.js'\nimport { injectStyles } from '../styles.js'\n\nconst STYLES = `\nnymbal-payment-element {\n display: block;\n font-family: var(--nymbal-font-family);\n}\nnymbal-payment-element .nymbal-payment-note {\n margin: 0;\n font-size: var(--nymbal-font-size-sm, 0.875rem);\n color: var(--nymbal-color-text-muted, #71717a);\n}\nnymbal-payment-element .nymbal-payment-card {\n padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);\n border: 1px solid var(--nymbal-color-border, #e4e4e7);\n border-radius: var(--nymbal-radius-md, 0.5rem);\n background: var(--nymbal-color-surface, #fff);\n min-height: 40px;\n}\nnymbal-payment-element .nymbal-payment-error {\n margin: 0;\n font-size: var(--nymbal-font-size-sm, 0.875rem);\n color: var(--nymbal-color-error, #dc2626);\n}\n`\n\n/** `pending` while a driver mounts; `error` when no payment can be taken, which a checkout must not submit past. */\nexport type PaymentElementStatus = 'pending' | 'ready' | 'error'\n\n/** No client half: nothing to collect, so nothing is confirmed here. */\nconst NO_PAYMENT_STEP: PaymentConfirmation = { ok: true, confirmed: false }\n\nfunction parseClient(value: string | null): PaymentClient | null | undefined {\n if (value === null || value === '' || value === 'null') return null\n try {\n const parsed = JSON.parse(value) as Partial<PaymentClient> | null\n if (parsed === null) return null\n if (typeof parsed.driver !== 'string' || typeof parsed.options !== 'object') return undefined\n return { driver: parsed.driver, options: { ...(parsed.options ?? {}) } }\n } catch {\n return undefined\n }\n}\n\n/**\n * <nymbal-payment-element client='<json>'>: renders the payments adapter's client half (GET /api/capabilities'\n * `payments.client`) through the driver the SDK registry holds under its `driver` name, and confirms a payment\n * through it. It emits `nymbal:payment:status` whenever `status` changes.\n */\nexport class NymbalPaymentElement extends HTMLElementBase {\n static get observedAttributes(): string[] {\n return ['client']\n }\n\n private _status: PaymentElementStatus = 'pending'\n private _error = ''\n private _driver: PaymentDriver | null = null\n private _mounted: Promise<boolean> = Promise.resolve(true)\n private _rendered: string | null | undefined = undefined\n private _generation = 0\n\n get status(): PaymentElementStatus {\n return this._status\n }\n\n connectedCallback(): void {\n injectStyles('nymbal-payment-element', STYLES)\n this.render()\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.render()\n }\n\n /**\n * Completes a payment the API left `requires_action`, once the driver has mounted, handing the driver the\n * checkout's `context`; the driver's answer as is.\n */\n async confirm(clientSecret: string, context?: PaymentConfirmContext): Promise<PaymentConfirmation> {\n const driver = this._driver\n if (this._status === 'error') return { ok: false, error: this._error }\n if (driver === null) return NO_PAYMENT_STEP\n if (!(await this._mounted)) return { ok: false, error: this._error }\n return driver.confirm(clientSecret, context)\n }\n\n private render(): void {\n const attribute = this.getAttribute('client')\n // The same client half again (a reconnect, a framework re-setting the attribute) keeps what is mounted.\n if (attribute === this._rendered) return\n this._rendered = attribute\n const generation = ++this._generation\n this._driver = null\n this._mounted = Promise.resolve(true)\n this.replaceChildren()\n\n const client = parseClient(attribute)\n if (client === undefined)\n return this.fail('The store sent a payment client this page cannot read.')\n if (client === null) return this.setStatus('ready')\n const driver = getPaymentDriver(client.driver)\n if (driver === undefined) {\n return this.fail(`Payment method \"${client.driver}\" is not available on this storefront.`)\n }\n\n this._driver = driver\n this.setStatus('pending')\n this._mounted = Promise.resolve()\n .then(() => driver.mount(this, client.options))\n .then(\n () => {\n if (generation === this._generation) this.setStatus('ready')\n return true\n },\n (err: unknown) => {\n if (generation === this._generation) {\n this.fail(err instanceof Error ? err.message : 'The payment form could not be loaded.')\n }\n return false\n },\n )\n }\n\n private fail(message: string): void {\n this._error = message\n const p = document.createElement('p')\n p.className = 'nymbal-payment-error'\n p.setAttribute('data-testid', 'payment-element-error')\n p.setAttribute('role', 'alert')\n p.textContent = message\n this.replaceChildren(p)\n this.setStatus('error')\n }\n\n private setStatus(status: PaymentElementStatus): void {\n if (status === this._status) return\n this._status = status\n this.dispatchEvent(\n new CustomEvent('nymbal:payment:status', {\n bubbles: true,\n composed: true,\n detail: { status },\n }),\n )\n }\n}\n","import { DEFAULT_PRODUCT_SORT, PRODUCT_SORT_LABELS, type ProductSortKey } from '@nymbalhq/types'\nimport { HTMLElementBase } from '../base-element.js'\n\nfunction parseKeys(value: string | null): string[] {\n if (!value) return []\n try {\n const parsed: unknown = JSON.parse(value)\n return Array.isArray(parsed) ? parsed.filter((k): k is string => typeof k === 'string') : []\n } catch (err) {\n console.error('[nymbal-sort-dropdown] failed to parse sort-keys attribute', err)\n return []\n }\n}\n\n/**\n * <nymbal-sort-dropdown sort-keys='[…]' value default-sort>: one option per sort key the store reports, in its order,\n * labelled from PRODUCT_SORT_LABELS. A `value` the keys lack shows `default-sort`. Choosing an option emits\n * `nymbal:sort:changed` with `{ sort }`. A `<select>` already inside it (a server render's) is the one it fills.\n */\nexport class NymbalSortDropdown extends HTMLElementBase {\n static get observedAttributes(): string[] {\n return ['sort-keys', 'value', 'default-sort']\n }\n\n private _select: HTMLSelectElement | null = null\n\n /** The key the dropdown shows. */\n get value(): string {\n return this._select?.value ?? ''\n }\n\n connectedCallback(): void {\n this.render()\n }\n\n attributeChangedCallback(): void {\n if (this.isConnected) this.render()\n }\n\n private selectElement(): HTMLSelectElement {\n if (this._select !== null && this.contains(this._select)) return this._select\n let select = this.querySelector('select')\n if (select === null) {\n select = document.createElement('select')\n select.setAttribute('aria-label', 'Sort products')\n this.appendChild(select)\n }\n if (!select.hasAttribute('data-testid')) select.setAttribute('data-testid', 'sort-dropdown')\n select.addEventListener('change', () => {\n this.dispatchEvent(\n new CustomEvent('nymbal:sort:changed', {\n bubbles: true,\n composed: true,\n detail: { sort: select.value },\n }),\n )\n })\n this._select = select\n return select\n }\n\n private render(): void {\n const keys = parseKeys(this.getAttribute('sort-keys'))\n const wanted = this.getAttribute('value') ?? ''\n const fallback = this.getAttribute('default-sort') ?? DEFAULT_PRODUCT_SORT\n const selected = keys.includes(wanted) ? wanted : keys.includes(fallback) ? fallback : keys[0]\n\n const select = this.selectElement()\n select.replaceChildren(\n ...keys.map((key) => {\n const option = document.createElement('option')\n option.value = key\n option.textContent = PRODUCT_SORT_LABELS[key as ProductSortKey] ?? key\n return option\n }),\n )\n if (selected !== undefined) select.value = selected\n }\n}\n","export { registerClient, getClient } from './registry.js'\nexport { NymbalElement } from './base-element.js'\nexport { injectStyles } from './styles.js'\n\nimport { NymbalAddToCart } from './components/add-to-cart.js'\nimport { NymbalCartDrawer } from './components/cart-drawer.js'\nimport { NymbalMiniCart } from './components/mini-cart.js'\nimport { NymbalVariantSelector } from './components/variant-selector.js'\nimport { NymbalQuantitySelector } from './components/quantity-selector.js'\nimport { NymbalSearchBar } from './components/search-bar.js'\nimport { NymbalProductFilter } from './components/product-filter.js'\nimport { NymbalToast } from './components/toast.js'\nimport { NymbalPaymentElement } from './components/payment-element.js'\nimport { NymbalSortDropdown } from './components/sort-dropdown.js'\nimport { getPaymentDriver, registerPaymentDriver, type PaymentDriver } from '@nymbalhq/sdk'\nimport { testModeDriver } from './payment-drivers/test-mode.js'\nimport { stripeDriver } from './payment-drivers/stripe.js'\n\nexport type { PaymentElementStatus } from './components/payment-element.js'\n\nexport {\n NymbalAddToCart,\n NymbalCartDrawer,\n NymbalMiniCart,\n NymbalVariantSelector,\n NymbalQuantitySelector,\n NymbalSearchBar,\n NymbalProductFilter,\n NymbalToast,\n NymbalPaymentElement,\n NymbalSortDropdown,\n}\n\nexport function registerComponents(): void {\n const components: Array<[string, CustomElementConstructor]> = [\n ['nymbal-add-to-cart', NymbalAddToCart],\n ['nymbal-cart-drawer', NymbalCartDrawer],\n ['nymbal-mini-cart', NymbalMiniCart],\n ['nymbal-variant-selector', NymbalVariantSelector],\n ['nymbal-quantity-selector', NymbalQuantitySelector],\n ['nymbal-search-bar', NymbalSearchBar],\n ['nymbal-product-filter', NymbalProductFilter],\n ['nymbal-toast', NymbalToast],\n ['nymbal-payment-element', NymbalPaymentElement],\n ['nymbal-sort-dropdown', NymbalSortDropdown],\n ]\n // A driver the project registered under a built-in's name wins, as a project-defined tag does.\n const drivers: Array<[string, PaymentDriver]> = [\n ['test-mode', testModeDriver],\n ['stripe', stripeDriver],\n ]\n\n for (const [name, driver] of drivers) {\n if (getPaymentDriver(name) === undefined) registerPaymentDriver(name, driver)\n }\n for (const [name, ctor] of components) {\n if (!customElements.get(name)) {\n customElements.define(name, ctor)\n }\n }\n}\n","import type { PaymentDriver } from '@nymbalhq/sdk'\n\n/**\n * For a store whose payments need no shopper input (the native stub): nothing to collect, and nothing confirmed here.\n * An order the stub holds as `requires_action` stays pending until its webhook pays it.\n */\nexport const testModeDriver: PaymentDriver = {\n mount(el) {\n el.innerHTML = '<p class=\"nymbal-payment-note\">Test mode — payment skipped</p>'\n },\n confirm() {\n return Promise.resolve({ ok: true, confirmed: false })\n },\n}\n","import type { PaymentConfirmContext, PaymentConfirmation, PaymentDriver } from '@nymbalhq/sdk'\n\n// Stripe.js from Stripe's own host, as Stripe requires, so no project installs a Stripe package to take a card.\nconst STRIPE_JS = 'https://js.stripe.com/v3/'\n\ninterface StripeCard {\n mount(target: HTMLElement): void\n}\n\ninterface StripeBillingDetails {\n email?: string\n name?: string\n address?: {\n line1: string\n line2?: string\n city: string\n state: string\n postal_code: string\n country: string\n }\n}\n\ninterface StripeInstance {\n elements(): { create(type: 'card', options?: Record<string, unknown>): StripeCard }\n confirmCardPayment(\n clientSecret: string,\n data: { payment_method: { card: StripeCard; billing_details?: StripeBillingDetails } },\n ): Promise<{ paymentIntent?: { status: string }; error?: { message?: string } }>\n}\n\n/** The checkout's shopper details as Stripe's `billing_details`, which its fraud checks read; none when empty. */\nfunction billingDetails(context: PaymentConfirmContext | undefined): StripeBillingDetails | undefined {\n const details: StripeBillingDetails = {}\n if (context?.email) details.email = context.email\n const billing = context?.billing\n if (billing) {\n const name = `${billing.firstName} ${billing.lastName}`.trim()\n if (name) details.name = name\n details.address = {\n line1: billing.addressLine1,\n ...(billing.addressLine2 ? { line2: billing.addressLine2 } : {}),\n city: billing.city,\n state: billing.region,\n postal_code: billing.postalCode,\n country: billing.country,\n }\n }\n return Object.keys(details).length > 0 ? details : undefined\n}\n\ntype StripeFactory = (publishableKey: string) => StripeInstance\n\nlet loading: Promise<StripeFactory> | null = null\n\n/** `window.Stripe`, injecting Stripe.js once per page when it is not there yet. */\nfunction loadStripeJs(): Promise<StripeFactory> {\n const win = window as unknown as { Stripe?: StripeFactory }\n if (win.Stripe) return Promise.resolve(win.Stripe)\n loading ??= new Promise<StripeFactory>((resolve, reject) => {\n const script = document.createElement('script')\n script.src = STRIPE_JS\n script.async = true\n script.addEventListener('load', () => {\n if (win.Stripe) resolve(win.Stripe)\n else reject(new Error('Stripe.js loaded but window.Stripe is missing.'))\n })\n script.addEventListener('error', () => {\n loading = null\n script.remove()\n reject(new Error('Stripe.js could not be loaded.'))\n })\n document.head.appendChild(script)\n })\n return loading\n}\n\nconst instances = new Map<string, StripeInstance>()\nlet mounted: Array<{ host: HTMLElement; stripe: StripeInstance; card: StripeCard }> = []\n\n/** A card form from Stripe.js; confirm pays the intent with the card the shopper typed into. */\nexport const stripeDriver: PaymentDriver = {\n async mount(el, options) {\n const key = options['publishableKey']\n if (!key)\n throw new Error('Card payments are not configured: the store has no Stripe publishable key.')\n const factory = await loadStripeJs()\n let stripe = instances.get(key)\n if (stripe === undefined) {\n stripe = factory(key)\n instances.set(key, stripe)\n }\n const target = document.createElement('div')\n target.className = 'nymbal-payment-card'\n el.replaceChildren(target)\n const card = stripe.elements().create('card', {\n style: {\n base: { fontSize: '16px', color: '#1a1a1a', '::placeholder': { color: '#9ca3af' } },\n },\n })\n card.mount(target)\n mounted = [\n ...mounted.filter((m) => m.host.isConnected && m.host !== el),\n { host: el, stripe, card },\n ]\n },\n\n async confirm(clientSecret, context): Promise<PaymentConfirmation> {\n const current = mounted.findLast((m) => m.host.isConnected) ?? mounted.at(-1)\n if (current === undefined) return { ok: false, error: 'The card form is not ready.' }\n const billing_details = billingDetails(context)\n const result = await current.stripe.confirmCardPayment(clientSecret, {\n payment_method: { card: current.card, ...(billing_details ? { billing_details } : {}) },\n })\n if (result.error) return { ok: false, error: result.error.message ?? 'Payment failed.' }\n // `processing` is accepted but not paid yet: the webhook confirms it.\n return { ok: true, confirmed: result.paymentIntent?.status === 'succeeded' }\n },\n}\n"],"mappings":"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","names":["STYLES","STYLES","STYLES","STYLES","STYLES","STYLES","STYLES","HTMLElementBase","STYLES","getPaymentDriver","getPaymentDriver"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,51 @@
1
+ import * as lit from 'lit';
2
+ import { CSSResult } from 'lit';
3
+ import { PaymentConfirmContext, PaymentConfirmation } from '@nymbalhq/sdk';
4
+ import { N as NymbalElement, a as ElementSchema } from './base-element-CPMgAdyQ.js';
5
+
6
+ /** `pending` while a driver mounts; `error` when no payment can be taken, which a checkout must not submit past. */
7
+ type PaymentElementStatus = 'pending' | 'ready' | 'error';
8
+ /**
9
+ * <nymbal-payment-element client='<json>'>: renders the payments adapter's client half (GET /api/capabilities'
10
+ * `payments.client`) through the driver the SDK registry holds under its `driver` name, and confirms a payment
11
+ * through it. It emits `nymbal:payment:status` whenever `status` changes.
12
+ */
13
+ declare class NymbalPaymentElement extends NymbalElement {
14
+ static schema: ElementSchema;
15
+ /** The built-in drivers, except a name the project registered first: the project's driver wins, as its tag does. */
16
+ static beforeDefine(): void;
17
+ static properties: lit.PropertyDeclarations;
18
+ static styles: CSSResult;
19
+ private _status;
20
+ private _error;
21
+ private _driver;
22
+ private _mounted;
23
+ private _rendered;
24
+ private _generation;
25
+ get status(): PaymentElementStatus;
26
+ /**
27
+ * The light DOM, so the payment driver's UI (Stripe's iframe) and the checkout form share one tree. Its styles join
28
+ * the sheets of the tree it is in, where a shadow root would have held them.
29
+ */
30
+ protected createRenderRoot(): HTMLElement;
31
+ connectedCallback(): void;
32
+ attributeChangedCallback(name: string, old: string | null, value: string | null): void;
33
+ /** The children are the driver's, mounted imperatively, so Lit renders none of its own. */
34
+ protected render(): symbol;
35
+ /**
36
+ * Completes a payment the API left `requires_action`, once the driver has mounted, handing the driver the
37
+ * checkout's `context`; the driver's answer as is.
38
+ */
39
+ confirm(clientSecret: string, context?: PaymentConfirmContext): Promise<PaymentConfirmation>;
40
+ private mountClient;
41
+ private fail;
42
+ /**
43
+ * Replaces what a driver or an error rendered. Lit's marker comment stays: its next update (a new `client`) writes
44
+ * at it, and throws once it is gone.
45
+ */
46
+ private clear;
47
+ private setStatus;
48
+ }
49
+
50
+ export { NymbalPaymentElement as N };
51
+ export type { PaymentElementStatus as P };
@@ -0,0 +1,47 @@
1
+ import * as lit from 'lit';
2
+ import { nothing } from 'lit';
3
+ import { N as NymbalElement, a as ElementSchema } from './base-element-CPMgAdyQ.js';
4
+
5
+ /** The fields a card reads; a search result or a listing product carries them. */
6
+ interface CardProduct {
7
+ slug: string;
8
+ name: string;
9
+ priceMinor?: number | null;
10
+ priceRange?: {
11
+ minMinor: number;
12
+ maxMinor: number;
13
+ } | null;
14
+ currency?: string | null;
15
+ imageUrl?: string | null;
16
+ media?: Array<{
17
+ url?: string;
18
+ alt?: string;
19
+ }>;
20
+ }
21
+ /**
22
+ * The product's own image, else a placeholder seeded by its slug so a card without media keeps its shape. Exported so
23
+ * a page preloads exactly the image its first card requests.
24
+ */
25
+ declare function cardImageOf(p: CardProduct): {
26
+ url: string;
27
+ alt: string;
28
+ };
29
+ /**
30
+ * A product as a card reads it, and nothing else: a listing's products carry their variants, descriptions and
31
+ * categories, which a page of cards would otherwise put in its HTML once per card.
32
+ */
33
+ declare function cardProductOf(p: Omit<CardProduct, 'media'> & {
34
+ media?: unknown;
35
+ }): CardProduct;
36
+ /** One product as a link to its page: image, name and price. */
37
+ declare class NymbalProductCard extends NymbalElement {
38
+ static schema: ElementSchema;
39
+ static properties: lit.PropertyDeclarations;
40
+ static styles: lit.CSSResult[];
41
+ product: string | undefined;
42
+ eager: boolean | undefined;
43
+ protected render(): typeof nothing | lit.TemplateResult<1>;
44
+ }
45
+
46
+ export { NymbalProductCard as N, cardProductOf as a, cardImageOf as c };
47
+ export type { CardProduct as C };
@@ -0,0 +1,46 @@
1
+ import { NymbalAddToCart } from './elements/nymbal-add-to-cart.js';
2
+ import { NymbalCartDrawer } from './elements/nymbal-cart-drawer.js';
3
+ import { NymbalMiniCart } from './elements/nymbal-mini-cart.js';
4
+ import { NymbalVariantSelector } from './elements/nymbal-variant-selector.js';
5
+ import { NymbalQuantitySelector } from './elements/nymbal-quantity-selector.js';
6
+ import { NymbalSearchBar } from './elements/nymbal-search-bar.js';
7
+ import { NymbalProductFilter } from './elements/nymbal-product-filter.js';
8
+ import { NymbalToast } from './elements/nymbal-toast.js';
9
+ import { NymbalPaymentElement } from './elements/nymbal-payment-element.js';
10
+ import { NymbalSortDropdown } from './elements/nymbal-sort-dropdown.js';
11
+ import { NymbalCartPage } from './elements/nymbal-cart-page.js';
12
+ import { NymbalProductCard } from './elements/nymbal-product-card.js';
13
+ import { NymbalSearchResults } from './elements/nymbal-search-results.js';
14
+ import { NymbalLoginForm } from './elements/nymbal-login-form.js';
15
+ import { NymbalRegisterForm } from './elements/nymbal-register-form.js';
16
+ import { NymbalProfileForm } from './elements/nymbal-profile-form.js';
17
+ import { NymbalAddressForm } from './elements/nymbal-address-form.js';
18
+ import { NymbalAddressBook } from './elements/nymbal-address-book.js';
19
+ import { NymbalCheckout } from './elements/nymbal-checkout.js';
20
+ import { NymbalProductGrid } from './elements/nymbal-product-grid.js';
21
+ import { NymbalProductPrice } from './elements/nymbal-product-price.js';
22
+ import { NymbalStockBadge } from './elements/nymbal-stock-badge.js';
23
+ import { NymbalBreadcrumb } from './elements/nymbal-breadcrumb.js';
24
+ import { NymbalImageGallery } from './elements/nymbal-image-gallery.js';
25
+ import { NymbalSiteHeader } from './elements/nymbal-site-header.js';
26
+ import { NymbalSiteFooter } from './elements/nymbal-site-footer.js';
27
+ import { NymbalCategoryNav } from './elements/nymbal-category-nav.js';
28
+ import { NymbalReviewList } from './elements/nymbal-review-list.js';
29
+ import { NymbalReviewForm } from './elements/nymbal-review-form.js';
30
+ import { NymbalOrderSummary } from './elements/nymbal-order-summary.js';
31
+ import '@nymbalhq/sdk';
32
+ import 'lit';
33
+ import './base-element-CPMgAdyQ.js';
34
+ import './form-element-C-qo3gpD.js';
35
+ import '@nymbalhq/types';
36
+ import './selected-variant-Dym0shlJ.js';
37
+
38
+ /** Every element the package defines. */
39
+ declare const ELEMENTS: (typeof NymbalAddToCart | typeof NymbalCartDrawer | typeof NymbalMiniCart | typeof NymbalVariantSelector | typeof NymbalQuantitySelector | typeof NymbalSearchBar | typeof NymbalProductFilter | typeof NymbalToast | typeof NymbalPaymentElement | typeof NymbalSortDropdown | typeof NymbalCartPage | typeof NymbalProductCard | typeof NymbalSearchResults | typeof NymbalLoginForm | typeof NymbalRegisterForm | typeof NymbalProfileForm | typeof NymbalAddressForm | typeof NymbalAddressBook | typeof NymbalCheckout | typeof NymbalProductGrid | typeof NymbalProductPrice | typeof NymbalStockBadge | typeof NymbalBreadcrumb | typeof NymbalImageGallery | typeof NymbalSiteHeader | typeof NymbalSiteFooter | typeof NymbalCategoryNav | typeof NymbalReviewList | typeof NymbalReviewForm | typeof NymbalOrderSummary)[];
40
+ /**
41
+ * Defines every element, and registers the built-in payment drivers, except a tag or driver name the project has
42
+ * already defined: the project's wins. A page that renders a few elements passes those to `define` instead.
43
+ */
44
+ declare function registerComponents(): void;
45
+
46
+ export { ELEMENTS, registerComponents };
@@ -0,0 +1,48 @@
1
+ import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
2
+ import {
3
+ ELEMENTS,
4
+ registerComponents
5
+ } from "./chunk-XE6IWISA.js";
6
+ import "./chunk-H3ZBYNHV.js";
7
+ import "./chunk-7JAAOVCE.js";
8
+ import "./chunk-4COVK727.js";
9
+ import "./chunk-RAOGZH3Z.js";
10
+ import "./chunk-FIF6GQ6U.js";
11
+ import "./chunk-W23P7SI4.js";
12
+ import "./chunk-EBMA7JGV.js";
13
+ import "./chunk-O2YKCDR2.js";
14
+ import "./chunk-2TPQNQYO.js";
15
+ import "./chunk-WEEHXWM3.js";
16
+ import "./chunk-5VWZ2U5K.js";
17
+ import "./chunk-RZVFA3N5.js";
18
+ import "./chunk-DXWMNB5F.js";
19
+ import "./chunk-UYSZOEOA.js";
20
+ import "./chunk-WTEVTCIL.js";
21
+ import "./chunk-NW47OJVN.js";
22
+ import "./chunk-NE6UHTOT.js";
23
+ import "./chunk-VTQVGNVC.js";
24
+ import "./chunk-HPBC3OG7.js";
25
+ import "./chunk-IYT7VXFS.js";
26
+ import "./chunk-6XCCAAMF.js";
27
+ import "./chunk-U2PU4CWB.js";
28
+ import "./chunk-42SSME5H.js";
29
+ import "./chunk-2XXBQPDB.js";
30
+ import "./chunk-SM7TASEW.js";
31
+ import "./chunk-RVSKX2RX.js";
32
+ import "./chunk-W7D3STJH.js";
33
+ import "./chunk-LHYXNQWY.js";
34
+ import "./chunk-B73QVSA5.js";
35
+ import "./chunk-V55K2CS5.js";
36
+ import "./chunk-PN6QKYE4.js";
37
+ import "./chunk-GHXTJ2CF.js";
38
+ import "./chunk-N4Y5DI4X.js";
39
+ import "./chunk-LO2EW5YP.js";
40
+ import "./chunk-LSQPUZK6.js";
41
+ import "./chunk-DR5QB5VN.js";
42
+ import "./chunk-EYDMJNNK.js";
43
+ import "./chunk-UCEVCLQ7.js";
44
+ export {
45
+ ELEMENTS,
46
+ registerComponents
47
+ };
48
+ //# sourceMappingURL=register-components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,23 @@
1
+ import * as _nymbalhq_sdk from '@nymbalhq/sdk';
2
+ import { DenormalisedProduct, DenormalisedVariant } from '@nymbalhq/sdk';
3
+ import { N as NymbalElement } from './base-element-CPMgAdyQ.js';
4
+
5
+ /**
6
+ * An element showing one product's selected variant (its price, its stock). It renders from its attributes until the
7
+ * product store settles on the product its `product-id` names, then from the store's selected variant. A store
8
+ * settled on another product (the page a soft navigation left) is not this element's, so it keeps its attributes.
9
+ */
10
+ declare abstract class NymbalVariantElement extends NymbalElement {
11
+ productId: string | undefined;
12
+ private following;
13
+ protected stores(): _nymbalhq_sdk.ProductStore[];
14
+ protected storeSettled(): void;
15
+ private ownProduct;
16
+ /** The store's product and its selected variant, once this element follows the store; else null. */
17
+ protected selected(): {
18
+ product: DenormalisedProduct;
19
+ variant: DenormalisedVariant | null;
20
+ } | null;
21
+ }
22
+
23
+ export { NymbalVariantElement as N };
@@ -0,0 +1,30 @@
1
+ export { C as CardProduct, c as cardImageOf, a as cardProductOf } from '../nymbal-product-card-C8HkE_rG.js';
2
+ import 'lit';
3
+ import '../base-element-CPMgAdyQ.js';
4
+ import '@nymbalhq/sdk';
5
+
6
+ /** Thrown for a tag the server does not render: neither a package element nor one a project registered. */
7
+ declare class UnknownElement extends Error {
8
+ name: string;
9
+ }
10
+ /**
11
+ * Registers a project's own element classes by tag, as its elements entry exports them: the server renders each in
12
+ * place of the package's element under that tag, as the browser defines it there. A tag keeps the first class it was
13
+ * registered with; a different class under it is refused, so the server and the browser cannot disagree.
14
+ */
15
+ declare function registerServerElements(map: Record<string, CustomElementConstructor>): void;
16
+ interface RenderOptions {
17
+ /** The host's attributes; a JSON attribute's value is its JSON text. */
18
+ attributes?: Record<string, string> | undefined;
19
+ /** Light-DOM HTML after the shadow root: a slotted child, as the payment element is the checkout's. */
20
+ children?: string | undefined;
21
+ }
22
+ /**
23
+ * One element as HTML: `<tag …attributes><template shadowrootmode="open">…</template>…children</tag>`, the template
24
+ * holding the element's first render from its attributes (no client, no store) with its styles, and the markers Lit's
25
+ * hydration reads. The browser parses the template into the element's shadow root, and the element takes it over.
26
+ */
27
+ declare function renderElement(tag: string, options?: RenderOptions): string;
28
+
29
+ export { UnknownElement, registerServerElements, renderElement };
30
+ export type { RenderOptions };
@@ -0,0 +1,143 @@
1
+ import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
2
+ import {
3
+ ELEMENTS
4
+ } from "../chunk-XE6IWISA.js";
5
+ import "../chunk-H3ZBYNHV.js";
6
+ import "../chunk-7JAAOVCE.js";
7
+ import "../chunk-4COVK727.js";
8
+ import "../chunk-RAOGZH3Z.js";
9
+ import "../chunk-FIF6GQ6U.js";
10
+ import "../chunk-W23P7SI4.js";
11
+ import "../chunk-EBMA7JGV.js";
12
+ import "../chunk-O2YKCDR2.js";
13
+ import "../chunk-2TPQNQYO.js";
14
+ import "../chunk-WEEHXWM3.js";
15
+ import "../chunk-5VWZ2U5K.js";
16
+ import {
17
+ cardImageOf,
18
+ cardProductOf
19
+ } from "../chunk-RZVFA3N5.js";
20
+ import "../chunk-DXWMNB5F.js";
21
+ import "../chunk-UYSZOEOA.js";
22
+ import "../chunk-WTEVTCIL.js";
23
+ import "../chunk-NW47OJVN.js";
24
+ import "../chunk-NE6UHTOT.js";
25
+ import "../chunk-VTQVGNVC.js";
26
+ import "../chunk-HPBC3OG7.js";
27
+ import "../chunk-IYT7VXFS.js";
28
+ import "../chunk-6XCCAAMF.js";
29
+ import "../chunk-U2PU4CWB.js";
30
+ import "../chunk-42SSME5H.js";
31
+ import "../chunk-2XXBQPDB.js";
32
+ import "../chunk-SM7TASEW.js";
33
+ import "../chunk-RVSKX2RX.js";
34
+ import "../chunk-W7D3STJH.js";
35
+ import "../chunk-LHYXNQWY.js";
36
+ import "../chunk-B73QVSA5.js";
37
+ import "../chunk-V55K2CS5.js";
38
+ import "../chunk-PN6QKYE4.js";
39
+ import "../chunk-GHXTJ2CF.js";
40
+ import "../chunk-N4Y5DI4X.js";
41
+ import "../chunk-LO2EW5YP.js";
42
+ import "../chunk-LSQPUZK6.js";
43
+ import "../chunk-DR5QB5VN.js";
44
+ import "../chunk-EYDMJNNK.js";
45
+ import "../chunk-UCEVCLQ7.js";
46
+
47
+ // src/ssr/render-root.ts
48
+ import { LitElement } from "lit";
49
+ var prototype = LitElement.prototype;
50
+ var createRenderRoot = prototype.createRenderRoot;
51
+ function restoreCreateRenderRoot() {
52
+ prototype.createRenderRoot = createRenderRoot;
53
+ }
54
+
55
+ // src/ssr/index.ts
56
+ import { LitElementRenderer } from "@lit-labs/ssr/lib/lit-element-renderer.js";
57
+ import { collectResultSync } from "@lit-labs/ssr/lib/render-result.js";
58
+ restoreCreateRenderRoot();
59
+ var UnknownElement = class extends Error {
60
+ name = "UnknownElement";
61
+ };
62
+ var CLIENT_MOUNTED = /* @__PURE__ */ new Set(["nymbal-payment-element"]);
63
+ var PACKAGE = new Map(
64
+ ELEMENTS.filter((e) => !CLIENT_MOUNTED.has(e.schema.tag)).map((e) => [
65
+ e.schema.tag,
66
+ e
67
+ ])
68
+ );
69
+ var projectElements = /* @__PURE__ */ new Map();
70
+ function registerServerElements(map) {
71
+ for (const [tag, element] of Object.entries(map)) {
72
+ const lit = element;
73
+ if (lit._$litElement$ !== true) {
74
+ throw new TypeError(`${tag}: the server renders Lit elements only`);
75
+ }
76
+ const registered = projectElements.get(tag);
77
+ if (registered !== void 0 && registered !== lit) {
78
+ throw new Error(`${tag} is already registered for the server with another class`);
79
+ }
80
+ projectElements.set(tag, lit);
81
+ }
82
+ }
83
+ function classFor(tag) {
84
+ return projectElements.get(tag) ?? PACKAGE.get(tag);
85
+ }
86
+ var ServerElementRenderer = class extends LitElementRenderer {
87
+ static matchesClass(_ctor, tagName) {
88
+ return tagName !== void 0 && classFor(tagName) !== void 0;
89
+ }
90
+ constructor(tagName) {
91
+ super(tagName);
92
+ const element = classFor(tagName);
93
+ if (this.element.constructor !== element) this.element = new element();
94
+ }
95
+ };
96
+ function defineAll() {
97
+ for (const tag of /* @__PURE__ */ new Set([...projectElements.keys(), ...PACKAGE.keys()])) {
98
+ const element = classFor(tag);
99
+ if (customElements.get(tag) === void 0) customElements.define(tag, element);
100
+ else if (customElements.getName(element) === null)
101
+ customElements.define(`${tag}-server`, element);
102
+ }
103
+ }
104
+ function compactStyles(html) {
105
+ return html.replace(
106
+ /<style>([^<]*)<\/style>/g,
107
+ (_, css) => `<style>${css.replace(/\s+/g, " ").trim()}</style>`
108
+ );
109
+ }
110
+ function renderElement(tag, options = {}) {
111
+ if (CLIENT_MOUNTED.has(tag)) {
112
+ throw new UnknownElement(`${tag} is client-mounted and is not server-rendered`);
113
+ }
114
+ if (classFor(tag) === void 0) {
115
+ throw new UnknownElement(`${tag} is neither a Nymbal element nor a registered server element`);
116
+ }
117
+ defineAll();
118
+ const renderer = new ServerElementRenderer(tag);
119
+ for (const [name, value] of Object.entries(options.attributes ?? {})) {
120
+ renderer.setAttribute(name, value);
121
+ }
122
+ renderer.connectedCallback();
123
+ const renderInfo = {
124
+ elementRenderers: [ServerElementRenderer, LitElementRenderer],
125
+ customElementInstanceStack: [renderer],
126
+ customElementHostStack: [renderer],
127
+ eventTargetStack: [renderer.element],
128
+ slotStack: [],
129
+ deferHydration: false
130
+ };
131
+ const attributes = collectResultSync(renderer.renderAttributes());
132
+ const shadow = compactStyles(collectResultSync(renderer.renderShadow(renderInfo)));
133
+ const { mode = "open" } = renderer.shadowRootOptions;
134
+ return `<${tag}${attributes}><template shadowrootmode="${mode}">${shadow}</template>${options.children ?? ""}</${tag}>`;
135
+ }
136
+ export {
137
+ UnknownElement,
138
+ cardImageOf,
139
+ cardProductOf,
140
+ registerServerElements,
141
+ renderElement
142
+ };
143
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ssr/render-root.ts","../../src/ssr/index.ts"],"sourcesContent":["import { LitElement } from 'lit'\n\ntype WithRenderRoot = { createRenderRoot: () => HTMLElement | DocumentFragment }\n\n// Lit SSR replaces LitElement's createRenderRoot when it loads, dropping the hydrate support's, which is what makes a\n// client element take over a server's shadow root. A realm that both renders on the server and runs elements (a test,\n// a DOM-shimmed server) keeps the one it had: this module is imported before Lit SSR, and the ssr entry restores it.\nconst prototype = LitElement.prototype as unknown as WithRenderRoot\nconst createRenderRoot = prototype.createRenderRoot\n\nexport function restoreCreateRenderRoot(): void {\n prototype.createRenderRoot = createRenderRoot\n}\n","import { restoreCreateRenderRoot } from './render-root.js'\nimport type { RenderInfo } from '@lit-labs/ssr'\nimport { LitElementRenderer } from '@lit-labs/ssr/lib/lit-element-renderer.js'\nimport { collectResultSync } from '@lit-labs/ssr/lib/render-result.js'\nimport type { LitElement } from 'lit'\nimport { ELEMENTS } from '../register-components.js'\n\nexport { cardImageOf, cardProductOf, type CardProduct } from '../components/product-card.js'\n\nrestoreCreateRenderRoot()\n\n/** Thrown for a tag the server does not render: neither a package element nor one a project registered. */\nexport class UnknownElement extends Error {\n override name = 'UnknownElement'\n}\n\ntype LitElementClass = (new () => LitElement) & { _$litElement$?: boolean }\n\n/** Mounted by its payment driver in the browser, in the light DOM; a checkout's server render leaves its slot. */\nconst CLIENT_MOUNTED = new Set(['nymbal-payment-element'])\n\nconst PACKAGE = new Map<string, LitElementClass>(\n ELEMENTS.filter((e) => !CLIENT_MOUNTED.has(e.schema.tag)).map((e) => [\n e.schema.tag,\n e as unknown as LitElementClass,\n ]),\n)\n\n/** The project's elements by tag (its `serverElements`), which the server renders in place of the package's. */\nconst projectElements = new Map<string, LitElementClass>()\n\n/**\n * Registers a project's own element classes by tag, as its elements entry exports them: the server renders each in\n * place of the package's element under that tag, as the browser defines it there. A tag keeps the first class it was\n * registered with; a different class under it is refused, so the server and the browser cannot disagree.\n */\nexport function registerServerElements(map: Record<string, CustomElementConstructor>): void {\n for (const [tag, element] of Object.entries(map)) {\n const lit = element as unknown as LitElementClass\n if (lit._$litElement$ !== true) {\n throw new TypeError(`${tag}: the server renders Lit elements only`)\n }\n const registered = projectElements.get(tag)\n if (registered !== undefined && registered !== lit) {\n throw new Error(`${tag} is already registered for the server with another class`)\n }\n projectElements.set(tag, lit)\n }\n}\n\n/** The class the server renders under `tag`, resolved per call, so a registration after a first render wins. */\nfunction classFor(tag: string): LitElementClass | undefined {\n return projectElements.get(tag) ?? PACKAGE.get(tag)\n}\n\n/**\n * Lit SSR finds the elements a template renders, and constructs them, through `customElements`, which defines a tag\n * once per process. This renderer constructs the class `classFor` resolves instead, so a project's element renders\n * under its tag whatever `customElements` held first.\n */\nclass ServerElementRenderer extends LitElementRenderer {\n static override matchesClass(_ctor: typeof HTMLElement, tagName?: string): boolean {\n return tagName !== undefined && classFor(tagName) !== undefined\n }\n\n constructor(tagName: string) {\n super(tagName)\n const element = classFor(tagName)!\n if (this.element.constructor !== element) this.element = new element()\n }\n}\n\n/**\n * Every tag the server may render is known to `customElements`, which is where Lit SSR finds nested elements. A DOM\n * (not Lit's server shim) constructs only the classes it defined, so a project class whose tag already holds another\n * class is defined under a name of its own.\n */\nfunction defineAll(): void {\n for (const tag of new Set([...projectElements.keys(), ...PACKAGE.keys()])) {\n const element = classFor(tag)!\n if (customElements.get(tag) === undefined) customElements.define(tag, element)\n else if (customElements.getName(element) === null)\n customElements.define(`${tag}-server`, element)\n }\n}\n\n/**\n * The elements' styles, with their indentation collapsed: written for reading, they would otherwise be bytes a page\n * downloads before its first paint, once per element.\n */\nfunction compactStyles(html: string): string {\n return html.replace(\n /<style>([^<]*)<\\/style>/g,\n (_, css: string) => `<style>${css.replace(/\\s+/g, ' ').trim()}</style>`,\n )\n}\n\nexport interface RenderOptions {\n /** The host's attributes; a JSON attribute's value is its JSON text. */\n attributes?: Record<string, string> | undefined\n /** Light-DOM HTML after the shadow root: a slotted child, as the payment element is the checkout's. */\n children?: string | undefined\n}\n\n/**\n * One element as HTML: `<tag …attributes><template shadowrootmode=\"open\">…</template>…children</tag>`, the template\n * holding the element's first render from its attributes (no client, no store) with its styles, and the markers Lit's\n * hydration reads. The browser parses the template into the element's shadow root, and the element takes it over.\n */\nexport function renderElement(tag: string, options: RenderOptions = {}): string {\n if (CLIENT_MOUNTED.has(tag)) {\n throw new UnknownElement(`${tag} is client-mounted and is not server-rendered`)\n }\n if (classFor(tag) === undefined) {\n throw new UnknownElement(`${tag} is neither a Nymbal element nor a registered server element`)\n }\n defineAll()\n\n const renderer = new ServerElementRenderer(tag)\n for (const [name, value] of Object.entries(options.attributes ?? {})) {\n renderer.setAttribute(name, value)\n }\n renderer.connectedCallback()\n const renderInfo: RenderInfo = {\n elementRenderers: [ServerElementRenderer, LitElementRenderer],\n customElementInstanceStack: [renderer],\n customElementHostStack: [renderer],\n eventTargetStack: [renderer.element],\n slotStack: [],\n deferHydration: false,\n }\n const attributes = collectResultSync(renderer.renderAttributes())\n const shadow = compactStyles(collectResultSync(renderer.renderShadow(renderInfo)))\n const { mode = 'open' } = renderer.shadowRootOptions\n return `<${tag}${attributes}><template shadowrootmode=\"${mode}\">${shadow}</template>${options.children ?? ''}</${tag}>`\n}\n"],"mappings":"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","names":[]}