🐞 fix: Animate team-grid bio with JS measuring natural height
This commit is contained in:
Vendored
+2687
-3845
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.team-grid__read-bio::after {
|
.team-grid__read-bio::after {
|
||||||
content: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20transform%3D%22rotate(0%200%200)%22%3E%3Cpath%20d%3D%22M6.28033%2010.5947C5.98744%2010.3018%205.51256%2010.3018%205.21967%2010.5947C4.92678%2010.8876%204.92678%2011.3624%205.21967%2011.6553L11.4697%2017.9053C11.7626%2018.1982%2012.2374%2018.1982%2012.5303%2017.9053L18.7803%2011.6553C19.0732%2011.3624%2019.0732%2010.8876%2018.7803%2010.5947C18.4874%2010.3018%2018.0126%2010.3018%2017.7197%2010.5947L12%2016.3143L6.28033%2010.5947Z%22%20fill%3D%22%23006196%22%2F%3E%3Cpath%20opacity%3D%221%22%20d%3D%22M6.28033%206.09467C5.98744%205.80178%205.51256%205.80178%205.21967%206.09467C4.92678%206.38756%204.92678%206.86244%205.21967%207.15533L11.4697%2013.4053C11.7626%2013.6982%2012.2374%2013.6982%2012.5303%2013.4053L18.7803%207.15533C19.0732%206.86244%2019.0732%206.38756%2018.7803%206.09467C18.4874%205.80178%2018.0126%205.80178%2017.7197%206.09467L12%2011.8143L6.28033%206.09467Z%22%20fill%3D%22%23006196%22%2F%3E%3C%2Fsvg%3E");
|
content: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20transform%3D%22rotate(0%200%200)%22%3E%3Cpath%20d%3D%22M6.28033%2010.5947C5.98744%2010.3018%205.51256%2010.3018%205.21967%2010.5947C4.92678%2010.8876%204.92678%2011.3624%205.21967%2011.6553L11.4697%2017.9053C11.7626%2018.1982%2012.2374%2018.1982%2012.5303%2017.9053L18.7803%2011.6553C19.0732%2011.3624%2019.0732%2010.8876%2018.7803%2010.5947C18.4874%2010.3018%2018.0126%2010.3018%2017.7197%2010.5947L12%2016.3143L6.28033%2010.5947Z%22%20fill%3D%22%23006196%22%2F%3E%3Cpath%20opacity%3D%221%22%20d%3D%22M6.28033%206.09467C5.98744%205.80178%205.51256%205.80178%205.21967%206.09467C4.92678%206.38756%204.92678%206.86244%205.21967%207.15533L11.4697%2013.4053C11.7626%2013.6982%2012.2374%2018.1982%2012.5303%2013.4053L18.7803%207.15533C19.0732%206.86244%2019.0732%206.38756%2018.7803%206.09467C18.4874%205.80178%2018.0126%205.80178%2017.7197%206.09467L12%2011.8143L6.28033%206.09467Z%22%20fill%3D%22%23006196%22%2F%3E%3C%2Fsvg%3E");
|
||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
}
|
}
|
||||||
@@ -42,28 +42,25 @@
|
|||||||
|
|
||||||
.team-grid__read-bio {
|
.team-grid__read-bio {
|
||||||
@apply flex gap-2 justify-center items-center text-cwc-blue-01 text-16px font-bold leading-snug mb-1;
|
@apply flex gap-2 justify-center items-center text-cwc-blue-01 text-16px font-bold leading-snug mb-1;
|
||||||
|
transition: transform 300ms ease;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20transform%3D%22rotate(0%200%200)%22%3E%3Cpath%20d%3D%22M6.28033%2010.5947C5.98744%2010.3018%205.51256%2010.3018%205.21967%2010.5947C4.92678%2010.8876%204.92678%2011.3624%205.21967%2011.6553L11.4697%2017.9053C11.7626%2018.1982%2012.2374%2018.1982%2012.5303%2017.9053L18.7803%2011.6553C19.0732%2011.3624%2019.0732%2010.8876%2018.7803%2010.5947C18.4874%2010.3018%2018.0126%2010.3018%2017.7197%2010.5947L12%2016.3143L6.28033%2010.5947Z%22%20fill%3D%22%23006196%22%2F%3E%3Cpath%20opacity%3D%220.5%22%20d%3D%22M6.28033%206.09467C5.98744%205.80178%205.51256%205.80178%205.21967%206.09467C4.92678%206.38756%204.92678%206.86244%205.21967%207.15533L11.4697%2013.4053C11.7626%2013.6982%2012.2374%2013.6982%2012.5303%2013.4053L18.7803%207.15533C19.0732%206.86244%2019.0732%206.38756%2018.7803%206.09467C18.4874%205.80178%2018.0126%205.80178%2017.7197%206.09467L12%2011.8143L6.28033%206.09467Z%22%20fill%3D%22%23006196%22%2F%3E%3C%2Fsvg%3E");
|
content: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20transform%3D%22rotate(0%200%200)%22%3E%3Cpath%20d%3D%22M6.28033%2010.5947C5.98744%2010.3018%205.51256%2010.3018%205.21967%2010.5947C4.92678%2010.8876%204.92678%2011.3624%205.21967%2011.6553L11.4697%2017.9053C11.7626%2018.1982%2012.2374%2018.1982%2012.5303%2017.9053L18.7803%2011.6553C19.0732%2011.3624%2019.0732%2010.8876%2018.7803%2010.5947C18.4874%2010.3018%2018.0126%2010.3018%2017.7197%2010.5947L12%2016.3143L6.28033%2010.5947Z%22%20fill%3D%22%23006196%22%2F%3E%3Cpath%20opacity%3D%220.5%22%20d%3D%22M6.28033%206.09467C5.98744%205.80178%205.51256%205.80178%205.21967%206.09467C4.92678%206.38756%204.92678%206.86244%205.21967%207.15533L11.4697%2013.4053C11.7626%2013.6982%2012.2374%2018.1982%2012.5303%2013.4053L18.7803%207.15533C19.0732%206.86244%2019.0732%206.38756%2018.7803%206.09467C18.4874%205.80178%2018.0126%205.80178%2017.7197%206.09467L12%2011.8143L6.28033%206.09467Z%22%20fill%3D%22%23006196%22%2F%3E%3C%2Fsvg%3E");
|
||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
|
transition: transform 300ms ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.team-grid__details[open] .team-grid__read-bio::after {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
.team-grid__bio-wrap {
|
.team-grid__bio-wrap {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height 300ms ease;
|
transition: max-height 300ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.team-grid__details[open] {
|
|
||||||
.team-grid__bio-wrap { max-height: 1000px; }
|
|
||||||
|
|
||||||
.team-grid__read-bio::after {
|
|
||||||
content: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20transform%3D%22rotate(0%200%200)%22%3E%3Cpath%20d%3D%22M6.28033%2010.5947C5.98744%2010.3018%205.51256%2010.3018%205.21967%2010.5947C4.92678%2010.8876%204.92678%2011.3624%205.21967%2011.6553L11.4697%2017.9053C11.7626%2018.1982%2012.2374%2018.1982%2012.5303%2017.9053L18.7803%2011.6553C19.0732%2011.3624%2019.0732%2010.8876%2018.7803%2010.5947C18.4874%2010.3018%2018.0126%2010.3018%2017.7197%2010.5947L12%2016.3143L6.28033%2010.5947Z%22%20fill%3D%22%23006196%22%2F%3E%3Cpath%20opacity%3D%221%22%20d%3D%22M6.28033%206.09467C5.98744%205.80178%205.51256%205.80178%205.21967%206.09467C4.92678%206.38756%204.92678%206.86244%205.21967%207.15533L11.4697%2013.4053C11.7626%2013.6982%2012.2374%2013.6982%2012.5303%2013.4053L18.7803%207.15533C19.0732%206.86244%2019.0732%206.38756%2018.7803%206.09467C18.4874%205.80178%2018.0126%205.80178%2017.7197%206.09467L12%2011.8143L6.28033%206.09467Z%22%20fill%3D%22%23006196%22%2F%3E%3C%2Fsvg%3E");
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-grid__bio { @apply text-16px font-light leading-snug pt-2 text-center text-balance; }
|
.team-grid__bio { @apply text-16px font-light leading-snug pt-2 text-center text-balance; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* Team Grid block — bio expand/collapse animation.
|
||||||
|
*
|
||||||
|
* Native <details>/<summary> handles the toggle, but CSS transitions on
|
||||||
|
* max-height need a concrete target value to animate to. This module
|
||||||
|
* measures each bio's natural height on open and animates max-height
|
||||||
|
* from current → measured (open) or current → 0 (close) so the
|
||||||
|
* transition fires in both directions.
|
||||||
|
*
|
||||||
|
* The module is enqueued per-block by the team-grid PHP template. It
|
||||||
|
* auto-initializes on import: queries the DOM for any existing
|
||||||
|
* .team-grid__details elements and attaches a toggle handler to each.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DETAILS_SELECTOR = '.team-grid__details';
|
||||||
|
const BIO_WRAP_SELECTOR = '.team-grid__bio-wrap';
|
||||||
|
|
||||||
|
const setMaxHeight = (el, value) => {
|
||||||
|
el.style.maxHeight = typeof value === 'number' ? `${value}px` : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const measureBioHeight = (bioWrap) => {
|
||||||
|
// Temporarily allow the inner content to render at its natural size so
|
||||||
|
// scrollHeight reports the real height rather than the clipped height.
|
||||||
|
const previousMax = bioWrap.style.maxHeight;
|
||||||
|
const previousOverflow = bioWrap.style.overflow;
|
||||||
|
|
||||||
|
setMaxHeight(bioWrap, 'none');
|
||||||
|
bioWrap.style.overflow = 'visible';
|
||||||
|
|
||||||
|
const height = bioWrap.scrollHeight;
|
||||||
|
|
||||||
|
bioWrap.style.overflow = previousOverflow;
|
||||||
|
setMaxHeight(bioWrap, previousMax || '');
|
||||||
|
|
||||||
|
return height;
|
||||||
|
};
|
||||||
|
|
||||||
|
const animateOpen = (bioWrap) => {
|
||||||
|
const target = measureBioHeight(bioWrap);
|
||||||
|
|
||||||
|
setMaxHeight(bioWrap, '0px');
|
||||||
|
|
||||||
|
// Force a reflow so the browser registers the starting value before
|
||||||
|
// we change it to the target — otherwise the transition is skipped.
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
bioWrap.offsetHeight;
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
setMaxHeight(bioWrap, `${target}px`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// After the transition completes, set max-height back to 'none' so
|
||||||
|
// dynamic content (e.g. images loading late) can grow the bio
|
||||||
|
// without being clipped.
|
||||||
|
const onEnd = (event) => {
|
||||||
|
if (event.propertyName !== 'max-height' || event.target !== bioWrap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bioWrap.removeEventListener('transitionend', onEnd);
|
||||||
|
setMaxHeight(bioWrap, 'none');
|
||||||
|
};
|
||||||
|
bioWrap.addEventListener('transitionend', onEnd);
|
||||||
|
};
|
||||||
|
|
||||||
|
const animateClose = (bioWrap) => {
|
||||||
|
// Capture the current rendered height so the browser has a concrete
|
||||||
|
// starting value for the transition. Without this, going from
|
||||||
|
// 'none' to '0px' snaps instead of animating.
|
||||||
|
const current = bioWrap.getBoundingClientRect().height;
|
||||||
|
|
||||||
|
setMaxHeight(bioWrap, `${current}px`);
|
||||||
|
|
||||||
|
// Force a reflow so the browser registers the starting value.
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
bioWrap.offsetHeight;
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
setMaxHeight(bioWrap, '0px');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const attach = (details) => {
|
||||||
|
if (details.dataset.teamGridBound === 'true') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
details.dataset.teamGridBound = 'true';
|
||||||
|
|
||||||
|
const bioWrap = details.querySelector(BIO_WRAP_SELECTOR);
|
||||||
|
|
||||||
|
if (!bioWrap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
details.addEventListener('toggle', () => {
|
||||||
|
if (details.open) {
|
||||||
|
animateOpen(bioWrap);
|
||||||
|
} else {
|
||||||
|
animateClose(bioWrap);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
document.querySelectorAll(DETAILS_SELECTOR).forEach(attach);
|
||||||
|
};
|
||||||
|
|
||||||
|
init();
|
||||||
@@ -17,6 +17,17 @@ if ( empty( $members ) ) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enqueue the per-block JS only when this block actually renders.
|
||||||
|
$js_path = '/views/blocks/team-grid/team-grid.js';
|
||||||
|
if ( file_exists( get_stylesheet_directory() . $js_path ) ) {
|
||||||
|
wp_enqueue_script_module(
|
||||||
|
'cwc-team-grid',
|
||||||
|
get_stylesheet_directory_uri() . $js_path,
|
||||||
|
array(),
|
||||||
|
(string) filemtime( get_stylesheet_directory() . $js_path )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$modeSingle = '';
|
$modeSingle = '';
|
||||||
|
|
||||||
$blockID = wp_unique_id( 'single-' );
|
$blockID = wp_unique_id( 'single-' );
|
||||||
|
|||||||
Reference in New Issue
Block a user