JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q94028F
  • License MIT

A flexible and resource-centric calendar component for Vue 3, designed for planning and scheduling tasks.

Package Exports

  • atempo-cal
  • atempo-cal/style.css

Readme

AtempoCal

A flexible and resource-centric calendar component for Vue 3, designed for planning and scheduling tasks. AtempoCal is built with TypeScript and leverages the power of the atemporal library for robust date and time handling.

Features

  • Resource-based View: Organizes events by resources (e.g., people, rooms, equipment).
  • Multiple Views: Switch between a full week view and a detailed day view.
  • Scrollable Resources: Week view now supports scrollable resource rows for better handling of many resources.
  • Smart Add Button: Intelligent positioning that automatically avoids overlapping with existing events.
  • Customizable Event Display: Show time, title, description, location, or any custom field in week view events.
  • Autonomous Operation: Works without external state management while still supporting controlled mode.
  • Configurable Dimensions: Set custom height and width through styleOptions.
  • Performance Optimized: Memoized calculations and optimized rendering for better performance.
  • Timezone Aware: Built on atemporal for reliable date/time logic.
  • Customizable: Use slots to customize rendering and CSS variables for theming.
  • TypeScript Support: Fully typed for a better development experience.
  • Lightweight: No heavy dependencies, just Vue and atemporal.

Installation

npm install atempo-cal atemporal vue

Smart Positioning & Enhanced Features

Smart Add Button Positioning

The add event button now features intelligent positioning that automatically detects existing events and positions itself to avoid overlaps. The addButtonPosition prop offers several options:

  • 'smart' (default): Automatically finds the best position to avoid overlapping with events
  • 'center': Always positions the button in the center of the time slot
  • 'top-left', 'top-right', 'bottom-left', 'bottom-right': Fixed corner positions

When events are present, the button automatically becomes smaller and less intrusive while maintaining full functionality.

Customizable Event Display

Control what information is displayed in week view events using the eventDisplayField prop:

  • 'time' (default): Shows the event time range
  • 'title': Shows the event title
  • 'description': Shows the event description
  • 'location': Shows the event location
  • Custom field name: Display any field from your event objects

If the specified field is empty, it gracefully falls back to showing the time.

Performance Optimizations

  • Memoized Calculations: Expensive computations are cached to improve rendering performance
  • Optimized Event Positioning: Enhanced algorithms for better event layout calculations
  • Efficient Re-rendering: Smart updates that only re-render when necessary

Usage

You can register AtempoCal as a global plugin or import it directly into your components.

As a Plugin

Register the component globally in your main application file.

import { AtempoCalPlugin } from 'atempo-cal';
import 'atempo-cal/style.css';

const app = createApp(App);
app.use(AtempoCalPlugin);
app.mount('#app');

As a Component

Import it directly where you need it.

<script setup lang="ts">
import { AtempoCal } from 'atempo-cal';
import 'atempo-cal/dist/style.css';
import { ref } from 'vue';
import type { Resource } from 'atempo-cal'; // Import types

const resources = ref<Resource[]>([
  // ... your resource and event data
]);
</script>

<template>
  <AtempoCal :resources="resources" />
</template>

Advanced Usage Examples

Smart Positioning with Custom Event Display

<template>
  <!-- Show event titles instead of time with smart button positioning -->
  <AtempoCal 
    :resources="resources" 
    event-display-field="title"
    add-button-position="smart"
  />
  
  <!-- Show event locations with fixed button position -->
  <AtempoCal 
    :resources="resources" 
    event-display-field="location"
    add-button-position="top-right"
  />
  
  <!-- Hide add button completely -->
  <AtempoCal 
    :resources="resources" 
    :show-add-button="false"
  />
  
  <!-- Custom field display with fallback to time -->
  <AtempoCal 
    :resources="resources" 
    event-display-field="priority"
    add-button-position="bottom-left"
  />
</template>

Complete Configuration Example

<script setup lang="ts">
import { AtempoCal } from 'atempo-cal';
import 'atempo-cal/dist/style.css';
import { ref } from 'vue';
import type { Resource } from 'atempo-cal';

const resources = ref<Resource[]>([
  {
    id: 1,
    name: 'Conference Room A',
    color: '#3B82F6',
    events: [
      {
        id: 1,
        title: 'Team Meeting',
        from: '2024-01-15T09:00:00',
        to: '2024-01-15T10:30:00',
        description: 'Weekly team sync',
        location: 'Room A',
        priority: 'High'
      }
    ]
  }
]);

const handleEventClick = (event) => {
  console.log('Event clicked:', event);
};

const handleAddEvent = (timeSlot) => {
  console.log('Add event at:', timeSlot);
};
</script>

<template>
  <AtempoCal 
    :resources="resources"
    title="Resource Planner"
    event-display-field="title"
    add-button-position="smart"
    :show-add-button="true"
    :dark-mode="false"
    @event-click="handleEventClick"
    @add-event="handleAddEvent"
  />
</template>

API

Props

