UNPKG

@fullcalendar/vue3

Version:

The official Vue 3 component for FullCalendar

139 lines 5.17 kB
import { defineComponent, h, Fragment, Teleport } from 'vue'; import { Calendar } from '@fullcalendar/core'; import { CustomRenderingStore } from '@fullcalendar/core/internal'; import { OPTION_IS_COMPLEX } from './options.js'; const FullCalendar = defineComponent({ props: { options: Object }, data() { return { renderId: 0, customRenderingMap: new Map() }; }, methods: { getApi() { return getSecret(this).calendar; }, buildOptions(suppliedOptions) { return { ...suppliedOptions, customRenderingMetaMap: kebabToCamelKeys(this.$slots), handleCustomRendering: getSecret(this).handleCustomRendering, }; }, }, render() { const customRenderingNodes = []; for (const customRendering of this.customRenderingMap.values()) { customRenderingNodes.push(h(CustomRenderingComponent, { key: customRendering.id, customRendering, })); } return h('div', { // when renderId is changed, Vue will trigger a real-DOM async rerender, calling beforeUpdate/updated attrs: { 'data-fc-render-id': this.renderId } }, h(Fragment, customRenderingNodes)); // for containing CustomRendering keys }, mounted() { const customRenderingStore = new CustomRenderingStore(); getSecret(this).handleCustomRendering = customRenderingStore.handle.bind(customRenderingStore); const calendarOptions = this.buildOptions(this.options); const calendar = new Calendar(this.$el, calendarOptions); getSecret(this).calendar = calendar; calendar.render(); customRenderingStore.subscribe((customRenderingMap) => { this.customRenderingMap = customRenderingMap; // likely same reference, so won't rerender this.renderId++; // force rerender getSecret(this).needCustomRenderingResize = true; }); }, beforeUpdate() { this.getApi().resumeRendering(); // the watcher handlers paused it }, updated() { if (getSecret(this).needCustomRenderingResize) { getSecret(this).needCustomRenderingResize = false; this.getApi().updateSize(); } }, beforeUnmount() { this.getApi().destroy(); }, watch: buildWatchers() }); export default FullCalendar; // Custom Rendering // ------------------------------------------------------------------------------------------------- const CustomRenderingComponent = defineComponent({ props: { customRendering: Object }, render() { const customRendering = this.customRendering; const innerContent = typeof customRendering.generatorMeta === 'function' ? customRendering.generatorMeta(customRendering.renderProps) : // vue-normalized slot function customRendering.generatorMeta; // probably a vue JSX node returned from content-inject func return h(Teleport, { to: customRendering.containerEl }, innerContent); } }); // storing internal state: // https://github.com/vuejs/vue/issues/1988#issuecomment-163013818 function getSecret(inst) { return inst; } function buildWatchers() { let watchers = { // watches changes of ALL options and their nested objects, // but this is only a means to be notified of top-level non-complex options changes. options: { deep: true, handler(options) { let calendar = this.getApi(); calendar.pauseRendering(); let calendarOptions = this.buildOptions(options); calendar.resetOptions(calendarOptions); this.renderId++; // will queue a rerender } } }; for (let complexOptionName in OPTION_IS_COMPLEX) { // handlers called when nested objects change watchers[`options.${complexOptionName}`] = { deep: true, handler(val) { // unfortunately the handler is called with undefined if new props were set, but the complex one wasn't ever set if (val !== undefined) { let calendar = this.getApi(); calendar.pauseRendering(); calendar.resetOptions({ [complexOptionName]: val }, [complexOptionName]); this.renderId++; // will queue a rerender } } }; } return watchers; } // General Utils // ------------------------------------------------------------------------------------------------- function kebabToCamelKeys(map) { const newMap = {}; for (const key in map) { newMap[kebabToCamel(key)] = map[key]; } return newMap; } function kebabToCamel(s) { return s .split('-') .map((word, index) => index ? capitalize(word) : word) .join(''); } function capitalize(s) { return s.charAt(0).toUpperCase() + s.slice(1); } //# sourceMappingURL=FullCalendar.js.map