@synapxlab/timeline

Carrousel de navigation hebdomadaire TypeScript — zéro dépendance runtime.
Drag & flick avec momentum, snap spring, thème auto, persistance localStorage. Drop-in dans n'importe quel projet.

  • Zéro dépendance runtime (pas de React, Vue, jQuery)
  • Drag & flick avec momentum physique et spring au snap
  • Thème auto dark/light via prefers-color-scheme
  • Persistance localStorage et adaptateur FullCalendar
  • ESM + UMD — fonctionne dans tous les frameworks
TypeScript ESM UMD MIT
timeline.ts
import { WeekTimeline } from '@synapxlab/timeline'; import '@synapxlab/timeline/style'; const tl = new WeekTimeline({ container: document.getElementById('tl'), theme: 'auto', storageKey: 'my-week', }); // Navigation programmatique tl.goToToday(); tl.setDate(new Date('2025-01-01'));

Démo interactive

Glissez, lancez, utilisez la molette ou les touches ← → Début. L'item central est toujours la semaine active.

Installation

# npm
npm install @synapxlab/timeline

# pnpm
pnpm add @synapxlab/timeline

# yarn
yarn add @synapxlab/timeline

Démarrage rapide

import { WeekTimeline } from '@synapxlab/timeline';
import '@synapxlab/timeline/style';

const timeline = new WeekTimeline({
  container:      document.getElementById('timeline'),
  theme:          'auto',         // suit le système
  storageKey:     'mon-app-week', // persistance localStorage
  firstDayOfWeek: 1,              // lundi
  onWeekChange(detail) {
    console.log(detail.week.start, '→', detail.week.end);
  },
});

Pour un usage via <script> UMD :

<link   rel="stylesheet" href="week-timeline.css">
<script src="week-timeline.umd.cjs"></script>
<script>
  const tl = new WeekTimeline({ container: document.getElementById('tl') });
</script>

Options

OptionTypeDéfautDescription
container HTMLElement Élément DOM cible (obligatoire)
theme 'light' | 'dark' | 'auto' 'light' 'auto' suit prefers-color-scheme en temps réel
locale string navigator.language Locale BCP-47. Détectée automatiquement (fr, en, de, it, es…)
firstDayOfWeek 0 | 1 1 0 = dimanche, 1 = lundi
storageKey string Clé localStorage pour mémoriser la dernière semaine entre rechargements
compact boolean false Mode compact, hauteur réduite
onWeekChange (detail) => void Callback appelé au snap et à la navigation programmatique avec { date, week: { start, end } }
onWeekPreview (detail) => void Callback temps réel pendant le drag, avant le snap

API publique

MéthodeDescription
setDate(date: Date) Navigue vers la semaine contenant la date donnée
getDate(): Date Retourne la date de référence de la semaine sélectionnée
goToToday() Navigue vers la semaine courante
goToPrevious() Navigue vers la semaine précédente
goToNext() Navigue vers la semaine suivante
on(event, handler) Abonnement aux événements DOM (weekchange, weekselect, weeknavigate)
connectAdapter(adapter) Connecte un adaptateur externe (ex. FullCalendar)
debugState() Retourne l'état interne complet (dev / inspection)
destroy() Supprime les listeners, les observers et le DOM

Événements DOM

La timeline émet des événements natifs CustomEvent sur son nœud conteneur.

ÉvénementDéclenchementdetail
weekchange Après le snap (navigation validée) { date, week: { start, end } }
weekselect Clic direct sur un item { date, week: { start, end } }
weeknavigate Navigation programmatique (setDate, goToToday…) { date, week: { start, end } }
// Écoute native
container.addEventListener('weekchange', (e) => {
  const { date, week } = (e as CustomEvent).detail;
  console.log('Semaine :', week.start, '→', week.end);
});

// Via l'API .on()
timeline.on('weekchange', (detail) => {
  console.log(detail.week.start);
});

Adaptateur FullCalendar

Liaison bidirectionnelle : la timeline pilote FullCalendar et vice-versa.

import { WeekTimeline, bindTimelineToCalendar } from '@synapxlab/timeline';
import { Calendar } from '@fullcalendar/core';

const calendar = new Calendar(calendarEl, { /* options FullCalendar */ });
calendar.render();

const timeline = new WeekTimeline({ container: timelineEl });

// Liaison bidirectionnelle
const unbind = bindTimelineToCalendar(timeline, calendar);

// Pour délier plus tard
unbind();

Ou via l'adaptateur bas niveau :

import { createFullCalendarAdapter } from '@synapxlab/timeline';

const adapter = createFullCalendarAdapter(calendar);
timeline.connectAdapter(adapter);

Thème & dark mode

Trois modes disponibles via l'option theme :

  • 'light' — thème clair (défaut)
  • 'dark' — thème sombre forcé
  • 'auto' — suit prefers-color-scheme en temps réel via MediaQueryList

En mode manuel, basculer le thème en toggleant la classe CSS :

// Forcer le dark sur le conteneur
container.querySelector('.wt').classList.toggle('wt--dark', true);

// Ou via attribut data
container.setAttribute('data-theme', 'dark');

Variables CSS

Personnalisez l'apparence via des propriétés CSS sur le conteneur ou globalement :

VariableDéfaut (light)Description
--wt-bg#f1f5f9Fond de la piste
--wt-item-bg#fffFond d'un item
--wt-item-bg-active#0ea5e9Fond de l'item sélectionné
--wt-text#0f172aCouleur de texte principale
--wt-text-muted#94a3b8Texte secondaire (année, mois tronqué)
--wt-accent#0ea5e9Couleur d'accentuation
--wt-today-dot#f97316Point indicateur semaine courante
--wt-radius10pxRayon des items
--wt-height72pxHauteur de la piste
/* Exemple : couleur d'accent personnalisée */
#mon-conteneur {
  --wt-accent:        #6366f1;
  --wt-item-bg-active: #6366f1;
}

Fonctionnalités

  • Drag & flick avec momentum physique et snap au centre
  • Animation spring au snap (rebond amorti, 420 ms)
  • Effet de profondeur scale + opacité pendant le glissement
  • Label de plage de dates avec Intl.DateTimeFormat.formatRange — sans répétition du mois ("18 – 24 août")
  • Mois complet sur la semaine sélectionnée, abrégé (3 lettres) aux frontières
  • Label d'année aux frontières annuelles
  • Point indicateur sur la semaine courante
  • Extension proactive de la liste pendant le drag (seuil × 2)
  • Navigation molette avec debounce, clavier (← → Début) et tactile
  • Feedback haptique sur mobile (navigator.vibrate)
  • Thème sombre automatique via prefers-color-scheme
  • Persistance localStorage configurable
  • Adaptateur FullCalendar bidirectionnel inclus
  • Propriétés CSS personnalisables (--wt-accent, --wt-bg…)
  • Mode compact via compact: true
  • ResizeObserver pour la gestion du redimensionnement
  • ESM + UMD — drop-in dans tous les frameworks

Compatibilité

Zéro dépendance runtime — fonctionne dans React, Vue, Angular, Svelte, Vanilla JS, ou tout autre environnement.
🌐
Chrome
≥ 90
🦊
Firefox
≥ 90
🧭
Safari
≥ 14
🔷
Edge
≥ 90
📱
iOS Safari
≥ 14
🤖
Android Chrome
≥ 90
📦
Node.js
≥ 18 (SSR)