> ## Documentation Index
> Fetch the complete documentation index at: https://super-calendar.afonsojramos.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless core

> Build a fully custom calendar from @super-calendar/core's pure logic.

`@super-calendar/core` is the render-agnostic engine both renderers are built on:
date math, the selection model, event layout, recurrence, time-zone conversion,
and the neutral theme tokens. Reach for it directly only when you want entirely
custom UI. Most apps use the [native](/quickstart) or
[react-dom](/guides/dom) components, which already wrap all of this.

```bash theme={null}
npm install @super-calendar/core date-fns
```

`react` is a peer dependency too, for the hooks; the pure functions work without it.

## Month grid

When you want your own day-cell markup but not the date maths, `useMonthGrid`
gives you the grid as data: the weeks, the weekday headers, and per-day state
(today, selected, in-range, disabled, current-month). You render whatever you
like.

```tsx theme={null}
import { View, Text, Pressable } from "react-native";
import { useMonthGrid } from "@super-calendar/core";

function MyMonth({ month, range }: { month: Date; range?: DateRange }) {
  const { weeks, weekdays } = useMonthGrid(month, {
    weekStartsOn: 1,
    selectedRange: range,
  });

  return (
    <View>
      <View style={{ flexDirection: "row" }}>
        {weekdays.map((w) => (
          <Text key={w.label} style={{ flex: 1, textAlign: "center" }}>
            {w.label}
          </Text>
        ))}
      </View>
      {weeks.map((week) => (
        <View key={week.id} style={{ flexDirection: "row" }}>
          {week.days.map((day) => (
            <Pressable key={day.id} style={{ flex: 1 }} disabled={day.isDisabled}>
              <Text
                style={{
                  textAlign: "center",
                  opacity: day.isCurrentMonth ? 1 : 0.4,
                  fontWeight: day.isToday ? "700" : "400",
                  color: day.isSelected ? "#fff" : "#000",
                }}
              >
                {day.label}
              </Text>
            </Pressable>
          ))}
        </View>
      ))}
    </View>
  );
}
```

### Per-day state

Each `day` in `weeks[].days` carries:

| Field                         | Notes                                              |
| ----------------------------- | -------------------------------------------------- |
| `date`                        | The `Date` for the cell.                           |
| `id`                          | Stable `yyyy-MM-dd` string (handy as a React key). |
| `label`                       | Day of month, e.g. `"1"`.                          |
| `isCurrentMonth`              | False for leading/trailing adjacent-month days.    |
| `isToday`                     | Matches the real today.                            |
| `isWeekend`                   | Saturday or Sunday.                                |
| `isDisabled`                  | Fails `minDate`/`maxDate`/`isDateDisabled`.        |
| `isSelected`                  | A `selectedDates` day or a range endpoint.         |
| `isRangeStart` / `isRangeEnd` | The range's two endpoints.                         |
| `isInRange`                   | Inside a complete range (endpoints included).      |

`useMonthGrid(month, options)` accepts `weekStartsOn`, `showSixWeeks`, `isRTL`,
`locale`, `selectedDates`, `selectedRange`, and the `minDate` / `maxDate` /
`isDateDisabled` constraints.

<Tip>
  Need the grid outside React (tests, server, exports)? Call the pure `buildMonthGrid(month,
      options)`; `useMonthGrid` is just a memoized wrapper around it. `buildMonthWeeks(month,
      weekStartsOn)` returns the raw `Date[][]`.
</Tip>

`layoutMonthWeek(days, events)` lays one week row's events out as spanning bars:
each event becomes a single segment carrying the `startCol` / `endCol` it covers,
a `lane` for stacking overlapping events, and `continuesBefore` / `continuesAfter`
flags for bars that run past the row's edges. It's the same layout the built-in
month grid uses, so a custom month cell can draw identical multi-day bars.

## Laying out timed events

`layoutDayEvents(events, day)` resolves overlaps into side-by-side columns for a
day/week grid — the same math the `TimeGrid` uses, with no rendering opinion. Each
`PositionedEvent` gives you placement:

```tsx theme={null}
import { layoutDayEvents } from "@super-calendar/core";

for (const pe of layoutDayEvents(events, day)) {
  // pe.event                              the original event
  // pe.startHours, pe.durationHours       vertical position (hours from midnight)
  // pe.column / pe.columns                left = (column / columns) * 100%, width = 100% / columns
  // pe.continuesBefore / pe.continuesAfter   multi-day clipping flags
}
```

To bucket events by calendar day (for a month or agenda), use
`groupEventsByDay(events)` — a `Map` keyed by `startOfDay(date).toISOString()`
that indexes multi-day events under every day they span. `eventDayKeys(event)`
returns those keys for a single event.

## More in core

Every helper below is pure (safe in tests, on a server, or in a worker). See the
TypeScript types for exact signatures.

* **Drag math** — `cellRangeFromDrag` (a sweep to start/end), `resolveDraggedBounds`
  (a move/resize to snapped bounds), `snapDeltaMinutes`, `shiftMinutes`.
* **Event display** — `eventTimeLabel`, `eventAccessibilityLabel`,
  `titleNumberOfLines` / `titleEllipsizeMode`, `isTimeVisibleAtHeight`, `formatHour`
  (the shared time-grid hour-axis label both renderers default to).
* **Month overflow** — `monthEventCapacity` + `monthVisibleCount` decide how many
  chips fit before a "+N more" row.
* **Business hours** — `closedHourBands(day, businessHours, minHour?, maxHour?)`
  returns the hour spans to shade.
* **Presentation** — `rangeBandKind`, `bandRounding`, `dayBadgeKind` map a day's
  selection state to pill/badge intent (exactly what both renderers consume).
* **Selection** — the `useDateRange` hook, plus pure `nextDateRange`,
  `daySelectionState`, `isDateSelectable`, `isRangeEndpoint`, `isWithinDateRange`.
* **Dates** — `getViewDays`, `getWeekDays`, `getIsToday`, `isWeekend`,
  `isSameCalendarDay`, `minutesIntoDay`, `isAllDayEvent`.
* **Theme tokens** — `lightColors` / `darkColors` (the neutral `CalendarColors`
  palette) to build a theme from scratch.

Recurrence (`expandRecurringEvents`) and time zones (`eventsInTimeZone`,
`toZonedTime`) are pure core helpers too; see the
[Recurring events](/guides/recurring-events) and [Time zones](/guides/time-zones)
guides.
