@dialpad/dialtone
Version:
Dialpad's Dialtone design system monorepo
274 lines (273 loc) • 8.93 kB
JavaScript
import { warn, resolveComponent, openBlock, createElementBlock, normalizeProps, guardReactiveProps, createElementVNode, mergeProps, renderSlot, createTextVNode, toDisplayString, createCommentVNode, normalizeClass, toHandlers, Fragment, renderList, createVNode } from "vue";
import { LABEL_SIZE_MODIFIERS, DESCRIPTION_SIZE_MODIFIERS } from "../../common/constants.js";
import { SELECT_SIZE_MODIFIERS, SELECT_STATE_MODIFIERS } from "./select_menu_constants.js";
import { hasSlotContent, getValidationState, getUniqueString, removeClassStyleAttrs, addClassStyleAttrs } from "../../common/utils.js";
import { MessagesMixin } from "../../common/mixins/input.js";
import { optionsValidator } from "./select_menu_validators.js";
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
import DtValidationMessages from "../validation_messages/validation_messages.vue.js";
const _sfc_main = {
compatConfig: { MODE: 3 },
name: "DtSelectMenu",
components: { DtValidationMessages },
mixins: [MessagesMixin],
inheritAttrs: false,
props: {
/**
* Label for the select
*/
label: {
type: String,
default: ""
},
/**
* Description for the select
*/
description: {
type: String,
default: ""
},
/**
* Select Menu Options, overridden by default slot. Each option has the following structure:
* `{ index: number (optional), value: number || string (required), label: string (required) }`
* @param {Object[]} options - Optional - A list that can be used to create a list of select menu options
* @param {number} options[].index - Optional - The index of the option
* @param {number|string} options[].value - Required - The option value
* @param {string} options[].label - Required - The option Label
*/
options: {
type: Array,
default: () => [],
validator: (options) => optionsValidator(options)
},
/**
* Controls the size of the select
* @values xs, sm, md, lg, xl
*/
size: {
type: String,
default: "md",
validator: (s) => Object.keys(SELECT_SIZE_MODIFIERS).includes(s)
},
/**
* Used to customize the label container
*/
labelClass: {
type: [String, Array, Object],
default: ""
},
/**
* Used to customize the description container
*/
descriptionClass: {
type: [String, Array, Object],
default: ""
},
/**
* Used to customize the select
*/
selectClass: {
type: [String, Array, Object],
default: ""
},
/**
* Used to customize each option, should options be provided via prop
*/
optionClass: {
type: [String, Array, Object],
default: ""
},
/**
* A set of props that are passed into the label container
*/
labelChildProps: {
type: Object,
default: () => ({})
},
/**
* A set of props that are passed into the description container
*/
descriptionChildProps: {
type: Object,
default: () => ({})
},
/**
* A set of props that are passed into each option, should options be provided via prop
*/
optionChildProps: {
type: Object,
default: () => ({})
},
/**
* Disabled state of the select
* @values true, false
*/
disabled: {
type: Boolean,
default: false
}
},
emits: [
/**
* Native input event
*
* @event input
* @type {String | Number}
*/
"input",
/**
* Native change event
*
* @event change
* @type {String | Number}
*/
"change"
],
data() {
return {
LABEL_SIZE_MODIFIERS,
DESCRIPTION_SIZE_MODIFIERS,
SELECT_SIZE_MODIFIERS,
SELECT_STATE_MODIFIERS,
hasSlotContent
};
},
computed: {
selectListeners() {
return {
/*
* Override input listener to as no-op. Prevents parent input listeners from being passed through onto the input
* element which will result in the handler being called twice (once on the select element and once by the
* emitted input event by the change listener).
*/
input: () => {
},
change: (event) => this.emitValue(event.target.value, event)
};
},
state() {
return getValidationState(this.formattedMessages);
},
selectKey() {
return getUniqueString();
},
descriptionKey() {
return `select-${this.selectKey}-description`;
},
labelAriaDetails() {
if (this.$slots.description || this.description) {
return this.descriptionKey;
}
return this.$attrs["aria-details"];
}
},
watch: {
// whenever question changes, this function will run
options() {
this.$nextTick(() => {
this.emitValue(this.$refs.selectElement.value, null);
});
}
},
mounted() {
this.emitValue(this.$refs.selectElement.value, null);
this.validateOptionsPresence();
},
beforeUpdate() {
this.validateOptionsPresence();
},
methods: {
removeClassStyleAttrs,
addClassStyleAttrs,
emitValue(value, event) {
this.$emit("input", value, event);
this.$emit("change", value, event);
},
getOptionKey(value) {
return `select-${this.selectKey}-option-${value}`;
},
validateOptionsPresence() {
var _a;
if (((_a = this.options) == null ? void 0 : _a.length) < 1 && !this.$slots.default) {
warn("Options are expected to be provided via prop or slot", this);
}
}
}
};
const _hoisted_1 = ["aria-details"];
const _hoisted_2 = ["id"];
const _hoisted_3 = ["disabled"];
const _hoisted_4 = ["value"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_dt_validation_messages = resolveComponent("dt-validation-messages");
return openBlock(), createElementBlock("div", normalizeProps(guardReactiveProps($options.addClassStyleAttrs(_ctx.$attrs))), [
createElementVNode("label", null, [
$data.hasSlotContent(_ctx.$slots.label) || $props.label ? (openBlock(), createElementBlock("div", mergeProps({
key: 0,
"aria-details": $options.labelAriaDetails,
class: [
"d-label",
$data.LABEL_SIZE_MODIFIERS[$props.size],
$props.labelClass
]
}, $props.labelChildProps, { "data-qa": "dt-select-label" }), [
renderSlot(_ctx.$slots, "label", {}, () => [
createTextVNode(toDisplayString($props.label), 1)
])
], 16, _hoisted_1)) : createCommentVNode("", true),
$data.hasSlotContent(_ctx.$slots.description) || $props.description ? (openBlock(), createElementBlock("div", mergeProps({
key: 1,
id: $options.descriptionKey,
class: [
"d-description",
$data.DESCRIPTION_SIZE_MODIFIERS[$props.size],
$props.descriptionClass
]
}, $props.descriptionChildProps, { "data-qa": "dt-select-description" }), [
renderSlot(_ctx.$slots, "description", {}, () => [
createTextVNode(toDisplayString($props.description), 1)
])
], 16, _hoisted_2)) : createCommentVNode("", true),
createElementVNode("div", {
class: normalizeClass([
"d-select",
$data.SELECT_SIZE_MODIFIERS[$props.size],
$props.selectClass,
{ "d-select--disabled": $props.disabled }
]),
"data-qa": "dt-select-wrapper"
}, [
createElementVNode("select", mergeProps({
ref: "selectElement",
class: [
"d-select__input",
$data.SELECT_STATE_MODIFIERS[$options.state]
]
}, $options.removeClassStyleAttrs(_ctx.$attrs), {
"data-qa": "dt-select",
disabled: $props.disabled
}, toHandlers($options.selectListeners, true)), [
renderSlot(_ctx.$slots, "default", {}, () => [
(openBlock(true), createElementBlock(Fragment, null, renderList($props.options, (option) => {
return openBlock(), createElementBlock("option", mergeProps({
key: $options.getOptionKey(option.value),
value: option.value,
class: $props.optionClass
}, $props.optionChildProps), toDisplayString(option.label), 17, _hoisted_4);
}), 128))
])
], 16, _hoisted_3)
], 2)
]),
createVNode(_component_dt_validation_messages, mergeProps({
"validation-messages": _ctx.formattedMessages,
"show-messages": _ctx.showMessages,
class: _ctx.messagesClass
}, _ctx.messagesChildProps, { "data-qa": "dt-select-messages" }), null, 16, ["validation-messages", "show-messages", "class"])
], 16);
}
const select_menu = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
select_menu as default
};
//# sourceMappingURL=select_menu.vue.js.map