@liquidcommerce/elements-sdk 2.7.0 → 2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -2750
- package/dist/index.checkout.esm.js +6898 -6837
- package/dist/index.esm.js +11463 -10993
- package/dist/types/auto-initialize/shared-utils.d.ts +5 -0
- package/dist/types/constants/core.constant.d.ts +0 -4
- package/dist/types/core/base-component.service.d.ts +2 -1
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +1 -0
- package/dist/types/enums/core.enum.d.ts +11 -0
- package/dist/types/interfaces/configs/product-list.interface.d.ts +2 -2
- package/dist/types/interfaces/core.interface.d.ts +5 -4
- package/dist/types/modules/address/address-input.component.d.ts +11 -0
- package/dist/types/modules/checkout/components/checkout-stripe-form.component.d.ts +2 -1
- package/dist/types/modules/product-list/components/card-components/index.d.ts +3 -0
- package/dist/types/modules/product-list/components/card-components/product-badge.d.ts +8 -0
- package/dist/types/modules/product-list/components/card-components/product-fulfillments.d.ts +2 -0
- package/dist/types/modules/product-list/components/card-components/product-price-and-personalization.d.ts +13 -0
- package/dist/types/modules/product-list/components/card-components/product-title.d.ts +6 -0
- package/dist/types/modules/product-list/components/index.d.ts +1 -0
- package/dist/types/modules/product-list/components/product-list-engraving.component.d.ts +5 -1
- package/dist/types/modules/product-list/components/product-list-product-pre-cart.component.d.ts +28 -0
- package/dist/types/modules/product-list/components/product-list-retailers.component.d.ts +10 -2
- package/dist/types/modules/product-list/product-list-card.component.d.ts +0 -5
- package/dist/types/modules/product-list/product-list.commands.d.ts +11 -2
- package/dist/types/modules/product-list/product-list.interface.d.ts +1 -0
- package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +11 -2
- package/dist/types/modules/ui-components/lce-element/lce-element.component.d.ts +2 -1
- package/dist/types/utils/dom-compat.d.ts +2 -0
- package/docs/gitbook/actions.md +964 -0
- package/docs/gitbook/address.md +48 -0
- package/docs/gitbook/cart.md +65 -0
- package/docs/gitbook/checkout.md +131 -0
- package/docs/gitbook/events.md +1765 -0
- package/docs/gitbook/overview.md +166 -0
- package/docs/gitbook/product.md +64 -0
- package/docs/gitbook/quick-start-guide.md +393 -0
- package/docs/v1/README.md +210 -0
- package/docs/v1/api/actions/address-actions.md +281 -0
- package/docs/v1/api/actions/cart-actions.md +337 -0
- package/docs/v1/api/actions/checkout-actions.md +387 -0
- package/docs/v1/api/actions/product-actions.md +115 -0
- package/docs/v1/api/client.md +482 -0
- package/docs/v1/api/configuration.md +1 -0
- package/docs/v1/api/injection-methods.md +247 -0
- package/docs/v1/api/typescript-types.md +1 -0
- package/docs/v1/api/ui-helpers.md +200 -0
- package/docs/v1/examples/advanced-patterns.md +96 -0
- package/docs/v1/examples/checkout-flow.md +91 -0
- package/docs/v1/examples/custom-theming.md +63 -0
- package/docs/v1/examples/multi-product-page.md +90 -0
- package/docs/v1/examples/simple-product-page.md +89 -0
- package/docs/v1/getting-started/concepts.md +507 -0
- package/docs/v1/getting-started/installation.md +328 -0
- package/docs/v1/getting-started/quick-start.md +405 -0
- package/docs/v1/guides/address-component.md +431 -0
- package/docs/v1/guides/best-practices.md +324 -0
- package/docs/v1/guides/cart-component.md +737 -0
- package/docs/v1/guides/checkout-component.md +672 -0
- package/docs/v1/guides/events.md +926 -0
- package/docs/v1/guides/product-component.md +686 -0
- package/docs/v1/guides/product-list-component.md +598 -0
- package/docs/v1/guides/theming.md +216 -0
- package/docs/v1/integration/angular.md +39 -0
- package/docs/v1/integration/laravel.md +41 -0
- package/docs/v1/integration/nextjs.md +60 -0
- package/docs/v1/integration/proxy-setup.md +89 -0
- package/docs/v1/integration/react.md +64 -0
- package/docs/v1/integration/vanilla-js.md +84 -0
- package/docs/v1/integration/vue.md +34 -0
- package/docs/v1/reference/browser-support.md +44 -0
- package/docs/v1/reference/error-handling.md +70 -0
- package/docs/v1/reference/performance.md +54 -0
- package/docs/v1/reference/troubleshooting.md +64 -0
- package/package.json +1 -1
- package/docs/ACTIONS.md +0 -1301
- package/docs/BROWSER_SUPPORT.md +0 -279
- package/docs/CONFIGURATION.md +0 -997
- package/docs/DOCUMENTATION_INDEX.md +0 -319
- package/docs/EVENTS.md +0 -798
- package/docs/PROXY.md +0 -228
- package/docs/THEMING.md +0 -681
- package/docs/TROUBLESHOOTING.md +0 -793
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
# Product List Component
|
|
2
|
+
|
|
3
|
+
The Product List component provides a filterable, searchable product catalog with infinite scroll for building category pages and search results.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Product List component:
|
|
8
|
+
- Displays products in a responsive grid
|
|
9
|
+
- Supports infinite scroll pagination
|
|
10
|
+
- Provides search functionality
|
|
11
|
+
- Offers advanced filtering options
|
|
12
|
+
- Links to product detail pages
|
|
13
|
+
- Shows real-time availability
|
|
14
|
+
- Supports add-to-cart from list view
|
|
15
|
+
|
|
16
|
+
## Basic Usage
|
|
17
|
+
|
|
18
|
+
### Declarative Setup
|
|
19
|
+
|
|
20
|
+
Use data attributes to configure the product list:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<script
|
|
24
|
+
defer
|
|
25
|
+
data-liquid-commerce-elements
|
|
26
|
+
data-token="YOUR_API_KEY"
|
|
27
|
+
data-env="production"
|
|
28
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
29
|
+
></script>
|
|
30
|
+
|
|
31
|
+
<div
|
|
32
|
+
data-liquid-commerce-elements-products-list
|
|
33
|
+
data-rows="3"
|
|
34
|
+
data-columns="4"
|
|
35
|
+
data-filters="price,brand,category"
|
|
36
|
+
data-product-url="/product/{identifier}"
|
|
37
|
+
></div>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Attributes:**
|
|
41
|
+
- `data-liquid-commerce-elements-products-list`: Marks element as product list container
|
|
42
|
+
- `data-rows`: Number of rows to display (default: 3)
|
|
43
|
+
- `data-columns`: Number of columns (default: 4)
|
|
44
|
+
- `data-filters`: Comma-separated filter types
|
|
45
|
+
- `data-product-url`: URL pattern for product detail pages (optional)
|
|
46
|
+
|
|
47
|
+
The `{identifier}` placeholder in `data-product-url` is replaced with the product's identifier.
|
|
48
|
+
|
|
49
|
+
### With Search and Filters
|
|
50
|
+
|
|
51
|
+
Separate containers for search and filters:
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<!-- Search container -->
|
|
55
|
+
<div data-search-container></div>
|
|
56
|
+
|
|
57
|
+
<!-- Filters container -->
|
|
58
|
+
<div data-filters-container data-filters="price,brand,fulfillment"></div>
|
|
59
|
+
|
|
60
|
+
<!-- Product list -->
|
|
61
|
+
<div
|
|
62
|
+
data-liquid-commerce-elements-products-list
|
|
63
|
+
data-rows="4"
|
|
64
|
+
data-columns="3"
|
|
65
|
+
data-product-url="/products/{identifier}"
|
|
66
|
+
></div>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Programmatic Setup
|
|
70
|
+
|
|
71
|
+
Use JavaScript for dynamic configuration:
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
75
|
+
|
|
76
|
+
// Inject product list
|
|
77
|
+
await client.injectProductList({
|
|
78
|
+
containerId: 'products',
|
|
79
|
+
rows: 3,
|
|
80
|
+
columns: 4,
|
|
81
|
+
filters: ['price', 'brand', 'category', 'fulfillment'],
|
|
82
|
+
productUrl: '/product/{identifier}'
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Inject search (optional)
|
|
86
|
+
await client.injectProductListSearch({
|
|
87
|
+
containerId: 'search'
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Inject filters (optional)
|
|
91
|
+
await client.injectProductListFilters({
|
|
92
|
+
containerId: 'filters',
|
|
93
|
+
filters: ['price', 'brand']
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Available Filters
|
|
98
|
+
|
|
99
|
+
### Price Range
|
|
100
|
+
|
|
101
|
+
Filter products by price:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
filters: ['price']
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Shows price range slider with min/max values.
|
|
108
|
+
|
|
109
|
+
### Brand
|
|
110
|
+
|
|
111
|
+
Filter by brand/manufacturer:
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
filters: ['brand']
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Shows checkboxes for all available brands.
|
|
118
|
+
|
|
119
|
+
### Category
|
|
120
|
+
|
|
121
|
+
Filter by product category:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
filters: ['category']
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Shows category selection dropdown or checkboxes.
|
|
128
|
+
|
|
129
|
+
### Fulfillment Type
|
|
130
|
+
|
|
131
|
+
Filter by shipping vs. on-demand delivery:
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
filters: ['fulfillment']
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Options:
|
|
138
|
+
- Shipping only
|
|
139
|
+
- On-demand delivery only
|
|
140
|
+
- Both
|
|
141
|
+
|
|
142
|
+
### Engraving
|
|
143
|
+
|
|
144
|
+
Filter products that support personalization:
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
filters: ['engraving']
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Options:
|
|
151
|
+
- Can be engraved
|
|
152
|
+
- Cannot be engraved
|
|
153
|
+
- Show all
|
|
154
|
+
|
|
155
|
+
### Size
|
|
156
|
+
|
|
157
|
+
Filter by product size (volume):
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
filters: ['size']
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Shows available sizes (e.g., 750ml, 1L, 1.75L).
|
|
164
|
+
|
|
165
|
+
### Rating
|
|
166
|
+
|
|
167
|
+
Filter by customer ratings:
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
filters: ['rating']
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Options:
|
|
174
|
+
- 4+ stars
|
|
175
|
+
- 3+ stars
|
|
176
|
+
- All ratings
|
|
177
|
+
|
|
178
|
+
### Availability
|
|
179
|
+
|
|
180
|
+
Filter by stock status:
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
filters: ['availability']
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Options:
|
|
187
|
+
- In stock only
|
|
188
|
+
- All products
|
|
189
|
+
|
|
190
|
+
## Search Functionality
|
|
191
|
+
|
|
192
|
+
### Search Box
|
|
193
|
+
|
|
194
|
+
The search component provides full-text search across:
|
|
195
|
+
- Product names
|
|
196
|
+
- Descriptions
|
|
197
|
+
- Brand names
|
|
198
|
+
- Categories
|
|
199
|
+
- SKUs/UPCs
|
|
200
|
+
|
|
201
|
+
### Search Behavior
|
|
202
|
+
|
|
203
|
+
- Real-time search as user types (debounced)
|
|
204
|
+
- Minimum 2 characters to trigger search
|
|
205
|
+
- Highlights matching terms in results
|
|
206
|
+
- Shows result count
|
|
207
|
+
- "Clear search" button appears when active
|
|
208
|
+
|
|
209
|
+
### Programmatic Search
|
|
210
|
+
|
|
211
|
+
Control search via JavaScript:
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
// Get current search term
|
|
215
|
+
const currentSearch = store.get('productList.search.query');
|
|
216
|
+
|
|
217
|
+
// Set search programmatically
|
|
218
|
+
store.set('productList.search.query', 'whiskey');
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Grid Layout
|
|
222
|
+
|
|
223
|
+
### Responsive Grid
|
|
224
|
+
|
|
225
|
+
The grid automatically adjusts for screen sizes:
|
|
226
|
+
|
|
227
|
+
**Desktop** (> 1024px):
|
|
228
|
+
- Uses configured columns (e.g., 4 columns)
|
|
229
|
+
|
|
230
|
+
**Tablet** (768px - 1024px):
|
|
231
|
+
- Reduces to 3 or 2 columns
|
|
232
|
+
|
|
233
|
+
**Mobile** (< 768px):
|
|
234
|
+
- Single column or 2 columns depending on space
|
|
235
|
+
|
|
236
|
+
### Configuring Layout
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
await client.injectProductList({
|
|
240
|
+
containerId: 'products',
|
|
241
|
+
rows: 5, // Number of rows per page
|
|
242
|
+
columns: 4 // Columns in grid (desktop)
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Total products per page = rows × columns (e.g., 5 × 4 = 20 products)
|
|
247
|
+
|
|
248
|
+
## Infinite Scroll
|
|
249
|
+
|
|
250
|
+
### How It Works
|
|
251
|
+
|
|
252
|
+
1. Initial products load (rows × columns)
|
|
253
|
+
2. User scrolls to bottom
|
|
254
|
+
3. Next page loads automatically
|
|
255
|
+
4. Appends to existing products
|
|
256
|
+
5. Continues until all products shown
|
|
257
|
+
|
|
258
|
+
### Loading States
|
|
259
|
+
|
|
260
|
+
Shows loading indicator:
|
|
261
|
+
- On initial load
|
|
262
|
+
- When loading next page
|
|
263
|
+
- When applying filters
|
|
264
|
+
- When searching
|
|
265
|
+
|
|
266
|
+
### End of Results
|
|
267
|
+
|
|
268
|
+
When all products are shown:
|
|
269
|
+
- Infinite scroll stops
|
|
270
|
+
- Shows "No more products" message
|
|
271
|
+
- Scroll to top button may appear
|
|
272
|
+
|
|
273
|
+
## Product Cards
|
|
274
|
+
|
|
275
|
+
Each product card shows:
|
|
276
|
+
|
|
277
|
+
- Product image
|
|
278
|
+
- Product name
|
|
279
|
+
- Brand
|
|
280
|
+
- Price (or price range for multiple sizes)
|
|
281
|
+
- Rating (if available)
|
|
282
|
+
- "Quick View" or "View Details" button
|
|
283
|
+
- "Add to Cart" button (optional)
|
|
284
|
+
- Availability indicator
|
|
285
|
+
|
|
286
|
+
### Card Interaction
|
|
287
|
+
|
|
288
|
+
**Click on card:** Navigate to product detail page (if `productUrl` configured)
|
|
289
|
+
|
|
290
|
+
**Quick Add:** Add product to cart directly from list view (if enabled)
|
|
291
|
+
|
|
292
|
+
**Click on image:** Open image in lightbox or navigate to product page
|
|
293
|
+
|
|
294
|
+
## Customization
|
|
295
|
+
|
|
296
|
+
### Theme Configuration
|
|
297
|
+
|
|
298
|
+
```javascript
|
|
299
|
+
const client = await Elements('YOUR_API_KEY', {
|
|
300
|
+
env: 'production',
|
|
301
|
+
customTheme: {
|
|
302
|
+
productList: {
|
|
303
|
+
theme: {
|
|
304
|
+
cardBackgroundColor: '#ffffff',
|
|
305
|
+
cardBorderColor: '#e0e0e0',
|
|
306
|
+
cardHoverShadow: '0 4px 8px rgba(0,0,0,0.1)'
|
|
307
|
+
},
|
|
308
|
+
layout: {
|
|
309
|
+
showProductImages: true,
|
|
310
|
+
showBrand: true,
|
|
311
|
+
showPrice: true,
|
|
312
|
+
showRating: true,
|
|
313
|
+
showAvailability: true,
|
|
314
|
+
showAddToCartButton: false, // Enable quick add
|
|
315
|
+
cardImageAspectRatio: '1:1', // or '4:3', '16:9'
|
|
316
|
+
gridGap: '20px',
|
|
317
|
+
enableInfiniteScroll: true,
|
|
318
|
+
productsPerPage: 12 // Override rows × columns
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Use Cases
|
|
326
|
+
|
|
327
|
+
### Category Page
|
|
328
|
+
|
|
329
|
+
```html
|
|
330
|
+
<!DOCTYPE html>
|
|
331
|
+
<html>
|
|
332
|
+
<head>
|
|
333
|
+
<title>Whiskey Collection</title>
|
|
334
|
+
<script
|
|
335
|
+
defer
|
|
336
|
+
data-liquid-commerce-elements
|
|
337
|
+
data-token="YOUR_API_KEY"
|
|
338
|
+
data-env="production"
|
|
339
|
+
src="https://assets-elements.liquidcommerce.us/all/elements.js"
|
|
340
|
+
></script>
|
|
341
|
+
</head>
|
|
342
|
+
<body>
|
|
343
|
+
<h1>Whiskey Collection</h1>
|
|
344
|
+
|
|
345
|
+
<!-- Search -->
|
|
346
|
+
<div data-search-container></div>
|
|
347
|
+
|
|
348
|
+
<div class="catalog">
|
|
349
|
+
<!-- Filters sidebar -->
|
|
350
|
+
<aside>
|
|
351
|
+
<div data-filters-container data-filters="price,brand,size"></div>
|
|
352
|
+
</aside>
|
|
353
|
+
|
|
354
|
+
<!-- Product grid -->
|
|
355
|
+
<main>
|
|
356
|
+
<div
|
|
357
|
+
data-liquid-commerce-elements-products-list
|
|
358
|
+
data-rows="4"
|
|
359
|
+
data-columns="3"
|
|
360
|
+
data-product-url="/whiskey/{identifier}"
|
|
361
|
+
></div>
|
|
362
|
+
</main>
|
|
363
|
+
</div>
|
|
364
|
+
</body>
|
|
365
|
+
</html>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Search Results Page
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
import { Elements } from '@liquidcommerce/elements-sdk';
|
|
372
|
+
|
|
373
|
+
const client = await Elements('YOUR_API_KEY', { env: 'production' });
|
|
374
|
+
|
|
375
|
+
// Get search query from URL
|
|
376
|
+
const params = new URLSearchParams(window.location.search);
|
|
377
|
+
const searchQuery = params.get('q');
|
|
378
|
+
|
|
379
|
+
// Inject product list
|
|
380
|
+
await client.injectProductList({
|
|
381
|
+
containerId: 'search-results',
|
|
382
|
+
rows: 5,
|
|
383
|
+
columns: 4,
|
|
384
|
+
filters: ['price', 'brand', 'category']
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Apply search
|
|
388
|
+
if (searchQuery) {
|
|
389
|
+
store.set('productList.search.query', searchQuery);
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Dynamic Filtering
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
// Listen for filter changes
|
|
397
|
+
window.addEventListener('lce:productList.filterChanged', (event) => {
|
|
398
|
+
const { filterType, filterValue } = event.detail;
|
|
399
|
+
|
|
400
|
+
console.log(`Filter changed: ${filterType} = ${filterValue}`);
|
|
401
|
+
|
|
402
|
+
// Track filter usage
|
|
403
|
+
gtag('event', 'filter_applied', {
|
|
404
|
+
filter_type: filterType,
|
|
405
|
+
filter_value: filterValue
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Listen for search
|
|
410
|
+
window.addEventListener('lce:productList.searchChanged', (event) => {
|
|
411
|
+
const { query, resultCount } = event.detail;
|
|
412
|
+
|
|
413
|
+
console.log(`Search: "${query}" (${resultCount} results)`);
|
|
414
|
+
|
|
415
|
+
// Track search
|
|
416
|
+
gtag('event', 'search', {
|
|
417
|
+
search_term: query,
|
|
418
|
+
result_count: resultCount
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Custom Product URL Patterns
|
|
424
|
+
|
|
425
|
+
Different URL patterns for different product types:
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
// Get product type from data
|
|
429
|
+
const productType = getProductTypeFromData();
|
|
430
|
+
|
|
431
|
+
let urlPattern;
|
|
432
|
+
switch (productType) {
|
|
433
|
+
case 'whiskey':
|
|
434
|
+
urlPattern = '/spirits/whiskey/{identifier}';
|
|
435
|
+
break;
|
|
436
|
+
case 'wine':
|
|
437
|
+
urlPattern = '/wine/{identifier}';
|
|
438
|
+
break;
|
|
439
|
+
default:
|
|
440
|
+
urlPattern = '/products/{identifier}';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
await client.injectProductList({
|
|
444
|
+
containerId: 'products',
|
|
445
|
+
rows: 3,
|
|
446
|
+
columns: 4,
|
|
447
|
+
productUrl: urlPattern
|
|
448
|
+
});
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Events
|
|
452
|
+
|
|
453
|
+
While product list events are primarily internal, you can listen for cart events when users add products:
|
|
454
|
+
|
|
455
|
+
```javascript
|
|
456
|
+
window.addEventListener('lce:actions.cart_item_added', (event) => {
|
|
457
|
+
const { itemId, quantity } = event.detail.data;
|
|
458
|
+
console.log(`Product added from list: ${itemId}`);
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
## Accessibility
|
|
463
|
+
|
|
464
|
+
The product list component includes:
|
|
465
|
+
|
|
466
|
+
- Keyboard navigation support
|
|
467
|
+
- Screen reader labels
|
|
468
|
+
- ARIA attributes for filters and search
|
|
469
|
+
- Focus management
|
|
470
|
+
- High contrast support
|
|
471
|
+
|
|
472
|
+
### Keyboard Shortcuts
|
|
473
|
+
|
|
474
|
+
- `Tab`: Navigate between products and filters
|
|
475
|
+
- `Enter/Space`: Select product or toggle filter
|
|
476
|
+
- `Escape`: Clear search or close filters
|
|
477
|
+
- `Arrow keys`: Navigate grid (when focused)
|
|
478
|
+
|
|
479
|
+
## Performance
|
|
480
|
+
|
|
481
|
+
### Optimization Features
|
|
482
|
+
|
|
483
|
+
- **Image lazy loading**: Images load as they enter viewport
|
|
484
|
+
- **Virtual scrolling**: Only renders visible products
|
|
485
|
+
- **Debounced search**: Reduces API calls during typing
|
|
486
|
+
- **Filter caching**: Caches filter results
|
|
487
|
+
- **Progressive loading**: Loads in batches
|
|
488
|
+
|
|
489
|
+
### Large Catalogs
|
|
490
|
+
|
|
491
|
+
For catalogs with thousands of products:
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
await client.injectProductList({
|
|
495
|
+
containerId: 'products',
|
|
496
|
+
rows: 3,
|
|
497
|
+
columns: 4,
|
|
498
|
+
filters: ['price', 'brand'], // Limit filters to most useful
|
|
499
|
+
// More rows = larger pages = fewer API calls
|
|
500
|
+
});
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Best Practices
|
|
504
|
+
|
|
505
|
+
### Provide Clear Navigation
|
|
506
|
+
|
|
507
|
+
```html
|
|
508
|
+
<nav class="breadcrumb">
|
|
509
|
+
<a href="/">Home</a> >
|
|
510
|
+
<a href="/products">Products</a> >
|
|
511
|
+
<span>Whiskey</span>
|
|
512
|
+
</nav>
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Show Result Counts
|
|
516
|
+
|
|
517
|
+
Display the number of products found:
|
|
518
|
+
|
|
519
|
+
```javascript
|
|
520
|
+
window.addEventListener('lce:productList.updated', (event) => {
|
|
521
|
+
const { totalProducts, displayedProducts } = event.detail;
|
|
522
|
+
document.getElementById('result-count').textContent =
|
|
523
|
+
`Showing ${displayedProducts} of ${totalProducts} products`;
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Mobile-First Design
|
|
528
|
+
|
|
529
|
+
Ensure filters work well on mobile:
|
|
530
|
+
|
|
531
|
+
```css
|
|
532
|
+
@media (max-width: 768px) {
|
|
533
|
+
.filters-sidebar {
|
|
534
|
+
position: fixed;
|
|
535
|
+
bottom: 0;
|
|
536
|
+
left: 0;
|
|
537
|
+
right: 0;
|
|
538
|
+
transform: translateY(100%);
|
|
539
|
+
transition: transform 0.3s;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.filters-sidebar.open {
|
|
543
|
+
transform: translateY(0);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Default to Relevant Filters
|
|
549
|
+
|
|
550
|
+
For category pages, pre-select relevant filters:
|
|
551
|
+
|
|
552
|
+
```javascript
|
|
553
|
+
// On whiskey category page
|
|
554
|
+
await client.injectProductList({
|
|
555
|
+
containerId: 'products',
|
|
556
|
+
rows: 4,
|
|
557
|
+
columns: 3,
|
|
558
|
+
filters: ['price', 'brand', 'size'] // Most relevant for whiskey
|
|
559
|
+
});
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Troubleshooting
|
|
563
|
+
|
|
564
|
+
### Products Not Loading
|
|
565
|
+
|
|
566
|
+
1. Check browser console for errors
|
|
567
|
+
2. Verify API key is correct
|
|
568
|
+
3. Ensure container ID exists
|
|
569
|
+
4. Check network tab for API responses
|
|
570
|
+
5. Verify products exist in catalog
|
|
571
|
+
|
|
572
|
+
### Filters Not Working
|
|
573
|
+
|
|
574
|
+
1. Ensure filter types are spelled correctly
|
|
575
|
+
2. Check that products have filterable attributes
|
|
576
|
+
3. Verify theme config allows filters
|
|
577
|
+
4. Look for JavaScript errors
|
|
578
|
+
|
|
579
|
+
### Infinite Scroll Not Triggering
|
|
580
|
+
|
|
581
|
+
1. Check container has finite height
|
|
582
|
+
2. Verify scroll event listeners are attached
|
|
583
|
+
3. Ensure there are more products to load
|
|
584
|
+
4. Check console for errors
|
|
585
|
+
|
|
586
|
+
### Search Not Finding Products
|
|
587
|
+
|
|
588
|
+
1. Verify minimum character count is met (2 chars)
|
|
589
|
+
2. Check search is not case-sensitive (it shouldn't be)
|
|
590
|
+
3. Ensure products have searchable text fields
|
|
591
|
+
4. Look for API errors in network tab
|
|
592
|
+
|
|
593
|
+
## See Also
|
|
594
|
+
|
|
595
|
+
- [Product Component](./product-component.md) - Individual product display
|
|
596
|
+
- [Cart Component](./cart-component.md) - Add products to cart
|
|
597
|
+
- [Theming](./theming.md) - Customize appearance
|
|
598
|
+
- [Events](./events.md) - Available events
|