@thefittingroom/shop-ui 5.0.24 → 5.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/index.js +337 -71
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -18,13 +18,30 @@ npm ci
|
|
|
18
18
|
| Script | What it does |
|
|
19
19
|
|---|---|
|
|
20
20
|
| `npm run build` | Clean + production build into `dist/` |
|
|
21
|
-
| `npm run check` | Type-check (`tsc --noEmit`) |
|
|
21
|
+
| `npm run check` | Type-check (`tsc --noEmit`) + ESLint + Prettier |
|
|
22
22
|
| `npm run watch` | Vite build in watch mode |
|
|
23
23
|
| `npm run serve` | Static-serve the repo on `:5173` with CORS |
|
|
24
24
|
| `npm run watch-serve` | Both `watch` and `serve` together; Ctrl+C stops both |
|
|
25
|
+
| `npm run test` / `npm run test:e2e` | Playwright e2e suite (Chromium) against the built bundle |
|
|
26
|
+
| `npm run test:e2e:ui` | Playwright UI runner for local debugging |
|
|
25
27
|
| `npm run gen-types` | Regenerate `src/api/gen/*.ts` from `tfr-backend` Go types |
|
|
26
28
|
| `npm run promote-latest [version]` | Move npm dist-tag `latest` onto a published version (defaults to current `package.json` version) |
|
|
27
29
|
|
|
30
|
+
## Running e2e tests
|
|
31
|
+
|
|
32
|
+
First-time setup: `npm install && npx playwright install chromium` (the
|
|
33
|
+
second command downloads the Chromium binary once; cached afterwards). Then
|
|
34
|
+
`npm run test:e2e` runs the suite. Specs live under `tests/e2e/`; they boot
|
|
35
|
+
the built bundle in headless Chromium against a static fixture page
|
|
36
|
+
(`tests/e2e/fixtures/host.html`) that mimics the minimal contract the Shopify
|
|
37
|
+
theme provides. Firebase is mocked via `InitParams.testHooks`
|
|
38
|
+
(see `src/lib/firebase-mock.ts`); REST endpoints are mocked via
|
|
39
|
+
`page.route()`. See AGENTS.md for the architecture and constraints.
|
|
40
|
+
|
|
41
|
+
For an interactive debug loop, `npm run watch-serve &` in one terminal and
|
|
42
|
+
`npm run test:e2e:ui` in another — Playwright reuses the live-rebuilt
|
|
43
|
+
`:5173`.
|
|
44
|
+
|
|
28
45
|
## Release process
|
|
29
46
|
|
|
30
47
|
Releases are explicit, human-initiated steps via a single GitHub Actions
|
package/dist/index.js
CHANGED
|
@@ -14054,7 +14054,7 @@ function applyFrameBaseUrl(url, baseUrl2) {
|
|
|
14054
14054
|
return `${cleanBase}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
14055
14055
|
}
|
|
14056
14056
|
const STORAGE_KEY = "tfr:fitting-room:v1";
|
|
14057
|
-
const logger$
|
|
14057
|
+
const logger$g = getLogger("fitting-room-storage");
|
|
14058
14058
|
function readAll() {
|
|
14059
14059
|
try {
|
|
14060
14060
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
@@ -14067,7 +14067,7 @@ function readAll() {
|
|
|
14067
14067
|
}
|
|
14068
14068
|
return parsed;
|
|
14069
14069
|
} catch (error) {
|
|
14070
|
-
logger$
|
|
14070
|
+
logger$g.logWarn("Failed to read fitting room from localStorage", {
|
|
14071
14071
|
error
|
|
14072
14072
|
});
|
|
14073
14073
|
return {};
|
|
@@ -14077,7 +14077,7 @@ function writeAll(all) {
|
|
|
14077
14077
|
try {
|
|
14078
14078
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
|
|
14079
14079
|
} catch (error) {
|
|
14080
|
-
logger$
|
|
14080
|
+
logger$g.logWarn("Failed to write fitting room to localStorage", {
|
|
14081
14081
|
error
|
|
14082
14082
|
});
|
|
14083
14083
|
}
|
|
@@ -14103,7 +14103,7 @@ function _init$7() {
|
|
|
14103
14103
|
}
|
|
14104
14104
|
async function addFittingRoomItem(productId, handle, isPdp) {
|
|
14105
14105
|
const state = useMainStore.getState();
|
|
14106
|
-
logger$
|
|
14106
|
+
logger$g.logDebug("{{ts}} - Adding to fitting room", {
|
|
14107
14107
|
productId,
|
|
14108
14108
|
handle,
|
|
14109
14109
|
isPdp
|
|
@@ -14125,7 +14125,7 @@ async function addFittingRoomItem(productId, handle, isPdp) {
|
|
|
14125
14125
|
size = selection.size || null;
|
|
14126
14126
|
color = selection.color;
|
|
14127
14127
|
} catch (error) {
|
|
14128
|
-
logger$
|
|
14128
|
+
logger$g.logWarn("Failed to read selected options from currentProduct", {
|
|
14129
14129
|
error
|
|
14130
14130
|
});
|
|
14131
14131
|
}
|
|
@@ -14157,7 +14157,7 @@ async function toggleFittingRoomItem(productId, handle, isPdp) {
|
|
|
14157
14157
|
const state = useMainStore.getState();
|
|
14158
14158
|
const isInFittingRoom = state.fittingRoom.some((item) => item.externalId === productId);
|
|
14159
14159
|
if (isInFittingRoom) {
|
|
14160
|
-
logger$
|
|
14160
|
+
logger$g.logDebug("{{ts}} - Removing from fitting room", {
|
|
14161
14161
|
productId
|
|
14162
14162
|
});
|
|
14163
14163
|
state.removeFromFittingRoom(productId);
|
|
@@ -23058,7 +23058,7 @@ function isVersionServiceProvider(provider) {
|
|
|
23058
23058
|
}
|
|
23059
23059
|
const name$q = "@firebase/app";
|
|
23060
23060
|
const version$1$1 = "0.14.5";
|
|
23061
|
-
const logger$
|
|
23061
|
+
const logger$f = new Logger3("@firebase/app");
|
|
23062
23062
|
const name$p = "@firebase/app-compat";
|
|
23063
23063
|
const name$o = "@firebase/analytics-compat";
|
|
23064
23064
|
const name$n = "@firebase/analytics";
|
|
@@ -23125,13 +23125,13 @@ function _addComponent(app, component) {
|
|
|
23125
23125
|
try {
|
|
23126
23126
|
app.container.addComponent(component);
|
|
23127
23127
|
} catch (e) {
|
|
23128
|
-
logger$
|
|
23128
|
+
logger$f.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e);
|
|
23129
23129
|
}
|
|
23130
23130
|
}
|
|
23131
23131
|
function _registerComponent(component) {
|
|
23132
23132
|
const componentName = component.name;
|
|
23133
23133
|
if (_components.has(componentName)) {
|
|
23134
|
-
logger$
|
|
23134
|
+
logger$f.debug(`There were multiple attempts to register component ${componentName}.`);
|
|
23135
23135
|
return false;
|
|
23136
23136
|
}
|
|
23137
23137
|
_components.set(componentName, component);
|
|
@@ -23340,7 +23340,7 @@ function registerVersion(libraryKeyOrName, version2, variant) {
|
|
|
23340
23340
|
if (versionMismatch) {
|
|
23341
23341
|
warning.push(`version name "${version2}" contains illegal characters (whitespace or "/")`);
|
|
23342
23342
|
}
|
|
23343
|
-
logger$
|
|
23343
|
+
logger$f.warn(warning.join(" "));
|
|
23344
23344
|
return;
|
|
23345
23345
|
}
|
|
23346
23346
|
_registerComponent(new Component(
|
|
@@ -23384,12 +23384,12 @@ async function readHeartbeatsFromIndexedDB(app) {
|
|
|
23384
23384
|
return result;
|
|
23385
23385
|
} catch (e) {
|
|
23386
23386
|
if (e instanceof FirebaseError) {
|
|
23387
|
-
logger$
|
|
23387
|
+
logger$f.warn(e.message);
|
|
23388
23388
|
} else {
|
|
23389
23389
|
const idbGetError = ERROR_FACTORY.create("idb-get", {
|
|
23390
23390
|
originalErrorMessage: e?.message
|
|
23391
23391
|
});
|
|
23392
|
-
logger$
|
|
23392
|
+
logger$f.warn(idbGetError.message);
|
|
23393
23393
|
}
|
|
23394
23394
|
}
|
|
23395
23395
|
}
|
|
@@ -23402,12 +23402,12 @@ async function writeHeartbeatsToIndexedDB(app, heartbeatObject) {
|
|
|
23402
23402
|
await tx.done;
|
|
23403
23403
|
} catch (e) {
|
|
23404
23404
|
if (e instanceof FirebaseError) {
|
|
23405
|
-
logger$
|
|
23405
|
+
logger$f.warn(e.message);
|
|
23406
23406
|
} else {
|
|
23407
23407
|
const idbGetError = ERROR_FACTORY.create("idb-set", {
|
|
23408
23408
|
originalErrorMessage: e?.message
|
|
23409
23409
|
});
|
|
23410
|
-
logger$
|
|
23410
|
+
logger$f.warn(idbGetError.message);
|
|
23411
23411
|
}
|
|
23412
23412
|
}
|
|
23413
23413
|
}
|
|
@@ -23456,7 +23456,7 @@ class HeartbeatServiceImpl {
|
|
|
23456
23456
|
}
|
|
23457
23457
|
return this._storage.overwrite(this._heartbeatsCache);
|
|
23458
23458
|
} catch (e) {
|
|
23459
|
-
logger$
|
|
23459
|
+
logger$f.warn(e);
|
|
23460
23460
|
}
|
|
23461
23461
|
}
|
|
23462
23462
|
/**
|
|
@@ -23487,7 +23487,7 @@ class HeartbeatServiceImpl {
|
|
|
23487
23487
|
}
|
|
23488
23488
|
return headerString;
|
|
23489
23489
|
} catch (e) {
|
|
23490
|
-
logger$
|
|
23490
|
+
logger$f.warn(e);
|
|
23491
23491
|
return "";
|
|
23492
23492
|
}
|
|
23493
23493
|
}
|
|
@@ -41051,6 +41051,143 @@ registerAuth(
|
|
|
41051
41051
|
"Browser"
|
|
41052
41052
|
/* ClientPlatform.BROWSER */
|
|
41053
41053
|
);
|
|
41054
|
+
const logger$e = getLogger("firebase-mock");
|
|
41055
|
+
class MockFirestoreManager {
|
|
41056
|
+
constructor(seedDocs = {}) {
|
|
41057
|
+
const cloned = {};
|
|
41058
|
+
for (const [coll, byId] of Object.entries(seedDocs)) {
|
|
41059
|
+
cloned[coll] = {
|
|
41060
|
+
...byId
|
|
41061
|
+
};
|
|
41062
|
+
}
|
|
41063
|
+
this.docs = cloned;
|
|
41064
|
+
}
|
|
41065
|
+
async getDocData(collectionName, docId) {
|
|
41066
|
+
const doc2 = this.docs[collectionName]?.[docId];
|
|
41067
|
+
return doc2 ?? null;
|
|
41068
|
+
}
|
|
41069
|
+
async setDocData(collectionName, docId, data) {
|
|
41070
|
+
if (!this.docs[collectionName]) {
|
|
41071
|
+
this.docs[collectionName] = {};
|
|
41072
|
+
}
|
|
41073
|
+
this.docs[collectionName][docId] = data;
|
|
41074
|
+
}
|
|
41075
|
+
async mergeDocData(collectionName, docId, data) {
|
|
41076
|
+
if (!this.docs[collectionName]) {
|
|
41077
|
+
this.docs[collectionName] = {};
|
|
41078
|
+
}
|
|
41079
|
+
const existing = this.docs[collectionName][docId] ?? {};
|
|
41080
|
+
this.docs[collectionName][docId] = {
|
|
41081
|
+
...existing,
|
|
41082
|
+
...data
|
|
41083
|
+
};
|
|
41084
|
+
}
|
|
41085
|
+
listenToDoc(collectionName, docId, callback) {
|
|
41086
|
+
const doc2 = this.docs[collectionName]?.[docId];
|
|
41087
|
+
callback(doc2 ?? null);
|
|
41088
|
+
return () => {
|
|
41089
|
+
};
|
|
41090
|
+
}
|
|
41091
|
+
async queryDocs(collectionName, _constraints) {
|
|
41092
|
+
const entries = Object.values(this.docs[collectionName] ?? {});
|
|
41093
|
+
const docs = entries.map((data) => ({
|
|
41094
|
+
data: () => data
|
|
41095
|
+
}));
|
|
41096
|
+
const snapshot = {
|
|
41097
|
+
empty: docs.length === 0,
|
|
41098
|
+
docs,
|
|
41099
|
+
forEach: (cb) => docs.forEach(cb)
|
|
41100
|
+
};
|
|
41101
|
+
return snapshot;
|
|
41102
|
+
}
|
|
41103
|
+
}
|
|
41104
|
+
function makeMockAuthUser(seed) {
|
|
41105
|
+
const fake = {
|
|
41106
|
+
uid: seed.uid,
|
|
41107
|
+
email: seed.email,
|
|
41108
|
+
getIdToken: async (_forceRefresh) => seed.idToken
|
|
41109
|
+
};
|
|
41110
|
+
return fake;
|
|
41111
|
+
}
|
|
41112
|
+
class MockAuthManager {
|
|
41113
|
+
constructor(seed, firestore) {
|
|
41114
|
+
this.userProfile = null;
|
|
41115
|
+
this.authStateChangeListeners = /* @__PURE__ */ new Set();
|
|
41116
|
+
this.userProfileChangeListeners = /* @__PURE__ */ new Set();
|
|
41117
|
+
this.profileUnsub = null;
|
|
41118
|
+
this.seed = seed;
|
|
41119
|
+
this.currentUser = seed ? makeMockAuthUser(seed) : null;
|
|
41120
|
+
this.firestore = firestore;
|
|
41121
|
+
this.addAuthStateChangeListener((authUser) => this.handleAuthStateChanged(authUser));
|
|
41122
|
+
}
|
|
41123
|
+
addAuthStateChangeListener(callback) {
|
|
41124
|
+
this.authStateChangeListeners.add(callback);
|
|
41125
|
+
callback(this.currentUser);
|
|
41126
|
+
return () => {
|
|
41127
|
+
this.authStateChangeListeners.delete(callback);
|
|
41128
|
+
};
|
|
41129
|
+
}
|
|
41130
|
+
removeAuthStateChangeListener(callback) {
|
|
41131
|
+
this.authStateChangeListeners.delete(callback);
|
|
41132
|
+
}
|
|
41133
|
+
addUserProfileChangeListener(callback) {
|
|
41134
|
+
this.userProfileChangeListeners.add(callback);
|
|
41135
|
+
callback(this.userProfile);
|
|
41136
|
+
return () => {
|
|
41137
|
+
this.userProfileChangeListeners.delete(callback);
|
|
41138
|
+
};
|
|
41139
|
+
}
|
|
41140
|
+
removeUserProfileChangeListener(callback) {
|
|
41141
|
+
this.userProfileChangeListeners.delete(callback);
|
|
41142
|
+
}
|
|
41143
|
+
getAuthUser() {
|
|
41144
|
+
return this.currentUser;
|
|
41145
|
+
}
|
|
41146
|
+
async getAuthToken(_forceRefresh = false) {
|
|
41147
|
+
if (!this.currentUser || !this.seed) {
|
|
41148
|
+
throw new Error("No authenticated user");
|
|
41149
|
+
}
|
|
41150
|
+
return this.seed.idToken;
|
|
41151
|
+
}
|
|
41152
|
+
async getUserProfile(_forceRefresh = false) {
|
|
41153
|
+
return this.userProfile;
|
|
41154
|
+
}
|
|
41155
|
+
async login(_email, _password) {
|
|
41156
|
+
throw new Error("MockAuthManager.login is not supported — seed the user via InitParams.testHooks.auth");
|
|
41157
|
+
}
|
|
41158
|
+
async logout() {
|
|
41159
|
+
if (this.profileUnsub) {
|
|
41160
|
+
this.profileUnsub();
|
|
41161
|
+
this.profileUnsub = null;
|
|
41162
|
+
}
|
|
41163
|
+
this.currentUser = null;
|
|
41164
|
+
this.userProfile = null;
|
|
41165
|
+
this.authStateChangeListeners.forEach((cb) => cb(null));
|
|
41166
|
+
this.userProfileChangeListeners.forEach((cb) => cb(null));
|
|
41167
|
+
}
|
|
41168
|
+
async sendPasswordResetEmail(_email) {
|
|
41169
|
+
}
|
|
41170
|
+
async confirmPasswordReset(_code, _newPassword) {
|
|
41171
|
+
}
|
|
41172
|
+
handleAuthStateChanged(authUser) {
|
|
41173
|
+
if (this.profileUnsub) {
|
|
41174
|
+
this.profileUnsub();
|
|
41175
|
+
this.profileUnsub = null;
|
|
41176
|
+
}
|
|
41177
|
+
if (authUser) {
|
|
41178
|
+
logger$e.logDebug("Mock user logged in:", {
|
|
41179
|
+
uid: authUser.uid
|
|
41180
|
+
});
|
|
41181
|
+
this.profileUnsub = this.firestore.listenToDoc("users", authUser.uid, (profile) => {
|
|
41182
|
+
this.userProfile = profile;
|
|
41183
|
+
this.userProfileChangeListeners.forEach((cb) => cb(this.userProfile));
|
|
41184
|
+
});
|
|
41185
|
+
} else {
|
|
41186
|
+
this.userProfile = null;
|
|
41187
|
+
this.userProfileChangeListeners.forEach((cb) => cb(null));
|
|
41188
|
+
}
|
|
41189
|
+
}
|
|
41190
|
+
}
|
|
41054
41191
|
const firebaseDateToDayjs = (date) => {
|
|
41055
41192
|
return dayjs(date.seconds * 1e3);
|
|
41056
41193
|
};
|
|
@@ -41238,8 +41375,24 @@ function getAuthManager() {
|
|
|
41238
41375
|
async function _init$4() {
|
|
41239
41376
|
const {
|
|
41240
41377
|
brandId,
|
|
41241
|
-
config
|
|
41378
|
+
config,
|
|
41379
|
+
testHooks
|
|
41242
41380
|
} = getStaticData();
|
|
41381
|
+
if (testHooks !== void 0) {
|
|
41382
|
+
const seedDocs = {
|
|
41383
|
+
...testHooks.firestore?.docs ?? {}
|
|
41384
|
+
};
|
|
41385
|
+
if (testHooks.auth?.profile) {
|
|
41386
|
+
seedDocs.users = {
|
|
41387
|
+
...seedDocs.users ?? {},
|
|
41388
|
+
[testHooks.auth.uid]: testHooks.auth.profile
|
|
41389
|
+
};
|
|
41390
|
+
}
|
|
41391
|
+
firestoreManager = new MockFirestoreManager(seedDocs);
|
|
41392
|
+
authManager = new MockAuthManager(testHooks.auth ?? null, firestoreManager);
|
|
41393
|
+
logger$d.logDebug("Firebase initialized in MOCK mode (testHooks present)");
|
|
41394
|
+
return;
|
|
41395
|
+
}
|
|
41243
41396
|
{
|
|
41244
41397
|
const {
|
|
41245
41398
|
firebase: sdkFirebaseConfig
|
|
@@ -42644,6 +42797,35 @@ function AddToCartButton({
|
|
|
42644
42797
|
}) {
|
|
42645
42798
|
return /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "quick-view.add_to_cart", onClick });
|
|
42646
42799
|
}
|
|
42800
|
+
function ColorSelector({
|
|
42801
|
+
availableColorLabels,
|
|
42802
|
+
selectedColorLabel,
|
|
42803
|
+
onChangeColor
|
|
42804
|
+
}) {
|
|
42805
|
+
const css2 = useCss((theme) => ({
|
|
42806
|
+
colorContainer: {},
|
|
42807
|
+
colorLabelText: {
|
|
42808
|
+
fontSize: "12px"
|
|
42809
|
+
},
|
|
42810
|
+
colorSelect: {
|
|
42811
|
+
border: "none",
|
|
42812
|
+
color: theme.color_fg_text,
|
|
42813
|
+
fontFamily: theme.font_family,
|
|
42814
|
+
fontSize: "12px"
|
|
42815
|
+
}
|
|
42816
|
+
}));
|
|
42817
|
+
const handleColorSelectChange = reactExports.useCallback((e) => {
|
|
42818
|
+
const newColorLabel = e.target.value || null;
|
|
42819
|
+
onChangeColor(newColorLabel);
|
|
42820
|
+
}, [onChangeColor]);
|
|
42821
|
+
if (availableColorLabels.length < 2) {
|
|
42822
|
+
return null;
|
|
42823
|
+
}
|
|
42824
|
+
return /* @__PURE__ */ jsx$1("div", { css: css2.colorContainer, children: /* @__PURE__ */ jsxs("label", { children: [
|
|
42825
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.colorLabelText, t: "quick-view.color_label" }),
|
|
42826
|
+
/* @__PURE__ */ jsx$1("select", { value: selectedColorLabel ?? "", onChange: handleColorSelectChange, css: css2.colorSelect, children: availableColorLabels.map((colorLabel) => /* @__PURE__ */ jsx$1("option", { value: colorLabel, children: colorLabel }, colorLabel)) })
|
|
42827
|
+
] }) });
|
|
42828
|
+
}
|
|
42647
42829
|
function ItemFitDetails({
|
|
42648
42830
|
loadedProductData,
|
|
42649
42831
|
selectedSizeLabel
|
|
@@ -42754,6 +42936,7 @@ function DetailAccordionItem({
|
|
|
42754
42936
|
onToggleOpen,
|
|
42755
42937
|
onChangeDetailMode,
|
|
42756
42938
|
onChangeSize,
|
|
42939
|
+
onChangeColor,
|
|
42757
42940
|
onAddToCart,
|
|
42758
42941
|
onToggleUntuck
|
|
42759
42942
|
}) {
|
|
@@ -42789,13 +42972,23 @@ function DetailAccordionItem({
|
|
|
42789
42972
|
}
|
|
42790
42973
|
return null;
|
|
42791
42974
|
}, [productData, item.storage.colorwaySizeAssetId]);
|
|
42975
|
+
const availableColorLabels = reactExports.useMemo(() => {
|
|
42976
|
+
if (!productData || !selectedSizeLabel) {
|
|
42977
|
+
return [];
|
|
42978
|
+
}
|
|
42979
|
+
const sizeRec = productData.sizes.find((s) => s.sizeLabel === selectedSizeLabel);
|
|
42980
|
+
if (!sizeRec) {
|
|
42981
|
+
return [];
|
|
42982
|
+
}
|
|
42983
|
+
return sizeRec.colors.map((c) => c.colorLabel).filter((label) => !!label);
|
|
42984
|
+
}, [productData, selectedSizeLabel]);
|
|
42792
42985
|
const categoryLabel = item.styleCategory?.label_singular ?? item.styleCategory?.label ?? "";
|
|
42793
42986
|
const productName = item.merchantProduct?.productName ?? item.externalId;
|
|
42794
42987
|
const tuckable = !!item.styleCategory?.tuckable && canTuck;
|
|
42795
42988
|
if (platform === "desktop") {
|
|
42796
|
-
return /* @__PURE__ */ jsx$1(DesktopAccordionItem, { isOpen, categoryLabel, productData, currentPrice, selectedSizeLabel, onToggleOpen, onChangeSize, onAddToCart });
|
|
42989
|
+
return /* @__PURE__ */ jsx$1(DesktopAccordionItem, { isOpen, categoryLabel, productData, currentPrice, selectedSizeLabel, availableColorLabels, selectedColorLabel: item.storage.color, onToggleOpen, onChangeSize, onChangeColor, onAddToCart });
|
|
42797
42990
|
}
|
|
42798
|
-
return /* @__PURE__ */ jsx$1(MobileAccordionItem, { isOpen, categoryLabel, productName, productData, selectedSizeLabel, currentPrice, detailMode, isMobileQuickRow, tuckable, forceUntuck, onToggleOpen, onChangeDetailMode, onChangeSize, onAddToCart, onToggleUntuck });
|
|
42991
|
+
return /* @__PURE__ */ jsx$1(MobileAccordionItem, { isOpen, categoryLabel, productName, productData, selectedSizeLabel, availableColorLabels, selectedColorLabel: item.storage.color, currentPrice, detailMode, isMobileQuickRow, tuckable, forceUntuck, onToggleOpen, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
|
|
42799
42992
|
}
|
|
42800
42993
|
function DesktopAccordionItem({
|
|
42801
42994
|
isOpen,
|
|
@@ -42803,8 +42996,11 @@ function DesktopAccordionItem({
|
|
|
42803
42996
|
productData,
|
|
42804
42997
|
currentPrice,
|
|
42805
42998
|
selectedSizeLabel,
|
|
42999
|
+
availableColorLabels,
|
|
43000
|
+
selectedColorLabel,
|
|
42806
43001
|
onToggleOpen,
|
|
42807
43002
|
onChangeSize,
|
|
43003
|
+
onChangeColor,
|
|
42808
43004
|
onAddToCart
|
|
42809
43005
|
}) {
|
|
42810
43006
|
const ACCORDION_SHADE = "#F4F4F4";
|
|
@@ -42850,35 +43046,60 @@ function DesktopAccordionItem({
|
|
|
42850
43046
|
price: {
|
|
42851
43047
|
fontSize: "15px"
|
|
42852
43048
|
},
|
|
43049
|
+
// Padding matches quick-view's sizeRecommendationFrame (32px / 56px) so
|
|
43050
|
+
// the "fit box" feels visually consistent between the two overlays.
|
|
43051
|
+
//
|
|
43052
|
+
// No flex `gap` — the three text lines (recommended size, fit text,
|
|
43053
|
+
// select-a-size prompt) sit tight against each other (matching
|
|
43054
|
+
// quick-view), with explicit marginTop on the size selector + fit
|
|
43055
|
+
// details below them to introduce the larger break.
|
|
42853
43056
|
sizeBox: {
|
|
42854
43057
|
width: "100%",
|
|
42855
43058
|
border: `1px solid ${theme.color_fg_text}`,
|
|
42856
|
-
padding: "
|
|
43059
|
+
padding: "32px 56px",
|
|
42857
43060
|
display: "flex",
|
|
42858
43061
|
flexDirection: "column",
|
|
42859
43062
|
alignItems: "center",
|
|
42860
|
-
gap: "12px",
|
|
42861
43063
|
marginTop: "8px",
|
|
42862
43064
|
textAlign: "center"
|
|
42863
43065
|
},
|
|
43066
|
+
colorSelectorContainer: {
|
|
43067
|
+
width: "100%",
|
|
43068
|
+
marginTop: "8px"
|
|
43069
|
+
},
|
|
43070
|
+
// 14px / line-height 1.5 on these three text lines matches quick-view's
|
|
43071
|
+
// fit-box. Quick-view's first line wraps an InfoIcon button alongside
|
|
43072
|
+
// the recommended-size text, which stretches that line vertically; the
|
|
43073
|
+
// simpler line-height bump here matches the *visual* line spacing
|
|
43074
|
+
// without dragging the icon in. The two lines below it inherit
|
|
43075
|
+
// line-height from their containers in quick-view, which the host page's
|
|
43076
|
+
// body styles tend to set looser than Inter's intrinsic `normal` (~1.21).
|
|
42864
43077
|
recommendedSize: {
|
|
42865
|
-
fontSize: "
|
|
42866
|
-
fontWeight: "600"
|
|
43078
|
+
fontSize: "14px",
|
|
43079
|
+
fontWeight: "600",
|
|
43080
|
+
lineHeight: 1.5
|
|
42867
43081
|
},
|
|
42868
43082
|
selectPrompt: {
|
|
42869
|
-
fontSize: "
|
|
43083
|
+
fontSize: "14px",
|
|
43084
|
+
lineHeight: 1.5
|
|
42870
43085
|
},
|
|
42871
43086
|
fitText: {
|
|
42872
|
-
fontSize: "
|
|
43087
|
+
fontSize: "14px",
|
|
43088
|
+
lineHeight: 1.5,
|
|
43089
|
+
// Tight 8px lift to the recommended-size line above; matches
|
|
43090
|
+
// quick-view's `itemFitContainer` marginTop.
|
|
43091
|
+
marginTop: "8px"
|
|
42873
43092
|
},
|
|
42874
43093
|
fitDetails: {
|
|
42875
|
-
width: "100%"
|
|
43094
|
+
width: "100%",
|
|
43095
|
+
marginTop: "24px"
|
|
42876
43096
|
},
|
|
42877
43097
|
sizeRow: {
|
|
42878
43098
|
display: "flex",
|
|
42879
43099
|
gap: "8px",
|
|
42880
43100
|
alignItems: "center",
|
|
42881
|
-
justifyContent: "center"
|
|
43101
|
+
justifyContent: "center",
|
|
43102
|
+
marginTop: "24px"
|
|
42882
43103
|
},
|
|
42883
43104
|
cartContainer: {
|
|
42884
43105
|
width: "100%",
|
|
@@ -42899,6 +43120,7 @@ function DesktopAccordionItem({
|
|
|
42899
43120
|
!isOpen ? null : /* @__PURE__ */ jsx$1("div", { css: css2.body, children: productData ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42900
43121
|
/* @__PURE__ */ jsx$1(Text, { variant: "brand", css: css2.productName, children: productData.productName }),
|
|
42901
43122
|
currentPrice ? /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.price, children: currentPrice }) : null,
|
|
43123
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.colorSelectorContainer, children: /* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }) }),
|
|
42902
43124
|
/* @__PURE__ */ jsxs("div", { css: css2.sizeBox, children: [
|
|
42903
43125
|
/* @__PURE__ */ jsxs(Text, { variant: "base", css: css2.recommendedSize, children: [
|
|
42904
43126
|
"Recommended Size: ",
|
|
@@ -42922,6 +43144,8 @@ function MobileAccordionItem({
|
|
|
42922
43144
|
productName,
|
|
42923
43145
|
productData,
|
|
42924
43146
|
selectedSizeLabel,
|
|
43147
|
+
availableColorLabels,
|
|
43148
|
+
selectedColorLabel,
|
|
42925
43149
|
currentPrice,
|
|
42926
43150
|
detailMode,
|
|
42927
43151
|
isMobileQuickRow,
|
|
@@ -42930,6 +43154,7 @@ function MobileAccordionItem({
|
|
|
42930
43154
|
onToggleOpen,
|
|
42931
43155
|
onChangeDetailMode,
|
|
42932
43156
|
onChangeSize,
|
|
43157
|
+
onChangeColor,
|
|
42933
43158
|
onAddToCart,
|
|
42934
43159
|
onToggleUntuck
|
|
42935
43160
|
}) {
|
|
@@ -43069,6 +43294,7 @@ function MobileAccordionItem({
|
|
|
43069
43294
|
] }),
|
|
43070
43295
|
isMobileQuickRow ? /* @__PURE__ */ jsx$1("div", { css: css2.content, children: /* @__PURE__ */ jsx$1("div", { css: css2.quickRow, children: productData ? /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData: productData, selectedSizeLabel, onChangeSize }) : null }) }) : !isOpen ? null : /* @__PURE__ */ jsx$1("div", { css: css2.content, children: /* @__PURE__ */ jsx$1("div", { css: css2.body, children: productData ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
43071
43296
|
/* @__PURE__ */ jsx$1("div", { css: css2.sizeRow, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData: productData, selectedSizeLabel, onChangeSize }) }),
|
|
43297
|
+
/* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }),
|
|
43072
43298
|
/* @__PURE__ */ jsx$1(ItemFitText, { loadedProductData: productData }),
|
|
43073
43299
|
/* @__PURE__ */ jsx$1("div", { css: css2.fitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData: productData, selectedSizeLabel }) }),
|
|
43074
43300
|
/* @__PURE__ */ jsx$1("div", { css: css2.buttonContainer, children: /* @__PURE__ */ jsx$1(AddToCartButton, { onClick: onAddToCart }) }),
|
|
@@ -43095,6 +43321,7 @@ function DetailAccordion({
|
|
|
43095
43321
|
onOpenItem,
|
|
43096
43322
|
onChangeDetailMode,
|
|
43097
43323
|
onChangeSize,
|
|
43324
|
+
onChangeColor,
|
|
43098
43325
|
onAddToCart,
|
|
43099
43326
|
onToggleUntuck
|
|
43100
43327
|
}) {
|
|
@@ -43109,9 +43336,11 @@ function DetailAccordion({
|
|
|
43109
43336
|
gap
|
|
43110
43337
|
}, children: items.map((item) => {
|
|
43111
43338
|
const isOpen = openItemExternalId === item.externalId;
|
|
43112
|
-
return /* @__PURE__ */ jsx$1(DetailAccordionItem, { item, isOpen, platform, detailMode, isMobileQuickRow, forceUntuck, canTuck, onToggleOpen: () => onOpenItem(isOpen ? null : item.externalId), onChangeDetailMode, onChangeSize: (label) => onChangeSize(item.externalId, label), onAddToCart: () => onAddToCart(item.externalId), onToggleUntuck }, item.externalId);
|
|
43339
|
+
return /* @__PURE__ */ jsx$1(DetailAccordionItem, { item, isOpen, platform, detailMode, isMobileQuickRow, forceUntuck, canTuck, onToggleOpen: () => onOpenItem(isOpen ? null : item.externalId), onChangeDetailMode, onChangeSize: (label) => onChangeSize(item.externalId, label), onChangeColor: (label) => onChangeColor(item.externalId, label), onAddToCart: () => onAddToCart(item.externalId), onToggleUntuck }, item.externalId);
|
|
43113
43340
|
}) });
|
|
43114
43341
|
}
|
|
43342
|
+
const AXIS_LOCK_PX = 8;
|
|
43343
|
+
const ROTATE_STEP_PX = 50;
|
|
43115
43344
|
function ZoomModal({
|
|
43116
43345
|
frameUrls,
|
|
43117
43346
|
selectedFrameIndex,
|
|
@@ -43131,10 +43360,50 @@ function ZoomModal({
|
|
|
43131
43360
|
}, [onClose]);
|
|
43132
43361
|
const {
|
|
43133
43362
|
rotateLeft,
|
|
43134
|
-
rotateRight
|
|
43135
|
-
handleMouseDragStart,
|
|
43136
|
-
handleTouchDragStart
|
|
43363
|
+
rotateRight
|
|
43137
43364
|
} = useFrameRotation(frameUrls, setSelectedFrameIndex);
|
|
43365
|
+
const scrollAreaRef = reactExports.useRef(null);
|
|
43366
|
+
const handleImageMouseDown = reactExports.useCallback((e) => {
|
|
43367
|
+
e.preventDefault();
|
|
43368
|
+
const startX = e.clientX;
|
|
43369
|
+
const startY = e.clientY;
|
|
43370
|
+
const scrollArea = scrollAreaRef.current;
|
|
43371
|
+
const startScrollTop = scrollArea?.scrollTop ?? 0;
|
|
43372
|
+
let mode = "unknown";
|
|
43373
|
+
let lastRotateX = startX;
|
|
43374
|
+
const onMove = (move) => {
|
|
43375
|
+
const deltaX = move.clientX - startX;
|
|
43376
|
+
const deltaY = move.clientY - startY;
|
|
43377
|
+
if (mode === "unknown") {
|
|
43378
|
+
const absX = Math.abs(deltaX);
|
|
43379
|
+
const absY = Math.abs(deltaY);
|
|
43380
|
+
if (absX < AXIS_LOCK_PX && absY < AXIS_LOCK_PX) {
|
|
43381
|
+
return;
|
|
43382
|
+
}
|
|
43383
|
+
mode = absY > absX ? "scroll" : "rotate";
|
|
43384
|
+
lastRotateX = move.clientX;
|
|
43385
|
+
}
|
|
43386
|
+
if (mode === "scroll" && scrollArea) {
|
|
43387
|
+
scrollArea.scrollTop = startScrollTop - deltaY;
|
|
43388
|
+
} else if (mode === "rotate") {
|
|
43389
|
+
const rotateDelta = move.clientX - lastRotateX;
|
|
43390
|
+
if (Math.abs(rotateDelta) >= ROTATE_STEP_PX) {
|
|
43391
|
+
if (rotateDelta > 0) {
|
|
43392
|
+
rotateRight();
|
|
43393
|
+
} else {
|
|
43394
|
+
rotateLeft();
|
|
43395
|
+
}
|
|
43396
|
+
lastRotateX = move.clientX;
|
|
43397
|
+
}
|
|
43398
|
+
}
|
|
43399
|
+
};
|
|
43400
|
+
const onUp = () => {
|
|
43401
|
+
window.removeEventListener("mousemove", onMove);
|
|
43402
|
+
window.removeEventListener("mouseup", onUp);
|
|
43403
|
+
};
|
|
43404
|
+
window.addEventListener("mousemove", onMove);
|
|
43405
|
+
window.addEventListener("mouseup", onUp);
|
|
43406
|
+
}, [rotateLeft, rotateRight]);
|
|
43138
43407
|
const css2 = useCss((_theme) => ({
|
|
43139
43408
|
backdrop: {
|
|
43140
43409
|
position: "fixed",
|
|
@@ -43213,7 +43482,7 @@ function ZoomModal({
|
|
|
43213
43482
|
}));
|
|
43214
43483
|
const imageUrl = frameUrls[selectedFrameIndex ?? 0];
|
|
43215
43484
|
return /* @__PURE__ */ jsxs("div", { css: css2.backdrop, children: [
|
|
43216
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.scrollArea, children: /* @__PURE__ */ jsx$1("div", { css: css2.imageWrap, children: /* @__PURE__ */ jsx$1("img", { src: imageUrl, css: css2.image, alt: "", onMouseDown:
|
|
43485
|
+
/* @__PURE__ */ jsx$1("div", { ref: scrollAreaRef, css: css2.scrollArea, children: /* @__PURE__ */ jsx$1("div", { css: css2.imageWrap, children: /* @__PURE__ */ jsx$1("img", { src: imageUrl, css: css2.image, alt: "", onMouseDown: handleImageMouseDown }) }) }),
|
|
43217
43486
|
/* @__PURE__ */ jsx$1("div", { css: /* @__PURE__ */ css$1({
|
|
43218
43487
|
...css2.chevron,
|
|
43219
43488
|
...css2.chevronLeft
|
|
@@ -43246,6 +43515,7 @@ function DesktopLayout$1({
|
|
|
43246
43515
|
onOpenAccordionItem,
|
|
43247
43516
|
onChangeDetailMode,
|
|
43248
43517
|
onChangeSize,
|
|
43518
|
+
onChangeColor,
|
|
43249
43519
|
onAddToCart,
|
|
43250
43520
|
onToggleUntuck,
|
|
43251
43521
|
onSignOut
|
|
@@ -43342,7 +43612,7 @@ function DesktopLayout$1({
|
|
|
43342
43612
|
gridTemplateColumns
|
|
43343
43613
|
}, children: [
|
|
43344
43614
|
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls, selectedFrameIndex, setSelectedFrameIndex }) }),
|
|
43345
|
-
hasSelection ? /* @__PURE__ */ jsx$1("div", { css: css2.detailColumn, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "desktop", detailMode, isMobileQuickRow: false, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onAddToCart, onToggleUntuck }) }) : null,
|
|
43615
|
+
hasSelection ? /* @__PURE__ */ jsx$1("div", { css: css2.detailColumn, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "desktop", detailMode, isMobileQuickRow: false, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck }) }) : null,
|
|
43346
43616
|
/* @__PURE__ */ jsxs("div", { css: css2.railsColumn, children: [
|
|
43347
43617
|
/* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
|
|
43348
43618
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.signOutIcon }),
|
|
@@ -43477,13 +43747,14 @@ function MobileLayout$1({
|
|
|
43477
43747
|
onOpenAccordionItem,
|
|
43478
43748
|
onChangeDetailMode,
|
|
43479
43749
|
onChangeSize,
|
|
43750
|
+
onChangeColor,
|
|
43480
43751
|
onAddToCart,
|
|
43481
43752
|
onToggleUntuck
|
|
43482
43753
|
}) {
|
|
43483
43754
|
if (mode === "browse") {
|
|
43484
43755
|
return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onTryItOn });
|
|
43485
43756
|
}
|
|
43486
|
-
return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onAddToCart, onToggleUntuck });
|
|
43757
|
+
return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
|
|
43487
43758
|
}
|
|
43488
43759
|
function BrowseView({
|
|
43489
43760
|
resolved,
|
|
@@ -43583,6 +43854,7 @@ function TryOnView({
|
|
|
43583
43854
|
onOpenAccordionItem,
|
|
43584
43855
|
onChangeDetailMode,
|
|
43585
43856
|
onChangeSize,
|
|
43857
|
+
onChangeColor,
|
|
43586
43858
|
onAddToCart,
|
|
43587
43859
|
onToggleUntuck
|
|
43588
43860
|
}) {
|
|
@@ -43683,7 +43955,7 @@ function TryOnView({
|
|
|
43683
43955
|
/* @__PURE__ */ jsx$1(SvgDragHandle, {}),
|
|
43684
43956
|
/* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.sheetTitle, children: "RECOMMENDED SIZES" })
|
|
43685
43957
|
] }),
|
|
43686
|
-
sheetSnap === "collapsed" ? null : /* @__PURE__ */ jsx$1("div", { css: css2.sheetContent, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "mobile", detailMode, isMobileQuickRow, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onAddToCart, onToggleUntuck }) })
|
|
43958
|
+
sheetSnap === "collapsed" ? null : /* @__PURE__ */ jsx$1("div", { css: css2.sheetContent, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "mobile", detailMode, isMobileQuickRow, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck }) })
|
|
43687
43959
|
] }) })
|
|
43688
43960
|
] });
|
|
43689
43961
|
}
|
|
@@ -43956,6 +44228,25 @@ function FittingRoomOverlay({
|
|
|
43956
44228
|
color: csa.colorLabel
|
|
43957
44229
|
});
|
|
43958
44230
|
}, [resolved.items, updateFittingRoomItem]);
|
|
44231
|
+
const handleChangeColor = reactExports.useCallback((externalId, colorLabel) => {
|
|
44232
|
+
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
44233
|
+
if (!item || !item.storage.size) {
|
|
44234
|
+
return;
|
|
44235
|
+
}
|
|
44236
|
+
const productData = buildVtoProductDataFromResolved(item);
|
|
44237
|
+
if (!productData) {
|
|
44238
|
+
return;
|
|
44239
|
+
}
|
|
44240
|
+
const csa = findCsaByLabel(productData, item.storage.size, colorLabel);
|
|
44241
|
+
if (!csa) {
|
|
44242
|
+
return;
|
|
44243
|
+
}
|
|
44244
|
+
updateFittingRoomItem(externalId, {
|
|
44245
|
+
colorwaySizeAssetId: csa.colorwaySizeAssetId,
|
|
44246
|
+
size: item.storage.size,
|
|
44247
|
+
color: csa.colorLabel
|
|
44248
|
+
});
|
|
44249
|
+
}, [resolved.items, updateFittingRoomItem]);
|
|
43959
44250
|
const handleAddToCart = reactExports.useCallback(async (externalId) => {
|
|
43960
44251
|
const {
|
|
43961
44252
|
addToCart
|
|
@@ -44148,7 +44439,7 @@ function FittingRoomOverlay({
|
|
|
44148
44439
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.emptyTagline, t: "landing.description" }),
|
|
44149
44440
|
/* @__PURE__ */ jsx$1("div", { css: css2.emptyShopNow, children: /* @__PURE__ */ jsx$1(ButtonT, { variant: "primary", t: "fitting_room.shop_now", onClick: handleShopNow }) }),
|
|
44150
44441
|
userIsLoggedIn ? /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.emptySignOut, t: "fitting_room.sign_out", onClick: handleSignOut }) : null
|
|
44151
|
-
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck, onSignOut: handleSignOut }),
|
|
44442
|
+
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck, onSignOut: handleSignOut }),
|
|
44152
44443
|
vtoError ? /* @__PURE__ */ jsx$1(Snackbar, { messageKey: "fitting_room.vto_error", onDismiss: clearVtoError }) : null
|
|
44153
44444
|
] }) });
|
|
44154
44445
|
}
|
|
@@ -44942,7 +45233,9 @@ function QuickViewOverlay() {
|
|
|
44942
45233
|
const {
|
|
44943
45234
|
color: selectedColor
|
|
44944
45235
|
} = await currentProduct.getSelectedOptions();
|
|
44945
|
-
const
|
|
45236
|
+
const styleCategoryIndex = await loadStyleCategoryIndex();
|
|
45237
|
+
const styleCategoryGroup = styleCategoryIndex.groupForCategory(storeProduct.style.style_category_name);
|
|
45238
|
+
const styleCategoryLabel = styleCategoryGroup?.label ?? null;
|
|
44946
45239
|
const sizeRecommendationRecord = storeProduct.sizeFitRecommendation;
|
|
44947
45240
|
{
|
|
44948
45241
|
const recommendedSizeId = sizeRecommendationRecord.recommended_size.id || null;
|
|
@@ -45892,35 +46185,6 @@ function ProductSummaryRow({
|
|
|
45892
46185
|
/* @__PURE__ */ jsx$1("div", { css: css2.nameContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "brand", css: css2.nameText, children: loadedProductData.productName }) })
|
|
45893
46186
|
] });
|
|
45894
46187
|
}
|
|
45895
|
-
function ColorSelector({
|
|
45896
|
-
availableColorLabels,
|
|
45897
|
-
selectedColorLabel,
|
|
45898
|
-
onChangeColor
|
|
45899
|
-
}) {
|
|
45900
|
-
const css2 = useCss((theme) => ({
|
|
45901
|
-
colorContainer: {},
|
|
45902
|
-
colorLabelText: {
|
|
45903
|
-
fontSize: "12px"
|
|
45904
|
-
},
|
|
45905
|
-
colorSelect: {
|
|
45906
|
-
border: "none",
|
|
45907
|
-
color: theme.color_fg_text,
|
|
45908
|
-
fontFamily: theme.font_family,
|
|
45909
|
-
fontSize: "12px"
|
|
45910
|
-
}
|
|
45911
|
-
}));
|
|
45912
|
-
const handleColorSelectChange = reactExports.useCallback((e) => {
|
|
45913
|
-
const newColorLabel = e.target.value || null;
|
|
45914
|
-
onChangeColor(newColorLabel);
|
|
45915
|
-
}, []);
|
|
45916
|
-
if (availableColorLabels.length < 2) {
|
|
45917
|
-
return null;
|
|
45918
|
-
}
|
|
45919
|
-
return /* @__PURE__ */ jsx$1("div", { css: css2.colorContainer, children: /* @__PURE__ */ jsxs("label", { children: [
|
|
45920
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.colorLabelText, t: "quick-view.color_label" }),
|
|
45921
|
-
/* @__PURE__ */ jsx$1("select", { value: selectedColorLabel ?? "", onChange: handleColorSelectChange, css: css2.colorSelect, children: availableColorLabels.map((colorLabel) => /* @__PURE__ */ jsx$1("option", { value: colorLabel, children: colorLabel }, colorLabel)) })
|
|
45922
|
-
] }) });
|
|
45923
|
-
}
|
|
45924
46188
|
function RecommendedSizeText({
|
|
45925
46189
|
loadedProductData,
|
|
45926
46190
|
textCss
|
|
@@ -46501,9 +46765,9 @@ const SHARED_CONFIG = {
|
|
|
46501
46765
|
appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
|
|
46502
46766
|
},
|
|
46503
46767
|
build: {
|
|
46504
|
-
version: `${"5.0.
|
|
46505
|
-
commitHash: `${"
|
|
46506
|
-
date: `${"2026-05-
|
|
46768
|
+
version: `${"5.0.25"}`,
|
|
46769
|
+
commitHash: `${"101d833"}`,
|
|
46770
|
+
date: `${"2026-05-22T00:57:54.147Z"}`
|
|
46507
46771
|
}
|
|
46508
46772
|
};
|
|
46509
46773
|
const CONFIGS = {
|
|
@@ -46650,7 +46914,8 @@ async function init(initParams) {
|
|
|
46650
46914
|
debug,
|
|
46651
46915
|
productLookup,
|
|
46652
46916
|
getOverlayTopOffset,
|
|
46653
|
-
addToCart
|
|
46917
|
+
addToCart,
|
|
46918
|
+
testHooks
|
|
46654
46919
|
} = initParams;
|
|
46655
46920
|
if (!brandId || typeof brandId !== "number" || isNaN(brandId) || brandId <= 0) {
|
|
46656
46921
|
throw new Error(`Invalid brandId "${brandId}"`);
|
|
@@ -46676,7 +46941,8 @@ async function init(initParams) {
|
|
|
46676
46941
|
config,
|
|
46677
46942
|
productLookup: productLookup ?? null,
|
|
46678
46943
|
getOverlayTopOffset: getOverlayTopOffset ?? null,
|
|
46679
|
-
addToCart: addToCart ?? null
|
|
46944
|
+
addToCart: addToCart ?? null,
|
|
46945
|
+
testHooks
|
|
46680
46946
|
});
|
|
46681
46947
|
_init$7();
|
|
46682
46948
|
_init$5();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thefittingroom/shop-ui",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.25",
|
|
4
4
|
"description": "the fitting room UI library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,8 +22,12 @@
|
|
|
22
22
|
"promote-latest": "sh scripts/promote-latest.sh",
|
|
23
23
|
"lint": "eslint .",
|
|
24
24
|
"lint:fix": "eslint . --fix",
|
|
25
|
-
"format": "prettier --write src",
|
|
26
|
-
"format:check": "prettier --check src"
|
|
25
|
+
"format": "prettier --write src tests playwright.config.ts",
|
|
26
|
+
"format:check": "prettier --check src tests playwright.config.ts",
|
|
27
|
+
"test": "npm run test:e2e",
|
|
28
|
+
"test:e2e": "playwright test",
|
|
29
|
+
"test:e2e:debug": "PWDEBUG=1 playwright test",
|
|
30
|
+
"test:e2e:ui": "playwright test --ui"
|
|
27
31
|
},
|
|
28
32
|
"engines": {
|
|
29
33
|
"node": ">=22"
|
|
@@ -33,6 +37,7 @@
|
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
35
39
|
"@eslint/js": "^9.39.4",
|
|
40
|
+
"@playwright/test": "^1.60.0",
|
|
36
41
|
"@types/react": "^19.2.7",
|
|
37
42
|
"@types/react-dom": "^19.2.3",
|
|
38
43
|
"@types/react-modal": "^3.16.3",
|