News
Behind The Name | Mahana
Behind The Name | Mahana
Like many Hawaiians, Kumu Kamuela Yim takes the responsibility of naming seriously. Find out why Mahana men’s slipper gets its name in this episode of Behind The Name.
Shop The Story
{"id":6605673988231,
"handle":"mahana-mens-slippers-vapor-sahara",
"title":"Mahana - Vapor \/ Sahara",
"available":true,
"tags":["arch:standard","bedroom slippers","best:outdoor","best:warm_climate","collection:comfort-seeker","color:grey","drop-in heel®","fit:standard","foldable heal","gender:men","houseshoes","houseslippers","interest:driving","just in","laceless","landtextile","mahaha","mahana","material:jersey","mens","menslippers","Menslppers","mensslper","mhaha","mihana","mohana","Mohani","new","Outdoor","quilted","RGroup_10451","s ippers","size:true","slippers","split_color","style:10451","textile","Warm Climate","YGroup_10451"],
"type":"Men’s Heathered Cotton Slippers",
"options_with_values": [{"name":"Color","position":1,"values":["Vapor \/ Sahara"]},{"name":"Size","position":2,"values":["7","8","9","10","11","12","13","14","15"]}],
"price":15000,
"price_min":15000,
"price_max":15000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_001_M_Mahana_VaporSahara_6dc8e125-1255-4a27-b931-79e404960753.png?v=1790180996",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 46938964426887,
"featured_image_alt": "Vapor \/ Sahara",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_201_45edca87-7f2d-4be8-8edc-3122fe184c9a.jpg?v=1790180996",
"hover_image_alt": "Vapor \/ Sahara",
"images": [{
"id": 46938964426887,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_001_M_Mahana_VaporSahara_6dc8e125-1255-4a27-b931-79e404960753.png?v=1790180996",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
},{
"id": 46938964623495,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_201_45edca87-7f2d-4be8-8edc-3122fe184c9a.jpg?v=1790180996",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2001
},{
"id": 46938964721799,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_101_b81318e7-7929-41bd-af05-d0e095d1763d.jpg?v=1790180996",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
},{
"id": 46938964754567,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_002_M_Mahana_VaporSahara_236c474d-7f6f-4491-b096-0178cfb39d5e.png?v=1790180998",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
},{
"id": 46938964820103,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_102_da6f958b-c4ae-4428-b932-eb494f712168.jpg?v=1790180997",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
},{
"id": 46938964918407,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_004_M_Mahana_VaporSahara_b4ca2ce7-85ef-4330-a2bd-435888f06928.png?v=1790180998",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
},{
"id": 46938965082247,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_VPFM_005_M_Mahana_VaporSahara_8016aaf7-4684-4de3-b268-859f4648bfeb.png?v=1790180999",
"alt": "Vapor \/ Sahara",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "10613-VPFM-9"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{"id":6605674053767,
"handle":"mahana-mens-slippers-dark-shadow-black",
"title":"Mahana - Dark Shadow \/ Black",
"available":true,
"tags":["arch:standard","bedroom shoes","best:outdoor","best:warm_climate","collection:comfort-seeker","color:grey","dk shadow","drop-in heel®","fit:standard","gender:men","houseshoes","houseslippers","interest:driving","laceless","landtextile","mahaha","Mahana","material:jersey","mens","menslippers","Menslppers","mensslippers","mensslper","mhaha","mihana","Moana","Moanha","Mohaha","Mohana","Mohani","Moihana","Monah","Outdoor","quilted","RGroup_10451","s ippers","size:true","slippers","split_color","style:10451","textile","Warm Climate","YGroup_10451"],
"type":"Men’s Heathered Cotton Slippers",
"options_with_values": [{"name":"Color","position":1,"values":["Dark Shadow \/ Black"]},{"name":"Size","position":2,"values":["7","8","9","10","11","12","13","14","15"]}],
"price":15000,
"price_min":15000,
"price_max":15000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_001_M_Mahana_DarkShadowBlack_2c94e1d7-8140-4604-9752-9d8691be5f9d.png?v=1790180998",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 46938964885639,
"featured_image_alt": "Dark Shadow \/ Black",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_201_afc82817-6239-4ce0-b8d0-a6cab26c2948.jpg?v=1790180998",
"hover_image_alt": "Dark Shadow \/ Black",
"images": [{
"id": 46938964885639,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_001_M_Mahana_DarkShadowBlack_2c94e1d7-8140-4604-9752-9d8691be5f9d.png?v=1790180998",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938964983943,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_201_afc82817-6239-4ce0-b8d0-a6cab26c2948.jpg?v=1790180998",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965180551,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_101_1ec1ed62-f6a1-4874-bcc5-1e8980900773.jpg?v=1790180997",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965246087,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_002_M_Mahana_DarkShadowBlack_86111a79-d28b-44cf-9dc3-6ec3bf489255.png?v=1790180999",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965311623,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_202_dbc53532-36df-431e-95e5-b95d89c4bc7a.jpg?v=1790180999",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965377159,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_102_22d6e174-1c29-4eda-8170-526ec06c394f.jpg?v=1790181000",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2001
},{
"id": 46938965508231,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_003_M_Mahana_DarkShadowBlack_704750fb-b797-4292-912e-4cc6e3dd493c.png?v=1790181001",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965573767,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_004_M_Mahana_DarkShadowBlack_e33cd7f6-b85f-43f0-b126-d29d17c95639.png?v=1790181001",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
},{
"id": 46938965639303,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10451_6C40_005_M_Mahana_DarkShadowBlack_de86ddfa-5b38-42a6-a1d2-83902a2086ca.png?v=1790181001",
"alt": "Dark Shadow \/ Black",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "10613-6C40-7"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
Explore Similar Stories
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>