vira
Version:
A simple and highly versatile design system using element-vir.
81 lines (77 loc) • 2.52 kB
JavaScript
import { css, defineElementEvent, html, listen, onResize } from 'element-vir';
import { noNativeFormStyles, viraAnimationDurations } from '../styles/index.js';
import { defineViraElement } from './define-vira-element.js';
/**
* A wrapper element that can collapse and expand to fit its content dynamically and efficiently.
*
* @category Collapsible
* @category Elements
* @see https://electrovir.github.io/element-vir/vira/book/elements/vira-collapsible-wrapper
*/
export const ViraCollapsibleWrapper = defineViraElement()({
tagName: 'vira-collapsible-wrapper',
state() {
return {
contentHeight: 0,
};
},
hostClasses: {
'vira-collapsible-wrapper-expanded': ({ inputs }) => inputs.expanded,
},
slotNames: ['header'],
styles: ({ hostClasses }) => css `
:host {
display: flex;
flex-direction: column;
}
.header-wrapper {
${noNativeFormStyles};
cursor: pointer;
}
.content-wrapper,
.collapsing-element {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.collapsing-element {
transition: height ${viraAnimationDurations['vira-pretty-animation-duration'].value};
overflow: hidden;
}
${hostClasses['vira-collapsible-wrapper-expanded'].name} .collapsing-element {
pointer-events: none;
}
`,
events: {
expandChange: defineElementEvent(),
},
render({ state, slotNames, updateState, dispatch, events, inputs }) {
const collapsingStyles = inputs.expanded
? css `
height: ${state.contentHeight}px;
`
: css `
height: 0;
`;
return html `
<button
class="header-wrapper"
${listen('click', () => {
dispatch(new events.expandChange(!inputs.expanded));
})}
>
<slot name=${slotNames.header}>Header</slot>
</button>
<div class="collapsing-element" style=${collapsingStyles} disabled="disabled">
<div
${onResize(({ contentRect }) => {
updateState({ contentHeight: contentRect.height });
})}
class="content-wrapper"
>
<slot></slot>
</div>
</div>
`;
},
});