@liquidcommerce/elements-sdk 2.7.29 → 2.7.31

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.
@@ -1,5 +1,4 @@
1
1
  const ELEMENTS_ENV = {
2
- DEVELOPMENT: 'development',
3
2
  STAGING: 'staging',
4
3
  PRODUCTION: 'production',
5
4
  };
@@ -81,7 +81,6 @@ function isSDKSource(source) {
81
81
  }
82
82
 
83
83
  const ELEMENTS_ENV = {
84
- DEVELOPMENT: 'development',
85
84
  STAGING: 'staging',
86
85
  PRODUCTION: 'production',
87
86
  };
@@ -1,5 +1,4 @@
1
1
  export declare const API_CLIENT_URL: {
2
- development: string;
3
2
  staging: string;
4
3
  production: string;
5
4
  };
@@ -1 +1 @@
1
- export declare const DEBUG_PANEL_STYLES = "\n :host {\n position: fixed;\n z-index: 2147483647;\n display: block;\n }\n\n .panel {\n position: relative;\n background: rgba(15, 23, 42, 0.95);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;\n font-size: 12px;\n color: #e2e8f0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n user-select: none;\n transition: all 0.2s ease;\n width: 100%;\n height: 100%;\n }\n\n .panel:hover {\n border-color: rgba(148, 163, 184, 0.4);\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);\n }\n\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.2);\n background: rgba(30, 41, 59, 0.5);\n cursor: move;\n }\n\n .icon {\n font-size: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n }\n\n .title-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n margin: 0 12px;\n }\n \n .title-container > *:not(:first-child) {\n margin-top: 2px;\n }\n\n .title {\n font-weight: 600;\n color: #f1f5f9;\n font-size: 13px;\n }\n\n\n .subtitle {\n font-size: 10px;\n color: #94a3b8;\n }\n\n .minimize {\n background: none;\n border: none;\n color: #94a3b8;\n font-size: 18px;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: all 0.2s ease;\n line-height: 1;\n font-weight: bold;\n }\n\n .minimize:hover {\n background: rgba(148, 163, 184, 0.1);\n color: #cbd5e1;\n }\n\n .toggles {\n display: flex;\n padding: 8px 16px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.2);\n background: rgba(30, 41, 59, 0.3);\n align-items: center;\n }\n\n .toggles > *:not(:last-child) {\n margin-right: 12px;\n }\n\n .toggle {\n display: flex;\n align-items: center;\n cursor: pointer;\n font-size: 11px;\n color: #cbd5e1;\n transition: color 0.2s ease;\n }\n \n .toggle > *:not(:last-child) {\n margin-right: 6px;\n }\n\n .toggle:hover {\n color: #f1f5f9;\n }\n\n .toggle input[type=\"checkbox\"] {\n width: 12px;\n height: 12px;\n accent-color: #3b82f6;\n cursor: pointer;\n }\n\n .clear-btn {\n background: none;\n border: none;\n color: #ef4444;\n font-size: 14px;\n padding: 0;\n cursor: pointer;\n transition: all 0.2s ease;\n margin-left: auto;\n min-width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .clear-btn:hover {\n transform: scale(1.1);\n color: #dc2626;\n }\n\n .logs {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 8px;\n background: rgba(15, 23, 42, 0.8);\n min-height: 0;\n max-height: 100%;\n }\n\n .log-entry {\n display: flex;\n align-items: flex-start;\n padding: 8px 12px;\n margin-bottom: 2px;\n border-radius: 6px;\n font-size: 11px;\n line-height: 1.4;\n transition: background-color 0.2s ease;\n user-select: text;\n }\n \n .log-entry > *:not(:last-child) {\n margin-right: 8px;\n }\n\n .log-entry:hover {\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n /* Event type background colors */\n .log-entry.event {\n background: rgba(59, 130, 246, 0.1);\n }\n\n .log-entry.action {\n background: rgba(16, 185, 129, 0.1);\n }\n\n .log-entry.gtm {\n background: rgba(245, 158, 11, 0.1);\n }\n\n .log-entry.logger {\n background: rgba(139, 92, 246, 0.1);\n }\n\n\n .log-meta {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n min-width: 50px;\n }\n \n .log-meta > *:not(:first-child) {\n margin-top: 2px;\n }\n\n .log-type {\n font-weight: 600;\n font-size: 9px;\n padding: 2px 0;\n border-radius: 3px;\n white-space: nowrap;\n text-align: center;\n line-height: 1;\n font-weight: bold;\n letter-spacing: 0.5px;\n }\n\n .log-timestamp {\n color: #64748b;\n font-size: 9px;\n white-space: nowrap;\n line-height: 1;\n }\n\n .log-type.event {\n background: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .log-type.action {\n color: #34d399;\n }\n\n .log-type.gtm {\n color: #fbbf24;\n }\n\n .log-type.logger {\n color: #a78bfa;\n }\n\n .log-message {\n flex: 1;\n word-break: break-word;\n user-select: text;\n }\n\n .log-context {\n color: #94a3b8;\n font-size: 10px;\n margin-top: 2px;\n font-style: italic;\n }\n\n .log-data {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 4px;\n padding: 8px;\n margin-top: 6px;\n font-size: 10px;\n color: #cbd5e1;\n max-height: 120px;\n overflow-y: auto;\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;\n user-select: text;\n }\n\n .log-data pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .resize-handle {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 12px;\n height: 12px;\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.3) 30%, rgba(148, 163, 184, 0.3) 70%, transparent 70%);\n cursor: nw-resize;\n border-radius: 0 0 12px 0;\n }\n\n .resize-handle:hover {\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.7) 30%, rgba(148, 163, 184, 0.7) 70%, transparent 70%);\n transform: scale(1.1);\n }\n\n .resize-handle:active {\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.9) 30%, rgba(148, 163, 184, 0.9) 70%, transparent 70%);\n }\n\n /* Scrollbar styling */\n .logs::-webkit-scrollbar {\n width: 6px;\n }\n\n .logs::-webkit-scrollbar-track {\n background: rgba(30, 41, 59, 0.3);\n border-radius: 3px;\n }\n\n .logs::-webkit-scrollbar-thumb {\n background: rgba(148, 163, 184, 0.3);\n border-radius: 3px;\n }\n\n .logs::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.5);\n }\n\n .log-data::-webkit-scrollbar {\n width: 4px;\n }\n\n .log-data::-webkit-scrollbar-track {\n background: rgba(30, 41, 59, 0.3);\n border-radius: 2px;\n }\n\n .log-data::-webkit-scrollbar-thumb {\n background: rgba(148, 163, 184, 0.3);\n border-radius: 2px;\n }\n\n .log-data::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.5);\n }\n\n /* Floating button styles */\n .floating-btn {\n position: absolute;\n top: 20px;\n left: 20px;\n width: 40px;\n height: 40px;\n background: rgba(15, 23, 42, 0.95);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 50%;\n display: none;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 18px;\n user-select: none;\n z-index: 1;\n }\n\n .floating-btn:hover {\n background: rgba(30, 41, 59, 0.95);\n border-color: rgba(148, 163, 184, 0.4);\n }\n\n /* Mobile Responsiveness */\n @media (max-width: 768px) {\n .panel {\n font-size: 11px;\n border-radius: 8px;\n }\n\n .header {\n padding: 8px 12px;\n }\n\n .title {\n font-size: 12px;\n }\n\n .subtitle {\n font-size: 9px;\n }\n\n .toggles {\n padding: 6px 12px;\n flex-wrap: wrap;\n }\n \n .toggles > *:not(:last-child) {\n margin-right: 8px;\n }\n\n .toggle {\n font-size: 10px;\n }\n\n .toggle input[type=\"checkbox\"] {\n width: 10px;\n height: 10px;\n }\n\n .logs {\n padding: 6px;\n }\n\n .log-entry {\n padding: 6px 8px;\n font-size: 10px;\n }\n\n .log-type {\n font-size: 8px;\n }\n\n .log-timestamp {\n font-size: 8px;\n }\n\n .log-data {\n font-size: 9px;\n padding: 6px;\n max-height: 80px;\n }\n\n .floating-btn {\n width: 36px;\n height: 36px;\n font-size: 16px;\n top: 15px;\n left: 15px;\n }\n }\n\n @media (max-width: 480px) {\n .panel {\n font-size: 10px;\n border-radius: 6px;\n }\n\n .header {\n padding: 6px 10px;\n }\n\n .title {\n font-size: 11px;\n }\n\n .subtitle {\n font-size: 8px;\n }\n\n .toggles {\n padding: 4px 10px;\n }\n \n .toggles > *:not(:first-child) {\n margin-right: 6px;\n }\n\n .toggle {\n font-size: 9px;\n }\n\n .logs {\n padding: 4px;\n }\n\n .log-entry {\n padding: 4px 6px;\n font-size: 9px;\n }\n \n .log-entry > *:not(:first-child) {\n margin-top: 4px;\n }\n\n .log-meta {\n min-width: 40px;\n }\n\n .log-type {\n font-size: 7px;\n }\n\n .log-timestamp {\n font-size: 7px;\n }\n\n .log-data {\n font-size: 8px;\n padding: 4px;\n max-height: 60px;\n }\n\n .floating-btn {\n width: 32px;\n height: 32px;\n font-size: 14px;\n top: 10px;\n left: 10px;\n }\n }\n";
1
+ export declare const DEBUG_PANEL_STYLES = "\n :host {\n position: fixed;\n z-index: 2147483647;\n display: block;\n letter-spacing: normal;\n }\n\n .panel {\n position: relative;\n background: rgba(15, 23, 42, 0.95);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;\n font-size: 12px;\n color: #e2e8f0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n user-select: none;\n transition: all 0.2s ease;\n width: 100%;\n height: 100%;\n }\n\n .panel:hover {\n border-color: rgba(148, 163, 184, 0.4);\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);\n }\n\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.2);\n background: rgba(30, 41, 59, 0.5);\n cursor: move;\n }\n\n .icon {\n font-size: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n }\n\n .title-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n margin: 0 12px;\n }\n\n .title-container > *:not(:first-child) {\n margin-top: 2px;\n }\n\n .title {\n font-weight: 600;\n color: #f1f5f9;\n font-size: 13px;\n }\n\n\n .subtitle {\n font-size: 10px;\n color: #94a3b8;\n }\n\n .minimize {\n background: none;\n border: none;\n color: #94a3b8;\n font-size: 18px;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: all 0.2s ease;\n line-height: 1;\n font-weight: bold;\n }\n\n .minimize:hover {\n background: rgba(148, 163, 184, 0.1);\n color: #cbd5e1;\n }\n\n .toggles {\n display: flex;\n padding: 8px 16px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.2);\n background: rgba(30, 41, 59, 0.3);\n align-items: center;\n }\n\n .toggles > *:not(:last-child) {\n margin-right: 12px;\n }\n\n .toggle {\n display: flex;\n align-items: center;\n cursor: pointer;\n font-size: 11px;\n color: #cbd5e1;\n transition: color 0.2s ease;\n }\n\n .toggle > *:not(:last-child) {\n margin-right: 6px;\n }\n\n .toggle:hover {\n color: #f1f5f9;\n }\n\n .toggle input[type=\"checkbox\"] {\n width: 12px;\n height: 12px;\n accent-color: #3b82f6;\n cursor: pointer;\n }\n\n .clear-btn {\n background: none;\n border: none;\n color: #ef4444;\n font-size: 14px;\n padding: 0;\n cursor: pointer;\n transition: all 0.2s ease;\n margin-left: auto;\n min-width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .clear-btn:hover {\n transform: scale(1.1);\n color: #dc2626;\n }\n\n .logs {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 8px;\n background: rgba(15, 23, 42, 0.8);\n min-height: 0;\n max-height: 100%;\n }\n\n .log-entry {\n display: flex;\n align-items: flex-start;\n padding: 8px 12px;\n margin-bottom: 2px;\n border-radius: 6px;\n font-size: 11px;\n line-height: 1.4;\n transition: background-color 0.2s ease;\n user-select: text;\n }\n\n .log-entry > *:not(:last-child) {\n margin-right: 8px;\n }\n\n .log-entry:hover {\n background-color: rgba(148, 163, 184, 0.1);\n }\n\n /* Event type background colors */\n .log-entry.event {\n background: rgba(59, 130, 246, 0.1);\n }\n\n .log-entry.action {\n background: rgba(16, 185, 129, 0.1);\n }\n\n .log-entry.gtm {\n background: rgba(245, 158, 11, 0.1);\n }\n\n .log-entry.logger {\n background: rgba(139, 92, 246, 0.1);\n }\n\n\n .log-meta {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n min-width: 50px;\n }\n\n .log-meta > *:not(:first-child) {\n margin-top: 2px;\n }\n\n .log-type {\n font-weight: 600;\n font-size: 9px;\n padding: 2px 0;\n border-radius: 3px;\n white-space: nowrap;\n text-align: center;\n line-height: 1;\n font-weight: bold;\n letter-spacing: 0.5px;\n }\n\n .log-timestamp {\n color: #64748b;\n font-size: 9px;\n white-space: nowrap;\n line-height: 1;\n }\n\n .log-type.event {\n background: rgba(59, 130, 246, 0.2);\n color: #60a5fa;\n }\n\n .log-type.action {\n color: #34d399;\n }\n\n .log-type.gtm {\n color: #fbbf24;\n }\n\n .log-type.logger {\n color: #a78bfa;\n }\n\n .log-message {\n flex: 1;\n word-break: break-word;\n user-select: text;\n }\n\n .log-context {\n color: #94a3b8;\n font-size: 10px;\n margin-top: 2px;\n font-style: italic;\n }\n\n .log-data {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 4px;\n padding: 8px;\n margin-top: 6px;\n font-size: 10px;\n color: #cbd5e1;\n max-height: 120px;\n overflow-y: auto;\n font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;\n user-select: text;\n }\n\n .log-data pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .resize-handle {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 12px;\n height: 12px;\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.3) 30%, rgba(148, 163, 184, 0.3) 70%, transparent 70%);\n cursor: nw-resize;\n border-radius: 0 0 12px 0;\n }\n\n .resize-handle:hover {\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.7) 30%, rgba(148, 163, 184, 0.7) 70%, transparent 70%);\n transform: scale(1.1);\n }\n\n .resize-handle:active {\n background: linear-gradient(-45deg, transparent 30%, rgba(148, 163, 184, 0.9) 30%, rgba(148, 163, 184, 0.9) 70%, transparent 70%);\n }\n\n /* Scrollbar styling */\n .logs::-webkit-scrollbar {\n width: 6px;\n }\n\n .logs::-webkit-scrollbar-track {\n background: rgba(30, 41, 59, 0.3);\n border-radius: 3px;\n }\n\n .logs::-webkit-scrollbar-thumb {\n background: rgba(148, 163, 184, 0.3);\n border-radius: 3px;\n }\n\n .logs::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.5);\n }\n\n .log-data::-webkit-scrollbar {\n width: 4px;\n }\n\n .log-data::-webkit-scrollbar-track {\n background: rgba(30, 41, 59, 0.3);\n border-radius: 2px;\n }\n\n .log-data::-webkit-scrollbar-thumb {\n background: rgba(148, 163, 184, 0.3);\n border-radius: 2px;\n }\n\n .log-data::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.5);\n }\n\n /* Floating button styles */\n .floating-btn {\n position: absolute;\n top: 20px;\n left: 20px;\n width: 40px;\n height: 40px;\n background: rgba(15, 23, 42, 0.95);\n border: 1px solid rgba(148, 163, 184, 0.2);\n border-radius: 50%;\n display: none;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 18px;\n user-select: none;\n z-index: 1;\n }\n\n .floating-btn:hover {\n background: rgba(30, 41, 59, 0.95);\n border-color: rgba(148, 163, 184, 0.4);\n }\n\n /* Mobile Responsiveness */\n @media (max-width: 768px) {\n .panel {\n font-size: 11px;\n border-radius: 8px;\n }\n\n .header {\n padding: 8px 12px;\n }\n\n .title {\n font-size: 12px;\n }\n\n .subtitle {\n font-size: 9px;\n }\n\n .toggles {\n padding: 6px 12px;\n flex-wrap: wrap;\n }\n\n .toggles > *:not(:last-child) {\n margin-right: 8px;\n }\n\n .toggle {\n font-size: 10px;\n }\n\n .toggle input[type=\"checkbox\"] {\n width: 10px;\n height: 10px;\n }\n\n .logs {\n padding: 6px;\n }\n\n .log-entry {\n padding: 6px 8px;\n font-size: 10px;\n }\n\n .log-type {\n font-size: 8px;\n }\n\n .log-timestamp {\n font-size: 8px;\n }\n\n .log-data {\n font-size: 9px;\n padding: 6px;\n max-height: 80px;\n }\n\n .floating-btn {\n width: 36px;\n height: 36px;\n font-size: 16px;\n top: 15px;\n left: 15px;\n }\n }\n\n @media (max-width: 480px) {\n .panel {\n font-size: 10px;\n border-radius: 6px;\n }\n\n .header {\n padding: 6px 10px;\n }\n\n .title {\n font-size: 11px;\n }\n\n .subtitle {\n font-size: 8px;\n }\n\n .toggles {\n padding: 4px 10px;\n }\n\n .toggles > *:not(:first-child) {\n margin-right: 6px;\n }\n\n .toggle {\n font-size: 9px;\n }\n\n .logs {\n padding: 4px;\n }\n\n .log-entry {\n padding: 4px 6px;\n font-size: 9px;\n }\n\n .log-entry > *:not(:first-child) {\n margin-top: 4px;\n }\n\n .log-meta {\n min-width: 40px;\n }\n\n .log-type {\n font-size: 7px;\n }\n\n .log-timestamp {\n font-size: 7px;\n }\n\n .log-data {\n font-size: 8px;\n padding: 4px;\n max-height: 60px;\n }\n\n .floating-btn {\n width: 32px;\n height: 32px;\n font-size: 14px;\n top: 10px;\n left: 10px;\n }\n }\n";
@@ -1,5 +1,4 @@
1
1
  export declare const ELEMENTS_ENV: {
2
- readonly DEVELOPMENT: "development";
3
2
  readonly STAGING: "staging";
4
3
  readonly PRODUCTION: "production";
5
4
  };
