Base

Active Item Plugin

Track which item is currently active in the registry.

The Active Item Plugin tracks which item is currently active in the registry. It's perfect for implementing tabs, navigation menus, or any single-selection scenario where only one item should be active at a time.

Installation

import { useCheckIn } from 'vue-airport';
import { createActiveItemPlugin } from '@vue-airport/plugins-base';

const { createDesk } = useCheckIn<TabItem>();
const { desk } = createDesk('tabs', {
  plugins: [createActiveItemPlugin()]
});

Basic Usage

interface TabItem {
  label: string;
  content: string;
}

const { createDesk } = useCheckIn<TabItem>();
const { desk } = createDesk('tabs', {
  plugins: [createActiveItemPlugin()]
});

// Check in some tabs
desk.checkIn('tab-1', { label: 'Home', content: 'Welcome' });
desk.checkIn('tab-2', { label: 'About', content: 'About us' });
desk.checkIn('tab-3', { label: 'Contact', content: 'Get in touch' });

// Set active tab
desk.setActive('tab-1');

// Get active tab
const active = desk.getActive();
console.log(active?.data.label); // 'Home'

// Check if there's an active item
console.log(desk.hasActive); // true

// Get active ID directly
console.log(desk.activeId); // 'tab-1'

// Clear active
desk.clearActive();
console.log(desk.hasActive); // false

Events

The plugin emits an active-changed event whenever the active item changes:

desk.on('active-changed', ({ id, data }) => {
  if (id === undefined) {
    console.log('Active cleared');
  } else {
    console.log('Active changed to:', id, data);
  }
});

desk.setActive('tab-1');
// Logs: 'Active changed to: tab-1 { label: 'Home', content: 'Welcome' }'

desk.clearActive();
// Logs: 'Active cleared'

Component Integration

Here's how to use the Active Item Plugin in a Vue component:

<script setup lang="ts">
import { useCheckIn, createActiveItemPlugin } from 'vue-airport';

interface Tab {
  label: string;
  content: string;
}

const { createDesk } = useCheckIn<Tab>();
const { desk } = createDesk('tabs', {
  plugins: [createActiveItemPlugin()]
});

// Initialize tabs
const tabs = [
  { id: 'home', label: 'Home', content: 'Welcome home' },
  { id: 'about', label: 'About', content: 'About us' },
  { id: 'contact', label: 'Contact', content: 'Contact us' }
];

tabs.forEach(tab => {
  desk.checkIn(tab.id, { label: tab.label, content: tab.content });
});

// Set initial active tab
desk.setActive('home');

// Get active tab for display
const activeTab = computed(() => desk.getActive());
</script>

<template>
  <div class="tabs">
    <div class="tab-buttons">
      <button
        v-for="item in desk.items"
        :key="item.id"
        :class="{ active: desk.activeId === item.id }"
        @click="desk.setActive(item.id)"
      >
        {{ item.data.label }}
      </button>
    </div>
    
    <div class="tab-content">
      <p v-if="activeTab">{{ activeTab.data.content }}</p>
      <p v-else>No tab selected</p>
    </div>
  </div>
</template>

API Reference

Methods

setActive(id: string | number | null): boolean

Sets the active item by ID. Returns true if successful, false if the item doesn't exist.

desk.setActive('tab-1'); // true
desk.setActive('non-existent'); // false
desk.setActive(null); // Clears active, returns true

getActive(): CheckInItem<T> | null

Returns the currently active item or null if no item is active.

const active = desk.getActive();
if (active) {
  console.log(active.id, active.data);
}

clearActive(): boolean

Clears the active item. Equivalent to setActive(null).

desk.clearActive();
console.log(desk.hasActive); // false

Properties

activeId: Ref<string | number | null>

A reactive reference to the ID of the currently active item.

watchEffect(() => {
  console.log('Active ID:', desk.activeId);
});

desk.setActive('tab-1');
// Logs: 'Active ID: tab-1'

hasActive: boolean

A computed boolean indicating whether there's an active item.

if (desk.hasActive) {
  console.log('There is an active item');
}

Events

active-changed

Emitted when the active item changes.

desk.on('active-changed', ({ id, data }) => {
  // id and data are undefined when cleared
  // otherwise, id is the item ID and data is the item data
});

Use Cases

interface MenuItem {
  label: string;
  route: string;
}

const { desk } = createDesk('menu', {
  plugins: [createActiveItemPlugin()]
});

// Listen to route changes
desk.on('active-changed', ({ id, data }) => {
  if (data) {
    router.push(data.route);
  }
});
interface Image {
  url: string;
  caption: string;
}

const { desk } = createDesk('gallery', {
  plugins: [createActiveItemPlugin()]
});

// Show full-size image when selected
const selectedImage = computed(() => desk.getActive());

Form Sections

interface FormSection {
  title: string;
  fields: string[];
}

const { desk } = createDesk('form-sections', {
  plugins: [createActiveItemPlugin()]
});

// Navigate through form sections
const goToNextSection = () => {
  const current = desk.getActive();
  if (current) {
    const items = desk.items;
    const currentIndex = items.findIndex(item => item.id === current.id);
    if (currentIndex < items.length - 1) {
      desk.setActive(items[currentIndex + 1].id);
    }
  }
};

Tips

Auto-clearing on check-out: The active item is NOT automatically cleared when the active item is checked out. You need to handle this manually if desired.
desk.on('check-out', ({ id }) => {
  if (desk.activeId === id) {
    desk.clearActive();
    // Or set a new active item
    const remaining = desk.items;
    if (remaining.length > 0) {
      desk.setActive(remaining[0].id);
    }
  }
});
Setting active on non-existent items: Calling setActive() with an ID that doesn't exist in the registry will return false and not change the active item.

Examples

See the Tabs Example for a complete working implementation.