{"id":51008983,"url":"https://github.com/devendramilmile121/datelane","last_synced_at":"2026-06-21T00:02:38.837Z","repository":{"id":365066803,"uuid":"1258590407","full_name":"devendramilmile121/datelane","owner":"devendramilmile121","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-15T17:55:13.000Z","size":356,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T19:25:08.019Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devendramilmile121.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-03T18:16:43.000Z","updated_at":"2026-06-15T17:56:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/devendramilmile121/datelane","commit_stats":null,"previous_names":["devendramilmile121/datelane"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/devendramilmile121/datelane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devendramilmile121%2Fdatelane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devendramilmile121%2Fdatelane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devendramilmile121%2Fdatelane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devendramilmile121%2Fdatelane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devendramilmile121","download_url":"https://codeload.github.com/devendramilmile121/datelane/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devendramilmile121%2Fdatelane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34589220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-21T00:02:37.570Z","updated_at":"2026-06-21T00:02:38.831Z","avatar_url":"https://github.com/devendramilmile121.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Calendars"],"readme":"# @datelane/core\n\nA lightweight, fully customizable **Angular scheduler / calendar** — all 12 view modes\n(Day, Week, Work Week, Month, Year, Agenda, Month Agenda, and the five Timeline views) — with\n**zero hard runtime dependencies** and a **pluggable date layer** (Native, Luxon, or Moment).\n\n\u003e Status: `0.1.0` pre-release. The 12 views, drag/resize, a host-driven quick-view, resources,\n\u003e and auto-scroll are implemented. Recurrence, a full editor window, and keyboard grid navigation\n\u003e are on the roadmap (see [Limitations](#limitations)).\n\n## Highlights\n\n- **Lightweight** — core has no runtime deps; each view is a tree-shakeable factory; you ship only\n  the views you import.\n- **Bring your own date library** — Native (built in, `Intl`-based), Luxon, or Moment via separate\n  entry points. No date library baked into core.\n- **Controlled \u0026 unopinionated editing** — the library ships **no form**. It emits click events and\n  shows an optional quick-view popover you can fully replace; your app owns create/edit/delete.\n- **Customizable** — every color/size/motion value is a CSS custom property; the quick-view is\n  template-overridable; every fixed UI string is overridable via `provideSchedulerI18n(...)`.\n- **Built-in navigation** — period-aware prev / next / today and a view switcher in the header;\n  an all-day band (collapsible) for multi-day events on Day/Week/Work Week.\n- **Wide Angular support** — published in partial-Ivy mode, verified by real AOT builds on\n  **Angular 18–22**. RTL-safe, dark-mode-ready, responsive.\n\n## Install\n\n```bash\nnpm i @datelane/core\n# optional — only if you choose that date adapter:\nnpm i luxon      # or: npm i moment\n```\n\nPeer deps: `@angular/core` and `@angular/common` `\u003e=18.0.0 \u003c23.0.0`. `luxon`/`moment` are\n**optional** peers.\n\n## Quick start (standalone, Native dates)\n\nRegister the scheduler providers once at bootstrap:\n\n```ts\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { provideScheduler } from '@datelane/core';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, {\n  providers: [provideScheduler()], // Native date adapter by default\n});\n```\n\nUse the component and pick the views you want:\n\n```ts\nimport { Component } from '@angular/core';\nimport {\n  SchedulerComponent, weekView, monthView, timelineWeekView,\n  type FieldMap, type ViewDescriptor, type SchedulerViewType, type SchedulerChange,\n} from '@datelane/core';\n\n@Component({\n  standalone: true,\n  selector: 'app-root',\n  imports: [SchedulerComponent],\n  template: `\n    \u003cdl-scheduler\n      [(activeView)]=\"view\"\n      [(viewDate)]=\"date\"\n      [events]=\"events\"\n      [fieldMap]=\"fieldMap\"\n      [views]=\"views\"\n      height=\"640px\"\n      (eventClick)=\"onEventClick($event)\"\n      (eventEdit)=\"openMyForm($event)\"\n      (eventDelete)=\"onDelete($event)\"\n      (eventChange)=\"onDragResize($event)\"\n      (cellClick)=\"onEmptySlot($event)\"\u003e\n    \u003c/dl-scheduler\u003e`,\n})\nexport class AppComponent {\n  view: SchedulerViewType = 'week';\n  date = new Date();\n\n  views: ViewDescriptor[] = [\n    weekView({ isDefault: true, startHour: '08:00', endHour: '20:00' }),\n    monthView(),\n    timelineWeekView(),\n  ];\n\n  fieldMap: FieldMap = { id: 'id', subject: 'subject', start: 'start', end: 'end' };\n\n  events = [\n    { id: 1, subject: 'Standup', start: new Date(), end: new Date(Date.now() + 30 * 60_000) },\n  ];\n\n  onEventClick(c: SchedulerChange) { /* always fires on activation */ }\n  openMyForm(c: SchedulerChange) { /* quick-view \"Edit\" → open YOUR dialog */ }\n  onDelete(c: SchedulerChange) { this.events = this.events.filter(e =\u003e e.id !== c.event.id); }\n  onDragResize(c: SchedulerChange) { /* apply c.event.start/end back into your data */ }\n  onEmptySlot(p: { date: unknown; resourceId?: string | number }) { /* open create form */ }\n}\n```\n\n## Styling\n\nThe package ships **SCSS** (tokens + theme + component styles); there is no pre-compiled CSS yet.\nImport it once. Either add it to `angular.json`:\n\n```jsonc\n// angular.json → projects.\u003capp\u003e.architect.build.options.styles\n\"styles\": [\n  \"src/styles.scss\",\n  \"node_modules/@datelane/core/styles/scheduler.scss\"\n]\n```\n\n…or `@use` it from your global stylesheet:\n\n```scss\n/* src/styles.scss */\n@use '@datelane/core/styles/scheduler';\n```\n\n## Views\n\nAll 12 views are tree-shakeable factory functions returning a typed `ViewDescriptor`. Import only\nthe ones you use.\n\n| Factory | View | Engine |\n|---------|------|--------|\n| `dayView()` | Day | vertical-time |\n| `weekView()` | Week | vertical-time |\n| `workWeekView()` | Work Week | vertical-time |\n| `monthView()` | Month | calendar-grid |\n| `yearView()` | Year | year-grid |\n| `agendaView()` | Agenda | list |\n| `monthAgendaView()` | Month Agenda | mini-calendar + list |\n| `timelineDayView()` | Timeline Day | horizontal-time |\n| `timelineWeekView()` | Timeline Week | horizontal-time |\n| `timelineWorkWeekView()` | Timeline Work Week | horizontal-time |\n| `timelineMonthView()` | Timeline Month | horizontal-time |\n| `timelineYearView()` | Timeline Year | horizontal-time |\n\nEach factory takes a partial `ViewDescriptor` to configure that view:\n\n```ts\nimport { dayView, weekView, monthView, timelineYearView } from '@datelane/core';\n\nviews = [\n  dayView({ interval: 3, displayName: '3 Days', startHour: '08:00', endHour: '20:00' }),\n  weekView({ isDefault: true, firstDayOfWeek: 1, showWeekNumber: true }),\n  monthView({ showWeekend: false }),\n  timelineYearView({ orientation: 'vertical' }),\n];\n```\n\n`ViewDescriptor` fields: `type`, `displayName`, `isDefault`, `interval`, `dateFormat`, `readonly`,\n`showWeekend`, `showWeekNumber`, `workDays`, `firstDayOfWeek`, `startHour`, `endHour`,\n`timeScale: { enabled, slotCount }`, `orientation`, `headerRows`, `allowVirtualScrolling`,\n`grouping`. Only options that apply to a given view type are honored.\n\n## Data \u0026 `FieldMap`\n\nYou pass raw records via `[events]` and a `[fieldMap]` that maps your field names onto the canonical\nevent shape — no need to reshape your data.\n\n```ts\nfieldMap: FieldMap = {\n  id: 'Id',\n  subject: 'Subject',\n  start: 'StartTime',\n  end: 'EndTime',\n  isAllDay: 'IsAllDay',          // optional\n  recurrenceRule: 'RecurrenceRule', // optional (reserved; engine pending)\n  resource: 'OwnerId',           // optional — string or string[]\n  color: 'Color',                // optional — overrides resource color\n  location: 'Location',          // optional — shown in the quick-view\n  description: 'Description',     // optional — shown in the quick-view\n};\n```\n\nDates may be `Date`, ISO string, or epoch number — the active date adapter parses them.\n\n## Inputs\n\n| Input | Type | Default | Notes |\n|-------|------|---------|-------|\n| `activeView` | `SchedulerViewType` | `'week'` | two-way (`activeViewChange`) |\n| `viewDate` | adapter date | today | two-way (`viewDateChange`) |\n| `events` | `Record\u003cstring, unknown\u003e[]` | `[]` | raw records |\n| `fieldMap` | `FieldMap` | — | required to render events |\n| `views` | `ViewDescriptor[]` | `[]` | from the view factories |\n| `resources` | `ResourceDefinition[]` | `[]` | Timeline rows |\n| `grouping` | `GroupingConfig` | — | `{ resources: ['name'] }` |\n| `readonly` | `boolean` | `false` | disables drag/resize + quick-view actions |\n| `rowAutoHeight` | `boolean` | `false` | Timeline: grow rows vs `+N more` |\n| `agendaDaysCount` | `number` | `7` | Agenda span |\n| `hideEmptyAgendaDays` | `boolean` | `false` | Agenda |\n| `showQuickView` | `boolean` | `true` | built-in popover on activation |\n| `autoScroll` | `boolean` | `true` | scroll to first event (see below) |\n| `scrollHour` | `number` | — | time grids: scroll to this hour instead |\n| `height` | `string` | `'600px'` | required px height for Agenda / Month Agenda |\n| `width` | `string` | `'100%'` | |\n| `dir` | `'ltr' \\| 'rtl'` | `'ltr'` | RTL mirrors the layout |\n\n## Outputs\n\n| Output | Payload | When |\n|--------|---------|------|\n| `eventClick` | `SchedulerChange` | any event activation (always) |\n| `eventEdit` | `SchedulerChange` | quick-view **Edit** → open your form |\n| `eventDelete` | `SchedulerChange` | quick-view **Delete** |\n| `eventChange` | `SchedulerChange` | after a drag-move or resize |\n| `eventCreate` | `SchedulerChange` | reserved for the editor (pending) |\n| `cellClick` | `{ date, resourceId? }` | empty slot/cell — open your create form |\n| `navigate` | `NavigateEvent` | date navigation / drill-through |\n| `viewChange` | `SchedulerViewType` | active view changed |\n\n`SchedulerChange` = `{ event: SchedulerEvent; scope?: 'occurrence' | 'following' | 'series' }`.\nThe component never mutates your data — apply changes yourself and pass them back via `[events]`.\n\n## Editing model (bring your own form)\n\nThe library intentionally ships **no editor**. On event activation it:\n\n1. always emits `(eventClick)`, and\n2. (unless `[showQuickView]=\"false\"`) opens a small built-in **quick-view** popover.\n\nThe quick-view's **Edit** / **Delete** buttons forward to `(eventEdit)` / `(eventDelete)` so your\napp opens its own dialog. Replace the popover entirely with the `ngsQuickViewTemplate` directive:\n\n```html\n\u003cdl-scheduler …\u003e\n  \u003cng-template ngsQuickViewTemplate let-event let-close=\"close\" let-edit=\"edit\" let-delete=\"delete\"\u003e\n    \u003ch4\u003e{{ event.subject }}\u003c/h4\u003e\n    \u003cbutton (click)=\"edit()\"\u003eOpen my form\u003c/button\u003e\n    \u003cbutton (click)=\"delete()\"\u003eDelete\u003c/button\u003e\n    \u003cbutton (click)=\"close()\"\u003eClose\u003c/button\u003e\n  \u003c/ng-template\u003e\n\u003c/dl-scheduler\u003e\n```\n\nFor empty-slot creation, handle `(cellClick)` and open your own create dialog.\n\n## Resources \u0026 grouping (Timeline)\n\n```ts\nresources: ResourceDefinition[] = [{\n  field: 'ownerId', name: 'owners', title: 'Owner',\n  idField: 'id', textField: 'text', colorField: 'color',\n  dataSource: [\n    { id: 1, text: 'Alex',  color: '#2563eb' },\n    { id: 2, text: 'Priya', color: '#16a34a' },\n  ],\n}];\n```\n\n```html\n\u003cdl-scheduler [resources]=\"resources\" [grouping]=\"{ resources: ['owners'] }\" …\u003e\n```\n\nEvents are placed on the row whose `idField` matches the event's mapped `resource`. Single-level\ngrouping is supported today; hierarchical grouping is on the roadmap.\n\n## Auto-scroll\n\nScrolling views (Day/Week/Work Week, Timeline, Agenda, Year) scroll to the first event on first\nrender and when you navigate to a new period — but **not** on edits or drag, so a user's manual\nscroll is preserved. Configure with `[autoScroll]` (default `true`) and, for time grids,\n`[scrollHour]` to jump to a fixed hour instead of the first event.\n\n## Date adapters\n\nCore ships the zero-dependency `NativeDateAdapter`. Opt into Luxon or Moment via secondary entry\npoints (their libraries are optional peers):\n\n```ts\nimport { provideScheduler } from '@datelane/core';\nimport { provideLuxonDateAdapter } from '@datelane/core/luxon-adapter';\n// or: import { provideMomentDateAdapter } from '@datelane/core/moment-adapter';\n\nproviders: [provideScheduler(provideLuxonDateAdapter({ locale: 'fr' }))];\n```\n\n## Localizing UI strings\n\nDates and numbers are localized through the date adapter's `locale`. The fixed **UI strings**\n(header `Today` / prev / next labels, the view switcher, quick-view `Edit` / `Delete` / `Close`,\nthe all-day label, and the `+N more` / `Show less` overflow text) come from an injectable message\ntoken. Override any subset — the rest fall back to the built-in English defaults:\n\n```ts\nimport { provideScheduler } from '@datelane/core';\nimport { provideSchedulerI18n } from '@datelane/core';\n\nproviders: [\n  provideScheduler(),\n  provideSchedulerI18n({\n    today: \"Aujourd’hui\",\n    previous: 'Précédent',\n    next: 'Suivant',\n    edit: 'Modifier',\n    delete: 'Supprimer',\n    moreEvents: (n) =\u003e `+${n} de plus`,\n  }),\n];\n```\n\nThe full contract is the `SchedulerMessages` interface (token: `SCHEDULER_MESSAGES`).\n\n## Header navigation\n\nThe header renders **Today · ‹ · ›** plus a view switcher (shown when you pass two or more\n`[views]`). Prev / next step by the active view's own unit — a day (or `interval` days), a week, a\nmonth, a year, or the agenda's day count — and emit `(navigate)` with `action: 'prev' | 'next' |\n'today'`. Switching a view emits `(viewChange)`. Both drive the two-way `[(viewDate)]` /\n`[(activeView)]`, so the host stays the source of truth.\n\n## All-day band (Day / Week / Work Week)\n\nMulti-day and all-day events render as spanning bars in an all-day band above the time grid.\nOverlapping events stack into lanes; when there are more lanes than the collapsed cap the extra\nones fold behind a **`+N more`** toggle. Configure the cap on the view via `[allDayMaxLanes]`\n(default `2`).\n\n## Non-standalone apps\n\nThe components are standalone-only (no `NgModule` surface). Apps still organised around\n`NgModule`s import the standalone components directly — Angular has supported importing\nstandalone components into an `NgModule` since v14:\n\n```ts\nimport { SchedulerComponent } from '@datelane/core';\n\n@NgModule({ imports: [SchedulerComponent] })\nexport class AppModule {}\n```\n\n## Theming\n\nOverride any token on `.dl-scheduler` (or an ancestor) — no `::ng-deep`, no fork:\n\n```css\n.dl-scheduler {\n  --dl-accent: #2563eb;\n  --dl-radius-md: 10px;\n  --dl-slot-h: 48px;\n}\n.dl-scheduler[data-dl-theme=\"dark\"] { /* built-in dark theme */ }\n```\n\nFull token list is in [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md).\n\n## Angular support\n\n| Angular | Status |\n|---------|--------|\n| 18 | ✅ verified (AOT build) |\n| 19 | ✅ verified (AOT build) |\n| 20 | ✅ verified (AOT build) |\n| 21 | ✅ verified (AOT build) |\n| 22 | ✅ verified (AOT build) |\n\nPublished in **partial-Ivy** mode, so the consuming app's compiler links it (not locked to one\nruntime); declaration `minVersion` is **17**. `scripts/verify-angular.sh \u003cmajor\u003e` scaffolds a real\napp on a version, installs the packed tarball, and runs a production AOT build — CI runs it across\nall five majors.\n\n## Limitations\n\n- Recurrence (RRULE/EXDATE), a full editor window, and keyboard grid navigation are not yet\n  implemented.\n- Timeline resource grouping is single-level (no hierarchy yet).\n- Agenda does not yet virtualize long ranges.\n- Luxon/Moment adapters lack a shared parity test suite; Moment format-token parity is unverified.\n- No pre-compiled CSS is shipped yet — import the SCSS (see [Styling](#styling)).\n\nSee [scheduler-plan.md](scheduler-plan.md) for the full roadmap and [CHANGELOG.md](CHANGELOG.md) for\nrelease notes.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevendramilmile121%2Fdatelane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevendramilmile121%2Fdatelane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevendramilmile121%2Fdatelane/lists"}