@blotoutio/providers-evo-search-sdk 1.54.0 → 1.55.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 (4) hide show
  1. package/index.cjs.js +190 -50
  2. package/index.js +190 -50
  3. package/index.mjs +190 -50
  4. package/package.json +1 -1
package/index.cjs.js CHANGED
@@ -6118,6 +6118,78 @@ const handpickedProductsStyles = i$3 `
6118
6118
  .scroll-button-right {
6119
6119
  right: 1em;
6120
6120
  }
6121
+
6122
+ .skeleton-card {
6123
+ display: flex;
6124
+ width: 10em;
6125
+ height: 13.125em;
6126
+ padding: 0.625em 0;
6127
+ flex-direction: column;
6128
+ align-items: center;
6129
+ gap: 0.625em;
6130
+ border-radius: 0.375em;
6131
+ border: 0.0625em solid #cbd5e1;
6132
+ background: white;
6133
+ flex-shrink: 0;
6134
+ box-sizing: border-box;
6135
+ }
6136
+
6137
+ .skeleton-image {
6138
+ width: 5.875em;
6139
+ height: 6.25em;
6140
+ border-radius: 0.25em;
6141
+ flex-shrink: 0;
6142
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6143
+ background-size: 200% 100%;
6144
+ animation: shimmer 1.4s ease-in-out infinite;
6145
+ }
6146
+
6147
+ .skeleton-separator {
6148
+ width: 100%;
6149
+ height: 0.0625em;
6150
+ background-color: #cbd5e1;
6151
+ flex-shrink: 0;
6152
+ }
6153
+
6154
+ .skeleton-details {
6155
+ display: flex;
6156
+ height: 4.25em;
6157
+ padding: 0 0.5em;
6158
+ flex-direction: column;
6159
+ gap: 0.375em;
6160
+ width: 100%;
6161
+ box-sizing: border-box;
6162
+ }
6163
+
6164
+ .skeleton-line {
6165
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6166
+ background-size: 200% 100%;
6167
+ animation: shimmer 1.4s ease-in-out infinite;
6168
+ border-radius: 0.1875em;
6169
+ height: 0.75em;
6170
+ }
6171
+
6172
+ .skeleton-line-name {
6173
+ width: 80%;
6174
+ }
6175
+
6176
+ .skeleton-line-desc {
6177
+ width: 95%;
6178
+ }
6179
+
6180
+ .skeleton-line-price {
6181
+ width: 40%;
6182
+ margin-top: auto;
6183
+ }
6184
+
6185
+ @keyframes shimmer {
6186
+ 0% {
6187
+ background-position: 200% 0;
6188
+ }
6189
+ 100% {
6190
+ background-position: -200% 0;
6191
+ }
6192
+ }
6121
6193
  `;
6122
6194
 
6123
6195
  class HandpickedProducts extends ElementWithStylesheet {
@@ -6126,6 +6198,7 @@ class HandpickedProducts extends ElementWithStylesheet {
6126
6198
  this.products = [];
6127
6199
  this.trendingTitle = 'Handpicked for you';
6128
6200
  this.isSearchResults = false;
6201
+ this.loading = false;
6129
6202
  this.canScrollLeft = false;
6130
6203
  this.canScrollRight = true;
6131
6204
  }
@@ -6168,69 +6241,98 @@ class HandpickedProducts extends ElementWithStylesheet {
6168
6241
  (_a = this.carousel) === null || _a === void 0 ? void 0 : _a.scrollBy({ left: 170, behavior: 'smooth' });
6169
6242
  setTimeout(() => this.updateScrollButtons(), 300);
6170
6243
  }
6244
+ renderSkeleton() {
6245
+ const skeletonCount = 5;
6246
+ return b `
6247
+ <div class="products-carousel">
6248
+ ${Array.from({ length: skeletonCount }, () => b `
6249
+ <div class="skeleton-card" aria-hidden="true">
6250
+ <div class="skeleton-image"></div>
6251
+ <div class="skeleton-separator"></div>
6252
+ <div class="skeleton-details">
6253
+ <div class="skeleton-line skeleton-line-name"></div>
6254
+ <div class="skeleton-line skeleton-line-desc"></div>
6255
+ <div class="skeleton-line skeleton-line-price"></div>
6256
+ </div>
6257
+ </div>
6258
+ `)}
6259
+ </div>
6260
+ `;
6261
+ }
6171
6262
  render() {
6172
- if (!this.products.length) {
6263
+ if (!this.products.length && !this.loading) {
6173
6264
  return b ``;
6174
6265
  }
6266
+ const showSearchHeader = this.loading || this.isSearchResults;
6175
6267
  return b `
6176
- <div class="handpicked-products-container">
6268
+ <div
6269
+ class="handpicked-products-container"
6270
+ aria-busy=${this.loading ? 'true' : 'false'}
6271
+ >
6177
6272
  <h3 class="handpicked-title">
6178
6273
  <div class="icon-container">
6179
6274
  <bt-lucide-icon
6180
- name=${this.isSearchResults ? 'search' : 'handHeart'}
6275
+ name=${showSearchHeader ? 'search' : 'handHeart'}
6181
6276
  width="16"
6182
6277
  height="16"
6183
6278
  stroke="#EF4444"
6184
6279
  stroke-width="1"
6185
6280
  ></bt-lucide-icon>
6186
6281
  </div>
6187
- ${this.isSearchResults ? 'Matching Products' : this.trendingTitle}
6282
+ ${showSearchHeader ? 'Matching Products' : this.trendingTitle}
6188
6283
  </h3>
6189
6284
 
6190
6285
  <div class="carousel-wrapper">
6191
- ${this.canScrollLeft
6192
- ? b `
6193
- <button
6194
- class="scroll-button scroll-button-left"
6195
- @click=${this.handleScrollLeft}
6196
- aria-label="Scroll left"
6197
- >
6198
- <bt-lucide-icon
6199
- name="left"
6200
- width="20"
6201
- height="20"
6202
- stroke="#000000"
6203
- ></bt-lucide-icon>
6204
- </button>
6205
- `
6206
- : A}
6207
-
6208
- <div class="products-carousel" @scroll=${this.updateScrollButtons}>
6209
- ${this.products.map((product) => b `
6210
- <evs-product-card
6211
- .css=${this.css}
6212
- .product=${product}
6213
- .userId=${this.userId}
6214
- ></evs-product-card>
6215
- `)}
6216
- </div>
6217
-
6218
- ${this.canScrollRight
6219
- ? b `
6220
- <button
6221
- class="scroll-button scroll-button-right"
6222
- @click=${this.handleScrollRight}
6223
- aria-label="Scroll right"
6286
+ ${this.loading
6287
+ ? this.renderSkeleton()
6288
+ : b `
6289
+ ${this.canScrollLeft
6290
+ ? b `
6291
+ <button
6292
+ class="scroll-button scroll-button-left"
6293
+ @click=${this.handleScrollLeft}
6294
+ aria-label="Scroll left"
6295
+ >
6296
+ <bt-lucide-icon
6297
+ name="left"
6298
+ width="20"
6299
+ height="20"
6300
+ stroke="#000000"
6301
+ ></bt-lucide-icon>
6302
+ </button>
6303
+ `
6304
+ : A}
6305
+
6306
+ <div
6307
+ class="products-carousel"
6308
+ @scroll=${this.updateScrollButtons}
6224
6309
  >
6225
- <bt-lucide-icon
6226
- name="right"
6227
- width="20"
6228
- height="20"
6229
- stroke="#000000"
6230
- ></bt-lucide-icon>
6231
- </button>
6232
- `
6233
- : A}
6310
+ ${this.products.map((product) => b `
6311
+ <evs-product-card
6312
+ .css=${this.css}
6313
+ .product=${product}
6314
+ .userId=${this.userId}
6315
+ ></evs-product-card>
6316
+ `)}
6317
+ </div>
6318
+
6319
+ ${this.canScrollRight
6320
+ ? b `
6321
+ <button
6322
+ class="scroll-button scroll-button-right"
6323
+ @click=${this.handleScrollRight}
6324
+ aria-label="Scroll right"
6325
+ >
6326
+ <bt-lucide-icon
6327
+ name="right"
6328
+ width="20"
6329
+ height="20"
6330
+ stroke="#000000"
6331
+ ></bt-lucide-icon>
6332
+ </button>
6333
+ `
6334
+ : A}
6335
+ `}
6234
6336
  </div>
6235
6337
  </div>
6236
6338
  `;
@@ -6249,6 +6351,10 @@ __decorate([
6249
6351
  n$1({ type: Boolean }),
6250
6352
  __metadata("design:type", Object)
6251
6353
  ], HandpickedProducts.prototype, "isSearchResults", void 0);
6354
+ __decorate([
6355
+ n$1({ type: Boolean }),
6356
+ __metadata("design:type", Object)
6357
+ ], HandpickedProducts.prototype, "loading", void 0);
6252
6358
  __decorate([
6253
6359
  n$1({ type: String }),
6254
6360
  __metadata("design:type", Object)
@@ -6310,6 +6416,34 @@ const searchDropdownStyles = i$3 `
6310
6416
  }
6311
6417
  }
6312
6418
 
6419
+ .progress-bar {
6420
+ position: sticky;
6421
+ top: 0;
6422
+ height: 0.125em;
6423
+ width: 100%;
6424
+ background: var(--evosearch-border, #cbd5e1);
6425
+ overflow: hidden;
6426
+ z-index: 1;
6427
+ }
6428
+
6429
+ .progress-bar::after {
6430
+ content: '';
6431
+ display: block;
6432
+ height: 100%;
6433
+ width: 40%;
6434
+ background: var(--evosearch-accent, #ef4444);
6435
+ animation: progress-slide 1.2s ease-in-out infinite;
6436
+ }
6437
+
6438
+ @keyframes progress-slide {
6439
+ 0% {
6440
+ transform: translateX(-100%);
6441
+ }
6442
+ 100% {
6443
+ transform: translateX(250%);
6444
+ }
6445
+ }
6446
+
6313
6447
  /* Empty State */
6314
6448
  .dropdown-empty {
6315
6449
  display: flex;
@@ -6500,10 +6634,13 @@ class SearchDropdown extends ElementWithStylesheet {
6500
6634
  const hasContent = this.suggestions.length > 0;
6501
6635
  return b `
6502
6636
  <div class="dropdown-container">
6503
- ${this.loading
6504
- ? this.renderLoading()
6505
- : hasContent
6506
- ? this.renderSuggestions()
6637
+ ${this.loading && hasContent
6638
+ ? b `<div class="progress-bar" aria-hidden="true"></div>`
6639
+ : A}
6640
+ ${hasContent
6641
+ ? this.renderSuggestions()
6642
+ : this.loading
6643
+ ? this.renderLoading()
6507
6644
  : this.renderEmpty()}
6508
6645
  </div>
6509
6646
  `;
@@ -6752,6 +6889,7 @@ class SearchWidget extends ElementWithStylesheet {
6752
6889
  clearTimeout(this.autocompleteTimer);
6753
6890
  if (query.length > 2) {
6754
6891
  this.dropdownVisible = true;
6892
+ this.dropdownLoading = true;
6755
6893
  this.performSearch(query);
6756
6894
  }
6757
6895
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6777,6 +6915,7 @@ class SearchWidget extends ElementWithStylesheet {
6777
6915
  }, 0);
6778
6916
  if (suggestion.length > 2) {
6779
6917
  this.dropdownVisible = true;
6918
+ this.dropdownLoading = true;
6780
6919
  this.performSearch(suggestion);
6781
6920
  }
6782
6921
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6857,6 +6996,7 @@ class SearchWidget extends ElementWithStylesheet {
6857
6996
  : this.handpickedProducts}
6858
6997
  .isSearchResults=${this.dropdownVisible &&
6859
6998
  this.searchProducts.length > 0}
6999
+ .loading=${this.dropdownVisible && this.dropdownLoading}
6860
7000
  .trendingTitle=${this.handpickedProductsTitle}
6861
7001
  .userId=${this.userId}
6862
7002
  ></evs-handpicked>
package/index.js CHANGED
@@ -6119,6 +6119,78 @@ var ProvidersEvoSearchSdk = (function () {
6119
6119
  .scroll-button-right {
6120
6120
  right: 1em;
6121
6121
  }
6122
+
6123
+ .skeleton-card {
6124
+ display: flex;
6125
+ width: 10em;
6126
+ height: 13.125em;
6127
+ padding: 0.625em 0;
6128
+ flex-direction: column;
6129
+ align-items: center;
6130
+ gap: 0.625em;
6131
+ border-radius: 0.375em;
6132
+ border: 0.0625em solid #cbd5e1;
6133
+ background: white;
6134
+ flex-shrink: 0;
6135
+ box-sizing: border-box;
6136
+ }
6137
+
6138
+ .skeleton-image {
6139
+ width: 5.875em;
6140
+ height: 6.25em;
6141
+ border-radius: 0.25em;
6142
+ flex-shrink: 0;
6143
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6144
+ background-size: 200% 100%;
6145
+ animation: shimmer 1.4s ease-in-out infinite;
6146
+ }
6147
+
6148
+ .skeleton-separator {
6149
+ width: 100%;
6150
+ height: 0.0625em;
6151
+ background-color: #cbd5e1;
6152
+ flex-shrink: 0;
6153
+ }
6154
+
6155
+ .skeleton-details {
6156
+ display: flex;
6157
+ height: 4.25em;
6158
+ padding: 0 0.5em;
6159
+ flex-direction: column;
6160
+ gap: 0.375em;
6161
+ width: 100%;
6162
+ box-sizing: border-box;
6163
+ }
6164
+
6165
+ .skeleton-line {
6166
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6167
+ background-size: 200% 100%;
6168
+ animation: shimmer 1.4s ease-in-out infinite;
6169
+ border-radius: 0.1875em;
6170
+ height: 0.75em;
6171
+ }
6172
+
6173
+ .skeleton-line-name {
6174
+ width: 80%;
6175
+ }
6176
+
6177
+ .skeleton-line-desc {
6178
+ width: 95%;
6179
+ }
6180
+
6181
+ .skeleton-line-price {
6182
+ width: 40%;
6183
+ margin-top: auto;
6184
+ }
6185
+
6186
+ @keyframes shimmer {
6187
+ 0% {
6188
+ background-position: 200% 0;
6189
+ }
6190
+ 100% {
6191
+ background-position: -200% 0;
6192
+ }
6193
+ }
6122
6194
  `;
6123
6195
 
6124
6196
  class HandpickedProducts extends ElementWithStylesheet {
@@ -6127,6 +6199,7 @@ var ProvidersEvoSearchSdk = (function () {
6127
6199
  this.products = [];
6128
6200
  this.trendingTitle = 'Handpicked for you';
6129
6201
  this.isSearchResults = false;
6202
+ this.loading = false;
6130
6203
  this.canScrollLeft = false;
6131
6204
  this.canScrollRight = true;
6132
6205
  }
@@ -6169,69 +6242,98 @@ var ProvidersEvoSearchSdk = (function () {
6169
6242
  (_a = this.carousel) === null || _a === void 0 ? void 0 : _a.scrollBy({ left: 170, behavior: 'smooth' });
6170
6243
  setTimeout(() => this.updateScrollButtons(), 300);
6171
6244
  }
6245
+ renderSkeleton() {
6246
+ const skeletonCount = 5;
6247
+ return b `
6248
+ <div class="products-carousel">
6249
+ ${Array.from({ length: skeletonCount }, () => b `
6250
+ <div class="skeleton-card" aria-hidden="true">
6251
+ <div class="skeleton-image"></div>
6252
+ <div class="skeleton-separator"></div>
6253
+ <div class="skeleton-details">
6254
+ <div class="skeleton-line skeleton-line-name"></div>
6255
+ <div class="skeleton-line skeleton-line-desc"></div>
6256
+ <div class="skeleton-line skeleton-line-price"></div>
6257
+ </div>
6258
+ </div>
6259
+ `)}
6260
+ </div>
6261
+ `;
6262
+ }
6172
6263
  render() {
6173
- if (!this.products.length) {
6264
+ if (!this.products.length && !this.loading) {
6174
6265
  return b ``;
6175
6266
  }
6267
+ const showSearchHeader = this.loading || this.isSearchResults;
6176
6268
  return b `
6177
- <div class="handpicked-products-container">
6269
+ <div
6270
+ class="handpicked-products-container"
6271
+ aria-busy=${this.loading ? 'true' : 'false'}
6272
+ >
6178
6273
  <h3 class="handpicked-title">
6179
6274
  <div class="icon-container">
6180
6275
  <bt-lucide-icon
6181
- name=${this.isSearchResults ? 'search' : 'handHeart'}
6276
+ name=${showSearchHeader ? 'search' : 'handHeart'}
6182
6277
  width="16"
6183
6278
  height="16"
6184
6279
  stroke="#EF4444"
6185
6280
  stroke-width="1"
6186
6281
  ></bt-lucide-icon>
6187
6282
  </div>
6188
- ${this.isSearchResults ? 'Matching Products' : this.trendingTitle}
6283
+ ${showSearchHeader ? 'Matching Products' : this.trendingTitle}
6189
6284
  </h3>
6190
6285
 
6191
6286
  <div class="carousel-wrapper">
6192
- ${this.canScrollLeft
6193
- ? b `
6194
- <button
6195
- class="scroll-button scroll-button-left"
6196
- @click=${this.handleScrollLeft}
6197
- aria-label="Scroll left"
6198
- >
6199
- <bt-lucide-icon
6200
- name="left"
6201
- width="20"
6202
- height="20"
6203
- stroke="#000000"
6204
- ></bt-lucide-icon>
6205
- </button>
6206
- `
6207
- : A}
6208
-
6209
- <div class="products-carousel" @scroll=${this.updateScrollButtons}>
6210
- ${this.products.map((product) => b `
6211
- <evs-product-card
6212
- .css=${this.css}
6213
- .product=${product}
6214
- .userId=${this.userId}
6215
- ></evs-product-card>
6216
- `)}
6217
- </div>
6218
-
6219
- ${this.canScrollRight
6220
- ? b `
6221
- <button
6222
- class="scroll-button scroll-button-right"
6223
- @click=${this.handleScrollRight}
6224
- aria-label="Scroll right"
6287
+ ${this.loading
6288
+ ? this.renderSkeleton()
6289
+ : b `
6290
+ ${this.canScrollLeft
6291
+ ? b `
6292
+ <button
6293
+ class="scroll-button scroll-button-left"
6294
+ @click=${this.handleScrollLeft}
6295
+ aria-label="Scroll left"
6296
+ >
6297
+ <bt-lucide-icon
6298
+ name="left"
6299
+ width="20"
6300
+ height="20"
6301
+ stroke="#000000"
6302
+ ></bt-lucide-icon>
6303
+ </button>
6304
+ `
6305
+ : A}
6306
+
6307
+ <div
6308
+ class="products-carousel"
6309
+ @scroll=${this.updateScrollButtons}
6225
6310
  >
6226
- <bt-lucide-icon
6227
- name="right"
6228
- width="20"
6229
- height="20"
6230
- stroke="#000000"
6231
- ></bt-lucide-icon>
6232
- </button>
6233
- `
6234
- : A}
6311
+ ${this.products.map((product) => b `
6312
+ <evs-product-card
6313
+ .css=${this.css}
6314
+ .product=${product}
6315
+ .userId=${this.userId}
6316
+ ></evs-product-card>
6317
+ `)}
6318
+ </div>
6319
+
6320
+ ${this.canScrollRight
6321
+ ? b `
6322
+ <button
6323
+ class="scroll-button scroll-button-right"
6324
+ @click=${this.handleScrollRight}
6325
+ aria-label="Scroll right"
6326
+ >
6327
+ <bt-lucide-icon
6328
+ name="right"
6329
+ width="20"
6330
+ height="20"
6331
+ stroke="#000000"
6332
+ ></bt-lucide-icon>
6333
+ </button>
6334
+ `
6335
+ : A}
6336
+ `}
6235
6337
  </div>
6236
6338
  </div>
6237
6339
  `;
@@ -6250,6 +6352,10 @@ var ProvidersEvoSearchSdk = (function () {
6250
6352
  n$1({ type: Boolean }),
6251
6353
  __metadata("design:type", Object)
6252
6354
  ], HandpickedProducts.prototype, "isSearchResults", void 0);
6355
+ __decorate([
6356
+ n$1({ type: Boolean }),
6357
+ __metadata("design:type", Object)
6358
+ ], HandpickedProducts.prototype, "loading", void 0);
6253
6359
  __decorate([
6254
6360
  n$1({ type: String }),
6255
6361
  __metadata("design:type", Object)
@@ -6311,6 +6417,34 @@ var ProvidersEvoSearchSdk = (function () {
6311
6417
  }
6312
6418
  }
6313
6419
 
6420
+ .progress-bar {
6421
+ position: sticky;
6422
+ top: 0;
6423
+ height: 0.125em;
6424
+ width: 100%;
6425
+ background: var(--evosearch-border, #cbd5e1);
6426
+ overflow: hidden;
6427
+ z-index: 1;
6428
+ }
6429
+
6430
+ .progress-bar::after {
6431
+ content: '';
6432
+ display: block;
6433
+ height: 100%;
6434
+ width: 40%;
6435
+ background: var(--evosearch-accent, #ef4444);
6436
+ animation: progress-slide 1.2s ease-in-out infinite;
6437
+ }
6438
+
6439
+ @keyframes progress-slide {
6440
+ 0% {
6441
+ transform: translateX(-100%);
6442
+ }
6443
+ 100% {
6444
+ transform: translateX(250%);
6445
+ }
6446
+ }
6447
+
6314
6448
  /* Empty State */
6315
6449
  .dropdown-empty {
6316
6450
  display: flex;
@@ -6501,10 +6635,13 @@ var ProvidersEvoSearchSdk = (function () {
6501
6635
  const hasContent = this.suggestions.length > 0;
6502
6636
  return b `
6503
6637
  <div class="dropdown-container">
6504
- ${this.loading
6505
- ? this.renderLoading()
6506
- : hasContent
6507
- ? this.renderSuggestions()
6638
+ ${this.loading && hasContent
6639
+ ? b `<div class="progress-bar" aria-hidden="true"></div>`
6640
+ : A}
6641
+ ${hasContent
6642
+ ? this.renderSuggestions()
6643
+ : this.loading
6644
+ ? this.renderLoading()
6508
6645
  : this.renderEmpty()}
6509
6646
  </div>
6510
6647
  `;
@@ -6753,6 +6890,7 @@ var ProvidersEvoSearchSdk = (function () {
6753
6890
  clearTimeout(this.autocompleteTimer);
6754
6891
  if (query.length > 2) {
6755
6892
  this.dropdownVisible = true;
6893
+ this.dropdownLoading = true;
6756
6894
  this.performSearch(query);
6757
6895
  }
6758
6896
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6778,6 +6916,7 @@ var ProvidersEvoSearchSdk = (function () {
6778
6916
  }, 0);
6779
6917
  if (suggestion.length > 2) {
6780
6918
  this.dropdownVisible = true;
6919
+ this.dropdownLoading = true;
6781
6920
  this.performSearch(suggestion);
6782
6921
  }
6783
6922
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6858,6 +6997,7 @@ var ProvidersEvoSearchSdk = (function () {
6858
6997
  : this.handpickedProducts}
6859
6998
  .isSearchResults=${this.dropdownVisible &&
6860
6999
  this.searchProducts.length > 0}
7000
+ .loading=${this.dropdownVisible && this.dropdownLoading}
6861
7001
  .trendingTitle=${this.handpickedProductsTitle}
6862
7002
  .userId=${this.userId}
6863
7003
  ></evs-handpicked>
package/index.mjs CHANGED
@@ -6116,6 +6116,78 @@ const handpickedProductsStyles = i$3 `
6116
6116
  .scroll-button-right {
6117
6117
  right: 1em;
6118
6118
  }
6119
+
6120
+ .skeleton-card {
6121
+ display: flex;
6122
+ width: 10em;
6123
+ height: 13.125em;
6124
+ padding: 0.625em 0;
6125
+ flex-direction: column;
6126
+ align-items: center;
6127
+ gap: 0.625em;
6128
+ border-radius: 0.375em;
6129
+ border: 0.0625em solid #cbd5e1;
6130
+ background: white;
6131
+ flex-shrink: 0;
6132
+ box-sizing: border-box;
6133
+ }
6134
+
6135
+ .skeleton-image {
6136
+ width: 5.875em;
6137
+ height: 6.25em;
6138
+ border-radius: 0.25em;
6139
+ flex-shrink: 0;
6140
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6141
+ background-size: 200% 100%;
6142
+ animation: shimmer 1.4s ease-in-out infinite;
6143
+ }
6144
+
6145
+ .skeleton-separator {
6146
+ width: 100%;
6147
+ height: 0.0625em;
6148
+ background-color: #cbd5e1;
6149
+ flex-shrink: 0;
6150
+ }
6151
+
6152
+ .skeleton-details {
6153
+ display: flex;
6154
+ height: 4.25em;
6155
+ padding: 0 0.5em;
6156
+ flex-direction: column;
6157
+ gap: 0.375em;
6158
+ width: 100%;
6159
+ box-sizing: border-box;
6160
+ }
6161
+
6162
+ .skeleton-line {
6163
+ background: linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 50%, #f1f5f9 100%);
6164
+ background-size: 200% 100%;
6165
+ animation: shimmer 1.4s ease-in-out infinite;
6166
+ border-radius: 0.1875em;
6167
+ height: 0.75em;
6168
+ }
6169
+
6170
+ .skeleton-line-name {
6171
+ width: 80%;
6172
+ }
6173
+
6174
+ .skeleton-line-desc {
6175
+ width: 95%;
6176
+ }
6177
+
6178
+ .skeleton-line-price {
6179
+ width: 40%;
6180
+ margin-top: auto;
6181
+ }
6182
+
6183
+ @keyframes shimmer {
6184
+ 0% {
6185
+ background-position: 200% 0;
6186
+ }
6187
+ 100% {
6188
+ background-position: -200% 0;
6189
+ }
6190
+ }
6119
6191
  `;
6120
6192
 
6121
6193
  class HandpickedProducts extends ElementWithStylesheet {
@@ -6124,6 +6196,7 @@ class HandpickedProducts extends ElementWithStylesheet {
6124
6196
  this.products = [];
6125
6197
  this.trendingTitle = 'Handpicked for you';
6126
6198
  this.isSearchResults = false;
6199
+ this.loading = false;
6127
6200
  this.canScrollLeft = false;
6128
6201
  this.canScrollRight = true;
6129
6202
  }
@@ -6166,69 +6239,98 @@ class HandpickedProducts extends ElementWithStylesheet {
6166
6239
  (_a = this.carousel) === null || _a === void 0 ? void 0 : _a.scrollBy({ left: 170, behavior: 'smooth' });
6167
6240
  setTimeout(() => this.updateScrollButtons(), 300);
6168
6241
  }
6242
+ renderSkeleton() {
6243
+ const skeletonCount = 5;
6244
+ return b `
6245
+ <div class="products-carousel">
6246
+ ${Array.from({ length: skeletonCount }, () => b `
6247
+ <div class="skeleton-card" aria-hidden="true">
6248
+ <div class="skeleton-image"></div>
6249
+ <div class="skeleton-separator"></div>
6250
+ <div class="skeleton-details">
6251
+ <div class="skeleton-line skeleton-line-name"></div>
6252
+ <div class="skeleton-line skeleton-line-desc"></div>
6253
+ <div class="skeleton-line skeleton-line-price"></div>
6254
+ </div>
6255
+ </div>
6256
+ `)}
6257
+ </div>
6258
+ `;
6259
+ }
6169
6260
  render() {
6170
- if (!this.products.length) {
6261
+ if (!this.products.length && !this.loading) {
6171
6262
  return b ``;
6172
6263
  }
6264
+ const showSearchHeader = this.loading || this.isSearchResults;
6173
6265
  return b `
6174
- <div class="handpicked-products-container">
6266
+ <div
6267
+ class="handpicked-products-container"
6268
+ aria-busy=${this.loading ? 'true' : 'false'}
6269
+ >
6175
6270
  <h3 class="handpicked-title">
6176
6271
  <div class="icon-container">
6177
6272
  <bt-lucide-icon
6178
- name=${this.isSearchResults ? 'search' : 'handHeart'}
6273
+ name=${showSearchHeader ? 'search' : 'handHeart'}
6179
6274
  width="16"
6180
6275
  height="16"
6181
6276
  stroke="#EF4444"
6182
6277
  stroke-width="1"
6183
6278
  ></bt-lucide-icon>
6184
6279
  </div>
6185
- ${this.isSearchResults ? 'Matching Products' : this.trendingTitle}
6280
+ ${showSearchHeader ? 'Matching Products' : this.trendingTitle}
6186
6281
  </h3>
6187
6282
 
6188
6283
  <div class="carousel-wrapper">
6189
- ${this.canScrollLeft
6190
- ? b `
6191
- <button
6192
- class="scroll-button scroll-button-left"
6193
- @click=${this.handleScrollLeft}
6194
- aria-label="Scroll left"
6195
- >
6196
- <bt-lucide-icon
6197
- name="left"
6198
- width="20"
6199
- height="20"
6200
- stroke="#000000"
6201
- ></bt-lucide-icon>
6202
- </button>
6203
- `
6204
- : A}
6205
-
6206
- <div class="products-carousel" @scroll=${this.updateScrollButtons}>
6207
- ${this.products.map((product) => b `
6208
- <evs-product-card
6209
- .css=${this.css}
6210
- .product=${product}
6211
- .userId=${this.userId}
6212
- ></evs-product-card>
6213
- `)}
6214
- </div>
6215
-
6216
- ${this.canScrollRight
6217
- ? b `
6218
- <button
6219
- class="scroll-button scroll-button-right"
6220
- @click=${this.handleScrollRight}
6221
- aria-label="Scroll right"
6284
+ ${this.loading
6285
+ ? this.renderSkeleton()
6286
+ : b `
6287
+ ${this.canScrollLeft
6288
+ ? b `
6289
+ <button
6290
+ class="scroll-button scroll-button-left"
6291
+ @click=${this.handleScrollLeft}
6292
+ aria-label="Scroll left"
6293
+ >
6294
+ <bt-lucide-icon
6295
+ name="left"
6296
+ width="20"
6297
+ height="20"
6298
+ stroke="#000000"
6299
+ ></bt-lucide-icon>
6300
+ </button>
6301
+ `
6302
+ : A}
6303
+
6304
+ <div
6305
+ class="products-carousel"
6306
+ @scroll=${this.updateScrollButtons}
6222
6307
  >
6223
- <bt-lucide-icon
6224
- name="right"
6225
- width="20"
6226
- height="20"
6227
- stroke="#000000"
6228
- ></bt-lucide-icon>
6229
- </button>
6230
- `
6231
- : A}
6308
+ ${this.products.map((product) => b `
6309
+ <evs-product-card
6310
+ .css=${this.css}
6311
+ .product=${product}
6312
+ .userId=${this.userId}
6313
+ ></evs-product-card>
6314
+ `)}
6315
+ </div>
6316
+
6317
+ ${this.canScrollRight
6318
+ ? b `
6319
+ <button
6320
+ class="scroll-button scroll-button-right"
6321
+ @click=${this.handleScrollRight}
6322
+ aria-label="Scroll right"
6323
+ >
6324
+ <bt-lucide-icon
6325
+ name="right"
6326
+ width="20"
6327
+ height="20"
6328
+ stroke="#000000"
6329
+ ></bt-lucide-icon>
6330
+ </button>
6331
+ `
6332
+ : A}
6333
+ `}
6232
6334
  </div>
6233
6335
  </div>
6234
6336
  `;
@@ -6247,6 +6349,10 @@ __decorate([
6247
6349
  n$1({ type: Boolean }),
6248
6350
  __metadata("design:type", Object)
6249
6351
  ], HandpickedProducts.prototype, "isSearchResults", void 0);
6352
+ __decorate([
6353
+ n$1({ type: Boolean }),
6354
+ __metadata("design:type", Object)
6355
+ ], HandpickedProducts.prototype, "loading", void 0);
6250
6356
  __decorate([
6251
6357
  n$1({ type: String }),
6252
6358
  __metadata("design:type", Object)
@@ -6308,6 +6414,34 @@ const searchDropdownStyles = i$3 `
6308
6414
  }
6309
6415
  }
6310
6416
 
6417
+ .progress-bar {
6418
+ position: sticky;
6419
+ top: 0;
6420
+ height: 0.125em;
6421
+ width: 100%;
6422
+ background: var(--evosearch-border, #cbd5e1);
6423
+ overflow: hidden;
6424
+ z-index: 1;
6425
+ }
6426
+
6427
+ .progress-bar::after {
6428
+ content: '';
6429
+ display: block;
6430
+ height: 100%;
6431
+ width: 40%;
6432
+ background: var(--evosearch-accent, #ef4444);
6433
+ animation: progress-slide 1.2s ease-in-out infinite;
6434
+ }
6435
+
6436
+ @keyframes progress-slide {
6437
+ 0% {
6438
+ transform: translateX(-100%);
6439
+ }
6440
+ 100% {
6441
+ transform: translateX(250%);
6442
+ }
6443
+ }
6444
+
6311
6445
  /* Empty State */
6312
6446
  .dropdown-empty {
6313
6447
  display: flex;
@@ -6498,10 +6632,13 @@ class SearchDropdown extends ElementWithStylesheet {
6498
6632
  const hasContent = this.suggestions.length > 0;
6499
6633
  return b `
6500
6634
  <div class="dropdown-container">
6501
- ${this.loading
6502
- ? this.renderLoading()
6503
- : hasContent
6504
- ? this.renderSuggestions()
6635
+ ${this.loading && hasContent
6636
+ ? b `<div class="progress-bar" aria-hidden="true"></div>`
6637
+ : A}
6638
+ ${hasContent
6639
+ ? this.renderSuggestions()
6640
+ : this.loading
6641
+ ? this.renderLoading()
6505
6642
  : this.renderEmpty()}
6506
6643
  </div>
6507
6644
  `;
@@ -6750,6 +6887,7 @@ class SearchWidget extends ElementWithStylesheet {
6750
6887
  clearTimeout(this.autocompleteTimer);
6751
6888
  if (query.length > 2) {
6752
6889
  this.dropdownVisible = true;
6890
+ this.dropdownLoading = true;
6753
6891
  this.performSearch(query);
6754
6892
  }
6755
6893
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6775,6 +6913,7 @@ class SearchWidget extends ElementWithStylesheet {
6775
6913
  }, 0);
6776
6914
  if (suggestion.length > 2) {
6777
6915
  this.dropdownVisible = true;
6916
+ this.dropdownLoading = true;
6778
6917
  this.performSearch(suggestion);
6779
6918
  }
6780
6919
  this.dispatchEvent(new CustomEvent('search-submit', {
@@ -6855,6 +6994,7 @@ class SearchWidget extends ElementWithStylesheet {
6855
6994
  : this.handpickedProducts}
6856
6995
  .isSearchResults=${this.dropdownVisible &&
6857
6996
  this.searchProducts.length > 0}
6997
+ .loading=${this.dropdownVisible && this.dropdownLoading}
6858
6998
  .trendingTitle=${this.handpickedProductsTitle}
6859
6999
  .userId=${this.userId}
6860
7000
  ></evs-handpicked>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-evo-search-sdk",
3
- "version": "1.54.0",
3
+ "version": "1.55.0",
4
4
  "description": "Evo Search SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",