skills/mapbox-store-locator-patterns/references/optimization-a11y.md

2.9 KiB

Performance, Best Practices & Accessibility

Performance Optimization

function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

const debouncedFilter = debounce(filterStores, 300);

document.getElementById('search-input').addEventListener('input', (e) => {
  debouncedFilter(e.target.value);
});

Best Practices

Data Management

// GOOD: Load data once, filter in memory
const allStores = await fetch('/api/stores').then((r) => r.json());

function filterStores(criteria) {
  return {
    type: 'FeatureCollection',
    features: allStores.features.filter(criteria)
  };
}

// BAD: Fetch on every filter
async function filterStores(criteria) {
  return await fetch(`/api/stores?filter=${criteria}`).then((r) => r.json());
}

Error Handling

// Geolocation error handling
navigator.geolocation.getCurrentPosition(
  successCallback,
  (error) => {
    let message = 'Unable to get your location.';

    switch (error.code) {
      case error.PERMISSION_DENIED:
        message = 'Please enable location access to see nearby stores.';
        break;
      case error.POSITION_UNAVAILABLE:
        message = 'Location information is unavailable.';
        break;
      case error.TIMEOUT:
        message = 'Location request timed out.';
        break;
    }

    showNotification(message);
  },
  {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0
  }
);

// API error handling
async function loadStores() {
  try {
    const response = await fetch('/api/stores');

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Failed to load stores:', error);
    showNotification('Unable to load store locations. Please try again.');
    return { type: 'FeatureCollection', features: [] };
  }
}

Accessibility

// Add ARIA labels
document.getElementById('search-input').setAttribute('aria-label', 'Search stores');

// Keyboard navigation
document.querySelectorAll('.listing').forEach((listing, index) => {
  listing.setAttribute('tabindex', '0');
  listing.setAttribute('role', 'button');
  listing.setAttribute('aria-label', `View ${listing.querySelector('.title').textContent}`);

  listing.addEventListener('keypress', (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      listing.click();
    }
  });
});

// Focus management
function highlightListing(id) {
  const listing = document.getElementById(`listing-${id}`);
  listing.classList.add('active');
  listing.focus();
  listing.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}