Last active
June 25, 2022 11:00
-
-
Save AvocadoVenom/2fa11b082ecb07e61eae90d05099336f to your computer and use it in GitHub Desktop.
Autonomous expandable block content which detects toggle button need
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <template> | |
| <div class="block-content"> | |
| <transition | |
| @before-enter="onBeforeEnter" | |
| @enter="onEnter" | |
| @after-enter="onAfterEnter" | |
| @before-leave="onBeforeLeave" | |
| @leave="onLeave" | |
| mode="out-in" | |
| > | |
| <div v-if="!isExpanded" class="block-content__preview"> | |
| <p ref="preview" v-html="content" /> | |
| </div> | |
| <p | |
| v-else | |
| :class="{ | |
| 'block-content__paragraph': true, | |
| 'block-content__paragraph--is-expanded': isExpanded, | |
| }" | |
| v-html="content" | |
| /> | |
| </transition> | |
| <button | |
| v-if="isToggleButtonRequired" | |
| type="button" | |
| class="block-content__button" | |
| aria-label="Toggle button" | |
| @click="isExpanded = !isExpanded" | |
| > | |
| {{ toggleCtaLabel }} | |
| </button> | |
| </div> | |
| </template> | |
| <script lang="ts"> | |
| import { computed, defineComponent, onMounted, ref, toRefs } from "vue"; | |
| export default defineComponent({ | |
| name: "ExpandableBlockContent", | |
| props: { | |
| content: { type: String }, | |
| visibleLines: { type: Number, default: 4 }, | |
| }, | |
| setup(props) { | |
| const { visibleLines } = toRefs(props); | |
| // Collapsed state | |
| // Assuming that default line-height is 24px | |
| const LINE_HEIGHT = 24; | |
| const maxHeightCollapsed = computed(() => LINE_HEIGHT * visibleLines.value); | |
| // Expanded state | |
| const isExpanded = ref(false); | |
| // Toggle button | |
| const preview = ref<HTMLElement | null>(null); | |
| onMounted(() => { | |
| const previewHeight = (preview.value ?? {}).clientHeight ?? 0; | |
| isToggleButtonRequired.value = previewHeight > maxHeightCollapsed.value; | |
| }); | |
| const isToggleButtonRequired = ref(false); | |
| const toggleCtaLabel = computed(() => | |
| isExpanded.value ? "Read less" : "Read more" | |
| ); | |
| // Animation hooks (omitted to minimize snippet length) | |
| const onBeforeEnter = (el: Element) => { /** ... */ }; | |
| const onEnter = (el: Element) => { /** ... */ }; | |
| const onAfterEnter = (el: Element) => { /** ... */ }; | |
| const onBeforeLeave = (el: Element) => { /** ... */ }; | |
| const onLeave = (el: Element) => { /** ... */ }; | |
| return { | |
| isExpanded, | |
| preview, | |
| isToggleButtonRequired, | |
| toggleCtaLabel, | |
| onBeforeEnter, | |
| onEnter, | |
| onAfterEnter, | |
| onBeforeLeave, | |
| onLeave, | |
| }; | |
| }, | |
| }); | |
| </script> | |
| <style lang="scss" scoped> | |
| /** ... */ | |
| </style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment