UNPKG

bootstrap-vue

Version:

With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens

303 lines (283 loc) 11.2 kB
var _watch; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import { extend } from '../../vue'; import { NAME_FORM_DATEPICKER } from '../../constants/components'; import { EVENT_NAME_CONTEXT, EVENT_NAME_HIDDEN, EVENT_NAME_SHOWN } from '../../constants/events'; import { PROP_TYPE_BOOLEAN, PROP_TYPE_DATE_STRING, PROP_TYPE_STRING } from '../../constants/props'; import { SLOT_NAME_BUTTON_CONTENT } from '../../constants/slots'; import { createDate, constrainDate, formatYMD, parseYMD } from '../../utils/date'; import { attemptBlur, attemptFocus } from '../../utils/dom'; import { isUndefinedOrNull } from '../../utils/inspect'; import { makeModelMixin } from '../../utils/model'; import { omit, pick, sortKeys } from '../../utils/object'; import { makeProp, makePropsConfigurable, pluckProps } from '../../utils/props'; import { idMixin, props as idProps } from '../../mixins/id'; import { BIconCalendar, BIconCalendarFill } from '../../icons/icons'; import { BButton } from '../button/button'; import { BCalendar, props as BCalendarProps } from '../calendar/calendar'; import { BVFormBtnLabelControl, props as BVFormBtnLabelControlProps } from '../form-btn-label-control/bv-form-btn-label-control'; // --- Constants --- var _makeModelMixin = makeModelMixin('value', { type: PROP_TYPE_DATE_STRING }), modelMixin = _makeModelMixin.mixin, modelProps = _makeModelMixin.props, MODEL_PROP_NAME = _makeModelMixin.prop, MODEL_EVENT_NAME = _makeModelMixin.event; // --- Props --- var calendarProps = omit(BCalendarProps, ['block', 'hidden', 'id', 'noKeyNav', 'roleDescription', 'value', 'width']); var formBtnLabelControlProps = omit(BVFormBtnLabelControlProps, ['formattedValue', 'id', 'lang', 'rtl', 'value']); export var props = makePropsConfigurable(sortKeys(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, idProps), modelProps), calendarProps), formBtnLabelControlProps), {}, { // Width of the calendar dropdown calendarWidth: makeProp(PROP_TYPE_STRING, '270px'), closeButton: makeProp(PROP_TYPE_BOOLEAN, false), closeButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-secondary'), // Dark mode dark: makeProp(PROP_TYPE_BOOLEAN, false), labelCloseButton: makeProp(PROP_TYPE_STRING, 'Close'), labelResetButton: makeProp(PROP_TYPE_STRING, 'Reset'), labelTodayButton: makeProp(PROP_TYPE_STRING, 'Select today'), noCloseOnSelect: makeProp(PROP_TYPE_BOOLEAN, false), resetButton: makeProp(PROP_TYPE_BOOLEAN, false), resetButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-danger'), resetValue: makeProp(PROP_TYPE_DATE_STRING), todayButton: makeProp(PROP_TYPE_BOOLEAN, false), todayButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-primary') })), NAME_FORM_DATEPICKER); // --- Main component --- // @vue/component export var BFormDatepicker = /*#__PURE__*/extend({ name: NAME_FORM_DATEPICKER, mixins: [idMixin, modelMixin], props: props, data: function data() { return { // We always use `YYYY-MM-DD` value internally localYMD: formatYMD(this[MODEL_PROP_NAME]) || '', // If the popup is open isVisible: false, // Context data from BCalendar localLocale: null, isRTL: false, formattedValue: '', activeYMD: '' }; }, computed: { calendarYM: function calendarYM() { // Returns the calendar year/month // Returns the `YYYY-MM` portion of the active calendar date return this.activeYMD.slice(0, -3); }, computedLang: function computedLang() { return (this.localLocale || '').replace(/-u-.*$/i, '') || null; }, computedResetValue: function computedResetValue() { return formatYMD(constrainDate(this.resetValue)) || ''; } }, watch: (_watch = {}, _defineProperty(_watch, MODEL_PROP_NAME, function (newValue) { this.localYMD = formatYMD(newValue) || ''; }), _defineProperty(_watch, "localYMD", function localYMD(newValue) { // We only update the v-model when the datepicker is open if (this.isVisible) { this.$emit(MODEL_EVENT_NAME, this.valueAsDate ? parseYMD(newValue) || null : newValue || ''); } }), _defineProperty(_watch, "calendarYM", function calendarYM(newValue, oldValue) { // Displayed calendar month has changed // So possibly the calendar height has changed... // We need to update popper computed position if (newValue !== oldValue && oldValue) { try { this.$refs.control.updatePopper(); } catch (_unused) {} } }), _watch), methods: { // Public methods focus: function focus() { if (!this.disabled) { attemptFocus(this.$refs.control); } }, blur: function blur() { if (!this.disabled) { attemptBlur(this.$refs.control); } }, // Private methods setAndClose: function setAndClose(ymd) { var _this = this; this.localYMD = ymd; // Close calendar popup, unless `noCloseOnSelect` if (!this.noCloseOnSelect) { this.$nextTick(function () { _this.$refs.control.hide(true); }); } }, onSelected: function onSelected(ymd) { var _this2 = this; this.$nextTick(function () { _this2.setAndClose(ymd); }); }, onInput: function onInput(ymd) { if (this.localYMD !== ymd) { this.localYMD = ymd; } }, onContext: function onContext(ctx) { var activeYMD = ctx.activeYMD, isRTL = ctx.isRTL, locale = ctx.locale, selectedYMD = ctx.selectedYMD, selectedFormatted = ctx.selectedFormatted; this.isRTL = isRTL; this.localLocale = locale; this.formattedValue = selectedFormatted; this.localYMD = selectedYMD; this.activeYMD = activeYMD; // Re-emit the context event this.$emit(EVENT_NAME_CONTEXT, ctx); }, onTodayButton: function onTodayButton() { // Set to today (or min/max if today is out of range) this.setAndClose(formatYMD(constrainDate(createDate(), this.min, this.max))); }, onResetButton: function onResetButton() { this.setAndClose(this.computedResetValue); }, onCloseButton: function onCloseButton() { this.$refs.control.hide(true); }, // Menu handlers onShow: function onShow() { this.isVisible = true; }, onShown: function onShown() { var _this3 = this; this.$nextTick(function () { attemptFocus(_this3.$refs.calendar); _this3.$emit(EVENT_NAME_SHOWN); }); }, onHidden: function onHidden() { this.isVisible = false; this.$emit(EVENT_NAME_HIDDEN); }, // Render helpers defaultButtonFn: function defaultButtonFn(_ref) { var isHovered = _ref.isHovered, hasFocus = _ref.hasFocus; return this.$createElement(isHovered || hasFocus ? BIconCalendarFill : BIconCalendar, { attrs: { 'aria-hidden': 'true' } }); } }, render: function render(h) { var localYMD = this.localYMD, disabled = this.disabled, readonly = this.readonly, dark = this.dark, $props = this.$props, $scopedSlots = this.$scopedSlots; var placeholder = isUndefinedOrNull(this.placeholder) ? this.labelNoDateSelected : this.placeholder; // Optional footer buttons var $footer = []; if (this.todayButton) { var label = this.labelTodayButton; $footer.push(h(BButton, { props: { disabled: disabled || readonly, size: 'sm', variant: this.todayButtonVariant }, attrs: { 'aria-label': label || null }, on: { click: this.onTodayButton } }, label)); } if (this.resetButton) { var _label = this.labelResetButton; $footer.push(h(BButton, { props: { disabled: disabled || readonly, size: 'sm', variant: this.resetButtonVariant }, attrs: { 'aria-label': _label || null }, on: { click: this.onResetButton } }, _label)); } if (this.closeButton) { var _label2 = this.labelCloseButton; $footer.push(h(BButton, { props: { disabled: disabled, size: 'sm', variant: this.closeButtonVariant }, attrs: { 'aria-label': _label2 || null }, on: { click: this.onCloseButton } }, _label2)); } if ($footer.length > 0) { $footer = [h('div', { staticClass: 'b-form-date-controls d-flex flex-wrap', class: { 'justify-content-between': $footer.length > 1, 'justify-content-end': $footer.length < 2 } }, $footer)]; } var $calendar = h(BCalendar, { staticClass: 'b-form-date-calendar w-100', props: _objectSpread(_objectSpread({}, pluckProps(calendarProps, $props)), {}, { hidden: !this.isVisible, value: localYMD, valueAsDate: false, width: this.calendarWidth }), on: { selected: this.onSelected, input: this.onInput, context: this.onContext }, scopedSlots: pick($scopedSlots, ['nav-prev-decade', 'nav-prev-year', 'nav-prev-month', 'nav-this-month', 'nav-next-month', 'nav-next-year', 'nav-next-decade']), key: 'calendar', ref: 'calendar' }, $footer); return h(BVFormBtnLabelControl, { staticClass: 'b-form-datepicker', props: _objectSpread(_objectSpread({}, pluckProps(formBtnLabelControlProps, $props)), {}, { formattedValue: localYMD ? this.formattedValue : '', id: this.safeId(), lang: this.computedLang, menuClass: [{ 'bg-dark': dark, 'text-light': dark }, this.menuClass], placeholder: placeholder, rtl: this.isRTL, value: localYMD }), on: { show: this.onShow, shown: this.onShown, hidden: this.onHidden }, scopedSlots: _defineProperty({}, SLOT_NAME_BUTTON_CONTENT, $scopedSlots[SLOT_NAME_BUTTON_CONTENT] || this.defaultButtonFn), ref: 'control' }, [$calendar]); } });