/** * Planner — a month of days, each carrying what falls on it. * * ```tsx * const [month, setMonth] = useState(new Date()); * * * * * * * * * * * {(date, entries) => {entries.length} on {date.toDateString()}} * * * ``` * * ## How it differs from Calendar * * `Calendar` picks a date and answers with one. This shows what is already on * the days and answers with the day you asked about — the selection exists to * open something, not to be submitted. * * ## Why it draws its own Frame * * A month at a glance is a widget: a boundary, a strip along the top carrying * the month and the way through it, and a footer that holds still while the * middle changes. That is `Frame`, so the root renders one instead of leaving * every caller to assemble the same shell. Pass `frame={false}` to drop it, * for a planner in a sheet or a card that already draws its own edge. * * ## Why the grid is always six weeks * * A month can span five weeks or six. Drawn at its natural height the panel * jumps as you page through the year and the days appear to move under your * thumb, so the grid is always six rows and the last one is sometimes all * next month. `Calendar` fixes its height for the same reason. * * ## Why a day says more than its date * * The marker on a day is a coloured dot, and colour is a signal that does not * reach everyone looking at it. So the legend prints its label beside every * swatch, and a day is spoken as its date, how many entries it carries and * which categories they belong to. Neither is decoration: between them they * are the whole content of the grid for somebody who cannot see it. */ import { type ReactNode } from 'react'; import { View, type ViewProps } from 'react-native'; import { type TextProps } from '../../primitives/text.js'; import { type CalendarSystem, type DateLocale } from '../../utils/date.js'; import { type PlannerCountedCategory } from './planner-entries.js'; /** * What a day cell draws. * * `default` is a number, a marker and small icons. `tiles` gives the day over * to one large icon tinted with its category's colour, with the date in the * corner. `calendar` names each entry in a block under a centred date, on an * open grid ruled off by week. */ export type PlannerVariant = 'default' | 'tiles' | 'calendar'; /** One thing that falls on a day. */ export interface PlannerEntry { /** Stable across renders; it keys the cell's contents. */ id: string; /** When it falls. The time of day is kept but not read by the grid. */ date: Date; /** Named in the dialog and, through its category, in the day's spoken label. */ label: string; /** Matches a `PlannerCategory` id. Without one the entry is still counted. */ category?: string; /** Drawn in the cell — a brand mark, an avatar, a glyph. */ icon?: ReactNode; /** * This entry's own colour, for a mark that belongs to the entry rather than * to a group of them — a brand. It wins over the category's colour, and * under `tiles` it is what tints the day. */ color?: string; } /** A group of entries: the key to a colour, and a line in the legend. */ export interface PlannerCategory { id: string; /** Printed beside the swatch, and spoken as part of a day that carries it. */ label: string; /** * Which `--color-chart-*` token the dot takes, 1 to 5. Categories without * one are numbered in the order they are declared. */ colorIndex?: number; /** An explicit colour, for a brand that is not the theme's to choose. */ color?: string; } export interface PlannerProps extends Omit { className?: string; /** The month on show. Leave it out for an uncontrolled planner. */ month?: Date; defaultMonth?: Date; onMonthChange?: (month: Date) => void; /** Everything the planner knows about, in any order and any month. */ entries?: PlannerEntry[]; /** The colour key. Declaration order is legend order and palette order. */ categories?: PlannerCategory[]; /** The open day. `null` is none. Leave it out for an uncontrolled planner. */ selected?: Date | null; defaultSelected?: Date | null; onSelectedChange?: (date: Date | null) => void; /** Runs before the selection moves, whether or not `Details` is present. */ onDayPress?: (date: Date, entries: PlannerEntry[]) => void; /** * What each day draws. `tiles` is one large icon per day, tinted by its * category; `calendar` names every entry and needs the height to do it. */ variant?: PlannerVariant; /** * Stretch the grid to its container instead of standing at its own height. * For a planner that owns a screen — the six weeks share out whatever is * left after the header, the legend and anything below them. */ fill?: boolean; /** * How many entries a cell draws before it counts the rest. Default `2`, or * `3` under `calendar`, which has the room; `tiles` draws one whatever you * pass. */ entryLimit?: number; /** First day of the week, 0 is Sunday. Defaults to the locale's. */ weekStartsOn?: number | 'auto'; locale?: DateLocale; calendar?: CalendarSystem; /** Draw the surrounding `Frame`. Off for a planner in a sheet or a card. */ frame?: boolean; children?: ReactNode; } export interface PlannerHeaderProps { children?: ReactNode; } /** * The strip along the top of the frame. Put `Title`, `Today` and `Nav` in it. * * The strip has two ends rather than an even spread. What the month *is* — * its name, and the way back to today — reads from the leading edge; what * *moves* it sits at the trailing edge, under the thumb that reaches for it. * Spaced evenly across a full-width strip they read as three unrelated * controls instead of a label and a pair of buttons. */ declare function PlannerHeader({ children }: PlannerHeaderProps): import("react").JSX.Element; declare namespace PlannerHeader { var displayName: string; } export interface PlannerTitleProps extends Omit { /** Replaces the month name, for a title that says something else. */ children?: ReactNode; } /** The month on show, in the calendar system and locale the grid uses. */ declare function PlannerTitle({ children, className, ...props }: PlannerTitleProps): import("react").JSX.Element; declare namespace PlannerTitle { var displayName: string; } export interface PlannerTodayProps { /** Replaces the word on the pill. */ children?: ReactNode; } /** Jumps back to the month today is in, and selects nothing. */ declare function PlannerToday({ children }: PlannerTodayProps): import("react").JSX.Element; declare namespace PlannerToday { var displayName: string; } export interface PlannerNavProps { className?: string; } /** Back and forward a month. */ declare function PlannerNav({ className }: PlannerNavProps): import("react").JSX.Element; declare namespace PlannerNav { var displayName: string; } export interface PlannerActionProps { children?: ReactNode; } /** The trailing end of the header strip, for a button of the caller's. */ declare function PlannerAction({ children }: PlannerActionProps): import("react").JSX.Element; declare namespace PlannerAction { var displayName: string; } /** What a custom cell is handed. Everything the default cell draws from. */ export interface PlannerDayState { date: Date; entries: PlannerEntry[]; isToday: boolean; isSelected: boolean; isInMonth: boolean; } export type PlannerDayRenderer = (state: PlannerDayState) => ReactNode; export interface PlannerGridProps { className?: string; /** Draws a cell yourself. It is handed the day and what falls on it. */ renderDay?: PlannerDayRenderer; } /** * The weekday row and the six weeks below it. * * React Native has no per-cell grid vocabulary — no `gridcell`, no `row` — so * a screen reader never hears "row three, column five" and cannot fall back on * position for context. Every day therefore carries its own full date, and the * weekday headings are hidden rather than read out 42 times over. */ declare function PlannerGrid({ className, renderDay }: PlannerGridProps): import("react").JSX.Element; declare namespace PlannerGrid { var displayName: string; } export interface PlannerDayProps { date: Date; renderDay?: PlannerDayRenderer; } /** One cell. Pressing it selects the day and opens whatever is bound to it. */ declare function PlannerDay({ date, renderDay }: PlannerDayProps): import("react").JSX.Element; export interface PlannerLegendProps { className?: string; /** Print each category's count for the month beside its label. */ counts?: boolean; /** Sits at the trailing end — a total, a currency, whatever the month adds to. */ children?: ReactNode; } /** * The key to the dots. * * It prints the label beside every swatch, because a column of coloured dots * with nothing to read them against is a quiz. */ declare function PlannerLegend({ className, counts, children }: PlannerLegendProps): import("react").JSX.Element; declare namespace PlannerLegend { var displayName: string; } export interface PlannerSummaryProps extends Omit { /** Replaces the count, for a total that is money rather than entries. */ children?: ReactNode; } /** What the month adds up to. Counts this month only, never the days either side. */ declare function PlannerSummary({ children, ...props }: PlannerSummaryProps): import("react").JSX.Element; declare namespace PlannerSummary { var displayName: string; } export interface PlannerFooterProps { className?: string; children?: ReactNode; } /** The strip along the bottom, for tools that act on the month. */ declare function PlannerFooter({ className, children }: PlannerFooterProps): import("react").JSX.Element; declare namespace PlannerFooter { var displayName: string; } export interface PlannerDetailsProps { className?: string; /** Title above the children. Defaults to the day's full date. */ title?: ReactNode; /** * The line under the title. Defaults to how many entries the day carries, * so the dialog answers "how much of this is there" before it is read. * Pass `null` to drop it. */ description?: ReactNode; /** Given the open day and what falls on it. */ children: (date: Date, entries: PlannerEntry[]) => ReactNode; } /** * A dialog bound to the open day. * * The planner owns the grid and the binding; what the dialog says is the * application's, because the contents of a day are its data and not the * component's. Leave it out and `onDayPress` is still called — a planner that * pushes a screen instead of opening a dialog wants that and nothing else. */ declare function PlannerDetails({ className, title, description, children }: PlannerDetailsProps): import("react").JSX.Element; declare namespace PlannerDetails { var displayName: string; } export interface PlannerScrollerProps { className?: string; /** * How many weeks either side of the opening month can be reached. Default * `53`, about a year each way. */ weeks?: number; /** The height of one week row. Default `96`. */ rowHeight?: number; /** Draws a cell yourself. It is handed the day and what falls on it. */ renderDay?: PlannerDayRenderer; } /** * The weeks of the year, scrolled through rather than paged. * * A month grid answers "what does this month look like"; a scroller answers * "what is coming", which does not stop at the end of a month. The week * straddling the boundary is drawn once, in one piece, instead of appearing cut * in half at the bottom of one page and again at the top of the next. * * The range is bounded rather than endless. A scroller has to know its own * height to place a scrollbar and to jump to a month without rendering its way * there, and neither is possible over a list with no end. * * The month in the header follows the scroll: whichever month holds most of the * first week on screen is the one named, and the days either side of it grey * out. `Planner.Nav` and `Planner.Today` still work — they scroll the list * rather than replacing what is in it. */ declare function PlannerScroller({ className, weeks: span, rowHeight, renderDay, }: PlannerScrollerProps): import("react").JSX.Element; declare namespace PlannerScroller { var displayName: string; } export declare const Planner: import("react").ForwardRefExoticComponent> & { Header: typeof PlannerHeader; Title: typeof PlannerTitle; Today: typeof PlannerToday; Nav: typeof PlannerNav; Action: typeof PlannerAction; Grid: typeof PlannerGrid; Scroller: typeof PlannerScroller; Day: typeof PlannerDay; Legend: typeof PlannerLegend; Summary: typeof PlannerSummary; Footer: typeof PlannerFooter; Details: typeof PlannerDetails; }; export type { PlannerCountedCategory }; //# sourceMappingURL=index.d.ts.map