@dialpad/dialtone
Version:
Dialpad's Dialtone design system monorepo
259 lines (258 loc) • 7.83 kB
JavaScript
import { getUniqueString, extractVueListeners, hasSlotContent } from "../../common/utils.js";
import DtCollapsibleLazyShow from "./collapsible_lazy_show.vue.js";
import { DtIconChevronDown, DtIconChevronRight } from "@dialpad/dialtone-icons/vue3";
import { resolveComponent, openBlock, createBlock, resolveDynamicComponent, mergeProps, toHandlers, withCtx, createElementVNode, normalizeClass, renderSlot, createVNode, normalizeStyle, toDisplayString } from "vue";
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
import DtButton from "../button/button.vue.js";
import DtLazyShow from "../lazy_show/lazy_show.vue.js";
const _sfc_main = {
compatConfig: { MODE: 3 },
name: "DtCollapsible",
components: {
DtButton,
DtCollapsibleLazyShow,
DtLazyShow,
DtIconChevronDown,
DtIconChevronRight
},
props: {
/**
* Text that is displayed on the anchor if nothing is passed in the slot.
* Ignored if the anchor slot is used.
*/
anchorText: {
type: String,
default: null
},
/**
* Controls whether the collapsible is shown. Leaving this null will have the collapsible start
* expanded and trigger on click by default. If you set this value, the default trigger
* behavior will be disabled, and you can control it as you need.
* Supports .sync modifier
* @values null, true, false
*/
open: {
type: Boolean,
default: null
},
/**
* The id of the content wrapper.
*/
id: {
type: String,
default() {
return getUniqueString();
}
},
/**
* HTML element type (tag name) of the root element of the component.
*/
elementType: {
type: String,
default: "div"
},
/**
* HTML element type (tag name) of the content wrapper element.
*/
contentElementType: {
type: String,
default: "div"
},
/**
* Additional class name for the anchor wrapper element.
*/
anchorClass: {
type: [String, Array, Object],
default: null
},
/**
* Additional class name for the content wrapper element.
*/
contentClass: {
type: [String, Array, Object],
default: null
},
/**
* The maximum width of the anchor and collapsible element.
* Possible units rem|px|%|em
*/
maxWidth: {
type: String,
default: null
},
/**
* The maximum height of the collapsible element.
* Possible units rem|px|%|em
*/
maxHeight: {
type: String,
default: null
},
/**
* Label on the collapsible content. Should provide this or ariaLabelledBy but not both.
*/
ariaLabel: {
type: String,
default: null
},
/**
* Id of the element that labels the collapsible content. Defaults to the anchor element.
* Should provide this or ariaLabel but not both.
*/
ariaLabelledBy: {
type: String,
default: null
}
},
emits: [
/**
* Event fired to sync the open prop with the parent component
* @event update:open
*/
"update:open",
/**
* Event fired when the content is shown or hidden
*
* @event opened
* @type {Boolean}
*/
"opened"
],
data() {
return {
isOpen: true
};
},
computed: {
labelledBy() {
return this.ariaLabelledBy || !this.ariaLabel && getUniqueString("DtCollapsible__anchor");
},
collapsibleListeners() {
return extractVueListeners(this.$attrs);
}
},
watch: {
open: {
handler: function(open) {
if (open !== null) {
this.isOpen = open;
}
},
immediate: true
}
},
created() {
this.validateProperAnchor();
},
methods: {
onLeaveTransitionComplete() {
this.$emit("opened", false);
if (this.open !== null) {
this.$emit("update:open", false);
}
},
onEnterTransitionComplete() {
this.$emit("opened", true, this.$refs.content);
if (this.open !== null) {
this.$emit("update:open", true);
}
},
defaultToggleOpen() {
if (this.open === null) {
this.toggleOpen();
}
},
toggleOpen() {
this.isOpen = !this.isOpen;
},
validateProperAnchor() {
if (!this.anchorText && !hasSlotContent(this.$slots.anchor)) {
console.error("anchor text and anchor slot content cannot both be falsy");
}
}
}
};
const _hoisted_1 = ["id"];
const _hoisted_2 = ["title"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_dt_icon_chevron_down = resolveComponent("dt-icon-chevron-down");
const _component_dt_icon_chevron_right = resolveComponent("dt-icon-chevron-right");
const _component_dt_button = resolveComponent("dt-button");
const _component_dt_collapsible_lazy_show = resolveComponent("dt-collapsible-lazy-show");
return openBlock(), createBlock(resolveDynamicComponent($props.elementType), mergeProps({ ref: "collapsible" }, toHandlers($options.collapsibleListeners)), {
default: withCtx(() => [
createElementVNode("div", {
id: !$props.ariaLabelledBy && $options.labelledBy,
ref: "anchor",
class: normalizeClass($props.anchorClass)
}, [
renderSlot(_ctx.$slots, "anchor", {
attrs: {
"aria-controls": $props.id,
"aria-expanded": $data.isOpen.toString(),
"role": "button"
}
}, () => [
createVNode(_component_dt_button, {
importance: "clear",
kind: "muted",
"aria-controls": $props.id,
"aria-expanded": `${$data.isOpen}`,
style: normalizeStyle({
"width": $props.maxWidth
}),
onClick: $options.defaultToggleOpen
}, {
default: withCtx(() => [
$data.isOpen ? (openBlock(), createBlock(_component_dt_icon_chevron_down, {
key: 0,
class: "d-collapsible__icon",
size: "300"
})) : (openBlock(), createBlock(_component_dt_icon_chevron_right, {
key: 1,
class: "d-collapsible__icon",
size: "300"
})),
createElementVNode("span", {
class: "d-collapsible__anchor-text",
title: $props.anchorText
}, toDisplayString($props.anchorText), 9, _hoisted_2)
]),
_: 1
}, 8, ["aria-controls", "aria-expanded", "style", "onClick"])
])
], 10, _hoisted_1),
createVNode(_component_dt_collapsible_lazy_show, mergeProps({
id: $props.id,
ref: "contentWrapper",
"aria-hidden": `${!$data.isOpen}`,
"aria-labelledby": $options.labelledBy,
"aria-label": $props.ariaLabel,
show: $data.isOpen,
"element-type": $props.contentElementType,
class: $props.contentClass,
style: {
"max-height": $props.maxHeight,
"max-width": $props.maxWidth
},
"data-qa": "dt-collapsible--content",
tabindex: "-1",
appear: ""
}, toHandlers($options.collapsibleListeners), {
onAfterLeave: $options.onLeaveTransitionComplete,
onAfterEnter: $options.onEnterTransitionComplete
}), {
default: withCtx(() => [
renderSlot(_ctx.$slots, "content")
]),
_: 3
}, 16, ["id", "aria-hidden", "aria-labelledby", "aria-label", "show", "element-type", "class", "style", "onAfterLeave", "onAfterEnter"])
]),
_: 3
}, 16);
}
const DtCollapsible = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
DtCollapsible as default
};
//# sourceMappingURL=collapsible.vue.js.map