calendar-tsx

List view

An agenda of the days that have events.

An agenda: the days that have events, each with its events in order.

Loading the preview…

Live, with sample events. Click an event to see what it reports.
import { listView } from '@calendar-tsx/core';

listView({ days: 7 });
listView({ period: 'month' });
listView({ period: 'quarter' });
listView({ months: 3 });
listView({ weeks: 1, hiddenDays: [6, 7] });

Every view factory takes exactly one of days, weeks, months or period. Counts are positive integers.

DurationRangenext() / prev()
days: NN dates from date; 7 keeps week alignment.N days.
weeks: NN whole weeks from firstDayOfWeek.N weeks, keeping the weekday.
months: NN calendar months from the first of the anchor month.N months, landing on the first day.
period'month', 'quarter' or 'year', aligned to its calendar boundary.One period, landing on its first day.

The list shows only days with at least one event, so a quiet range has no days; render ListViewEmpty for it. hiddenDays omits weekdays as in the other views (see hidden weekdays).

Resource grouping

groupBy turns the agenda into resource and date sections:

listView({ weeks: 1, groupBy: 'resource' });
listView({ weeks: 1, groupBy: ['resource', 'date'] });
listView({ weeks: 1, groupBy: ['date', 'resource'] });

'resource' and ['resource'] mean resources first, then their dates; the ordered pairs choose which comes outside. Omitting groupBy, or passing 'date' or ['date'], gives the ordinary agenda. Keys cannot repeat, and 'month' grouping exists only in day grids.

Resources follow their input order and dates are chronological. An event assigned to several known resources appears in each group. Resource agendas leave out unassigned events and unknown resource IDs, as resource grids and timelines do; ordinary agendas include them. Empty dates and resources are omitted, so an agenda with no matching events has one list-wide empty state.

Resources before dates

With groupBy: 'resource' or ['resource', 'date'], each section names a resource and lists its dates.

Loading the preview…

Live, with sample events. Click an event to see what it reports.

Open the resource-first agenda in the playground.

Dates before resources

With groupBy: ['date', 'resource'], each section shows a date and lists the resources with events on that date.

Loading the preview…

Live, with sample events. Click an event to see what it reports.

Open the date-first agenda in the playground.

Render layout.sections with ListViewSection and ListViewSectionHeader, then each section's days with the day and event parts. Day headings show dates in resource-first lists and resource names in date-first lists. Both orders work with every duration and hiddenDays.

Date headings

The supplied themes place the date beside its event rows. Give ListViewDayHeader a <time dateTime={day.date.toString()}> holding a <strong> day number and a <span> with the weekday and month or year, as the React and Solid examples do. The full date stays the heading's accessible name; you format it.

The date column narrows with the list and its labels wrap. --calendar-list-date-width (default 10rem) caps its width. ListViewDay emits --cal-events so the heading spans the day's event rows; render the header and events as direct children of the day.

Example

useLayout narrows the layout for <Show>; see narrowing the layout.

list-view.tsx
export const Agenda = () => {
  const list = useLayout('list');

  return (
    <Show when={list()}>
      {list => (
        <ListView model={list()}>
          <For each={list().sections}>
            {section => (
              <ListViewSection
                section={section}
                aria-label={section.resource?.title ?? section.date?.toLocaleString('en-US', { dateStyle: 'full' })}
              >
                <Show when={section.resource || section.date}>
                  <ListViewSectionHeader section={section}>
                    {section.resource?.title ?? section.date?.toLocaleString('en-US', { dateStyle: 'full' })}
                  </ListViewSectionHeader>
                </Show>
                <For each={section.days}>
                  {day => (
                    <ListViewDay day={day}>
                      <ListViewDayHeader
                        day={day}
                        aria-label={
                          section.date ? day.resource?.title : day.date.toLocaleString('en-US', { dateStyle: 'full' })
                        }
                      >
                        <Show when={!section.date} fallback={day.resource?.title}>
                          <time dateTime={day.date.toString()}>
                            <strong>{day.date.toLocaleString('en-US', { day: 'numeric' })}</strong>{' '}
                            <span>
                              <span>{day.date.toLocaleString('en-US', { weekday: 'short' })}</span>{' '}
                              <span>{day.date.toLocaleString('en-US', { month: 'short', year: 'numeric' })}</span>
                            </span>
                          </time>
                        </Show>
                      </ListViewDayHeader>
                      <For each={day.events}>
                        {event => <ListViewEvent event={event}>{event.data.title}</ListViewEvent>}
                      </For>
                    </ListViewDay>
                  )}
                </For>
              </ListViewSection>
            )}
          </For>
          <ListViewEmpty>No events this week</ListViewEmpty>
        </ListView>
      )}
    </Show>
  );
};

Model

layout is { kind: 'list', coordinates, sections, days }.

  • Each section is { key, resource?, date?, days }. resource identifies a resource-first section; date identifies a date-first section. Ordinary lists have one section with neither field.
  • Each day is { key, date, resource?, events }. Grouped day keys identify both the date and resource.
  • layout.days is a flat index of the same day objects in section order. Section headings need sections.

Calendar_ListLayout, Calendar_ListSection and Calendar_ListDay take event data, resource data and features as generic parameters. A feature that decorates days must update the sections and rebuild the flat index from them.

Parts

PartModel propElementNotes
ListViewmodeldivrole='region', labelled "Event list".
ListViewSectionsectionsectiondata-date or data-resource-id; supply an accessible label for grouped sections.
ListViewSectionHeadersectionh2Consumer-supplied date or resource heading.
ListViewDaydaysectiondata-date, optional data-resource-id.
ListViewDayHeaderdayh3
ListViewEventeventbutton
ListViewEmptynonedivRenders only when the list has no days.