Prop Type Default Description
title string 'Internal Resource Planner' The main title displayed in the calendar header.
resources Resource[] [] An array of resource objects, each containing its events. Required.
startDate Date | string atemporal().toDate() The initial date the calendar will display. Defaults to current date.
resourceHeaderText string 'Resources' The text for the header of the resource column.
view 'week' | 'day' 'week' The current view of the calendar. If not provided, managed internally.
styleOptions object See below Styling options for the calendar component.
darkMode boolean false Enables dark mode styling for the calendar.
addButtonPosition AddButtonPosition 'smart' Position of the add event button. Options: 'smart', 'center', 'top-left', 'top-right', 'bottom-left', 'bottom-right'.
eventDisplayField string 'time' Field to display in week view events. Options: 'time', 'title', 'description', 'location', or any custom field name.
showAddButton boolean true Controls visibility of the add event button.

styleOptions Object

interface StyleOptions {
  height?: string;            // Default: 'auto' (min height for 3 resources)
  width?: string;            // Default: '100%'
  dayViewItemWidthPercent?: number; // Default: 95
}

Events

Event Payload Description
view-change (view: 'week' | 'day') Emitted when the user changes the view (e.g., clicks 'Week' or 'Day'). Only emitted when the view prop is provided.
date-change (date: Date) Emitted when the user navigates to a new date period (next/prev/today).
event-click (event: CalendarEvent) Emitted when a user clicks on an event chip. The payload is the full event object.

Slots

Name Scope ({ resource }) Description
header-title - Replaces the entire title section in the header.
header-controls - Replaces the entire control section (navigation and view switcher).
resource-label Resource Customizes the rendering of a resource's name in the resource column.

Data Structures

Here are the primary data structures you'll work with.

Resource

interface Resource {
  id: string | number;
  name: string;
  color?: string; // Optional: will be assigned a color if not provided
  events: Omit<CalendarEvent, 'resourceId' | 'resourceName' | 'color'>[];
}

CalendarEvent

interface CalendarEvent {
  id: string | number;
  title: string;
  from: Date | string;        // Start time (replaces startTime)
  to: Date | string;          // End time (replaces endTime)
  description?: string;       // Event description
  location?: string;          // Event location
  type?: string;              // For custom styling via classes
  // The following are added internally:
  resourceId?: string | number;
  resourceName?: string;
  color?: string;
  start?: Date;               // Processed start date
  end?: Date;                 // Processed end date
  layout?: any;               // Layout information
}

AddButtonPosition

type AddButtonPosition = 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'smart';

Performance

AtempoCal v0.1.7+ includes several performance optimizations:

Memoization

  • Event Processing: Expensive event calculations are memoized to prevent unnecessary re-computation
  • Position Calculations: Smart positioning algorithms cache results for better performance
  • Resource Processing: Resource consolidation and color assignment are optimized

Optimized Rendering

  • Selective Updates: Components only re-render when their specific data changes
  • Efficient Event Layout: Improved algorithms for calculating event positions and overlaps
  • Smart Button Positioning: Collision detection is optimized to run only when necessary

Memory Management

  • Computed Properties: Better use of Vue's reactivity system for automatic dependency tracking
  • Event Listeners: Optimized event handling to prevent memory leaks
  • DOM Updates: Minimized DOM manipulations through efficient virtual DOM usage

Best Practices for Performance

<script setup lang="ts">
// ✅ Good: Use reactive refs for data that changes
const resources = ref<Resource[]>([]);

// ✅ Good: Memoize expensive computations
const processedEvents = computed(() => {
  return resources.value.flatMap(r => r.events);
});

// ❌ Avoid: Creating new objects in template
// <AtempoCal :style-options="{ height: '500px' }" />

// ✅ Better: Define style options outside template
const styleOptions = { height: '500px' };
</script>

<template>
  <AtempoCal 
    :resources="resources"
    :style-options="styleOptions"
  />
</template>

Styling

The component comes with a default stylesheet that you should import.

import 'atempo-cal/dist/style.css';

You can override the default styles using standard CSS. The component uses BEM-like class names (e.g., .atempo-cal, .atempo-cal__header). For more targeted overrides, you can use more specific selectors.

Changelog

v0.1.7 (Latest)

🚀 New Features:

  • Smart Add Button Positioning: Intelligent button placement that avoids overlapping with events
  • Customizable Event Display: Show title, description, location, or any custom field in week view
  • Enhanced Button Control: New showAddButton prop to control button visibility
  • Multiple Positioning Options: Choose from 6 different button positions including smart mode

⚡ Performance Improvements:

  • Memoized expensive calculations for better rendering performance
  • Optimized event positioning algorithms
  • Enhanced memory management and DOM updates
  • Selective component re-rendering

🎨 Visual Enhancements:

  • Better contrast and accessibility
  • Smoother animations and transitions
  • Improved responsive design
  • Enhanced hover states and interactions

🔧 Technical:

  • Full backward compatibility maintained
  • Enhanced TypeScript support
  • Improved prop validation
  • Better error handling

Previous Versions

  • v0.1.6: Bug fixes and stability improvements
  • v0.1.5: Initial scrollable resources support
  • v0.1.0: Initial release with basic calendar functionality

Contributing

Contributions are welcome! Please open an issue or submit a pull request on our GitHub repository.

License

MIT