@@ -1,3 +1,4 @@
1
+ import type { FulfillmentType } from '@/enums';
1
2
  import type { DeepPartial } from '@/interfaces/config.interface';
2
3
  export type FulfillmentDisplayType = 'carousel' | 'popup';
3
4
  export type DescriptionPositionType = 'above' | 'below';
@@ -13,6 +14,7 @@ export interface IProductLayout {
13
14
  fulfillmentDisplay: FulfillmentDisplayType;
14
15
  enableShippingFulfillment: boolean;
15
16
  enableOnDemandFulfillment: boolean;
17
+ primaryFulfillmentMethod: FulfillmentType;
16
18
  addToCartButtonText: string;
17
19
  addToCartButtonShowTotalPrice: boolean;
18
20
  buyNowButtonText: string;
@@ -14,6 +14,7 @@ export interface IInjectProductListParams {
14
14
  columns?: number;
15
15
  filters?: ProductListFilterType[];
16
16
  productUrl?: PLCProductUrl;
17
+ productOrder?: string[];
17
18
  }
18
19
  export interface IInjectProductListSearchParams {
19
20
  containerId: string;
@@ -12,7 +12,7 @@ export declare function renderPopupRetailerCard({ fulfillment, selectedFulfillme
12
12
  selectedSizeAttributes: IProductSizeAttributes | null;
13
13
  interactive?: boolean;
14
14
  }): HTMLElement;
15
- export declare function renderFulfillmentTabsContainer({ shippingFulfillments, onDemandFulfillments, shippingSelected, onDemandSelected, onTabClick, enableShippingFulfillment, enableOnDemandFulfillment, }: {
15
+ export declare function renderFulfillmentTabsContainer({ shippingFulfillments, onDemandFulfillments, shippingSelected, onDemandSelected, onTabClick, enableShippingFulfillment, enableOnDemandFulfillment, primaryFulfillmentMethod, }: {
16
16
  shippingFulfillments: IProductFulfillmentStore[];
17
17
  onDemandFulfillments: IProductFulfillmentStore[];
18
18
  shippingSelected: boolean;
@@ -20,4 +20,5 @@ export declare function renderFulfillmentTabsContainer({ shippingFulfillments, o
20
20
  onTabClick: (event: Event) => void;
21
21
  enableShippingFulfillment: boolean;
22
22
  enableOnDemandFulfillment: boolean;
23
+ primaryFulfillmentMethod: FulfillmentType;
23
24
  }): HTMLElement;
@@ -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;
@@ -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,7 @@ export declare class ProductListComponent extends BaseComponent<IProductListComp
35
39
  private lastAnnouncedSentinelState;
36
40
  private renderProducts;
37
41
  private announceResultCount;
42
+ private insertOrderedProducts;
38
43
  private appendNewProducts;
39
44
  private setupInfiniteScroll;
40
45
  private createScrollSentinel;
@@ -1,15 +1,18 @@
1
1
  import type { IProductStore } from '@/core/store/interfaces/product.interface';
2
2
  import type { IPLProductStore } from '@/core/store/interfaces/product-list.interface';
3
+ import { type FulfillmentType } from '@/enums';
3
4
  import type { IProduct, IProductAvailabilityResponse } from '@/interfaces/api/product.interface';
4
5
  export interface IPrepareApiProductForStoreParams {
5
6
  context: 'product-list' | 'product-page';
6
7
  product: IProduct;
7
8
  retailers: IProductAvailabilityResponse['retailers'];
8
9
  enableShippingFulfillment: boolean;
10
+ enableOnDemandFulfillment?: boolean;
11
+ primaryFulfillmentMethod?: FulfillmentType;
9
12
  }
10
13
  export declare function buildSizeLabel(size: {
11
14
  size: string;
12
15
  pack: boolean;
13
16
  packDesc: string;
14
17
  }): string;
15
- export declare function prepareApiProductForStore({ context, product, retailers, enableShippingFulfillment, }: IPrepareApiProductForStoreParams): IProductStore | IPLProductStore;
18
+ export declare function prepareApiProductForStore({ context, product, retailers, enableShippingFulfillment, enableOnDemandFulfillment, primaryFulfillmentMethod, }: IPrepareApiProductForStoreParams): IProductStore | IPLProductStore;
@@ -103,7 +103,7 @@ Complete configuration interface for the full SDK.
103
103
  ```typescript
104
104
  interface ILiquidCommerceElementsConfig {
105
105
  // Optional
106
- env?: ElementsEnv; // defaults to 'production' ('development' | 'staging' | 'production')
106
+ env?: ElementsEnv; // defaults to 'production' ('staging' | 'production')
107
107
  debugMode?: DebugMode; // 'none' | 'console' | 'panel'
108
108
  customTheme?: IClientCustomThemeConfig;
109
109
  promoTicker?: IPromoTicker[];
@@ -116,7 +116,7 @@ interface ILiquidCommerceElementsConfig {
116
116
  #### Environment
117
117
 
118
118
  ```typescript
119
- type ElementsEnv = 'development' | 'staging' | 'production';
119
+ type ElementsEnv = 'staging' | 'production';
120
120
  ```
121
121
 
122
122
  Determines which API environment to use.
@@ -22,7 +22,7 @@ interface ILiquidCommerceElementsConfig {
22
22
 
23
23
  | Property | Type | Required | Description |
24
24
  |----------|------|----------|-------------|
25
- | `env` | `'development' \| 'staging' \| 'production'` | No | API environment |
25
+ | `env` | `'staging' \| 'production'` | No | API environment |
26
26
  | `promoTicker` | `IPromoTicker[]` | No | Promotional ticker configurations |
27
27
  | `customTheme` | `IClientCustomThemeConfig` | No | Theme overrides for all components |
28
28
  | `debugMode` | `'none' \| 'console' \| 'panel'` | No | Debug output mode |
@@ -30,7 +30,7 @@ interface ILiquidCommerceElementsConfig {
30
30
  | `proxy` | `IElementsProxyConfig` | No | Proxy configuration for API requests |
31
31
  | `development` | `ILiquidCommerceElementsDevelopmentConfig` | No | Development/testing options |
32
32
 
33
- > **Note:** `debugMode` (`'console'` or `'panel'`) is **ignored in production** -- it is forced off when `env` is `'production'`. It only takes effect in non-production environments (`'development'` / `'staging'`).
33
+ > **Note:** `debugMode` (`'console'` or `'panel'`) is **ignored in production** -- it is forced off when `env` is `'production'`. It only takes effect outside production (`'staging'`).
34
34
 
35
35
  ---
36
36
 
@@ -201,6 +201,7 @@ interface IProductLayout {
201
201
  fulfillmentDisplay: 'carousel' | 'popup';
202
202
  enableShippingFulfillment: boolean;
203
203
  enableOnDemandFulfillment: boolean;
204
+ primaryFulfillmentMethod: 'shipping' | 'onDemand';
204
205
  addToCartButtonText: string;
205
206
  addToCartButtonShowTotalPrice: boolean;
206
207
  buyNowButtonText: string;
@@ -223,6 +224,7 @@ interface IProductLayout {
223
224
  | `fulfillmentDisplay` | `'carousel' \| 'popup'` | How to display fulfillment/retailer options |
224
225
  | `enableShippingFulfillment` | `boolean` | Enable shipping fulfillment option |
225
226
  | `enableOnDemandFulfillment` | `boolean` | Enable on-demand delivery option |
227
+ | `primaryFulfillmentMethod` | `'shipping' \| 'onDemand'` | Fulfillment method shown first and selected by default; falls back to the other enabled method when it has no availability |
226
228
  | `addToCartButtonText` | `string` | Custom text for add-to-cart button |
227
229
  | `addToCartButtonShowTotalPrice` | `boolean` | Show total price on add-to-cart button |
228
230
  | `buyNowButtonText` | `string` | Custom text for buy-now button |
@@ -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()
@@ -197,6 +197,7 @@ interface IInjectProductListParams {
197
197
  columns?: number;
198
198
  filters?: ProductListFilterType[];
199
199
  productUrl?: PLCProductUrl;
200
+ productOrder?: string[]; // display order, by UPC or grouping ID
200
201
  }
201
202
  ```
202
203
 
@@ -310,7 +311,7 @@ See [Actions API](./actions/) for detailed method signatures.
310
311
  ### ElementsEnv
311
312
 
312
313
  ```typescript
313
- type ElementsEnv = 'development' | 'staging' | 'production';
314
+ type ElementsEnv = 'staging' | 'production';
314
315
  ```
315
316
 
316
317
  ### DebugMode
@@ -379,7 +379,7 @@ Enable debug mode for detailed logging:
379
379
 
380
380
  ```javascript
381
381
  const client = await Elements('YOUR_API_KEY', {
382
- env: 'development',
382
+ env: 'staging',
383
383
  debugMode: 'console' // or 'panel'
384
384
  });
385
385
  ```
@@ -409,9 +409,9 @@ Your API key is used for authentication but has limited privileges:
409
409
  Use different API keys per environment:
410
410
 
411
411
  ```javascript
412
- // Development
413
- const client = await Elements('dev_key_abc123', {
414
- env: 'development'
412
+ // Staging
413
+ const client = await Elements('staging_key_abc123', {
414
+ env: 'staging'
415
415
  });
416
416
 
417
417
  // Production
@@ -46,7 +46,7 @@ The path segment selects which bundle is served:
46
46
  |-----------|----------|-------------|
47
47
  | `data-liquid-commerce-elements` | Yes | Identifies this as the Elements SDK script |
48
48
  | `data-token` | Yes | Your LiquidCommerce API key |
49
- | `data-env` | No | Environment: `development`, `staging`, or `production`. Defaults to `production` if omitted. |
49
+ | `data-env` | No | Environment: `staging` or `production`. Defaults to `production` if omitted. |
50
50
  | `defer` | Recommended | Allows non-blocking script loading |
51
51
 
52
52
  ### Where to Place the Script
@@ -264,7 +264,7 @@ The SDK accepts a configuration object during initialization:
264
264
 
265
265
  ```javascript
266
266
  const client = await Elements('YOUR_API_KEY', {
267
- env: 'production', // Optional (defaults to 'production'): 'development' | 'staging' | 'production'
267
+ env: 'production', // Optional (defaults to 'production'): 'staging' | 'production'
268
268
  debugMode: 'console', // Optional: 'none' | 'console' | 'panel'
269
269
  customTheme: { /* ... */ }, // Optional: Theme customization
270
270
  promoTicker: [ /* ... */ ], // Optional: Promo ticker configuration
@@ -274,7 +274,7 @@ const client = await Elements('YOUR_API_KEY', {
274
274
  });
275
275
  ```
276
276
 
277
- > **Note:** `debugMode` is ignored when `env` is `'production'`. Debug logging and the debug panel are only activated in non-production environments (`development` or `staging`).
277
+ > **Note:** `debugMode` is ignored when `env` is `'production'`. Debug logging and the debug panel are only activated outside production (`staging`).
278
278
 
279
279
  See [Configuration Reference](../api/configuration.md) for complete configuration options.
280
280
 
@@ -269,20 +269,20 @@ Prevents ad blockers and protects API keys.
269
269
  ```javascript
270
270
  const apiKey = process.env.NODE_ENV === 'production'
271
271
  ? 'prod_key_xyz'
272
- : 'dev_key_abc';
272
+ : 'staging_key_abc';
273
273
 
274
274
  const client = await Elements(apiKey, {
275
- env: process.env.NODE_ENV === 'production' ? 'production' : 'development'
275
+ env: process.env.NODE_ENV === 'production' ? 'production' : 'staging'
276
276
  });
277
277
  ```
278
278
 
279
279
  ## Testing
280
280
 
281
- ### Use Development Mode
281
+ ### Use Staging With Debug Options
282
282
 
283
283
  ```javascript
284
284
  const client = await Elements('YOUR_API_KEY', {
285
- env: 'development',
285
+ env: 'staging',
286
286
  debugMode: 'console', // or 'panel'
287
287
  development: {
288
288
  openShadowDom: true // Makes debugging easier
@@ -375,6 +375,7 @@ const client = await Elements('YOUR_API_KEY', {
375
375
  fulfillmentDisplay: 'carousel', // or 'popup'
376
376
  enableShippingFulfillment: true,
377
377
  enableOnDemandFulfillment: true,
378
+ primaryFulfillmentMethod: 'shipping', // or 'onDemand'
378
379
  addToCartButtonText: 'Add to Cart',
379
380
  addToCartButtonShowTotalPrice: true,
380
381
  buyNowButtonText: 'Buy Now',
@@ -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
@@ -227,6 +228,66 @@ await client.injectProductList({
227
228
 
228
229
  Total products per page = rows × columns (e.g., 5 × 4 = 20 products)
229
230
 
231
+ ## Product Order
232
+
233
+ By default the grid renders products in the order the API returns them for the
234
+ list's slug. `productOrder` overrides that with an explicit order you control
235
+ from the page.
236
+
237
+ ```javascript
238
+ await client.injectProductList({
239
+ containerId: 'products',
240
+ slug: 'my-collection-slug',
241
+ productOrder: [
242
+ '00832889005513',
243
+ 'GROUPING-33277',
244
+ '00619947000020',
245
+ ],
246
+ });
247
+ ```
248
+
249
+ ```html
250
+ <div
251
+ data-liquid-commerce-elements-products-list="my-collection-slug"
252
+ data-product-order="00832889005513,GROUPING-33277,00619947000020"
253
+ ></div>
254
+ ```
255
+
256
+ **Identifiers.** Each entry is a UPC or a `salsifyGrouping` ID — the same identifier
257
+ concept the [Product URL Map](#product-url-map) keys on and `injectProductElement`
258
+ accepts. The two forms mix freely in one array. A UPC identifies a single size, so
259
+ naming any size of a product positions that product.
260
+
261
+ **It reorders; it does not select.** The slug still decides which products the list
262
+ contains. An identifier for a product outside the list matches nothing, and no error
263
+ is raised. Products the array doesn't name render after the ones it does, keeping
264
+ their API order among themselves — so a partial list reorders only what it names.
265
+
266
+ **Pagination.** A product named early keeps its position even if the API returns it on
267
+ a later page. Each new page is spliced into the grid at the right slots rather than
268
+ appended, so cards already on screen are left untouched — scroll position and keyboard
269
+ focus survive loading a page. For a small curated set, size `rows × columns` to cover
270
+ it in a single page so no scroll is needed at all.
271
+
272
+ **Search and filters** re-query the API for a narrower result set. The order is
273
+ re-applied to whatever comes back, so named products keep their relative order among
274
+ the results that survive.
275
+
276
+ **Nothing about `productOrder` throws.** Ordering is presentational and the grid
277
+ renders fine without it, so a malformed value costs you the ordering and nothing
278
+ else — never the product list itself.
279
+
280
+ - An entry that isn't a non-empty string is skipped with a console warning, the way
281
+ an unrecognized `filters` value is. The surviving entries keep their relative
282
+ order, so the rest of your ordering still applies around the dropped one.
283
+ - A `productOrder` that isn't an array is ignored entirely with a warning, and the
284
+ list renders in the order the API returns.
285
+
286
+ > The warning goes through the SDK logger, which is silent in production and at the
287
+ > default `debugMode: 'none'`. On a live storefront a dropped entry produces no
288
+ > console output at all, so validate the array you generate rather than relying on
289
+ > the warning to surface a bad one.
290
+
230
291
  ## Infinite Scroll
231
292
 
232
293
  ### How It Works
@@ -274,6 +335,32 @@ Product card images automatically have their white/near-white backgrounds remove
274
335
 
275
336
  **Click on image:** Navigate to the configured `productUrl` (only when `productUrl` is set — otherwise the image is not a link)
276
337
 
338
+ ### Card Identifiers
339
+
340
+ Each `product-list-card-lc` host carries the product's identifiers as data
341
+ attributes, so a card can be traced back to catalogue data while inspecting the
342
+ page:
343
+
344
+ ```html
345
+ <product-list-card-lc data-grouping="GROUPING-33277" data-upc="00832889005513">
346
+ ```
347
+
348
+ - `data-grouping` — the product's `salsifyGrouping` ID. Fixed for the life of the card.
349
+ - `data-upc` — the **selected size's** UPC, the same value `{upc}` resolves to in a
350
+ `productUrl` template. It updates when the shopper changes size.
351
+
352
+ Both use the identifier forms accepted everywhere else in the SDK, so a value read
353
+ off a card can be pasted straight into `productOrder`, a `productUrl` map key, or
354
+ `injectProductElement`.
355
+
356
+ > **These are for inspection, not for scripting.** Cards render inside the SDK's
357
+ > shadow root, which is **always closed in production** — `openShadowDom` is forced
358
+ > to `false` there and only has effect in development. Chrome DevTools displays
359
+ > closed shadow roots, so the attributes are visible when inspecting the page, but
360
+ > `document.querySelector('[data-upc]')` from partner JavaScript will not reach them
361
+ > on a live storefront. To react to card activity from your own code, use the
362
+ > [events](#events) instead.
363
+
277
364
  ## Customization
278
365
 
279
366
  ### Theme Configuration
@@ -118,6 +118,7 @@ customTheme: {
118
118
  fulfillmentDisplay: 'carousel',
119
119
  enableShippingFulfillment: true,
120
120
  enableOnDemandFulfillment: true,
121
+ primaryFulfillmentMethod: 'shipping',
121
122
  addToCartButtonText: 'Add to Cart',
122
123
  addToCartButtonShowTotalPrice: true,
123
124
  buyNowButtonText: 'Buy Now',
@@ -12,13 +12,12 @@ It coexists with a host site's own GTM — see [Coexisting With Your Own GTM](#c
12
12
 
13
13
  ## Supported Environments
14
14
 
15
- GTM initialization and every event push are enabled in production and staging. When the SDK is running in development or Builder mode, no container is loaded and no events are sent.
15
+ GTM initialization and every event push are enabled in production and staging. When the SDK is running in Builder mode, no container is loaded and no events are sent.
16
16
 
17
17
  Events are suppressed when any of the following is true:
18
18
 
19
19
  - `window` is undefined (server-side rendering).
20
20
  - The SDK is running in Builder mode.
21
- - The environment is `development`.
22
21
 
23
22
  The environment defaults to `production` when none is provided, so a standard production embed is analytics-enabled out of the box; a staging embed is also analytics-enabled when server GTM config is enabled for the partner.
24
23
 
@@ -13,7 +13,7 @@ Telemetry is enabled **only** when both conditions are true:
13
13
 
14
14
  In every other case it is **disabled** and no events are queued or sent:
15
15
 
16
- - Non-production environments (e.g. staging/development).
16
+ - Non-production environments (i.e. staging).
17
17
  - A custom API URL / proxy is configured via `development.customApiUrl`.
18
18
  - Internal telemetry errors are only logged to the console in non-production or when debugging is enabled — never sent.
19
19
 
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.29",
6
+ "version": "2.7.31",
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.18.0",
17
+ "packageManager": "pnpm@11.21.0",
18
18
  "exports": {
19
19
  ".": {
20
20
  "types": "./dist/types/index.d.ts",
@@ -107,9 +107,9 @@
107
107
  "theming"
108
108
  ],
109
109
  "devDependencies": {
110
- "@biomejs/biome": "^2.5.6",
111
- "@commitlint/cli": "^21.2.1",
112
- "@commitlint/config-conventional": "^21.2.0",
110
+ "@biomejs/biome": "^2.5.8",
111
+ "@commitlint/cli": "^21.2.2",
112
+ "@commitlint/config-conventional": "^21.2.2",
113
113
  "@rollup/plugin-alias": "^6.0.0",
114
114
  "@rollup/plugin-commonjs": "^29.0.3",
115
115
  "@rollup/plugin-json": "^6.1.0",
@@ -123,14 +123,14 @@
123
123
  "@semantic-release/npm": "^13.1.5",
124
124
  "@semantic-release/release-notes-generator": "^14.1.1",
125
125
  "@types/core-js": "^2.5.8",
126
- "@types/node": "^26.1.2",
127
- "conventional-changelog": "8.1.0",
126
+ "@types/node": "^26.2.0",
127
+ "conventional-changelog": "8.1.3",
128
128
  "husky": "^9.1.7",
129
129
  "process": "^0.11.10",
130
- "rollup": "^4.62.3",
130
+ "rollup": "^4.62.4",
131
131
  "rollup-obfuscator": "^4.1.1",
132
132
  "rollup-plugin-typescript2": "^0.37.0",
133
- "semantic-release": "^25.0.8",
133
+ "semantic-release": "^25.0.9",
134
134
  "ts-node": "^10.9.2",
135
135
  "typescript": "6.0.3"
136
136
  },