PageSourceSearch

https://pennyengineering.com/assets/js/AccordionListWrapper.5e2a6138d97c32f48e19.js

js pennyengineering.com collected 2026-10-09 21:39:44 UTC 14,742 bytes, 2 lines download raw bytes

1(globalThis.webpackChunkpenny_engineering_frontend=globalThis.webpackChunkpenny_engineering_frontend||[]).push([[20],{2894:(e,n,t)=>{"use strict";t.r(n),t.d(n,{default:()=>l});var o=t(1425);const a={class:"accordion-list"},r={key:1,class:"accordion-list__fade","aria-hidden":"true"},i={__name:"AccordionListWrapper",props:{maxVisible:{type:Number,default:4},moreLabel:{type:String,default:"Show All"}},setup(e){const n=e,t=(0,o.KR)(!1),i=(0,o.Ht)(),l=(0,o.KR)(null),s=(0,o.KR)(null),d=(0,o.KR)(0),c=(0,o.KR)("0px"),u=(0,o.EW)(()=>{const e=Number.isFinite(n.maxVisible)?n.maxVisible:4;return Math.max(4,e)}),h=(0,o.EW)(()=>(e=>{const n=[],t=e=>{e&&e.forEach(e=>{e&&e.type!==o.Mw&&e.type!==o.EY&&(e.type===o.FK&&Array.isArray(e.children)?t(e.children):n.push(e))})};return t(e),n})(i.default?i.default():[])),v=(0,o.EW)(()=>h.value.length>u.value),p=(0,o.EW)(()=>h.value.slice(0,u.value)),f=(0,o.EW)(()=>h.value.slice(u.value)),m=()=>{s.value?d.value=s.value.scrollHeight:d.value=0},g=()=>{if(!l.value||!v.value||t.value)return void l.value?.style.removeProperty("--accordion-fade-height");const e=l.value?l.value.querySelector(".accordion-list"):null;if(!e)return;const n=Array.from(e.querySelectorAll(".accordion-item"));if(!n.length)return void l.value.style.removeProperty("--accordion-fade-height");const o=Math.min(n.length,u.value);if(o<2)return void l.value.style.removeProperty("--accordion-fade-height");const a=n[o-1],r=n[o-2],i=r.offsetTop,s=i+r.offsetHeight,d=a.offsetTop,c=d+a.offsetHeight-i+Math.max(0,d-s);c>0&&l.value.style.setProperty("--accordion-fade-height",`${c}px`)},A=()=>{"undefined"!=typeof window&&(0,o.dY)(()=>{window.requestAnimationFrame(()=>{t.value?l.value?.style.removeProperty("--accordion-fade-height"):(m(),g(),c.value="0px")})})},x=()=>{v.value&&!t.value&&(m(),t.value=!0,c.value=`${d.value}px`)},w=()=>{A()},E=()=>{A()},b=e=>{"max-height"===e.propertyName&&s.value&&t.value&&(c.value="none")};return(0,o.sV)(()=>{(()=>{if("undefined"==typeof window||!l.value)return;let e=l.value.parentElement;for(;e&&!e.classList.contains("page-section");)e=e.parentElement;if(!e)return;const n=window.getComputedStyle(e).backgroundColor;n&&"rgba(0, 0, 0, 0)"!==n&&"transparent"!==n&&l.value.style.setProperty("--accordion-fade-bg",n)})(),A(),s.value&&s.value.addEventListener("transitionend",b),window.addEventListener("resize",w),window.addEventListener("load",E)}),(0,o.wB)(()=>h.value.length,()=>{A()}),(0,o.wB)(()=>t.value,()=>{A()}),(0,o.xo)(()=>{s.value&&s.value.removeEventListener("transitionend",b),window.removeEventListener("resize",w),window.removeEventListener("load",E)}),(n,i)=>((0,o.uX)(),(0,o.CE)("div",{class:"accordion-list-wrapper",ref_key:"rootEl",ref:l},[(0,o.Lk)("div",a,[(0,o.Q3)(" Primary (always visible) items "),((0,o.uX)(!0),(0,o.CE)(o.FK,null,(0,o.pI)(p.value,(e,n)=>((0,o.uX)(),(0,o.Wv)((0,o.$y)(e),{key:e.key??`primary-${n}`}))),128)),(0,o.Q3)(" Extra items that expand smoothly "),f.value.length?((0,o.uX)(),(0,o.CE)("div",{key:0,ref_key:"extraWrapper",ref:s,class:(0,o.C4)(["accordion-list__extra",{"accordion-list__extra--expanded":t.value}]),style:(0,o.Tr)({maxHeight:c.value})},[((0,o.uX)(!0),(0,o.CE)(o.FK,null,(0,o.pI)(f.value,(e,n)=>((0,o.uX)(),(0,o.Wv)((0,o.$y)(e),{key:e.key??`extra-${n}`}))),128))],6)):(0,o.Q3)("v-if",!0),(0,o.Q3)(" Fade over the bottom of the visible section "),v.value&&!t.value?((0,o.uX)(),(0,o.CE)("div",r)):(0,o.Q3)("v-if",!0)]),v.value&&!t.value?((0,o.uX)(),(0,o.CE)("button",{key:0,type:"button",class:"accordion-list-wrapper__toggle button button--white button--has-icon",onClick:x},[(0,o.Lk)("span",null,(0,o.v_)(e.moreLabel),1),i[0]||(i[0]=(0,o.Lk)("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 640 640"},[(0,o.Lk)("path",{d:"M342.6 534.6C330.1 547.1 309.8 547.1 297.3 534.6L137.3 374.6C128.1 365.4 125.4 351.7 130.4 339.7C135.4 327.7 147.1 320 160 320L256 320L256 144C256 117.5 277.5 96 304 96L336 96C362.5 96 384 117.5 384 144L384 320L480 320C492.9 320 504.6 327.8 509.6 339.8C514.6 351.8 511.8 365.5 502.7 374.7L342.7 534.7z"})],-1))])):(0,o.Q3)("v-if",!0)],512))}};t(7679);const l=(0,t(6262).A)(i,[["__scopeId","data-v-198817ce"]])},7679:(e,n,t)=>{var o=t(8404);o.__esModule&&(o=o.default),"string"==typeof o&&(o=[[e.id,o,""]]),o.locals&&(e.exports=o.locals);(0,t(534).A)("4a19a139",o,!0,{})},8404:(e,n,t)=>{"use strict";t.r(n),t.d(n,{default:()=>l});var o=t(1354),a=t.n(o),r=t(6314),i=t.n(r)()(a());
1i.push([e.id,"\n.accordion-list-wrapper[data-v-198817ce] {\n  position: relative;\n}\n.accordion-list[data-v-198817ce] {\n  position: relative;\n  /* Important: avoid stuff peeking out during the animation */\n  overflow: hidden;\n\n  /* Match the fade’s base colour so the transparent part blends in */\n  background-color: var(--accordion-fade-bg, #ffffff);\n}\n\n/* Extra items wrapper: we animate its height */\n.accordion-list__extra[data-v-198817ce] {\n  overflow: hidden;\n  transition: max-height 400ms ease;\n}\n.accordion-list__fade[data-v-198817ce] {\n  position: absolute;\n  left: 0;\n  right: 0;\n  bottom: 0;\n\n  /* JS sets: last 2 visible accordions + gap between them */\n  height: var(--accordion-fade-height, 14rem);\n\n  /* Block clicks on hidden accordions; button sits above this */\n  pointer-events: auto;\n  z-index: 1;\n\n  background: linear-gradient(180deg,\n      rgba(255, 255, 255, 0),\n      var(--accordion-fade-bg, #ffffff));\n}\n.accordion-list-wrapper__toggle[data-v-198817ce] {\n  position: absolute;\n  left: 50%;\n  bottom: 0;\n  transform: translateX(-50%);\n  z-index: 2;\n}\n","",{version:3,sources:["webpack://./src/js/vuejs/components/AccordionListWrapper.vue"],names:[],mappings:";AA+QA;EACE,kBAAkB;AACpB;AAEA;EACE,kBAAkB;EAClB,4DAA4D;EAC5D,gBAAgB;;EAEhB,mEAAmE;EACnE,mDAAmD;AACrD;;AAEA,+CAA+C;AAC/C;EACE,gBAAgB;EAChB,iCAAiC;AACnC;AAEA;EACE,kBAAkB;EAClB,OAAO;EACP,QAAQ;EACR,SAAS;;EAET,0DAA0D;EAC1D,2CAA2C;;EAE3C,8DAA8D;EAC9D,oBAAoB;EACpB,UAAU;;EAEV;;wCAEsC;AACxC;AAEA;EACE,kBAAkB;EAClB,SAAS;EACT,SAAS;EACT,2BAA2B;EAC3B,UAAU;AACZ",sourcesContent:["<template>\n  <div class=\"accordion-list-wrapper\" ref=\"rootEl\">\n    <div class=\"accordion-list\">\n      \x3c!-- Primary (always visible) items --\x3e\n      <component v-for=\"(child, index) in primaryChildren\" :key=\"child.key ?? `primary-${index}`\" :is=\"child\" />\n\n      \x3c!-- Extra items that expand smoothly --\x3e\n      <div v-if=\"extraChildren.length\" ref=\"extraWrapper\" class=\"accordion-list__extra\"\n        :class=\"{ 'accordion-list__extra--expanded': showAll }\" :style=\"{ maxHeight: extraMaxHeight }\">\n        <component v-for=\"(child, index) in extraChildren\" :key=\"child.key ?? `extra-${index}`\" :is=\"child\" />\n      </div>\n\n      \x3c!-- Fade over the bottom of the visible section --\x3e\n      <div v-if=\"hasOverflow && !showAll\" class=\"accordion-list__fade\" aria-hidden=\"true\"></div>\n    </div>\n\n    <button v-if=\"hasOverflow && !showAll\" type=\"button\"\n      class=\"accordion-list-wrapper__toggle button button--white button--has-icon\" @click=\"toggleShowAll\">
1\n      <span>{{ moreLabel }}</span>\n      <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 640\"><path d=\"M342.6 534.6C330.1 547.1 309.8 547.1 297.3 534.6L137.3 374.6C128.1 365.4 125.4 351.7 130.4 339.7C135.4 327.7 147.1 320 160 320L256 320L256 144C256 117.5 277.5 96 304 96L336 96C362.5 96 384 117.5 384 144L384 320L480 320C492.9 320 504.6 327.8 509.6 339.8C514.6 351.8 511.8 365.5 502.7 374.7L342.7 534.7z\"/></svg>\n    </button>\n  </div>\n</template>\n\n<script setup>\nimport {\n  computed,\n  ref,\n  useSlots,\n  Comment,\n  Text,\n  Fragment,\n  onMounted,\n  onBeforeUnmount,\n  nextTick,\n  watch\n} from 'vue';\n\nconst MIN_VISIBLE = 4;\n\nconst props = defineProps({\n  maxVisible: {\n    type: Number,\n    default: MIN_VISIBLE\n  },\n  moreLabel: {\n    type: String,\n    default: 'Show All'\n  }\n});\n\nconst showAll = ref(false);\nconst slots = useSlots();\nconst rootEl = ref(null);\nconst extraWrapper = ref(null);\nconst extraHeight = ref(0);\nconst extraMaxHeight = ref('0px');\n\nconst effectiveMaxVisible = computed(() => {\n  const value = Number.isFinite(props.maxVisible) ? props.maxVisible : MIN_VISIBLE;\n  return Math.max(MIN_VISIBLE, value);\n});\n\nconst normalizeChildren = (nodes) => {\n  const result = [];\n\n  const walk = (children) => {\n    if (!children) return;\n\n    children.forEach((node) => {\n      if (!node) return;\n\n      if (node.type === Comment || node.type === Text) return;\n\n      if (node.type === Fragment && Array.isArray(node.children)) {\n        walk(node.children);\n        return;\n      }\n\n      result.push(node);\n    });\n  };\n\n  walk(nodes);\n  return result;\n};\n\nconst slotChildren = computed(() => {\n  const raw = slots.default ? slots.default() : [];\n  return normalizeChildren(raw);\n});\n\nconst hasOverflow = computed(\n  () => slotChildren.value.length > effectiveMaxVisible.value\n);\n\nconst primaryChildren = computed(() =>\n  slotChildren.value.slice(0, effectiveMaxVisible.value)\n);\n\nconst extraChildren = computed(() =>\n  slotChildren.value.slice(effectiveMaxVisible.value)\n);\n\nconst getListEl = () => {\n  if (!rootEl.value) return null;\n  return rootEl.value.querySelector('.accordion-list');\n};\n\n// Fade background from nearest .page-section\nconst setFadeBackgroundFromSection = () => {\n  if (typeof window === 'undefined' || !rootEl.value) return;\n\n  let el = rootEl.value.parentElement;\n\n  while (el && !el.classList.contains('page-section')) {\n    el = el.parentElement;\n  }\n\n  if (!el) return;\n\n  const styles = window.getComputedStyle(el);\n  const bgColor = styles.backgroundColor;\n\n  if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {\n    rootEl.value.style.setProperty('--accordion-fade-bg', bgColor);\n  }\n};\n\n// Height of the extra items (for smooth open)\nconst updateExtraHeight = () => {\n  if (!extraWrapper.value) {\n    extraHeight.value = 0;\n    return;\n  }\n\n  // ScrollHeight gives us the full content height even when max-height is 0\n  extraHeight.value = extraWrapper.value.scrollHeight;\n};\n\n// Fade height = last 2 *visible* accordions + gap between them\nconst computeFadeHeight = () => {\n  if (!rootEl.value || !hasOverflow.value || showAll.value) {\n    rootEl.value?.style.removeProperty('--accordion-fade-height');\n    return;\n  }\n\n  const listEl = getListEl();\n  if (!listEl) return;\n\n  // Use rendered DOM: your items have class \"accordion-item\"\n  const items = Array.from(listEl.querySelectorAll('.accordion-item'));\n\n  if (!items.length) {\n    rootEl.value.style.removeProperty('--accordion-fade-height');\n    return;\n  }\n\n  const visibleCount = Math.min(items.length, effectiveMaxVisible.value);\n\n  if (visibleCount < 2) {\n    rootEl.value.style.removeProperty('--accordion-fade-height');\n    return;\n  }\n\n  const last = items[visibleCount - 1];\n  const secondLast = items[visibleCount - 2];\n\n  const secondTop = secondLast.offsetTop;\n  const secondBottom = secondTop + secondLast.offsetHeight;\n  const lastTop = last.offsetTop;\n  const lastBottom = lastTop + last.offsetHeight;\n\n  // Base = top of second-last → bottom of last\n  const baseHeight = lastBottom - secondTop;\n\n  // Extra gap between them\n  const gap = Math.max(0, lastTop - secondBottom);
1\n\n  const height = baseHeight + gap;\n\n  if (height > 0) {\n    rootEl.value.style.setProperty('--accordion-fade-height', `${height}px`);\n  }\n};\n\n// Recalc measurements (fade + extra height)\nconst refreshMeasurements = () => {\n  if (typeof window === 'undefined') return;\n\n  nextTick(() => {\n    window.requestAnimationFrame(() => {\n      if (!showAll.value) {\n        updateExtraHeight();\n        computeFadeHeight();\n        // while collapsed, keep extra section closed\n        extraMaxHeight.value = '0px';\n      } else {\n        // fully open: no fade; don't touch maxHeight so it can stay 'none'\n        rootEl.value?.style.removeProperty('--accordion-fade-height');\n      }\n    });\n  });\n};\n\nconst toggleShowAll = () => {\n  if (!hasOverflow.value || showAll.value) return;\n\n  // Opening: measure extra content height then animate\n  updateExtraHeight();\n  showAll.value = true;\n  extraMaxHeight.value = `${extraHeight.value}px`;\n};\n\nconst handleResize = () => {\n  refreshMeasurements();\n};\n\nconst handleWindowLoad = () => {\n  refreshMeasurements();\n};\n\nconst onExtraTransitionEnd = (event) => {\n  // Only care about the max-height transition on the extra wrapper\n  if (event.propertyName !== 'max-height') return;\n  if (!extraWrapper.value) return;\n\n  if (showAll.value) {\n    // After the initial expand animation, uncap the height\n    // so inner accordions can open without being clipped\n    extraMaxHeight.value = 'none';\n  }\n};\n\nonMounted(() => {\n  setFadeBackgroundFromSection();\n  refreshMeasurements();\n\n  if (extraWrapper.value) {\n    extraWrapper.value.addEventListener('transitionend', onExtraTransitionEnd);\n  }\n\n  window.addEventListener('resize', handleResize);\n  window.addEventListener('load', handleWindowLoad);\n});\n\nwatch(\n  () => slotChildren.value.length,\n  () => {\n    refreshMeasurements();\n  }\n);\n\nwatch(\n  () => showAll.value,\n  () => {\n    refreshMeasurements();\n  }\n);\n\nonBeforeUnmount(() => {\n  if (extraWrapper.value) {\n    extraWrapper.value.removeEventListener('transitionend', onExtraTransitionEnd);\n  }\n\n  window.removeEventListener('resize', handleResize);\n  window.removeEventListener('load', handleWindowLoad);\n});\n<\/script>\n\n<style scoped>\n.accordion-list-wrapper {\n  position: relative;\n}\n\n.accordion-list {\n  position: relative;\n  /* Important: avoid stuff peeking out during the animation */\n  overflow: hidden;\n\n  /* Match the fade’s base colour so the transparent part blends in */\n  background-color: var(--accordion-fade-bg, #ffffff);\n}\n\n/* Extra items wrapper: we animate its height */\n.accordion-list__extra {\n  overflow: hidden;\n  transition: max-height 400ms ease;\n}\n\n.accordion-list__fade {\n  position: absolute;\n  left: 0;\n  right: 0;\n  bottom: 0;\n\n  /* JS sets: last 2 visible accordions + gap between them */\n  height: var(--accordion-fade-height, 14rem);\n\n  /* Block clicks on hidden accordions; button sits above this */\n  pointer-events: auto;\n  z-index: 1;\n\n  background: linear-gradient(180deg,\n      rgba(255, 255, 255, 0),\n      var(--accordion-fade-bg, #ffffff));\n}\n\n.accordion-list-wrapper__toggle {\n  position: absolute;\n  left: 50%;\n  bottom: 0;\n  transform: translateX(-50%);\n  z-index: 2;\n}\n</style>"],sourceRoot:""}]);const l=i}}]);
2//# sourceMappingURL=AccordionListWrapper.5e2a6138d97c32f48e19.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.