@nymbalhq/web-components 1.1.0 → 1.3.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-5G3C53A2.js +666 -0
  12. package/dist/chunk-5G3C53A2.js.map +1 -0
  13. package/dist/chunk-5VWZ2U5K.js +149 -0
  14. package/dist/chunk-5VWZ2U5K.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-XPFGMYBV.js +137 -0
  80. package/dist/chunk-XPFGMYBV.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
@@ -0,0 +1,204 @@
1
+ import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
2
+ import {
3
+ NymbalElement,
4
+ baseStyles,
5
+ propertiesOf
6
+ } from "./chunk-EYDMJNNK.js";
7
+
8
+ // src/components/search-bar.ts
9
+ import { css, html, nothing } from "lit";
10
+ var SCHEMA = {
11
+ tag: "nymbal-search-bar",
12
+ reactName: "SearchBar",
13
+ attributes: [
14
+ { name: "placeholder", prop: "placeholder", type: "string" },
15
+ { name: "debounce-ms", prop: "debounceMs", type: "number" }
16
+ ],
17
+ events: [
18
+ { name: "nymbal:search:selected", prop: "onSearchSelect", detail: "{ product: unknown }" }
19
+ ],
20
+ parts: ["input", "results", "loading", "result", "result-name", "result-price"],
21
+ slots: ["loading"],
22
+ children: false
23
+ };
24
+ var NO_SEARCH = { query: "", loading: false, results: [] };
25
+ function formatPrice(minor, currency) {
26
+ return new Intl.NumberFormat(void 0, { style: "currency", currency }).format(minor / 100);
27
+ }
28
+ var NymbalSearchBar = class extends NymbalElement {
29
+ static schema = SCHEMA;
30
+ static properties = propertiesOf(SCHEMA);
31
+ static styles = [
32
+ baseStyles,
33
+ css`
34
+ :host {
35
+ display: block;
36
+ position: relative;
37
+ font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);
38
+ }
39
+ [part~='input'] {
40
+ font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);
41
+ font-size: var(--nymbal-font-size-base, 1rem);
42
+ width: 100%;
43
+ padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);
44
+ border: 1px solid var(--nymbal-color-border, #e4e4e7);
45
+ border-radius: var(--nymbal-radius-md, 0.375rem);
46
+ outline: none;
47
+ transition: border-color var(--nymbal-transition-fast, 150ms ease);
48
+ }
49
+ [part~='input']:focus {
50
+ border-color: var(--nymbal-color-accent, #2563eb);
51
+ }
52
+ [part~='results'] {
53
+ position: absolute;
54
+ top: 100%;
55
+ left: 0;
56
+ right: 0;
57
+ background: var(--nymbal-color-surface, #ffffff);
58
+ border: 1px solid var(--nymbal-color-border, #e4e4e7);
59
+ border-top: none;
60
+ border-radius: 0 0 var(--nymbal-radius-md, 0.375rem) var(--nymbal-radius-md, 0.375rem);
61
+ box-shadow: var(--nymbal-shadow-md, 0 4px 6px rgba(0, 0, 0, 0.1));
62
+ z-index: var(--nymbal-z-dropdown, 100);
63
+ max-height: 300px;
64
+ overflow-y: auto;
65
+ }
66
+ [part~='result'] {
67
+ padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);
68
+ cursor: pointer;
69
+ transition: background var(--nymbal-transition-fast, 150ms ease);
70
+ }
71
+ [part~='result']:hover,
72
+ [part~='result'][aria-selected='true'] {
73
+ background: var(--nymbal-color-secondary, #f4f4f5);
74
+ }
75
+ [part~='result-name'] {
76
+ font-weight: var(--nymbal-font-weight-medium, 500);
77
+ }
78
+ [part~='result-price'] {
79
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
80
+ color: var(--nymbal-color-text-muted, #71717a);
81
+ }
82
+ [part~='loading'] {
83
+ padding: var(--nymbal-spacing-md, 1rem);
84
+ text-align: center;
85
+ color: var(--nymbal-color-text-muted, #71717a);
86
+ font-size: var(--nymbal-font-size-sm, 0.875rem);
87
+ }
88
+ `
89
+ ];
90
+ debounceTimer = null;
91
+ selectedIndex = -1;
92
+ stores() {
93
+ return [this.client.search];
94
+ }
95
+ render() {
96
+ const state = this.readsStores ? this.client.search.getState() : NO_SEARCH;
97
+ const placeholder = this.getAttribute("placeholder") ?? "Search products...";
98
+ let results = nothing;
99
+ if (state.query && document.querySelector("nymbal-search-results") === null) {
100
+ if (state.loading) {
101
+ results = html`<div part="results" data-testid="search-results">
102
+ <div part="loading"><slot name="loading">Searching...</slot></div>
103
+ </div>`;
104
+ } else if (state.results.length > 0) {
105
+ results = html`<div part="results" data-testid="search-results">
106
+ ${state.results.map(
107
+ (product, i) => html`
108
+ <div
109
+ part="result"
110
+ class="nymbal-search-result-item"
111
+ data-testid="search-result-${product.slug}"
112
+ data-slug=${product.slug}
113
+ aria-selected=${String(i === this.selectedIndex)}
114
+ @click=${() => this.select(product)}
115
+ >
116
+ <div part="result-name">${product.name}</div>
117
+ ${product.priceMinor !== null ? html`<div part="result-price">
118
+ ${formatPrice(product.priceMinor, product.currency ?? "USD")}
119
+ </div>` : nothing}
120
+ </div>
121
+ `
122
+ )}
123
+ </div>`;
124
+ }
125
+ }
126
+ return html`
127
+ <input
128
+ part="input"
129
+ data-testid="search-input"
130
+ type="search"
131
+ placeholder=${placeholder}
132
+ .value=${state.query}
133
+ autocomplete="off"
134
+ role="combobox"
135
+ aria-expanded=${String(results !== nothing && state.results.length > 0)}
136
+ aria-haspopup="listbox"
137
+ @input=${this.handleInput}
138
+ @keydown=${this.handleKeydown}
139
+ />
140
+ ${results}
141
+ `;
142
+ }
143
+ handleInput = (e) => {
144
+ const query = e.target.value;
145
+ const debounceMs = Number(this.getAttribute("debounce-ms")) || 300;
146
+ if (this.debounceTimer !== null) clearTimeout(this.debounceTimer);
147
+ this.debounceTimer = setTimeout(() => {
148
+ this.selectedIndex = -1;
149
+ if (query.trim()) {
150
+ void this.client.search.search(query);
151
+ } else {
152
+ this.client.search.clearSearch();
153
+ }
154
+ }, debounceMs);
155
+ };
156
+ handleKeydown = (e) => {
157
+ const { results } = this.client.search.getState();
158
+ if (e.key === "ArrowDown") {
159
+ e.preventDefault();
160
+ this.selectedIndex = Math.min(this.selectedIndex + 1, results.length - 1);
161
+ this.requestUpdate();
162
+ } else if (e.key === "ArrowUp") {
163
+ e.preventDefault();
164
+ this.selectedIndex = Math.max(this.selectedIndex - 1, -1);
165
+ this.requestUpdate();
166
+ } else if (e.key === "Enter") {
167
+ e.preventDefault();
168
+ const selected = this.selectedIndex >= 0 ? results[this.selectedIndex] : void 0;
169
+ if (selected) {
170
+ this.select(selected);
171
+ } else {
172
+ const query = e.target.value.trim();
173
+ if (query) {
174
+ window.location.href = `/search?q=${encodeURIComponent(query)}`;
175
+ }
176
+ }
177
+ } else if (e.key === "Escape") {
178
+ this.client.search.clearSearch();
179
+ this.selectedIndex = -1;
180
+ }
181
+ };
182
+ select(product) {
183
+ this.dispatchEvent(
184
+ new CustomEvent("nymbal:search:selected", {
185
+ bubbles: true,
186
+ composed: true,
187
+ detail: { product, query: product.name }
188
+ })
189
+ );
190
+ this.client.search.clearSearch();
191
+ }
192
+ disconnectedCallback() {
193
+ super.disconnectedCallback();
194
+ if (this.debounceTimer !== null) {
195
+ clearTimeout(this.debounceTimer);
196
+ this.debounceTimer = null;
197
+ }
198
+ }
199
+ };
200
+
201
+ export {
202
+ NymbalSearchBar
203
+ };
204
+ //# sourceMappingURL=chunk-4COVK727.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/search-bar.ts"],"sourcesContent":["import { css, html, nothing } from 'lit'\nimport type { DenormalisedProduct } from '@nymbalhq/sdk'\nimport { baseStyles, NymbalElement, propertiesOf, type ElementSchema } from '../base-element.js'\n\nconst SCHEMA: ElementSchema = {\n tag: 'nymbal-search-bar',\n reactName: 'SearchBar',\n attributes: [\n { name: 'placeholder', prop: 'placeholder', type: 'string' },\n { name: 'debounce-ms', prop: 'debounceMs', type: 'number' },\n ],\n events: [\n { name: 'nymbal:search:selected', prop: 'onSearchSelect', detail: '{ product: unknown }' },\n ],\n parts: ['input', 'results', 'loading', 'result', 'result-name', 'result-price'],\n slots: ['loading'],\n children: false,\n}\n\n/** What a search bar shows before any search, and on a server. */\nconst NO_SEARCH = { query: '', loading: false, results: [] as DenormalisedProduct[] }\n\nfunction formatPrice(minor: number, currency: string): string {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(minor / 100)\n}\n\nexport class NymbalSearchBar extends NymbalElement {\n static override schema = SCHEMA\n static override properties = propertiesOf(SCHEMA)\n\n static override styles = [\n baseStyles,\n css`\n :host {\n display: block;\n position: relative;\n font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);\n }\n [part~='input'] {\n font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);\n font-size: var(--nymbal-font-size-base, 1rem);\n width: 100%;\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.375rem);\n outline: none;\n transition: border-color var(--nymbal-transition-fast, 150ms ease);\n }\n [part~='input']:focus {\n border-color: var(--nymbal-color-accent, #2563eb);\n }\n [part~='results'] {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n background: var(--nymbal-color-surface, #ffffff);\n border: 1px solid var(--nymbal-color-border, #e4e4e7);\n border-top: none;\n border-radius: 0 0 var(--nymbal-radius-md, 0.375rem) var(--nymbal-radius-md, 0.375rem);\n box-shadow: var(--nymbal-shadow-md, 0 4px 6px rgba(0, 0, 0, 0.1));\n z-index: var(--nymbal-z-dropdown, 100);\n max-height: 300px;\n overflow-y: auto;\n }\n [part~='result'] {\n padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);\n cursor: pointer;\n transition: background var(--nymbal-transition-fast, 150ms ease);\n }\n [part~='result']:hover,\n [part~='result'][aria-selected='true'] {\n background: var(--nymbal-color-secondary, #f4f4f5);\n }\n [part~='result-name'] {\n font-weight: var(--nymbal-font-weight-medium, 500);\n }\n [part~='result-price'] {\n font-size: var(--nymbal-font-size-sm, 0.875rem);\n color: var(--nymbal-color-text-muted, #71717a);\n }\n [part~='loading'] {\n padding: var(--nymbal-spacing-md, 1rem);\n text-align: center;\n color: var(--nymbal-color-text-muted, #71717a);\n font-size: var(--nymbal-font-size-sm, 0.875rem);\n }\n `,\n ]\n\n private debounceTimer: ReturnType<typeof setTimeout> | null = null\n private selectedIndex = -1\n\n protected override stores() {\n return [this.client.search]\n }\n\n protected override render() {\n const state = this.readsStores ? this.client.search.getState() : NO_SEARCH\n const placeholder = this.getAttribute('placeholder') ?? 'Search products...'\n\n let results: unknown = nothing\n // A page that shows the search itself (`nymbal-search-results`) is not covered by the same results as suggestions.\n if (state.query && document.querySelector('nymbal-search-results') === null) {\n if (state.loading) {\n results = html`<div part=\"results\" data-testid=\"search-results\">\n <div part=\"loading\"><slot name=\"loading\">Searching...</slot></div>\n </div>`\n } else if (state.results.length > 0) {\n results = html`<div part=\"results\" data-testid=\"search-results\">\n ${state.results.map(\n (product, i) => html`\n <div\n part=\"result\"\n class=\"nymbal-search-result-item\"\n data-testid=\"search-result-${product.slug}\"\n data-slug=${product.slug}\n aria-selected=${String(i === this.selectedIndex)}\n @click=${() => this.select(product)}\n >\n <div part=\"result-name\">${product.name}</div>\n ${product.priceMinor !== null\n ? html`<div part=\"result-price\">\n ${formatPrice(product.priceMinor, product.currency ?? 'USD')}\n </div>`\n : nothing}\n </div>\n `,\n )}\n </div>`\n }\n }\n\n return html`\n <input\n part=\"input\"\n data-testid=\"search-input\"\n type=\"search\"\n placeholder=${placeholder}\n .value=${state.query}\n autocomplete=\"off\"\n role=\"combobox\"\n aria-expanded=${String(results !== nothing && state.results.length > 0)}\n aria-haspopup=\"listbox\"\n @input=${this.handleInput}\n @keydown=${this.handleKeydown}\n />\n ${results}\n `\n }\n\n private handleInput = (e: Event): void => {\n const query = (e.target as HTMLInputElement).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 void this.client.search.search(query)\n } else {\n this.client.search.clearSearch()\n }\n }, debounceMs)\n }\n\n private handleKeydown = (e: KeyboardEvent): void => {\n const { results } = this.client.search.getState()\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n this.selectedIndex = Math.min(this.selectedIndex + 1, results.length - 1)\n this.requestUpdate()\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n this.selectedIndex = Math.max(this.selectedIndex - 1, -1)\n this.requestUpdate()\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 = (e.target as HTMLInputElement).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 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 override disconnectedCallback(): void {\n super.disconnectedCallback()\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer)\n this.debounceTimer = null\n }\n }\n}\n"],"mappings":"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","names":[]}