BlockDex

Components

Registries

Free blocks

Method

BlockDex

Components

Registries

Free blocks

Method

Open API

BlockDex

Components

Registries

Free blocks

Method

Open API

Components/moumenlab/schedule-builder

Schedule Builder

moumenlab/schedule-builder
FreeComponent

A recurrence rule as a live English sentence over real occurrences, with month-end and DST traps.

Live preview

live · rendered by the registry
Rendered by moumenlab on their own page — this is the component running, not a screenshot of it.

Install it

npx shadcn@latest add https://lab.moumen.dev/r/schedule-builder.json

Source

registry/lab/schedule-builder/schedule-builder.tsxlab.moumen.dev/r/schedule-builder.json · first 6 KB
1"use client";
2
3import { useEffect, useMemo, useRef, useState } from "react";
4import { MotionConfig, motion } from "motion/react";
5
6// Schedule builder - a recurrence rule assembled as a live English sentence,
7// with the next N REAL occurrences underneath.
8//
9// The domain is the hard part: recurrence looks like dropdowns but is full of
10// calendar traps, and this build refuses to fake any of them:
11//
12// · Month boundaries. "Every month on day 31" cannot run in September.
13// RRULE semantics SKIP the month (and the list shows a ghost row saying
14// so); the `clamp` prop switches to the other real-world policy, where
15// day 31 becomes Sep 30.
16// · DST. Runs are built from local wall-clock components (year, month,
17// day, hour), so "9:00 AM" stays 9:00 AM across a daylight-saving jump -
18// the UTC offset is printed on every row and flagged when it differs
19// from the first run's.
20// · Nth-weekday math. "The 2nd Tuesday" and "the last Friday" are computed
21// from the month's first/last day, never by scanning.
22//
23// The sentence morphs word-by-word: words are keyed by text + occurrence and
24// carry motion's `layout` - surviving words glide to their new positions while
25// new words blur in. Change "week" to "month" and "at 9:00 AM" slides left
26// instead of re-rendering; the sentence reads as one object being edited, not
27// a string being replaced.
28//
29// Read the rule out through `onRuleChange` (it is the component's value).
30// Animation via motion/react; honours prefers-reduced-motion. Requires the
31// lab-theme tokens. Fully Tailwind, no CSS files.
32
33const EASE = [0.22, 1, 0.36, 1] as const;
34
35const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
36const ORDINALS: { value: number | "last"; label: string }[] = [
37 { value: 1, label: "1st" },
38 { value: 2, label: "2nd" },
39 { value: 3, label: "3rd" },
40 { value: 4, label: "4th" },
41 { value: "last", label: "last" },
42];
43
44export interface ScheduleRule {
45 freq: "daily" | "weekly" | "monthly";
46 interval: number;
47 weekdays: number[];
48 monthMode: "date" | "nth";
49 monthDay: number;
50 ordinal: number | "last";
51 weekday: number;
52 hour: number;
53 minute: number;
54}
55
56export interface ScheduleBuilderState {
57 sentence: string;
58 next: string | null;
59 skips: number;
60 dstChanges: number;
61 freq: ScheduleRule["freq"];
62}
63
64type RunEntry =
65 | { kind: "run"; date: Date; clamped?: boolean }
66// … truncated

What it pulls in

npm packages

  • motion

Other registry items

  • https://lab.moumen.dev/r/lab-theme.json

Files it writes

  • registry/lab/schedule-builder/schedule-builder.tsx

Facts

Registry
moumenlab
Type
registry:component
Access
Free
Files written
1
Licence
MIT
First indexed
2026-08-11
Last confirmed
today

Go to the source

Docs on moumenlab lab.moumen.dev moumen-soliman/lab on GitHub Raw registry item This item as JSON

More from moumenlab

All 14 items
Same registry, same kind — the ones you would have found next
ComponentRegistryKindAccessInstallsCommand
Caret-Anchored Mention Popovercaret-mention-popovermoumenlabComponentsFree1 dep
Command Palette with Argument Chipscommand-palettemoumenlabComponentsFree1 dep
Drag-to-Reorder Listdrag-to-reorder-listmoumenlabComponentsFree1 dep
File Upload Staging Areafile-upload-stagingmoumenlabComponentsFree1 dep
Hover-Expand Icon Striphover-expand-icon-stripmoumenlabComponentsFree1 dep
Inertial Wheel Listinertial-wheel-listmoumenlabComponentsFree1 dep
Morphing Checkout Flowmorphing-checkoutmoumenlabComponentsFree1 dep
OTP Segmented Inputotp-segmented-inputmoumenlabComponentsFree1 dep
BlockDex

Built by

Kynth Studios

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex

BlockDex

Built by

Kynth Studios

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex

BlockDex

Built by

Kynth Studios

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex