@wix/himalaya-cli 0.1580.0 → 0.1582.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.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-config.d.ts +18 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/network/src/index.d.ts +39 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/webview-page/src/capabilities.generated.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +12 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +6 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/network.mjs +45 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
- package/dist/cli.mjs +16481 -16739
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +1 -1
- package/guides/component-reference.json +5 -3
- package/guides/component-reference.md +10 -2
- package/guides/designing-himi-screens.md +24 -0
- package/guides/importable-sdks.md +1 -0
- package/guides/sdk-reference.json +38 -1
- package/guides/tier-5-add-a-screen.md +32 -0
- package/guides/web-page-sdk-reference.md +1 -0
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +197 -304
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +44 -13
- package/templates/branded-lite/dev/index.ts +197 -304
- package/templates/branded-lite/l10n/en.json +2 -2
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +49 -17
- package/templates/gym-fitness/dev/index.ts +197 -304
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +44 -13
- package/templates/portfolio-creative/dev/index.ts +197 -304
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +44 -13
- package/templates/retail-store/dev/index.ts +197 -304
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +49 -17
|
@@ -44,6 +44,7 @@ async function cartItemCount(): Promise<number> {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
interface GalleryItem {
|
|
47
|
+
id: string;
|
|
47
48
|
url: string;
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -134,8 +135,8 @@ function slotsOf(groups: StoreOption[], selection: StoreOptionSelection, showErr
|
|
|
134
135
|
out[`opt${n}Chips`] = (g?.choices ?? []).map((c) => ({ id: c.id, label: c.label, ...(g.kind === "color" && c.colorCode ? { swatch: c.colorCode } : {}), disabled: c.inStock === false }));
|
|
135
136
|
out[`opt${n}Selected`] = chosen ? [chosen] : [];
|
|
136
137
|
out[`opt${n}SelectedId`] = chosen;
|
|
137
|
-
out[`opt${n}Placeholder`] = g?.choices.find(c => c.id === chosen)?.label ?? copyTemplate("product.optionPlaceholder", "
|
|
138
|
-
const error = showErrors && g && !chosen ? copyTemplate("product.optionRequired", "
|
|
138
|
+
out[`opt${n}Placeholder`] = g?.choices.find(c => c.id === chosen)?.label ?? copyTemplate("product.optionPlaceholder", "Select {option}", { option: displayName || "option" });
|
|
139
|
+
const error = showErrors && g && !chosen ? copyTemplate("product.optionRequired", "Select a {option}", { option: g.name.toLowerCase() }) : "";
|
|
139
140
|
out[`opt${n}Error`] = error;
|
|
140
141
|
out[`noOpt${n}Error`] = !error;
|
|
141
142
|
out[`hasOpt${n}Error`] = !!error;
|
|
@@ -261,6 +262,11 @@ interface S {
|
|
|
261
262
|
/** FULL media gallery (media.items[] with the main image first) — the detail
|
|
262
263
|
* screen renders a Carousel over it when 2+ images exist. */
|
|
263
264
|
gallery: GalleryItem[];
|
|
265
|
+
galleryIndex: number;
|
|
266
|
+
galleryLabel: string;
|
|
267
|
+
opt1ScrollRequest: string;
|
|
268
|
+
opt2ScrollRequest: string;
|
|
269
|
+
opt3ScrollRequest: string;
|
|
264
270
|
hasGallery: boolean;
|
|
265
271
|
noGallery: boolean;
|
|
266
272
|
initial: string;
|
|
@@ -270,6 +276,7 @@ interface S {
|
|
|
270
276
|
cartCount: number;
|
|
271
277
|
/** An add-to-cart write is in flight (pending line under the CTA). */
|
|
272
278
|
adding: boolean;
|
|
279
|
+
addLabel: string;
|
|
273
280
|
notAdding: boolean;
|
|
274
281
|
/** The last add succeeded (confirmation + View cart under the CTA). */
|
|
275
282
|
added: boolean;
|
|
@@ -305,6 +312,8 @@ interface S {
|
|
|
305
312
|
/** Add to cart is blocked: this product has options and they are not all chosen. */
|
|
306
313
|
optionsIncomplete: boolean;
|
|
307
314
|
showOptionErrors: boolean;
|
|
315
|
+
optionValidationRequest: number;
|
|
316
|
+
optionValidationTarget: string;
|
|
308
317
|
addDisabled: boolean;
|
|
309
318
|
/** The product was served from the offline cache, which carries no option groups.
|
|
310
319
|
* "No groups" here means UNKNOWN, not "none" — so the CTA must stay blocked rather
|
|
@@ -352,7 +361,8 @@ export function productGallery(p: StoreProduct): GalleryItem[] {
|
|
|
352
361
|
// image no matter what the read asked for. One reader, not a private copy per
|
|
353
362
|
// worker — that is how the two layouts drifted apart in the first place.
|
|
354
363
|
for (const url of sdkProductGallery(p, WIX_DETAIL_IMAGE)) push(url);
|
|
355
|
-
|
|
364
|
+
for (const group of productOptions(p, WIX_DETAIL_IMAGE)) for (const choice of group.choices) push(choice.image);
|
|
365
|
+
return urls.map((url) => ({ id: url, url }));
|
|
356
366
|
}
|
|
357
367
|
|
|
358
368
|
/** The product's public page URL when the payload carries one ("" otherwise) —
|
|
@@ -390,6 +400,7 @@ function parseQuantity(raw: string): number | undefined {
|
|
|
390
400
|
|
|
391
401
|
function derive(s: S): S {
|
|
392
402
|
const empty = s.status === "ready" && !s.name;
|
|
403
|
+
const galleryIndex = Math.min(Math.max(0, Math.floor(Number(s.galleryIndex) || 0)), Math.max(0, s.gallery.length - 1));
|
|
393
404
|
const hasGallery = s.gallery.length > 1;
|
|
394
405
|
const hasSingleImage = !!s.image && !hasGallery;
|
|
395
406
|
const groups = s.optionGroups;
|
|
@@ -397,6 +408,8 @@ function derive(s: S): S {
|
|
|
397
408
|
const optionsIncomplete = s.optionsUnknown || !!outOfStockPick(groups, s.selection) || (groups.length > 0 && (overflow || !isSelectionComplete(groups, s.selection)));
|
|
398
409
|
return {
|
|
399
410
|
...s,
|
|
411
|
+
galleryIndex,
|
|
412
|
+
galleryLabel: s.gallery.length ? copyTemplate("product.galleryPage", "Image {index} of {count}", { index: String(galleryIndex + 1), count: String(s.gallery.length) }) : "",
|
|
400
413
|
notOnSale: !s.wasPrice,
|
|
401
414
|
wasPriceEmpty: !!s.wasPrice,
|
|
402
415
|
noSku: !s.skuLabel,
|
|
@@ -425,9 +438,12 @@ function derive(s: S): S {
|
|
|
425
438
|
// indistinguishable from one with none, and adding it would post the variant-less
|
|
426
439
|
// line this whole feature exists to prevent.
|
|
427
440
|
optionsIncomplete,
|
|
428
|
-
|
|
441
|
+
...Object.fromEntries([1, 2, 3].map(n => [`opt${n}ScrollRequest`,
|
|
442
|
+
s.showOptionErrors && groups[n - 1]?.id === s.optionValidationTarget && !s.selection[groups[n - 1].id] ? String(s.optionValidationRequest || "") : ""])),
|
|
443
|
+
addDisabled: s.adding || s.optionsUnknown || overflow || !!outOfStockPick(groups, s.selection),
|
|
429
444
|
optionsHint: groups.length ? optionsHint(groups, s.selection) : "",
|
|
430
445
|
saveLabel: s.saved ? copyParam("savedProducts.removeLabel", "Remove from wishlist") : copyParam("savedProducts.addLabel", "Add to wishlist"),
|
|
446
|
+
addLabel: s.adding ? copyParam("product.adding", "Adding to cart…") : copyParam("product.addToCart", "Add to cart"),
|
|
431
447
|
notAdding: !s.adding,
|
|
432
448
|
notAdded: !s.added,
|
|
433
449
|
isLoading: s.status === "loading",
|
|
@@ -461,7 +477,7 @@ const defineService = withIapPresentation<S>({
|
|
|
461
477
|
register: withOnlineWrites(registerState, ["beginAdd", "addToCart", "buy"], { derive, messageFields: action => action === "buy" ? ["buyNote"] : ["cartHint"] }),
|
|
462
478
|
adapters: SELLS_THROUGH_APPLE ? [storesProductOrders] : [],
|
|
463
479
|
onCreate: commerce => { productPricing = commerce; }, prefix: "product",
|
|
464
|
-
transientKeys: ["price", "optionsIncomplete", "cartHint", "cartHidden", "buyHidden", "buyLabel", "buyDisabled", "buyNote", "purchasedNote", "addedSheetPresented", "shareHint"], contentActions: ["load", "paintCached"], concurrentPublishActions: ["buy"],
|
|
480
|
+
transientKeys: ["optionValidationTarget", "optionValidationRequest", "opt1ScrollRequest", "opt2ScrollRequest", "opt3ScrollRequest", "galleryIndex", "price", "optionsIncomplete", "cartHint", "cartHidden", "buyHidden", "buyLabel", "buyDisabled", "buyNote", "purchasedNote", "addedSheetPresented", "shareHint"], contentActions: ["load", "paintCached"], concurrentPublishActions: ["buy"],
|
|
465
481
|
items: state => inputId() ? [{ reference: { kind: "storesProduct", id: inputId() }, commerceDisplayPrice: state.price }] : [],
|
|
466
482
|
present: (state, price, allowed) => {
|
|
467
483
|
const purchase = applePurchase(state);
|
|
@@ -469,9 +485,10 @@ const defineService = withIapPresentation<S>({
|
|
|
469
485
|
const blocked = lastProduct?.productType?.toLowerCase() === "digital" || (!state.optionsUnknown && !allowed(inputId()));
|
|
470
486
|
const cartHint = state.cartHint === offlineWriteMessage ? state.cartHint
|
|
471
487
|
: !purchase.appleRoute && blocked ? unavailable : state.cartHint === unavailable ? "" : state.cartHint;
|
|
488
|
+
const productState = derive(state);
|
|
472
489
|
return {
|
|
473
|
-
...state, price: price(inputId()), ...(purchase.appleRoute ? { wasPrice: "", wasPriceEmpty: false, notOnSale: true } : {}), optionsIncomplete:
|
|
474
|
-
cartHint, noCartHint: !cartHint || state.added, addDisabled:
|
|
490
|
+
...state, price: price(inputId()), ...(purchase.appleRoute ? { wasPrice: "", wasPriceEmpty: false, notOnSale: true } : {}), optionsIncomplete: productState.optionsIncomplete || !allowed(inputId()) || lastProduct?.productType?.toLowerCase() === "digital",
|
|
491
|
+
cartHint, noCartHint: !cartHint || state.added, addDisabled: productState.addDisabled || blocked,
|
|
475
492
|
cartHidden: purchase.appleRoute,
|
|
476
493
|
buyHidden: !purchase.appleRoute || purchase.accessReady, buyLabel: purchase.buyLabel, buyDisabled: purchase.buyDisabled,
|
|
477
494
|
buyNote: state.buyNote === offlineWriteMessage ? state.buyNote : purchase.buyNote,
|
|
@@ -505,6 +522,7 @@ const svc = defineService<S, {
|
|
|
505
522
|
toggleReturnPolicy: (s: S) => S;
|
|
506
523
|
toggleShippingInfo: (s: S) => S;
|
|
507
524
|
selectOption: (s: S, arg?: unknown) => S;
|
|
525
|
+
setGalleryIndex: (s: S, arg?: unknown) => S;
|
|
508
526
|
addToCart: (s: S) => Promise<S>;
|
|
509
527
|
beginAdd: (s: S, arg?: unknown) => S;
|
|
510
528
|
paintCached: (s: S, arg?: unknown) => S;
|
|
@@ -550,6 +568,9 @@ const svc = defineService<S, {
|
|
|
550
568
|
shippingInfoExpanded: false,
|
|
551
569
|
image: "",
|
|
552
570
|
gallery: [],
|
|
571
|
+
galleryIndex: 0,
|
|
572
|
+
opt1ScrollRequest: "", opt2ScrollRequest: "", opt3ScrollRequest: "",
|
|
573
|
+
galleryLabel: "",
|
|
553
574
|
hasGallery: false,
|
|
554
575
|
noGallery: true,
|
|
555
576
|
initial: "",
|
|
@@ -557,6 +578,7 @@ const svc = defineService<S, {
|
|
|
557
578
|
cartHint: "",
|
|
558
579
|
cartCount: 0,
|
|
559
580
|
adding: false,
|
|
581
|
+
addLabel: "",
|
|
560
582
|
notAdding: true,
|
|
561
583
|
added: false,
|
|
562
584
|
notAdded: true,
|
|
@@ -582,6 +604,8 @@ const svc = defineService<S, {
|
|
|
582
604
|
noOptionsOverflow: true,
|
|
583
605
|
optionsIncomplete: false,
|
|
584
606
|
showOptionErrors: false,
|
|
607
|
+
optionValidationRequest: 0,
|
|
608
|
+
optionValidationTarget: "",
|
|
585
609
|
addDisabled: false,
|
|
586
610
|
optionsUnknown: false,
|
|
587
611
|
optionsHint: "",
|
|
@@ -607,7 +631,7 @@ const svc = defineService<S, {
|
|
|
607
631
|
// Storage problems must not prevent browsing or buying a product.
|
|
608
632
|
let saved = false;
|
|
609
633
|
try { saved = isProductSaved(id); } catch { /* save action reports a retryable error */ }
|
|
610
|
-
s = { ...s, saved, saveHint: "", shareHint: "", adding: false, added: false, addedSheetPresented: false, quantity: 1, showOptionErrors: false, returnPolicyExpanded: false, shippingInfoExpanded: false };
|
|
634
|
+
s = { ...s, saved, saveHint: "", shareHint: "", adding: false, added: false, addedSheetPresented: false, quantity: 1, showOptionErrors: false, optionValidationRequest: 0, optionValidationTarget: "", galleryIndex: 0, returnPolicyExpanded: false, shippingInfoExpanded: false };
|
|
611
635
|
// A fresh navigation into the product resets any quantity left over
|
|
612
636
|
// from a previous visit to the same worker instance.
|
|
613
637
|
if (!id) {
|
|
@@ -625,7 +649,7 @@ const svc = defineService<S, {
|
|
|
625
649
|
// The live product read goes out FIRST too — the local-db read below must never delay it.
|
|
626
650
|
// Settled into a value so a failure is handled where it is awaited, never unhandled.
|
|
627
651
|
// DESCRIPTION widens the default fieldset with the V3 Ricos description (a V1 catalog ignores it).
|
|
628
|
-
const live = getStoreProduct(id, ["DESCRIPTION"]).then(
|
|
652
|
+
const live = getStoreProduct(id, ["DESCRIPTION", "PRODUCT_CHOICES_DISPLAY_IMAGE"]).then(
|
|
629
653
|
(r) => ({ ok: true as const, r }),
|
|
630
654
|
() => ({ ok: false as const }),
|
|
631
655
|
);
|
|
@@ -658,11 +682,11 @@ const svc = defineService<S, {
|
|
|
658
682
|
if (outcome.ok) {
|
|
659
683
|
const p = (outcome.r.product ?? (outcome.r as unknown as StoreProduct)) as StoreProduct;
|
|
660
684
|
const name = cleanTitle(p.name) || "Product";
|
|
661
|
-
const image = productImage(p, WIX_DETAIL_IMAGE);
|
|
685
|
+
const image = productImage(p, WIX_DETAIL_IMAGE) || productGallery(p)[0]?.url || "";
|
|
662
686
|
lastProduct = p;
|
|
663
687
|
// A group with exactly one choice is chosen for the shopper; a real choice
|
|
664
688
|
// is left blank so the pick is deliberate.
|
|
665
|
-
const optionGroups = productOptions(p);
|
|
689
|
+
const optionGroups = productOptions(p, WIX_DETAIL_IMAGE);
|
|
666
690
|
const sale = productSale(p);
|
|
667
691
|
// A pooled screen re-appearing re-runs `load`. Wiping `selection` there means a
|
|
668
692
|
// trip to the cart and back silently clears the size the shopper picked and
|
|
@@ -749,6 +773,11 @@ const svc = defineService<S, {
|
|
|
749
773
|
// One chip row per option group. `group` is the descriptor slot ("1".."3");
|
|
750
774
|
// FilterChips sends back the WHOLE selected set, which for a single-select row
|
|
751
775
|
// is either one id or none (re-tapping the active chip clears it).
|
|
776
|
+
setGalleryIndex: (s, arg) => {
|
|
777
|
+
const raw = argValue(arg, "index") || argValue(arg, "value");
|
|
778
|
+
const index = raw.trim() ? Number(raw) : NaN;
|
|
779
|
+
return Number.isInteger(index) && index >= 0 && index < s.gallery.length ? derive({ ...s, galleryIndex: index }) : s;
|
|
780
|
+
},
|
|
752
781
|
selectOption: (s, arg) => {
|
|
753
782
|
const slot = Math.floor(Number(argValue(arg, "group")));
|
|
754
783
|
const group = s.optionGroups[slot - 1];
|
|
@@ -763,7 +792,9 @@ const svc = defineService<S, {
|
|
|
763
792
|
if (choice) selection[group.id] = choice; else delete selection[group.id];
|
|
764
793
|
// A new choice invalidates the last add's confirmation — it was for the
|
|
765
794
|
// previous variant.
|
|
766
|
-
|
|
795
|
+
const image = group.choices.find(c => c.id === choice)?.image;
|
|
796
|
+
const imageIndex = image ? s.gallery.findIndex(page => page.url === image) : -1;
|
|
797
|
+
return derive({ ...s, selection, optionValidationTarget: "", ...(imageIndex >= 0 ? { galleryIndex: imageIndex } : {}), added: false, addedSheetPresented: false, cartHint: "" });
|
|
767
798
|
},
|
|
768
799
|
// The pending half of addToCart, as its own reducer so it PUBLISHES before the
|
|
769
800
|
// network write starts: the pending line shows and the top-bar badge ticks up in the same
|
|
@@ -819,7 +850,7 @@ const svc = defineService<S, {
|
|
|
819
850
|
if (s.optionsIncomplete) {
|
|
820
851
|
// With no groups in hand there is nothing for `optionsHint` to name, so the
|
|
821
852
|
// offline case needs its own reason rather than an empty string.
|
|
822
|
-
return derive({ ...s, showOptionErrors: true, cartHint: s.optionsUnknown
|
|
853
|
+
return derive({ ...s, showOptionErrors: true, optionValidationTarget: s.optionGroups.find(g => !s.selection[g.id])?.id ?? "", optionValidationRequest: (s.optionValidationRequest || 0) + 1, cartHint: s.optionsUnknown
|
|
823
854
|
? copyParam("product.cartHintOffline", "Reconnect to choose options and add this to your cart.")
|
|
824
855
|
: optionsHint(s.optionGroups, s.selection) || copyParam("product.cartHintNoVariant", "That combination is not available. Try another.") });
|
|
825
856
|
}
|