UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

274 lines (273 loc) 8.93 kB
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