@liquidcommerce/elements-sdk 2.7.30 → 2.7.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.checkout.esm.js +7623 -7605
- package/dist/index.esm.js +12672 -12516
- package/dist/types/constants/core.constant.d.ts +13 -13
- package/dist/types/interfaces/api/product-list.interface.d.ts +1 -1
- package/dist/types/interfaces/injection.interface.d.ts +1 -0
- package/dist/types/modules/product-list/components/filter-components/product-list-checkbox-filter.d.ts +1 -0
- package/dist/types/modules/product-list/components/filter-components/product-list-price-filter.d.ts +1 -0
- package/dist/types/modules/product-list/components/product-list-card.component.d.ts +1 -0
- package/dist/types/modules/product-list/components/product-list-filters.component.d.ts +7 -5
- package/dist/types/modules/product-list/product-list-filter.registry.d.ts +42 -0
- package/dist/types/modules/product-list/product-list-filter.utils.d.ts +1 -2
- package/dist/types/modules/product-list/product-list-order.utils.d.ts +3 -0
- package/dist/types/modules/product-list/product-list.component.d.ts +6 -0
- package/dist/types/modules/product-list/product-list.interface.d.ts +1 -0
- package/docs/v1/api/injection-methods.md +39 -0
- package/docs/v1/api/typescript-types.md +1 -0
- package/docs/v1/guides/product-list-component.md +101 -1
- package/package.json +3 -3
|
@@ -3,19 +3,19 @@ export declare const API_CLIENT_URL: {
|
|
|
3
3
|
production: string;
|
|
4
4
|
};
|
|
5
5
|
export declare const PRODUCT_LIST_FILTER_TYPES: {
|
|
6
|
-
ENGRAVING:
|
|
7
|
-
FULFILLMENT:
|
|
8
|
-
PRICE:
|
|
9
|
-
BRANDS:
|
|
10
|
-
CATEGORIES:
|
|
11
|
-
FLAVOR:
|
|
12
|
-
REGION:
|
|
13
|
-
VARIETY:
|
|
14
|
-
VINTAGE:
|
|
15
|
-
COUNTRY:
|
|
16
|
-
APPELLATION:
|
|
17
|
-
MATERIALS:
|
|
18
|
-
SIZES:
|
|
6
|
+
readonly ENGRAVING: "engraving";
|
|
7
|
+
readonly FULFILLMENT: "fulfillment";
|
|
8
|
+
readonly PRICE: "price";
|
|
9
|
+
readonly BRANDS: "brands";
|
|
10
|
+
readonly CATEGORIES: "categories";
|
|
11
|
+
readonly FLAVOR: "flavor";
|
|
12
|
+
readonly REGION: "region";
|
|
13
|
+
readonly VARIETY: "variety";
|
|
14
|
+
readonly VINTAGE: "vintage";
|
|
15
|
+
readonly COUNTRY: "country";
|
|
16
|
+
readonly APPELLATION: "appellation";
|
|
17
|
+
readonly MATERIALS: "materials";
|
|
18
|
+
readonly SIZES: "sizes";
|
|
19
19
|
};
|
|
20
20
|
export declare const Z_INDEX: {
|
|
21
21
|
readonly DRAWER_WRAPPER: 2147483640;
|
|
@@ -21,7 +21,7 @@ export interface IFilterParams {
|
|
|
21
21
|
export type FacetFilterKeys = typeof FILTER_KEYS.BRANDS | typeof FILTER_KEYS.CATEGORIES | typeof FILTER_KEYS.FLAVOR | typeof FILTER_KEYS.REGION | typeof FILTER_KEYS.VARIETY | typeof FILTER_KEYS.VINTAGE | typeof FILTER_KEYS.COUNTRY | typeof FILTER_KEYS.APPELLATION | typeof FILTER_KEYS.TAGS | typeof FILTER_KEYS.MATERIALS | typeof FILTER_KEYS.SIZES | typeof FILTER_KEYS.ENGRAVING | typeof FILTER_KEYS.FULFILLMENT | typeof FILTER_KEYS.PRICE | typeof FILTER_KEYS.AVAILABILITY | typeof FILTER_KEYS.COLORS;
|
|
22
22
|
export interface IFilterSchema {
|
|
23
23
|
type: FacetFilterKeys;
|
|
24
|
-
values: IFilterValue[];
|
|
24
|
+
values: IFilterValue[] | string[];
|
|
25
25
|
}
|
|
26
26
|
export interface IFilterValue {
|
|
27
27
|
value: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ICheckboxLabelStates, ICreateCheckboxFilterHeaderParams, ICreateCheckboxFilterSearchContainerParams, ICreateCheckboxItemParams, IHandleCheckboxFilterSearchParams, IRenderCheckboxItemsParams } from '../../product-list.interface';
|
|
2
2
|
export declare function createCheckboxItem(params: ICreateCheckboxItemParams): HTMLElement;
|
|
3
3
|
export declare function handleCheckboxFilterSearch(params: IHandleCheckboxFilterSearchParams): void;
|
|
4
|
+
export declare function checkboxFilterContentId(filterType: string): string;
|
|
4
5
|
export declare function createCheckboxFilterHeader(params: ICreateCheckboxFilterHeaderParams): HTMLElement;
|
|
5
6
|
export declare function createCheckboxFilterSearchContainer(params: ICreateCheckboxFilterSearchContainerParams): HTMLElement;
|
|
6
7
|
export declare function renderCheckboxItems(params: IRenderCheckboxItemsParams): void;
|
|
@@ -25,6 +25,7 @@ export declare class ProductListCardComponent extends BaseComponent<IProductList
|
|
|
25
25
|
private getSelectedSize;
|
|
26
26
|
private getDisplayPrice;
|
|
27
27
|
protected template(): HTMLElement[];
|
|
28
|
+
protected afterRender(): void;
|
|
28
29
|
private updatePriceDisplay;
|
|
29
30
|
private updateFulfillmentText;
|
|
30
31
|
private updateImage;
|
|
@@ -13,15 +13,13 @@ export declare class ProductListFiltersComponent extends BaseComponent<IProductL
|
|
|
13
13
|
private isPriceFilterCollapsed;
|
|
14
14
|
private isFulfillmentFilterCollapsed;
|
|
15
15
|
private appliedFiltersChipsContainer;
|
|
16
|
-
private
|
|
17
|
-
private fulfillmentFilterContainer?;
|
|
18
|
-
private priceFiltersContainer?;
|
|
19
|
-
private dynamicFiltersContainer?;
|
|
16
|
+
private filterSectionsContainer?;
|
|
20
17
|
private filterButtonContainer?;
|
|
21
18
|
private fulfillmentOptionsList?;
|
|
22
19
|
private priceFilterChevronIcon?;
|
|
23
20
|
private fulfillmentFilterChevronIcon?;
|
|
24
21
|
private priceSliderWrapper?;
|
|
22
|
+
private priceFilterHeaderButton;
|
|
25
23
|
private boundDrawerClosedHandler;
|
|
26
24
|
private priceFilterDebounceTimer;
|
|
27
25
|
constructor();
|
|
@@ -35,7 +33,8 @@ export declare class ProductListFiltersComponent extends BaseComponent<IProductL
|
|
|
35
33
|
private createFilterSection;
|
|
36
34
|
private rebuildContainer;
|
|
37
35
|
private refreshUIStates;
|
|
38
|
-
private
|
|
36
|
+
private buildFilterSections;
|
|
37
|
+
private refreshFilterButtonVisibility;
|
|
39
38
|
private fetchFilters;
|
|
40
39
|
private applyFiltersAndCloseDrawer;
|
|
41
40
|
protected template(): HTMLElement[];
|
|
@@ -44,7 +43,10 @@ export declare class ProductListFiltersComponent extends BaseComponent<IProductL
|
|
|
44
43
|
private buildFilterHeader;
|
|
45
44
|
private clearAllActiveFilters;
|
|
46
45
|
private removeSingleFilter;
|
|
46
|
+
private removeFacetValue;
|
|
47
47
|
private getFilteredAndSanitizedFilters;
|
|
48
|
+
private isFilterConfigured;
|
|
49
|
+
private hasVisibleFilters;
|
|
48
50
|
private buildAppliedFiltersChipsContainer;
|
|
49
51
|
private handleFilterChange;
|
|
50
52
|
private isEngravingCurrentlyDisabled;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { IFilterParamsValue } from '@/interfaces/api/product-list.interface';
|
|
2
|
+
import type { ProductListFilterType } from '@/interfaces/injection.interface';
|
|
3
|
+
import type { IProductListFilters } from './product-list.interface';
|
|
4
|
+
export declare const FILTER_KIND: {
|
|
5
|
+
readonly FACET: "facet";
|
|
6
|
+
readonly TOGGLE: "toggle";
|
|
7
|
+
readonly CHOICE: "choice";
|
|
8
|
+
readonly RANGE: "range";
|
|
9
|
+
};
|
|
10
|
+
export type FilterKind = (typeof FILTER_KIND)[keyof typeof FILTER_KIND];
|
|
11
|
+
interface IFilterDefinitionBase {
|
|
12
|
+
key: string;
|
|
13
|
+
type: ProductListFilterType;
|
|
14
|
+
}
|
|
15
|
+
export interface IFacetFilterDefinition extends IFilterDefinitionBase {
|
|
16
|
+
kind: typeof FILTER_KIND.FACET;
|
|
17
|
+
}
|
|
18
|
+
export interface IToggleFilterDefinition extends IFilterDefinitionBase {
|
|
19
|
+
kind: typeof FILTER_KIND.TOGGLE;
|
|
20
|
+
apiOn: string;
|
|
21
|
+
}
|
|
22
|
+
export interface IChoiceFilterDefinition extends IFilterDefinitionBase {
|
|
23
|
+
kind: typeof FILTER_KIND.CHOICE;
|
|
24
|
+
anyValue: string;
|
|
25
|
+
anyExpandsTo: string[];
|
|
26
|
+
values: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface IRangeFilterDefinition extends IFilterDefinitionBase {
|
|
29
|
+
kind: typeof FILTER_KIND.RANGE;
|
|
30
|
+
defaultMin: string;
|
|
31
|
+
defaultMax: string;
|
|
32
|
+
}
|
|
33
|
+
export type IFilterDefinition = IFacetFilterDefinition | IToggleFilterDefinition | IChoiceFilterDefinition | IRangeFilterDefinition;
|
|
34
|
+
export declare const FILTER_DEFINITIONS: IFilterDefinition[];
|
|
35
|
+
export declare function getFilterDefinition(key: string): IFilterDefinition | undefined;
|
|
36
|
+
export declare function getConfiguredFilterDefinitions(configuredFilters: ProductListFilterType[] | undefined): IFilterDefinition[];
|
|
37
|
+
export declare function getDefaultFilterValue(definition: IFilterDefinition): IProductListFilters[string];
|
|
38
|
+
export declare function createDefaultFilterValues(): IProductListFilters;
|
|
39
|
+
export declare function isFilterValueApplied(definition: IFilterDefinition, value: IProductListFilters[string]): boolean;
|
|
40
|
+
export declare function decodeStoredFilterValue(definition: IFilterDefinition, stored: unknown): IProductListFilters[string];
|
|
41
|
+
export declare function encodeFilterValueForApi(definition: IFilterDefinition, value: IProductListFilters[string]): IFilterParamsValue;
|
|
42
|
+
export {};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { IFilterSchema, IProductSearchParams } from '@/interfaces/api/product-list.interface';
|
|
2
2
|
import type { ProductListFilterType } from '@/interfaces/injection.interface';
|
|
3
3
|
import type { IExtendedFilterSchema, IProductListFilters } from './product-list.interface';
|
|
4
|
-
export declare const FILTER_TYPE_MAP: Record<string, string>;
|
|
5
4
|
export declare function getSanitizedFilters(filters: IFilterSchema[], configuredFilters: ProductListFilterType[]): IExtendedFilterSchema[];
|
|
6
5
|
export declare function syncFiltersToAppliedFormat(filters: IProductListFilters): Record<string, string[]>;
|
|
7
|
-
export declare function buildSearchParams(slug: string, page: number, perPage: number, searchTerm: string, currentFilters: IProductListFilters, configuredFilters: ProductListFilterType[]): IProductSearchParams;
|
|
8
6
|
export declare function buildCurrentFiltersFromState(stateFilters: Record<string, string[]>): IProductListFilters;
|
|
7
|
+
export declare function buildSearchParams(slug: string, page: number, perPage: number, searchTerm: string, currentFilters: IProductListFilters, configuredFilters: ProductListFilterType[]): IProductSearchParams;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IPLProductStore } from '@/core/store/interfaces/product-list.interface';
|
|
2
|
+
export declare function buildProductOrderIndex(productOrder: string[]): Map<string, number>;
|
|
3
|
+
export declare function sortProductsByOrder(products: IPLProductStore[], orderIndex: Map<string, number>): IPLProductStore[];
|
|
@@ -8,6 +8,7 @@ export interface IProductListComponentParams {
|
|
|
8
8
|
columns: number;
|
|
9
9
|
filters: ProductListFilterType[];
|
|
10
10
|
productUrl?: PLCProductUrl;
|
|
11
|
+
productOrder?: string[];
|
|
11
12
|
}
|
|
12
13
|
export declare class ProductListComponent extends BaseComponent<IProductListComponentParams, IProductListComponent> {
|
|
13
14
|
private products;
|
|
@@ -17,6 +18,7 @@ export declare class ProductListComponent extends BaseComponent<IProductListComp
|
|
|
17
18
|
private loadingState;
|
|
18
19
|
private scrollObserver;
|
|
19
20
|
private initializationPromise;
|
|
21
|
+
private productOrderIndex;
|
|
20
22
|
private unsubscribeFromState?;
|
|
21
23
|
get hostClasses(): string[];
|
|
22
24
|
constructor();
|
|
@@ -24,6 +26,8 @@ export declare class ProductListComponent extends BaseComponent<IProductListComp
|
|
|
24
26
|
protected afterRender(): void;
|
|
25
27
|
disconnected(): void;
|
|
26
28
|
private initializeComponent;
|
|
29
|
+
private getProductOrderIndex;
|
|
30
|
+
private hasProductOrder;
|
|
27
31
|
private toProductArray;
|
|
28
32
|
private setLoadingState;
|
|
29
33
|
private renderCurrentState;
|
|
@@ -35,6 +39,8 @@ export declare class ProductListComponent extends BaseComponent<IProductListComp
|
|
|
35
39
|
private lastAnnouncedSentinelState;
|
|
36
40
|
private renderProducts;
|
|
37
41
|
private announceResultCount;
|
|
42
|
+
private getListConfig;
|
|
43
|
+
private insertOrderedProducts;
|
|
38
44
|
private appendNewProducts;
|
|
39
45
|
private setupInfiniteScroll;
|
|
40
46
|
private createScrollSentinel;
|
|
@@ -26,6 +26,7 @@ export interface ICheckboxLabelStates {
|
|
|
26
26
|
filteredItems: IFilterValue[];
|
|
27
27
|
contentElement: HTMLElement | null;
|
|
28
28
|
iconElement: HTMLElement | null;
|
|
29
|
+
toggleButton: HTMLButtonElement | null;
|
|
29
30
|
hasUserInteraction: boolean;
|
|
30
31
|
}
|
|
31
32
|
export interface ICreateCheckboxItemParams {
|
|
@@ -134,6 +134,7 @@ interface IInjectProductListParams {
|
|
|
134
134
|
columns?: number; // Default: 4
|
|
135
135
|
filters?: ProductListFilterType[];
|
|
136
136
|
productUrl?: PLCProductUrl; // string template OR Record<identifier, url> map
|
|
137
|
+
productOrder?: string[]; // display order, by UPC or grouping ID
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
// String template: replace {upc} or {grouping} per product.
|
|
@@ -177,6 +178,39 @@ await client.injectProductList({
|
|
|
177
178
|
});
|
|
178
179
|
```
|
|
179
180
|
|
|
181
|
+
### Example — explicit product order
|
|
182
|
+
|
|
183
|
+
`productOrder` sets the display order of the grid. Entries are the same product
|
|
184
|
+
identifiers `productUrl` maps and `injectProductElement` accepts — a UPC (any size
|
|
185
|
+
of the product) or a `salsifyGrouping` ID — and may be mixed freely.
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
await client.injectProductList({
|
|
189
|
+
containerId: 'products',
|
|
190
|
+
slug: 'best-sellers',
|
|
191
|
+
productOrder: [
|
|
192
|
+
'00832889005513',
|
|
193
|
+
'GROUPING-33277',
|
|
194
|
+
'00619947000020',
|
|
195
|
+
],
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
It **reorders, it does not select.** The list's `slug` still decides which products
|
|
200
|
+
are returned; an identifier for a product outside the list matches nothing. Products
|
|
201
|
+
the array doesn't name render after the ones it does, in the order the API returned
|
|
202
|
+
them, so a partial list reorders only what it names.
|
|
203
|
+
|
|
204
|
+
Ordering also applies across pagination: a product named early in the array takes its
|
|
205
|
+
place even if the API returns it on a later page. Each new page is spliced into the
|
|
206
|
+
existing grid rather than appended, so cards already on screen are never re-rendered
|
|
207
|
+
and the scroll position holds. If the curated set is small, size `rows × columns` to
|
|
208
|
+
cover it in one page so no scroll is needed at all.
|
|
209
|
+
|
|
210
|
+
> A search term or an applied filter re-queries the API for a narrower result set.
|
|
211
|
+
> `productOrder` is re-applied to whatever comes back, so named products keep their
|
|
212
|
+
> relative order among the results that survive.
|
|
213
|
+
|
|
180
214
|
---
|
|
181
215
|
|
|
182
216
|
## injectProductListSearch()
|
|
@@ -240,6 +274,11 @@ await client.injectProductListFilters({
|
|
|
240
274
|
});
|
|
241
275
|
```
|
|
242
276
|
|
|
277
|
+
> **Note:** Every section of the panel is opt-in — a filter type absent from `filters` is not
|
|
278
|
+
> rendered, `'price'`, `'fulfillment'` and `'engraving'` included — and all sections render
|
|
279
|
+
> collapsed. See
|
|
280
|
+
> [Available Filters](../guides/product-list-component.md#available-filters).
|
|
281
|
+
|
|
243
282
|
---
|
|
244
283
|
|
|
245
284
|
## Component Management
|
|
@@ -43,6 +43,7 @@ Use data attributes to configure the product list:
|
|
|
43
43
|
- `data-columns`: Number of columns (default: 4)
|
|
44
44
|
- `data-filters`: Comma-separated filter types
|
|
45
45
|
- `data-product-url`: URL pattern for product detail pages (optional)
|
|
46
|
+
- `data-product-order`: Comma-separated product identifiers setting the display order (optional) — see [Product Order](#product-order)
|
|
46
47
|
|
|
47
48
|
`data-product-url` accepts a string template with one of two placeholders:
|
|
48
49
|
- `{grouping}` — replaced with the product's salsifyGrouping ID
|
|
@@ -113,7 +114,7 @@ The following filter type values can be used in the `filters` array:
|
|
|
113
114
|
| `'brands'` | Checkboxes for available brands |
|
|
114
115
|
| `'categories'` | Category selection checkboxes |
|
|
115
116
|
| `'fulfillment'`| Shipping vs. on-demand delivery toggle |
|
|
116
|
-
| `'engraving'` |
|
|
117
|
+
| `'engraving'` | Toggle: on shows only personalizable products, off shows all |
|
|
117
118
|
| `'sizes'` | Filter by product size/volume |
|
|
118
119
|
| `'flavor'` | Filter by flavor profile |
|
|
119
120
|
| `'region'` | Filter by region of origin |
|
|
@@ -128,6 +129,15 @@ The following filter type values can be used in the `filters` array:
|
|
|
128
129
|
filters: ['price', 'brands', 'categories', 'fulfillment', 'sizes']
|
|
129
130
|
```
|
|
130
131
|
|
|
132
|
+
Every section of the filters panel is opt-in — `'price'`, `'fulfillment'` and `'engraving'`
|
|
133
|
+
included. A value you leave out of the array is not rendered, and an empty array draws no
|
|
134
|
+
filters panel at all. Omit `filters` entirely and the list falls back to the server-configured
|
|
135
|
+
defaults for that slug.
|
|
136
|
+
|
|
137
|
+
Sections render **collapsed**; the shopper opens the ones they care about. Nothing is
|
|
138
|
+
auto-expanded, not even a filter seeded from the URL — an applied value shows as a removable
|
|
139
|
+
chip above the sections, so it stays visible without opening anything.
|
|
140
|
+
|
|
131
141
|
## URL Query Param Filters
|
|
132
142
|
|
|
133
143
|
The product list auto-applies filters from the page URL on first load. Useful for category landing pages, "shop the look" links, marketing emails, or any flow where you want to deep-link into a pre-filtered list.
|
|
@@ -150,6 +160,10 @@ Only filter keys that are configured for the list are honored — anything else
|
|
|
150
160
|
| `engraving` | `true` or `false` | `?engraving=true` |
|
|
151
161
|
| `price` | `min-max` range; `min-` or `-max` are accepted | `?price=20-150`, `?price=20-`, `?price=-150` |
|
|
152
162
|
|
|
163
|
+
`engraving=true` narrows the list to products that support personalization. `engraving=false` is
|
|
164
|
+
the filter's unset state and narrows nothing — it is equivalent to leaving the param off, not a
|
|
165
|
+
request for products that cannot be personalized.
|
|
166
|
+
|
|
153
167
|
Invalid values are dropped (e.g. `?fulfillment=garbage`, `?price=abc` — no error, the filter just isn't applied). Combining params is supported:
|
|
154
168
|
|
|
155
169
|
```
|
|
@@ -227,6 +241,66 @@ await client.injectProductList({
|
|
|
227
241
|
|
|
228
242
|
Total products per page = rows × columns (e.g., 5 × 4 = 20 products)
|
|
229
243
|
|
|
244
|
+
## Product Order
|
|
245
|
+
|
|
246
|
+
By default the grid renders products in the order the API returns them for the
|
|
247
|
+
list's slug. `productOrder` overrides that with an explicit order you control
|
|
248
|
+
from the page.
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
await client.injectProductList({
|
|
252
|
+
containerId: 'products',
|
|
253
|
+
slug: 'my-collection-slug',
|
|
254
|
+
productOrder: [
|
|
255
|
+
'00832889005513',
|
|
256
|
+
'GROUPING-33277',
|
|
257
|
+
'00619947000020',
|
|
258
|
+
],
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```html
|
|
263
|
+
<div
|
|
264
|
+
data-liquid-commerce-elements-products-list="my-collection-slug"
|
|
265
|
+
data-product-order="00832889005513,GROUPING-33277,00619947000020"
|
|
266
|
+
></div>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Identifiers.** Each entry is a UPC or a `salsifyGrouping` ID — the same identifier
|
|
270
|
+
concept the [Product URL Map](#product-url-map) keys on and `injectProductElement`
|
|
271
|
+
accepts. The two forms mix freely in one array. A UPC identifies a single size, so
|
|
272
|
+
naming any size of a product positions that product.
|
|
273
|
+
|
|
274
|
+
**It reorders; it does not select.** The slug still decides which products the list
|
|
275
|
+
contains. An identifier for a product outside the list matches nothing, and no error
|
|
276
|
+
is raised. Products the array doesn't name render after the ones it does, keeping
|
|
277
|
+
their API order among themselves — so a partial list reorders only what it names.
|
|
278
|
+
|
|
279
|
+
**Pagination.** A product named early keeps its position even if the API returns it on
|
|
280
|
+
a later page. Each new page is spliced into the grid at the right slots rather than
|
|
281
|
+
appended, so cards already on screen are left untouched — scroll position and keyboard
|
|
282
|
+
focus survive loading a page. For a small curated set, size `rows × columns` to cover
|
|
283
|
+
it in a single page so no scroll is needed at all.
|
|
284
|
+
|
|
285
|
+
**Search and filters** re-query the API for a narrower result set. The order is
|
|
286
|
+
re-applied to whatever comes back, so named products keep their relative order among
|
|
287
|
+
the results that survive.
|
|
288
|
+
|
|
289
|
+
**Nothing about `productOrder` throws.** Ordering is presentational and the grid
|
|
290
|
+
renders fine without it, so a malformed value costs you the ordering and nothing
|
|
291
|
+
else — never the product list itself.
|
|
292
|
+
|
|
293
|
+
- An entry that isn't a non-empty string is skipped with a console warning, the way
|
|
294
|
+
an unrecognized `filters` value is. The surviving entries keep their relative
|
|
295
|
+
order, so the rest of your ordering still applies around the dropped one.
|
|
296
|
+
- A `productOrder` that isn't an array is ignored entirely with a warning, and the
|
|
297
|
+
list renders in the order the API returns.
|
|
298
|
+
|
|
299
|
+
> The warning goes through the SDK logger, which is silent in production and at the
|
|
300
|
+
> default `debugMode: 'none'`. On a live storefront a dropped entry produces no
|
|
301
|
+
> console output at all, so validate the array you generate rather than relying on
|
|
302
|
+
> the warning to surface a bad one.
|
|
303
|
+
|
|
230
304
|
## Infinite Scroll
|
|
231
305
|
|
|
232
306
|
### How It Works
|
|
@@ -274,6 +348,32 @@ Product card images automatically have their white/near-white backgrounds remove
|
|
|
274
348
|
|
|
275
349
|
**Click on image:** Navigate to the configured `productUrl` (only when `productUrl` is set — otherwise the image is not a link)
|
|
276
350
|
|
|
351
|
+
### Card Identifiers
|
|
352
|
+
|
|
353
|
+
Each `product-list-card-lc` host carries the product's identifiers as data
|
|
354
|
+
attributes, so a card can be traced back to catalogue data while inspecting the
|
|
355
|
+
page:
|
|
356
|
+
|
|
357
|
+
```html
|
|
358
|
+
<product-list-card-lc data-grouping="GROUPING-33277" data-upc="00832889005513">
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
- `data-grouping` — the product's `salsifyGrouping` ID. Fixed for the life of the card.
|
|
362
|
+
- `data-upc` — the **selected size's** UPC, the same value `{upc}` resolves to in a
|
|
363
|
+
`productUrl` template. It updates when the shopper changes size.
|
|
364
|
+
|
|
365
|
+
Both use the identifier forms accepted everywhere else in the SDK, so a value read
|
|
366
|
+
off a card can be pasted straight into `productOrder`, a `productUrl` map key, or
|
|
367
|
+
`injectProductElement`.
|
|
368
|
+
|
|
369
|
+
> **These are for inspection, not for scripting.** Cards render inside the SDK's
|
|
370
|
+
> shadow root, which is **always closed in production** — `openShadowDom` is forced
|
|
371
|
+
> to `false` there and only has effect in development. Chrome DevTools displays
|
|
372
|
+
> closed shadow roots, so the attributes are visible when inspecting the page, but
|
|
373
|
+
> `document.querySelector('[data-upc]')` from partner JavaScript will not reach them
|
|
374
|
+
> on a live storefront. To react to card activity from your own code, use the
|
|
375
|
+
> [events](#events) instead.
|
|
376
|
+
|
|
277
377
|
## Customization
|
|
278
378
|
|
|
279
379
|
### Theme Configuration
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "LiquidCommerce Elements SDK",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": "LiquidCommerce Team",
|
|
6
|
-
"version": "2.7.
|
|
6
|
+
"version": "2.7.32",
|
|
7
7
|
"homepage": "https://docs.liquidcommerce.co/elements-sdk",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"module": "./dist/index.esm.js",
|
|
16
16
|
"types": "./dist/types/index.d.ts",
|
|
17
|
-
"packageManager": "pnpm@11.
|
|
17
|
+
"packageManager": "pnpm@11.22.0",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/types/index.d.ts",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"theming"
|
|
108
108
|
],
|
|
109
109
|
"devDependencies": {
|
|
110
|
-
"@biomejs/biome": "^2.5.
|
|
110
|
+
"@biomejs/biome": "^2.5.9",
|
|
111
111
|
"@commitlint/cli": "^21.2.2",
|
|
112
112
|
"@commitlint/config-conventional": "^21.2.2",
|
|
113
113
|
"@rollup/plugin-alias": "^6.0.0",
|