{"version":3,"file":"FeaturedPicks.D-Rcl-on.mjs","names":["useRef"],"sources":["https:/framerusercontent.com/modules/STTJejpFsZ8cgLMKcL0z/08ZQNsOsayMwXghsixyX/FeaturedPicks.js"],"sourcesContent":["// ---------------------------------------------------------------------------\n// FeaturedPicks — v2\n// ---------------------------------------------------------------------------\n// Shows N random cards out of whatever a Collection List loads. Used on:\n//  - \"You may also like\" (list filtered to Featured + Available)\n//  - Homepage category sections (list filtered to that category +\n//    Available, no limit) — one instance per section, unique Storage Key.\n//\n// v2 CHANGES\n//  - Finds cards by climbing one level at a time and stopping at the first\n//    level that has any, so it can't reach into neighbouring sections.\n//  - Retries for ~3s if the Collection List hasn't rendered yet when this\n//    component mounts (previously it gave up and left every card showing).\n//\n// WHAT IT DOES\n//  - The Collection List in \"You may also like\" is filtered in Framer to\n//    only load products with Featured = ON (and Available = ON).\n//  - This component then picks a random handful of those (default 4),\n//    hides the rest, and never shows the product the customer is\n//    currently looking at.\n//  - \"Once per visit\" (default): the picks stay the same while someone\n//    browses in one visit, and change the next time they come back.\n//    \"Every page view\": new picks on every product page.\n//\n// WHY IT'S SAFE FOR THE REST OF THE SITE\n//  - It's a separate component from RandomizeOrder, so Shop All and the\n//    homepage sections keep running exactly as they do now.\n//  - It only touches cards inside its own section (it climbs a set number\n//    of layers up from where it's placed, same as RandomizeOrder).\n//  - It never moves cards in the page structure — it only sets CSS\n//    `order` and hides extras with `display: none`, so the scroll-reveal\n//    animations aren't disturbed (same lesson as RandomizeOrder v2).\n//  - It does nothing on the Framer editing canvas.\n//\n// PLACEMENT: one instance, as a sibling of the \"You may also like\"\n// Collection List (the same spot the RandomizeOrder instance sits now —\n// replace that instance with this one).\n// ---------------------------------------------------------------------------\nimport{jsx as _jsx,jsxs as _jsxs}from\"react/jsx-runtime\";import{useLayoutEffect,useRef}from\"react\";import{addPropertyControls,ControlType,RenderTarget}from\"framer\";function climb(el,levels){let cur=el;for(let i=0;i<levels;i++){if(!cur.parentElement)break;cur=cur.parentElement;}return cur;}// Small, stable string hash (FNV-1a) — turns \"seed + product\" into a number\n// so the same product gets the same rank for the whole visit.\nfunction hash(str){let h=2166136261;for(let i=0;i<str.length;i++){h^=str.charCodeAt(i);h=Math.imul(h,16777619);}return h>>>0;}function getSeed(storageKey,mode){const fresh=String(Math.random()).slice(2);if(mode!==\"visit\")return fresh;const key=`herb:featuredPicks:${storageKey}:seed`;try{const existing=window.sessionStorage.getItem(key);if(existing)return existing;window.sessionStorage.setItem(key,fresh);}catch(e){// storage blocked (private mode etc.) — just use a fresh shuffle\n}return fresh;}function pathOf(href){try{return new URL(href,window.location.href).pathname.replace(/\\/$/,\"\");}catch(e){return\"\";}}/**\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight any\n */export default function FeaturedPicks(props){const{showCount,shuffleMode,storageKey,scopeAncestorLevels,cardLayerName,debug}=props;const ref=useRef(null);const isCanvas=RenderTarget.current()===RenderTarget.canvas;useLayoutEffect(()=>{if(isCanvas||typeof window===\"undefined\")return;const self=ref.current;if(!self)return;const log=(...a)=>{if(debug)console.log(\"[FeaturedPicks]\",...a);};const selector=`[data-framer-name=\"${cardLayerName}\"]`;let attempts=0;let timer=null;// Climb ONE level at a time and stop at the first ancestor that\n// contains any cards — so this can never reach past its own section\n// into another section's cards. Scope Levels is only the maximum.\nconst findCards=()=>{for(let level=1;level<=scopeAncestorLevels;level++){const scope=climb(self,level);const found=Array.from(scope.querySelectorAll(selector));if(found.length>0){log(`found ${found.length} card(s) at level ${level}`);return found;}}return[];};const run=()=>{const cards=findCards();if(cards.length===0){// The Collection List can finish rendering a moment after this\n// component mounts — retry for ~3 seconds before giving up.\nif(attempts++<20){timer=setTimeout(run,150);}else{log(`no cards named \"${cardLayerName}\" within ${scopeAncestorLevels} level(s) — check Card Layer Name or raise Scope Levels`);}return;}// The grid = the closest ancestor that contains every card.\nlet grid=cards[0].parentElement;while(grid&&!cards.every(c=>grid.contains(c))){grid=grid.parentElement;}if(!grid)return;const display=window.getComputedStyle(grid).display;if(!/(flex|grid)/.test(display)){log(`grid display is \"${display}\", not flex/grid — skipping`);return;}// Each card's slot = its ancestor that sits directly in the grid.\nconst items=[];cards.forEach(c=>{let el=c;while(el.parentElement&&el.parentElement!==grid){el=el.parentElement;}if(!items.includes(el))items.push(el);});const here=pathOf(window.location.href);const seed=getSeed(storageKey,shuffleMode);const ranked=items.map(item=>{const link=item.querySelector(\"a[href]\");const href=link?link.getAttribute(\"href\")||\"\":\"\";const id=href||(item.textContent||\"\").trim();const isCurrent=!!href&&pathOf(href)===here;return{item,id,isCurrent,rank:hash(seed+\"|\"+id)};}).filter(r=>{if(r.isCurrent)r.item.style.display=\"none\";return!r.isCurrent;}).sort((a,b)=>a.rank-b.rank);const limit=showCount>0?showCount:ranked.length;ranked.forEach((r,i)=>{if(i<limit){r.item.style.display=\"\";r.item.style.order=String(i);}else{r.item.style.display=\"none\";}});log(`seed ${seed} (${shuffleMode}) — showing ${Math.min(limit,ranked.length)} of ${ranked.length}:`,ranked.slice(0,limit).map(r=>r.id));};run();return()=>{if(timer)clearTimeout(timer);};},[]);if(isCanvas){return /*#__PURE__*/_jsxs(\"div\",{style:{padding:\"6px 10px\",fontSize:11,fontFamily:\"sans-serif\",background:\"rgba(199,243,74,0.25)\",border:\"1px dashed #C7F34A\",borderRadius:6,color:\"#888\",whiteSpace:\"nowrap\"},children:[\"FeaturedPicks \\xb7 shows \",showCount||\"all\",' random \\xb7 key \"',storageKey,'\"']});}return /*#__PURE__*/_jsx(\"div\",{ref:ref,\"aria-hidden\":true,style:{position:\"absolute\",width:0,height:0,overflow:\"hidden\",pointerEvents:\"none\"}});}FeaturedPicks.defaultProps={showCount:4,shuffleMode:\"visit\",storageKey:\"related\",scopeAncestorLevels:2,cardLayerName:\"Product Card\",debug:false};addPropertyControls(FeaturedPicks,{showCount:{type:ControlType.Number,title:\"Show Count\",defaultValue:4,min:0,max:24,step:1,displayStepper:true,description:\"0 = show all featured\"},shuffleMode:{type:ControlType.Enum,title:\"Shuffle\",options:[\"visit\",\"load\"],optionTitles:[\"Once per visit\",\"Every page view\"],defaultValue:\"visit\"},storageKey:{type:ControlType.String,title:\"Storage Key\",defaultValue:\"related\"},scopeAncestorLevels:{type:ControlType.Number,title:\"Scope Levels\",defaultValue:2,min:1,max:8,step:1,displayStepper:true},cardLayerName:{type:ControlType.String,title:\"Card Layer Name\",defaultValue:\"Product Card\"},debug:{type:ControlType.Boolean,title:\"Debug\",defaultValue:false}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"FeaturedPicks\",\"slots\":[],\"annotations\":{\"framerSupportedLayoutHeight\":\"any\",\"framerContractVersion\":\"1\",\"framerSupportedLayoutWidth\":\"any\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./FeaturedPicks.map"],"mappings":"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"}