react-native-roster 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +29 -0
- package/README.md +455 -2
- package/dist/src/adapters/rrule/cache.d.ts +15 -0
- package/dist/src/adapters/rrule/cache.d.ts.map +1 -0
- package/dist/src/adapters/rrule/cache.js +53 -0
- package/dist/src/adapters/rrule/cache.js.map +1 -0
- package/dist/src/adapters/rrule/envelope.d.ts +3 -0
- package/dist/src/adapters/rrule/envelope.d.ts.map +1 -0
- package/dist/src/adapters/rrule/envelope.js +9 -0
- package/dist/src/adapters/rrule/envelope.js.map +1 -0
- package/dist/src/adapters/rrule/expand.d.ts +4 -0
- package/dist/src/adapters/rrule/expand.d.ts.map +1 -0
- package/dist/src/adapters/rrule/expand.js +92 -0
- package/dist/src/adapters/rrule/expand.js.map +1 -0
- package/dist/src/adapters/rrule/hash.d.ts +3 -0
- package/dist/src/adapters/rrule/hash.d.ts.map +1 -0
- package/dist/src/adapters/rrule/hash.js +15 -0
- package/dist/src/adapters/rrule/hash.js.map +1 -0
- package/dist/src/adapters/rrule/index.d.ts +5 -0
- package/dist/src/adapters/rrule/index.d.ts.map +1 -0
- package/dist/src/adapters/rrule/index.js +12 -0
- package/dist/src/adapters/rrule/index.js.map +1 -0
- package/dist/src/adapters/rrule/net.d.ts +6 -0
- package/dist/src/adapters/rrule/net.d.ts.map +1 -0
- package/dist/src/adapters/rrule/net.js +31 -0
- package/dist/src/adapters/rrule/net.js.map +1 -0
- package/dist/src/adapters/rrule/occurrences.d.ts +6 -0
- package/dist/src/adapters/rrule/occurrences.d.ts.map +1 -0
- package/dist/src/adapters/rrule/occurrences.js +252 -0
- package/dist/src/adapters/rrule/occurrences.js.map +1 -0
- package/dist/src/adapters/rrule/types.d.ts +62 -0
- package/dist/src/adapters/rrule/types.d.ts.map +1 -0
- package/dist/src/adapters/rrule/types.js +3 -0
- package/dist/src/adapters/rrule/types.js.map +1 -0
- package/dist/src/adapters/rrule/validate.d.ts +6 -0
- package/dist/src/adapters/rrule/validate.d.ts.map +1 -0
- package/dist/src/adapters/rrule/validate.js +64 -0
- package/dist/src/adapters/rrule/validate.js.map +1 -0
- package/dist/src/components/layers/layers.types.d.ts +15 -0
- package/dist/src/components/layers/layers.types.d.ts.map +1 -0
- package/dist/src/components/layers/layers.types.js +3 -0
- package/dist/src/components/layers/layers.types.js.map +1 -0
- package/dist/src/components/layers/parts/gap.d.ts +3 -0
- package/dist/src/components/layers/parts/gap.d.ts.map +1 -0
- package/dist/src/components/layers/parts/gap.js +7 -0
- package/dist/src/components/layers/parts/gap.js.map +1 -0
- package/dist/src/components/layers/parts/interval.d.ts +3 -0
- package/dist/src/components/layers/parts/interval.d.ts.map +1 -0
- package/dist/src/components/layers/parts/interval.js +22 -0
- package/dist/src/components/layers/parts/interval.js.map +1 -0
- package/dist/src/components/layers/utils/styles.d.ts +7 -0
- package/dist/src/components/layers/utils/styles.d.ts.map +1 -0
- package/dist/src/components/layers/utils/styles.js +24 -0
- package/dist/src/components/layers/utils/styles.js.map +1 -0
- package/dist/src/components/primitives/press-point.d.ts +3 -0
- package/dist/src/components/primitives/press-point.d.ts.map +1 -0
- package/dist/src/components/primitives/press-point.js +7 -0
- package/dist/src/components/primitives/press-point.js.map +1 -0
- package/dist/src/components/primitives/press-point.types.d.ts +14 -0
- package/dist/src/components/primitives/press-point.types.d.ts.map +1 -0
- package/dist/src/components/primitives/press-point.types.js +3 -0
- package/dist/src/components/primitives/press-point.types.js.map +1 -0
- package/dist/src/components/primitives/press-point.web.d.ts +3 -0
- package/dist/src/components/primitives/press-point.web.d.ts.map +1 -0
- package/dist/src/components/primitives/press-point.web.js +17 -0
- package/dist/src/components/primitives/press-point.web.js.map +1 -0
- package/dist/src/components/primitives/region-style.d.ts +9 -0
- package/dist/src/components/primitives/region-style.d.ts.map +1 -0
- package/dist/src/components/primitives/region-style.js +20 -0
- package/dist/src/components/primitives/region-style.js.map +1 -0
- package/dist/src/components/roster/body-layout.d.ts +9 -0
- package/dist/src/components/roster/body-layout.d.ts.map +1 -0
- package/dist/src/components/roster/body-layout.js +9 -0
- package/dist/src/components/roster/body-layout.js.map +1 -0
- package/dist/src/components/roster/index.d.ts +3 -0
- package/dist/src/components/roster/index.d.ts.map +1 -0
- package/dist/src/components/roster/index.js +40 -0
- package/dist/src/components/roster/index.js.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.d.ts +3 -0
- package/dist/src/components/roster/lanes/interval-hover.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.js +7 -0
- package/dist/src/components/roster/lanes/interval-hover.js.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.types.d.ts +15 -0
- package/dist/src/components/roster/lanes/interval-hover.types.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.types.js +3 -0
- package/dist/src/components/roster/lanes/interval-hover.types.js.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.web.d.ts +3 -0
- package/dist/src/components/roster/lanes/interval-hover.web.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/interval-hover.web.js +20 -0
- package/dist/src/components/roster/lanes/interval-hover.web.js.map +1 -0
- package/dist/src/components/roster/lanes/lane.d.ts +10 -0
- package/dist/src/components/roster/lanes/lane.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/lane.js +32 -0
- package/dist/src/components/roster/lanes/lane.js.map +1 -0
- package/dist/src/components/roster/lanes/parts/incomplete.d.ts +8 -0
- package/dist/src/components/roster/lanes/parts/incomplete.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/parts/incomplete.js +30 -0
- package/dist/src/components/roster/lanes/parts/incomplete.js.map +1 -0
- package/dist/src/components/roster/lanes/parts/lane-label.d.ts +3 -0
- package/dist/src/components/roster/lanes/parts/lane-label.d.ts.map +1 -0
- package/dist/src/components/roster/lanes/parts/lane-label.js +18 -0
- package/dist/src/components/roster/lanes/parts/lane-label.js.map +1 -0
- package/dist/src/components/roster/layout.d.ts +17 -0
- package/dist/src/components/roster/layout.d.ts.map +1 -0
- package/dist/src/components/roster/layout.js +24 -0
- package/dist/src/components/roster/layout.js.map +1 -0
- package/dist/src/components/roster/parts/body.d.ts +7 -0
- package/dist/src/components/roster/parts/body.d.ts.map +1 -0
- package/dist/src/components/roster/parts/body.js +14 -0
- package/dist/src/components/roster/parts/body.js.map +1 -0
- package/dist/src/components/roster/parts/corner.d.ts +2 -0
- package/dist/src/components/roster/parts/corner.d.ts.map +1 -0
- package/dist/src/components/roster/parts/corner.js +7 -0
- package/dist/src/components/roster/parts/corner.js.map +1 -0
- package/dist/src/components/roster/parts/empty.d.ts +2 -0
- package/dist/src/components/roster/parts/empty.d.ts.map +1 -0
- package/dist/src/components/roster/parts/empty.js +9 -0
- package/dist/src/components/roster/parts/empty.js.map +1 -0
- package/dist/src/components/roster/parts/grid.d.ts +3 -0
- package/dist/src/components/roster/parts/grid.d.ts.map +1 -0
- package/dist/src/components/roster/parts/grid.js +16 -0
- package/dist/src/components/roster/parts/grid.js.map +1 -0
- package/dist/src/components/roster/parts/header-cell.d.ts +3 -0
- package/dist/src/components/roster/parts/header-cell.d.ts.map +1 -0
- package/dist/src/components/roster/parts/header-cell.js +9 -0
- package/dist/src/components/roster/parts/header-cell.js.map +1 -0
- package/dist/src/components/roster/parts/header.d.ts +3 -0
- package/dist/src/components/roster/parts/header.d.ts.map +1 -0
- package/dist/src/components/roster/parts/header.js +13 -0
- package/dist/src/components/roster/parts/header.js.map +1 -0
- package/dist/src/components/roster/parts/lane-label-column.d.ts +3 -0
- package/dist/src/components/roster/parts/lane-label-column.d.ts.map +1 -0
- package/dist/src/components/roster/parts/lane-label-column.js +18 -0
- package/dist/src/components/roster/parts/lane-label-column.js.map +1 -0
- package/dist/src/components/roster/parts/lane-list.d.ts +7 -0
- package/dist/src/components/roster/parts/lane-list.d.ts.map +1 -0
- package/dist/src/components/roster/parts/lane-list.js +25 -0
- package/dist/src/components/roster/parts/lane-list.js.map +1 -0
- package/dist/src/components/roster/roster.types.d.ts +145 -0
- package/dist/src/components/roster/roster.types.d.ts.map +1 -0
- package/dist/src/components/roster/roster.types.js +3 -0
- package/dist/src/components/roster/roster.types.js.map +1 -0
- package/dist/src/components/roster/use-roster.d.ts +3 -0
- package/dist/src/components/roster/use-roster.d.ts.map +1 -0
- package/dist/src/components/roster/use-roster.js +106 -0
- package/dist/src/components/roster/use-roster.js.map +1 -0
- package/dist/src/components/roster/utils/body-content-key.d.ts +3 -0
- package/dist/src/components/roster/utils/body-content-key.d.ts.map +1 -0
- package/dist/src/components/roster/utils/body-content-key.js +29 -0
- package/dist/src/components/roster/utils/body-content-key.js.map +1 -0
- package/dist/src/components/roster/utils/ticks.d.ts +4 -0
- package/dist/src/components/roster/utils/ticks.d.ts.map +1 -0
- package/dist/src/components/roster/utils/ticks.js +60 -0
- package/dist/src/components/roster/utils/ticks.js.map +1 -0
- package/dist/src/components/schedule/days/day.d.ts +20 -0
- package/dist/src/components/schedule/days/day.d.ts.map +1 -0
- package/dist/src/components/schedule/days/day.js +17 -0
- package/dist/src/components/schedule/days/day.js.map +1 -0
- package/dist/src/components/schedule/days/header-layout.d.ts +9 -0
- package/dist/src/components/schedule/days/header-layout.d.ts.map +1 -0
- package/dist/src/components/schedule/days/header-layout.js +9 -0
- package/dist/src/components/schedule/days/header-layout.js.map +1 -0
- package/dist/src/components/schedule/days/layout.d.ts +18 -0
- package/dist/src/components/schedule/days/layout.d.ts.map +1 -0
- package/dist/src/components/schedule/days/layout.js +9 -0
- package/dist/src/components/schedule/days/layout.js.map +1 -0
- package/dist/src/components/schedule/days/parts/column.d.ts +3 -0
- package/dist/src/components/schedule/days/parts/column.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/column.js +28 -0
- package/dist/src/components/schedule/days/parts/column.js.map +1 -0
- package/dist/src/components/schedule/days/parts/day-header.d.ts +5 -0
- package/dist/src/components/schedule/days/parts/day-header.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/day-header.js +10 -0
- package/dist/src/components/schedule/days/parts/day-header.js.map +1 -0
- package/dist/src/components/schedule/days/parts/grid.d.ts +3 -0
- package/dist/src/components/schedule/days/parts/grid.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/grid.js +14 -0
- package/dist/src/components/schedule/days/parts/grid.js.map +1 -0
- package/dist/src/components/schedule/days/parts/now-line.d.ts +5 -0
- package/dist/src/components/schedule/days/parts/now-line.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/now-line.js +9 -0
- package/dist/src/components/schedule/days/parts/now-line.js.map +1 -0
- package/dist/src/components/schedule/days/parts/skipped-date.d.ts +4 -0
- package/dist/src/components/schedule/days/parts/skipped-date.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/skipped-date.js +17 -0
- package/dist/src/components/schedule/days/parts/skipped-date.js.map +1 -0
- package/dist/src/components/schedule/days/parts/transition.d.ts +3 -0
- package/dist/src/components/schedule/days/parts/transition.d.ts.map +1 -0
- package/dist/src/components/schedule/days/parts/transition.js +42 -0
- package/dist/src/components/schedule/days/parts/transition.js.map +1 -0
- package/dist/src/components/schedule/index.d.ts +3 -0
- package/dist/src/components/schedule/index.d.ts.map +1 -0
- package/dist/src/components/schedule/index.js +44 -0
- package/dist/src/components/schedule/index.js.map +1 -0
- package/dist/src/components/schedule/layout.d.ts +15 -0
- package/dist/src/components/schedule/layout.d.ts.map +1 -0
- package/dist/src/components/schedule/layout.js +10 -0
- package/dist/src/components/schedule/layout.js.map +1 -0
- package/dist/src/components/schedule/parts/gutter.d.ts +3 -0
- package/dist/src/components/schedule/parts/gutter.d.ts.map +1 -0
- package/dist/src/components/schedule/parts/gutter.js +9 -0
- package/dist/src/components/schedule/parts/gutter.js.map +1 -0
- package/dist/src/components/schedule/parts/incomplete.d.ts +6 -0
- package/dist/src/components/schedule/parts/incomplete.d.ts.map +1 -0
- package/dist/src/components/schedule/parts/incomplete.js +9 -0
- package/dist/src/components/schedule/parts/incomplete.js.map +1 -0
- package/dist/src/components/schedule/schedule.types.d.ts +109 -0
- package/dist/src/components/schedule/schedule.types.d.ts.map +1 -0
- package/dist/src/components/schedule/schedule.types.js +3 -0
- package/dist/src/components/schedule/schedule.types.js.map +1 -0
- package/dist/src/components/schedule/use-schedule-viewport.d.ts +7 -0
- package/dist/src/components/schedule/use-schedule-viewport.d.ts.map +1 -0
- package/dist/src/components/schedule/use-schedule-viewport.js +15 -0
- package/dist/src/components/schedule/use-schedule-viewport.js.map +1 -0
- package/dist/src/components/schedule/use-schedule.d.ts +3 -0
- package/dist/src/components/schedule/use-schedule.d.ts.map +1 -0
- package/dist/src/components/schedule/use-schedule.js +71 -0
- package/dist/src/components/schedule/use-schedule.js.map +1 -0
- package/dist/src/components/schedule/utils/days.d.ts +17 -0
- package/dist/src/components/schedule/utils/days.d.ts.map +1 -0
- package/dist/src/components/schedule/utils/days.js +49 -0
- package/dist/src/components/schedule/utils/days.js.map +1 -0
- package/dist/src/core/axis.d.ts +18 -0
- package/dist/src/core/axis.d.ts.map +1 -0
- package/dist/src/core/axis.js +58 -0
- package/dist/src/core/axis.js.map +1 -0
- package/dist/src/core/cache.d.ts +29 -0
- package/dist/src/core/cache.d.ts.map +1 -0
- package/dist/src/core/cache.js +33 -0
- package/dist/src/core/cache.js.map +1 -0
- package/dist/src/core/columns.d.ts +3 -0
- package/dist/src/core/columns.d.ts.map +1 -0
- package/dist/src/core/columns.js +45 -0
- package/dist/src/core/columns.js.map +1 -0
- package/dist/src/core/coverage.d.ts +3 -0
- package/dist/src/core/coverage.d.ts.map +1 -0
- package/dist/src/core/coverage.js +60 -0
- package/dist/src/core/coverage.js.map +1 -0
- package/dist/src/core/flag.d.ts +3 -0
- package/dist/src/core/flag.d.ts.map +1 -0
- package/dist/src/core/flag.js +17 -0
- package/dist/src/core/flag.js.map +1 -0
- package/dist/src/core/hash.d.ts +5 -0
- package/dist/src/core/hash.d.ts.map +1 -0
- package/dist/src/core/hash.js +29 -0
- package/dist/src/core/hash.js.map +1 -0
- package/dist/src/core/hit-test.d.ts +6 -0
- package/dist/src/core/hit-test.d.ts.map +1 -0
- package/dist/src/core/hit-test.js +23 -0
- package/dist/src/core/hit-test.js.map +1 -0
- package/dist/src/core/index.d.ts +12 -0
- package/dist/src/core/index.d.ts.map +1 -0
- package/dist/src/core/index.js +30 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/layout.d.ts +3 -0
- package/dist/src/core/layout.d.ts.map +1 -0
- package/dist/src/core/layout.js +96 -0
- package/dist/src/core/layout.js.map +1 -0
- package/dist/src/core/order.d.ts +7 -0
- package/dist/src/core/order.d.ts.map +1 -0
- package/dist/src/core/order.js +12 -0
- package/dist/src/core/order.js.map +1 -0
- package/dist/src/core/scale.d.ts +9 -0
- package/dist/src/core/scale.d.ts.map +1 -0
- package/dist/src/core/scale.js +41 -0
- package/dist/src/core/scale.js.map +1 -0
- package/dist/src/core/snap.d.ts +10 -0
- package/dist/src/core/snap.d.ts.map +1 -0
- package/dist/src/core/snap.js +43 -0
- package/dist/src/core/snap.js.map +1 -0
- package/dist/src/core/spans.d.ts +3 -0
- package/dist/src/core/spans.d.ts.map +1 -0
- package/dist/src/core/spans.js +60 -0
- package/dist/src/core/spans.js.map +1 -0
- package/dist/src/core/types.d.ts +104 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/core/types.js +3 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/core/zone.d.ts +10 -0
- package/dist/src/core/zone.d.ts.map +1 -0
- package/dist/src/core/zone.js +103 -0
- package/dist/src/core/zone.js.map +1 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +67 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/nativewind/index.d.ts +59 -0
- package/dist/src/nativewind/index.d.ts.map +1 -0
- package/dist/src/nativewind/index.js +24 -0
- package/dist/src/nativewind/index.js.map +1 -0
- package/docs/migrations.md +61 -0
- package/llms.txt +498 -0
- package/package.json +155 -8
- package/src/adapters/rrule/README.md +41 -0
- package/src/adapters/rrule/cache.ts +50 -0
- package/src/adapters/rrule/envelope.ts +7 -0
- package/src/adapters/rrule/expand.ts +105 -0
- package/src/adapters/rrule/hash.ts +13 -0
- package/src/adapters/rrule/index.ts +11 -0
- package/src/adapters/rrule/net.ts +30 -0
- package/src/adapters/rrule/occurrences.ts +288 -0
- package/src/adapters/rrule/types.ts +52 -0
- package/src/adapters/rrule/validate.ts +78 -0
- package/src/components/layers/README.md +15 -0
- package/src/components/layers/layers.types.ts +6 -0
- package/src/components/layers/parts/gap.tsx +5 -0
- package/src/components/layers/parts/interval.tsx +24 -0
- package/src/components/layers/utils/styles.ts +24 -0
- package/src/components/primitives/README.md +12 -0
- package/src/components/primitives/press-point.tsx +5 -0
- package/src/components/primitives/press-point.types.ts +5 -0
- package/src/components/primitives/press-point.web.tsx +19 -0
- package/src/components/primitives/region-style.ts +21 -0
- package/src/components/roster/README.md +29 -0
- package/src/components/roster/body-layout.tsx +32 -0
- package/src/components/roster/index.tsx +108 -0
- package/src/components/roster/lanes/interval-hover.tsx +5 -0
- package/src/components/roster/lanes/interval-hover.types.ts +11 -0
- package/src/components/roster/lanes/interval-hover.web.tsx +19 -0
- package/src/components/roster/lanes/lane.tsx +93 -0
- package/src/components/roster/lanes/parts/incomplete.tsx +44 -0
- package/src/components/roster/lanes/parts/lane-label.tsx +41 -0
- package/src/components/roster/layout.tsx +68 -0
- package/src/components/roster/parts/body.tsx +24 -0
- package/src/components/roster/parts/corner.tsx +3 -0
- package/src/components/roster/parts/empty.tsx +5 -0
- package/src/components/roster/parts/grid.tsx +26 -0
- package/src/components/roster/parts/header-cell.tsx +10 -0
- package/src/components/roster/parts/header.tsx +23 -0
- package/src/components/roster/parts/lane-label-column.tsx +31 -0
- package/src/components/roster/parts/lane-list.tsx +74 -0
- package/src/components/roster/roster.types.ts +156 -0
- package/src/components/roster/use-roster.ts +133 -0
- package/src/components/roster/utils/body-content-key.ts +46 -0
- package/src/components/roster/utils/ticks.ts +62 -0
- package/src/components/schedule/README.md +23 -0
- package/src/components/schedule/days/day.tsx +89 -0
- package/src/components/schedule/days/header-layout.tsx +12 -0
- package/src/components/schedule/days/layout.tsx +38 -0
- package/src/components/schedule/days/parts/column.tsx +59 -0
- package/src/components/schedule/days/parts/day-header.tsx +18 -0
- package/src/components/schedule/days/parts/grid.tsx +21 -0
- package/src/components/schedule/days/parts/now-line.tsx +11 -0
- package/src/components/schedule/days/parts/skipped-date.tsx +22 -0
- package/src/components/schedule/days/parts/transition.tsx +70 -0
- package/src/components/schedule/index.tsx +108 -0
- package/src/components/schedule/layout.tsx +42 -0
- package/src/components/schedule/parts/gutter.tsx +16 -0
- package/src/components/schedule/parts/incomplete.tsx +13 -0
- package/src/components/schedule/schedule.types.ts +103 -0
- package/src/components/schedule/use-schedule-viewport.ts +13 -0
- package/src/components/schedule/use-schedule.ts +75 -0
- package/src/components/schedule/utils/days.ts +54 -0
- package/src/core/README.md +25 -0
- package/src/core/axis.ts +58 -0
- package/src/core/cache.ts +38 -0
- package/src/core/columns.ts +49 -0
- package/src/core/coverage.ts +56 -0
- package/src/core/flag.ts +14 -0
- package/src/core/hash.ts +28 -0
- package/src/core/hit-test.ts +27 -0
- package/src/core/index.ts +34 -0
- package/src/core/layout.ts +101 -0
- package/src/core/order.ts +18 -0
- package/src/core/scale.ts +45 -0
- package/src/core/snap.ts +52 -0
- package/src/core/spans.ts +58 -0
- package/src/core/types.ts +92 -0
- package/src/core/zone.ts +100 -0
- package/src/index.ts +52 -0
- package/src/nativewind/README.md +14 -0
- package/src/nativewind/index.ts +30 -0
- package/index.js +0 -4
package/NOTICE.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Notices and attributions
|
|
2
|
+
|
|
3
|
+
react-native-roster uses the MIT license; see [LICENSE](./LICENSE).
|
|
4
|
+
|
|
5
|
+
## Adapter dependencies
|
|
6
|
+
|
|
7
|
+
- **rrule-temporal**, ggaabe, MIT: <https://github.com/ggaabe/rrule-temporal>.
|
|
8
|
+
Version 1.6.0 supplies the recurrence engine.
|
|
9
|
+
- **@js-temporal/polyfill**, Temporal polyfill contributors, ISC:
|
|
10
|
+
<https://github.com/js-temporal/temporal-polyfill>. Version 0.5.1 supplies
|
|
11
|
+
the adapter's absolute-time conversion.
|
|
12
|
+
|
|
13
|
+
These dependencies are imported only through `./rrule`; root and core consumers
|
|
14
|
+
do not load them. They are installed as dependencies and are not bundled.
|
|
15
|
+
|
|
16
|
+
## Rendering peer
|
|
17
|
+
|
|
18
|
+
- **@legendapp/list**, Legend, MIT: <https://github.com/LegendApp/legend-list>.
|
|
19
|
+
A peer dependency, with 2.0.19 used in development; Roster uses it to virtualize lanes.
|
|
20
|
+
|
|
21
|
+
## Predecessor
|
|
22
|
+
|
|
23
|
+
[react-big-scheduler](https://github.com/StephenChou1017/react-big-scheduler),
|
|
24
|
+
Stephen Chou, is the predecessor this package replaces for the roster read surface.
|
|
25
|
+
react-native-roster is an independent implementation, not a fork; no predecessor
|
|
26
|
+
source is copied into this package.
|
|
27
|
+
|
|
28
|
+
Retain upstream licenses when adding third-party source or assets. Add new
|
|
29
|
+
attributions here in the same change. References do not imply endorsement.
|
package/README.md
CHANGED
|
@@ -1,5 +1,458 @@
|
|
|
1
1
|
# react-native-roster
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Lanes, layers, and sources on one time axis.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://simiancraft.github.io/react-native-roster/)
|
|
6
|
+
|
|
7
|
+
[](https://github.com/simiancraft/react-native-roster/actions/workflows/ci.yml)
|
|
8
|
+
[](https://codecov.io/github/simiancraft/react-native-roster)
|
|
9
|
+
[](#contract)
|
|
10
|
+
[](./.size-limit.json)
|
|
11
|
+
[](./demo/package.json)
|
|
12
|
+
[](./LICENSE)
|
|
13
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/simiancraft/react-native-roster)
|
|
14
|
+
|
|
15
|
+
A read surface for React Native and web that renders who is on, when, and why.
|
|
16
|
+
Feed it absolute intervals with provenance; press any filled or removed span and
|
|
17
|
+
get back the exact rules, rows, or exclusions that produced it. Daylight-saving
|
|
18
|
+
transitions are drawn honestly: skipped hours are hatched, repeated hours appear
|
|
19
|
+
twice. `Roster` stacks many lanes horizontally; `Schedule` opens one lane as a
|
|
20
|
+
week of wall-clock columns. The core is standard JavaScript plus `Intl`, under
|
|
21
|
+
15 kB, and recurrence expansion is an optional subpath.
|
|
22
|
+
|
|
23
|
+
It is not a calendar, a booking system, or a drag-to-create editor; you own
|
|
24
|
+
mutations and persistence. If you want an event grid with gestures, an event
|
|
25
|
+
calendar library is the better fit. If you need to explain coverage across two
|
|
26
|
+
hundred people without lying about time zones, this is the one.
|
|
27
|
+
|
|
28
|
+
- **Provenance on every span.** Intervals and gaps carry `sources`; presses
|
|
29
|
+
return the winning span's `(kind, id)` list, including the exclusion that
|
|
30
|
+
removed time.
|
|
31
|
+
- **Honest time.** Elapsed-time roster weeks are 167 or 169 hours wide across a
|
|
32
|
+
transition; schedule columns hatch skipped hours and draw repeated hours twice.
|
|
33
|
+
- **Layers with roles.** `availability`, `booking`, and `custom` layers stack by
|
|
34
|
+
z-order; coverage math unions availability, subtracts bookings, and sorts.
|
|
35
|
+
- **Recurrence adapter.** Weekly, daily, and monthly rules with exclusions,
|
|
36
|
+
caps, and content-keyed caches, kept out of the core.
|
|
37
|
+
- **Zones everywhere.** Input-bearing regions accept component types, singletons accept nodes, and
|
|
38
|
+
every chrome region takes `style` plus a NativeWind `className` twin.
|
|
39
|
+
- **Virtualized and measured.** Geometry runs only for mounted lanes; CI gates
|
|
40
|
+
layout, coverage, bundle size, and browser action budgets.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
bun add react-native-roster @legendapp/list
|
|
46
|
+
bunx expo install react-native-reanimated --bun
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
To try an unreleased checkout instead, pack it with `bun pm pack --destination
|
|
50
|
+
.cache` and `bun add` the printed tarball path. Keep React, React Native, and
|
|
51
|
+
Expo aligned with your SDK; the
|
|
52
|
+
tested demo uses Expo SDK 54, React 19.1, React Native 0.81.5, LegendList
|
|
53
|
+
2.0.19, and Reanimated 3.19.5. Web also needs React DOM and React Native Web.
|
|
54
|
+
Peer ranges are React 18.2+, React Native 0.74+, and LegendList 2+; Reanimated
|
|
55
|
+
is optional for core-only use and required by `Roster`. On Metro before React
|
|
56
|
+
Native 0.79, enable `resolver.unstable_enablePackageExports` so the `/core`,
|
|
57
|
+
`/rrule`, and `/nativewind` subpaths resolve.
|
|
58
|
+
|
|
59
|
+
## Quick start: static intervals
|
|
60
|
+
|
|
61
|
+
Twenty lines, no adapter. Give the component a bounded height.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { Roster } from 'react-native-roster';
|
|
65
|
+
import type { Lane } from 'react-native-roster/core';
|
|
66
|
+
|
|
67
|
+
const lanes: Lane[] = [{
|
|
68
|
+
id: 'one', label: 'Lane one', layers: [{
|
|
69
|
+
id: 'open', role: 'availability', z: 0,
|
|
70
|
+
style: { color: '#4f9478' },
|
|
71
|
+
intervals: [{
|
|
72
|
+
start: Date.UTC(2024, 0, 1, 9), end: Date.UTC(2024, 0, 1, 17),
|
|
73
|
+
sources: [{ kind: 'table', id: 'row-one' }],
|
|
74
|
+
}],
|
|
75
|
+
}],
|
|
76
|
+
}];
|
|
77
|
+
|
|
78
|
+
export function Example() {
|
|
79
|
+
return <Roster lanes={lanes}
|
|
80
|
+
style={{ height: 480, flex: undefined }}
|
|
81
|
+
windowSpec={{ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' }}
|
|
82
|
+
onIntervalPress={(rect, lane) => console.log(lane.id, rect.sources)} />;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Press the interval to receive its `table / row-one` source. `minuteStep`
|
|
87
|
+
defaults to 60 and accepts any positive divisor of 60; it changes ticks and
|
|
88
|
+
empty-space snapping, never interval boundaries. `rowHeight` defaults to 48 and
|
|
89
|
+
`pxPerMinute` to a minimum of 0.5, growing to fit wider viewports.
|
|
90
|
+
|
|
91
|
+
## Quick start: recurring local hours
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { Roster } from 'react-native-roster';
|
|
95
|
+
import type { Lane, WindowSpec } from 'react-native-roster/core';
|
|
96
|
+
import { windowFor } from 'react-native-roster/core';
|
|
97
|
+
import { expandRuleSet } from 'react-native-roster/rrule';
|
|
98
|
+
import type { RuleSet } from 'react-native-roster/rrule';
|
|
99
|
+
|
|
100
|
+
const spec: WindowSpec = {
|
|
101
|
+
span: 'week', anchorDate: '2024-01-01', timezone: 'America/Chicago',
|
|
102
|
+
};
|
|
103
|
+
const set: RuleSet = {
|
|
104
|
+
rules: [{
|
|
105
|
+
id: 'weekday-hours', kind: 'include', frequency: 'WEEKLY',
|
|
106
|
+
dtstart: '2024-01-01', byweekday: [0, 1, 2, 3, 4],
|
|
107
|
+
hourstart: 9, hourend: 17, timezone: 'America/Chicago',
|
|
108
|
+
}],
|
|
109
|
+
dates: [{
|
|
110
|
+
id: 'closed', kind: 'exclude', date: '2024-01-02',
|
|
111
|
+
timezone: 'America/Chicago', note: 'Closed all day',
|
|
112
|
+
}],
|
|
113
|
+
};
|
|
114
|
+
const result = expandRuleSet(set, windowFor(spec));
|
|
115
|
+
const lane: Lane = {
|
|
116
|
+
id: 'one', label: 'Lane one', timezone: 'America/Chicago',
|
|
117
|
+
complete: result.complete,
|
|
118
|
+
layers: [{
|
|
119
|
+
id: 'open', role: 'availability', z: 0, style: { color: '#4f9478' },
|
|
120
|
+
intervals: result.intervals, gaps: result.gaps,
|
|
121
|
+
}],
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export function RecurringExample() {
|
|
125
|
+
return <Roster lanes={[lane]} windowSpec={spec}
|
|
126
|
+
style={{ height: 480, flex: undefined }}
|
|
127
|
+
onGapPress={(rect) => console.log(rect.sources)} />;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Tuesday is a gap carrying the dated exclusion; the other weekdays carry the
|
|
132
|
+
include rule. Expand once per `windowFor(spec)` in your screen's hook, never
|
|
133
|
+
inside a slot component; content-keyed caches reuse unchanged occurrences. The
|
|
134
|
+
[adapter guide](./docs/adapters.md) covers validation, caps, cache lifetime,
|
|
135
|
+
and mapping tables or feeds without a recurrence dependency;
|
|
136
|
+
[recurrence semantics](./docs/recurrence.md) records the exact anchor, UNTIL,
|
|
137
|
+
COUNT, and BYSETPOS rules.
|
|
138
|
+
|
|
139
|
+
## Contract
|
|
140
|
+
|
|
141
|
+
| Term | Meaning |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| roster | Shared time axis, lanes, and layers. |
|
|
144
|
+
| lane | One person or resource row; `id`, `label`, `layers`, and optional display metadata. |
|
|
145
|
+
| layer | Ordered intervals and gaps with `id`, `role`, `z`, and `style`. |
|
|
146
|
+
| interval | Covered `[start, end)` in epoch milliseconds, with `sources: Source[]`. |
|
|
147
|
+
| gap | Removed `[start, end)` with exclusion sources; survives complete subtraction. |
|
|
148
|
+
| source | `{ kind, id, label? }`; identity is `(kind, id)`, never the label. |
|
|
149
|
+
| window | Absolute `{ start, end }` only; span and resolution belong to the axis. |
|
|
150
|
+
| projection | Horizontal elapsed time, or day columns with wall-clock hours. |
|
|
151
|
+
| adapter | Consumer-side conversion from upstream data to lanes and layers. |
|
|
152
|
+
| schedule | One lane projected into days across and hours down. |
|
|
153
|
+
|
|
154
|
+
`LayerRole` is `'availability' | 'booking' | 'custom'`. The first two feed
|
|
155
|
+
coverage math (`availabilityMinutes`, `bookingMinutes`, and
|
|
156
|
+
`availabilityMinusBookingMinutes`); use `custom` for anything else. `LayerStyle`
|
|
157
|
+
is `{ color, highlightColor?, inset?, opacity? }`; the engine applies inset on
|
|
158
|
+
the cross axis and returns final bounds for drawing and hit testing.
|
|
159
|
+
|
|
160
|
+
`Lane` also accepts optional data-quality fields: `version` (bump when layers
|
|
161
|
+
change), `timezone` (a badge), `flag: 'never-set'` for lanes you know were never
|
|
162
|
+
configured, `complete: false` when an adapter cap truncated the result, and
|
|
163
|
+
`meta` for your own display data. The notices default to "No availability set"
|
|
164
|
+
and "Availability may be incomplete"; both are localizable props.
|
|
165
|
+
|
|
166
|
+
## Entry points
|
|
167
|
+
|
|
168
|
+
| Import | Shipped surface |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `react-native-roster` | `Roster`, `Schedule`, `useRoster`, `useSchedule`, slot components, and all core exports. |
|
|
171
|
+
| `react-native-roster/core` | Types, `layoutLane`, `coverageFor`, `flagFor`, axis helpers, comparators, and counters. Standard JavaScript and `Intl` only. |
|
|
172
|
+
| `react-native-roster/rrule` | `expandRuleSet`, `envelopeFor`, types, and expansion counters and caches. Uses pinned `rrule-temporal` and `@js-temporal/polyfill`. |
|
|
173
|
+
| `react-native-roster/nativewind` | Registers `Roster` and `Schedule` with NativeWind so their `className` props resolve; re-exports the registered components. |
|
|
174
|
+
|
|
175
|
+
Root and core never import recurrence dependencies. Metro selects TypeScript
|
|
176
|
+
source through the `react-native` export condition; other bundlers select
|
|
177
|
+
emitted CommonJS with declarations in `dist/src`. The emit is CommonJS, so
|
|
178
|
+
importing one function from the root costs the whole root bundle; import from
|
|
179
|
+
`/core` for a core-only bundle. Cache keys, counters, and clearing are in
|
|
180
|
+
[caches](./docs/caches.md).
|
|
181
|
+
|
|
182
|
+
## Navigation and interaction
|
|
183
|
+
|
|
184
|
+
A `WindowSpec` is `{ span: 'day' | 'week' | 'month', anchorDate, timezone, wkst? }`
|
|
185
|
+
or `{ span: 'custom', window, timezone }`. `anchorDate` is a local `YYYY-MM-DD`.
|
|
186
|
+
`windowFor`, `prev`, `next`, and `today` handle bounds and navigation; weeks
|
|
187
|
+
start Monday (weekday 0) unless `wkst` says otherwise. Components accept
|
|
188
|
+
`onNavigate` but ship no toolbar; your controls update the controlled spec.
|
|
189
|
+
|
|
190
|
+
Three zones take part in a render: the rule timezone interprets local hours in
|
|
191
|
+
the adapter, the lane timezone is a badge, and `windowSpec.timezone` drives the
|
|
192
|
+
projection. Changing the view zone preserves the local anchor and usually reuses
|
|
193
|
+
expanded occurrences. Column spans, rollbacks across midnight, and pointer
|
|
194
|
+
inversion are documented in [timezones](./docs/timezones.md).
|
|
195
|
+
|
|
196
|
+
Presses resolve one result: intervals before gaps, highest z first, later
|
|
197
|
+
layers winning equal-z ties. `onIntervalPress(rect, lane)` and
|
|
198
|
+
`onGapPress(rect, lane)` return the contributing sources; `onCellPress(lane,
|
|
199
|
+
time)` returns snapped absolute time for empty space. `onIntervalHover` is
|
|
200
|
+
Roster's web-only pointer callback. `highlightSource={{ kind, id }}` applies
|
|
201
|
+
`highlightColor` to every matching rect without new geometry. Sorting defaults
|
|
202
|
+
to `byLabel`; `byCoverage({ measure })` sorts by coverage descending.
|
|
203
|
+
|
|
204
|
+
## Roster zones
|
|
205
|
+
|
|
206
|
+
Props ending in `Component` accept `ComponentType<Input>` and are mounted by React.
|
|
207
|
+
Props ending in `Zone` accept `ReactNode`. Define components at module scope so
|
|
208
|
+
state survives rerenders; hooks and class components are supported. Compose the
|
|
209
|
+
exported default components inside replacements to retain scrolling, geometry,
|
|
210
|
+
or press behavior. Pass `null` to a node slot to suppress its default.
|
|
211
|
+
|
|
212
|
+
| Slot | Component inputs or node | Default and behavior |
|
|
213
|
+
| --- | --- | --- |
|
|
214
|
+
| `emptyZone` | `ReactNode` | `RosterEmpty`: No lanes. |
|
|
215
|
+
| `cornerZone` | `ReactNode` | `RosterCorner`: nothing; the cell above the labels, `laneLabelWidth` wide. |
|
|
216
|
+
| `laneLabelComponent` | `lane`, `flag`, `complete`, `viewTimezone`, localized labels | `RosterLaneLabel`: label, differing IANA zone badge, and notices. |
|
|
217
|
+
| `headerCellComponent` | `HeaderCellInput` (`tick`) | `RosterHeaderCell`: tick label. |
|
|
218
|
+
| `intervalComponent` | `rect`, `layer`, `lane`, `highlighted` | `RosterInterval`: positioned colored rect, with final inset bounds. |
|
|
219
|
+
| `gapComponent` | `rect`, `layer`, `lane` | `RosterGap`: no visible content; the row supplies pressable bounds. |
|
|
220
|
+
| `gridComponent` | `ticks`, `contentWidth` | `RosterGrid`: one hairline per tick behind every lane. |
|
|
221
|
+
| `headerComponent` | `ticks`, `projection`, `scroll`, `contentWidth`, `headerCellComponent` | `RosterHeader`: frozen header following horizontal offset. |
|
|
222
|
+
| `laneLabelColumnComponent` | `labels`, `projection`, `scroll`, `laneLabelComponent` | `RosterLaneLabelColumn`: frozen labels following vertical offset. |
|
|
223
|
+
| `bodyComponent` | Ordered `lanes`, `window`, `geometryFor`, `projection`, `scroll`, `press`, `ticks`, `viewport`, `contentWidth`, highlight and hover, incomplete label, and rect components | `RosterBody`: virtualized lanes. |
|
|
224
|
+
|
|
225
|
+
`RosterBody` composes `RosterBodyLayout`, which arranges `gridZone` and `listZone`
|
|
226
|
+
nodes with scroll wiring, and `RosterLaneList`, which owns LegendList and its
|
|
227
|
+
per-lane callback. The body waits for viewport measurement before mounting the list.
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import type { LaneLabelInput } from 'react-native-roster';
|
|
231
|
+
import { Text } from 'react-native';
|
|
232
|
+
|
|
233
|
+
function LaneLabel({ lane }: LaneLabelInput) {
|
|
234
|
+
return <Text>{lane.label}</Text>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
<Roster lanes={lanes} windowSpec={windowSpec}
|
|
238
|
+
laneLabelComponent={LaneLabel} cornerZone={<Text>People</Text>} />
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
A custom interval component positions at `rect.x/y`, uses `rect.width/height/z`,
|
|
242
|
+
and sets `pointerEvents="none"` so the parent hit-test walk owns presses. Gap
|
|
243
|
+
fillers are already inside positioned pressables. `useRoster` exposes ordered
|
|
244
|
+
lanes, coverage, lane state, ticks, `geometryFor`, shared scrolling, `press`,
|
|
245
|
+
viewport measurement, navigation, and status for fully custom layouts.
|
|
246
|
+
|
|
247
|
+
Chrome regions take style props: `style`, `headerStyle` (the 40 px header row
|
|
248
|
+
holding the corner and ticks), `laneLabelColumnStyle`, and `bodyStyle`.
|
|
249
|
+
`laneLabelWidth` sizes the corner and label column, default 180. Each style
|
|
250
|
+
prop has a `className` twin; see [NativeWind](#nativewind).
|
|
251
|
+
|
|
252
|
+
### Consumer data in slot components
|
|
253
|
+
|
|
254
|
+
For consumer data beyond a slot's Input, mount a React context provider above
|
|
255
|
+
`Roster` and read it with `useContext` in a module-scope slot component. This
|
|
256
|
+
example supplies density and locale while keeping the header cell type stable:
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
import { createContext, useContext } from 'react';
|
|
260
|
+
import { Text } from 'react-native';
|
|
261
|
+
import type { HeaderCellInput, RosterProps } from 'react-native-roster';
|
|
262
|
+
import { Roster } from 'react-native-roster';
|
|
263
|
+
|
|
264
|
+
type SlotPreferences = {
|
|
265
|
+
density: 'compact' | 'comfortable';
|
|
266
|
+
locale: string;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const SlotPreferencesContext = createContext<SlotPreferences>({
|
|
270
|
+
density: 'comfortable',
|
|
271
|
+
locale: 'en-US',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
function LocalizedHeaderCell({ tick }: HeaderCellInput) {
|
|
275
|
+
const { density, locale } = useContext(SlotPreferencesContext);
|
|
276
|
+
const label = new Intl.DateTimeFormat(locale, {
|
|
277
|
+
timeZone: 'UTC',
|
|
278
|
+
...(tick.kind === 'day'
|
|
279
|
+
? { month: 'short', day: 'numeric' }
|
|
280
|
+
: { hour: 'numeric', minute: '2-digit' }),
|
|
281
|
+
}).format(tick.time);
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<Text numberOfLines={1} style={{ padding: density === 'compact' ? 2 : 6 }}>
|
|
285
|
+
{label}
|
|
286
|
+
</Text>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function ConsumerRoster({ lanes }: Pick<RosterProps, 'lanes'>) {
|
|
291
|
+
return (
|
|
292
|
+
<SlotPreferencesContext.Provider value={{ density: 'compact', locale: 'en-GB' }}>
|
|
293
|
+
<Roster
|
|
294
|
+
lanes={lanes}
|
|
295
|
+
windowSpec={{ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' }}
|
|
296
|
+
style={{ height: 480, flex: undefined }}
|
|
297
|
+
headerCellComponent={LocalizedHeaderCell}
|
|
298
|
+
/>
|
|
299
|
+
</SlotPreferencesContext.Provider>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
An inline closure or a memoized factory that returns a new component per render
|
|
305
|
+
is not the recommended path. A new interval component type remounts every interval
|
|
306
|
+
and defeats the body's content key. Context supplies changing consumer data while
|
|
307
|
+
preserving the module-scope component type.
|
|
308
|
+
|
|
309
|
+
## Schedule and its zones
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
import { Schedule } from 'react-native-roster';
|
|
313
|
+
import type { Lane } from 'react-native-roster/core';
|
|
314
|
+
|
|
315
|
+
export function Week({ lane }: { lane: Lane }) {
|
|
316
|
+
return <Schedule lane={lane} minuteStep={60}
|
|
317
|
+
style={{ height: 600, flex: undefined }}
|
|
318
|
+
windowSpec={{ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' }}
|
|
319
|
+
onIntervalPress={(rect) => console.log(rect.sources)} />;
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Only day and week specs are accepted. The component measures its width,
|
|
324
|
+
reserves a 48 px gutter, and fits the day columns without horizontal scrolling.
|
|
325
|
+
`pxPerHour` defaults to 48. Chrome takes `style`, `headerStyle`, `gutterStyle`,
|
|
326
|
+
and `daysStyle`, each with a `className` twin.
|
|
327
|
+
|
|
328
|
+
| Slot | Component inputs or node | Default and behavior |
|
|
329
|
+
| --- | --- | --- |
|
|
330
|
+
| `gutterComponent` | `hours`, `pxPerHour` | `ScheduleGutter`: 24 frozen hour labels. |
|
|
331
|
+
| `gridComponent` | `hours`, `pxPerHour` | `ScheduleGrid`: 24 bordered hour bands behind each day's rects. |
|
|
332
|
+
| `dayHeaderComponent` | `day` | `ScheduleDayHeader`: weekday, localDate, and transition badge. |
|
|
333
|
+
| `skippedDateComponent` | `localDate` | `ScheduleSkippedDate`: zero-width header marker for a wholly skipped date. |
|
|
334
|
+
| `columnComponent` | `day`, `rects`, `gapRects`, `lane`, `highlightSource`, `press`, interval and gap components | `ScheduleColumn`: final rect bounds in layer order. |
|
|
335
|
+
| `transitionComponent` | `day`, `transition`, `y`, `dividerY`, `height`, `width` | `ScheduleTransition`: skipped-time hatch, or repeat divider and again label. |
|
|
336
|
+
| `nowLineComponent` | `y`, `column` | `ScheduleNowLine`: line in the current day's column, updated each minute. |
|
|
337
|
+
| `intervalComponent`, `gapComponent` | Same inputs as Roster | Shared `RosterInterval` and `RosterGap`. |
|
|
338
|
+
| `incompleteComponent` | `lane`, `label` | `ScheduleIncomplete`: notice above the grid when the lane is incomplete. |
|
|
339
|
+
|
|
340
|
+
## NativeWind
|
|
341
|
+
|
|
342
|
+
`className` is a first-class prop on `Roster` and `Schedule`, alongside `style`.
|
|
343
|
+
Every chrome style prop has a class twin: `className`, `headerClassName`,
|
|
344
|
+
`laneLabelColumnClassName`, and `bodyClassName` on Roster; `className`,
|
|
345
|
+
`headerClassName`, `gutterClassName`, and `daysClassName` on Schedule. A class
|
|
346
|
+
on a region replaces that region's default paint (background and border colors)
|
|
347
|
+
while its structure (size, flex, overflow) stays. This is deliberate: React
|
|
348
|
+
Native Web renders object styles inline, and inline paint would otherwise beat
|
|
349
|
+
any class.
|
|
350
|
+
|
|
351
|
+
Set up NativeWind 4 as usual (the demo's [babel.config.js](./demo/babel.config.js),
|
|
352
|
+
[metro.config.js](./demo/metro.config.js), [tailwind.config.js](./demo/tailwind.config.js),
|
|
353
|
+
and [global.css](./demo/global.css) are a working reference), add the optional
|
|
354
|
+
peer with `bun add nativewind`, and register the components once at your app
|
|
355
|
+
root:
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
// app/_layout.tsx
|
|
359
|
+
import '../global.css';
|
|
360
|
+
import 'react-native-roster/nativewind';
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
import { Roster } from 'react-native-roster';
|
|
365
|
+
|
|
366
|
+
<Roster
|
|
367
|
+
lanes={lanes}
|
|
368
|
+
windowSpec={windowSpec}
|
|
369
|
+
className="flex-1 rounded-xl bg-background"
|
|
370
|
+
headerClassName="border-b border-border bg-card"
|
|
371
|
+
laneLabelColumnClassName="border-r border-border bg-card"
|
|
372
|
+
laneLabelWidth={220}
|
|
373
|
+
/>
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Slot components are ordinary React Native views, so a custom `laneLabelComponent` or
|
|
377
|
+
`intervalComponent` uses `className` on `View` and `Text` directly. Without the
|
|
378
|
+
entry point, class props are ignored and style props still work. The entry
|
|
379
|
+
point is the package's only module with side effects and is listed in
|
|
380
|
+
`sideEffects`. The [showcase route](./demo/app/showcase.tsx) styles every region
|
|
381
|
+
and zone this way in light and dark palettes.
|
|
382
|
+
|
|
383
|
+
## Gallery and platform support
|
|
384
|
+
|
|
385
|
+
The [Expo gallery](https://simiancraft.github.io/react-native-roster/) is the
|
|
386
|
+
demo; there is no Storybook. Run it locally with `bun install --frozen-lockfile`,
|
|
387
|
+
`bun run build`, and `bun run demo:web` (add `EXPO_OFFLINE=1` in a restricted
|
|
388
|
+
network). The home page lists every fixture route:
|
|
389
|
+
|
|
390
|
+
- Empty, one, 20, and 200 lanes; inset layers; default and replaced zones.
|
|
391
|
+
- Day, week, and month routes at 15, 30, and 60-minute steps.
|
|
392
|
+
- Full-day gaps, lane flags, equal-z precedence, highlight, coverage sorting,
|
|
393
|
+
and incomplete expansion.
|
|
394
|
+
- Chicago DST weeks, mixed rule, lane, and view zones, and editable adapter routes.
|
|
395
|
+
- Schedule empty, layered, excluded, spring, fall, Lord Howe, Apia, incomplete,
|
|
396
|
+
midnight, side-by-side projections, and every zone.
|
|
397
|
+
- The showcase at `/showcase`: twelve generated people across seven zones,
|
|
398
|
+
weekly hours and exclusions from the recurrence adapter, booked events, day
|
|
399
|
+
and week spans, sorting, filtering, and a per-person Schedule, styled with
|
|
400
|
+
NativeWind class props and slot components, with a sun and moon theme toggle.
|
|
401
|
+
Names, titles, and the organization come from `@faker-js/faker` with a fixed
|
|
402
|
+
seed; any resemblance to real people is coincidental.
|
|
403
|
+
|
|
404
|
+
| Platform | Support and evidence |
|
|
405
|
+
| --- | --- |
|
|
406
|
+
| Web via React Native Web | Static export and Chromium gallery checks; first-class target. |
|
|
407
|
+
| iOS | React Native implementation; device rendering and Hermes behavior not yet verified here. |
|
|
408
|
+
| Android | React Native implementation; device rendering and release performance not yet captured. |
|
|
409
|
+
| Node and Bun | Built core and adapter work without a renderer; root components require native peers or a web bundler. |
|
|
410
|
+
|
|
411
|
+
## Performance
|
|
412
|
+
|
|
413
|
+
Workload W is 200 lanes, one week, two layers, a 24-lane viewport, and
|
|
414
|
+
15-minute ticks: 63 interval rects and 7 gap rects per lane. The
|
|
415
|
+
[committed CI baseline](./test/performance/baseline.json) on GitHub Actions
|
|
416
|
+
ubuntu-latest records target-cold layout of 24 lanes at 2.070 ms and coverage of
|
|
417
|
+
all 200 lanes at 1.063 ms, gated below 16 ms everywhere and within 1.5 times the
|
|
418
|
+
baseline in CI. Size gates hold core under 15 kB and root under 44 kB. Device
|
|
419
|
+
captures and the paired comparison against other libraries are described, not
|
|
420
|
+
yet recorded, in the [performance guide](./docs/performance.md); CI timings are
|
|
421
|
+
not phone frame rates.
|
|
422
|
+
|
|
423
|
+
## What this isn't
|
|
424
|
+
|
|
425
|
+
This is a read surface. Consumers own creation, dragging, resizing,
|
|
426
|
+
persistence, and permission checks through their own interactions. It is not a
|
|
427
|
+
month grid or an arbitrary event list, and it does not expand rules inside the
|
|
428
|
+
core. The short [design note](./docs/design.md) explains the reasoning.
|
|
429
|
+
|
|
430
|
+
## Development and reference
|
|
431
|
+
|
|
432
|
+
```sh
|
|
433
|
+
bunx playwright install chromium
|
|
434
|
+
bun run check
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
`check` runs Biome, library, test, and demo typechecks, React Compiler safety,
|
|
438
|
+
the library build, the static web export, tests with coverage, knip, strict
|
|
439
|
+
publint, size-limit, and Playwright.
|
|
440
|
+
|
|
441
|
+
- [Migrations](https://github.com/simiancraft/react-native-roster/blob/main/docs/migrations.md) lists prop renames by version with before-and-after examples.
|
|
442
|
+
- [Adapter guide](./docs/adapters.md), [recurrence semantics](./docs/recurrence.md),
|
|
443
|
+
[timezones](./docs/timezones.md), [caches](./docs/caches.md), and the
|
|
444
|
+
[performance guide](./docs/performance.md).
|
|
445
|
+
- [Design note](./docs/design.md): precompute, then render geometry.
|
|
446
|
+
- Area landing pages: [core](./src/core/README.md), [Roster](./src/components/roster/README.md),
|
|
447
|
+
[Schedule](./src/components/schedule/README.md), [layers](./src/components/layers/README.md),
|
|
448
|
+
[primitives](./src/components/primitives/README.md), [rrule adapter](./src/adapters/rrule/README.md),
|
|
449
|
+
[nativewind](./src/nativewind/README.md), the [gallery](./demo/components/gallery/README.md), and the
|
|
450
|
+
[showcase](./demo/components/team-roster/README.md), and the [theme](./demo/components/theme/README.md);
|
|
451
|
+
[adding an adapter](./docs/adding-an-adapter.md)
|
|
452
|
+
is the contributor recipe.
|
|
453
|
+
- [llms.txt](./llms.txt): integration instructions for agents.
|
|
454
|
+
- [CONTRIBUTING.md](./CONTRIBUTING.md) and [AGENTS.md](./AGENTS.md): contributor workflow.
|
|
455
|
+
- [CHANGELOG.md](./CHANGELOG.md): release history, maintained by semantic-release.
|
|
456
|
+
- [SECURITY.md](./SECURITY.md), [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md), and [NOTICE.md](./NOTICE.md).
|
|
457
|
+
|
|
458
|
+
MIT, copyright 2026 Jesse Harlin (the-simian). See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Window } from '../../core';
|
|
2
|
+
import type { ExpandStats } from './types';
|
|
3
|
+
export type Occurrences = {
|
|
4
|
+
spans: Window[];
|
|
5
|
+
capped: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare const occurrences: Map<string, Occurrences>;
|
|
8
|
+
export declare function touch<T>(cache: Map<string, T>, key: string, value: T): T;
|
|
9
|
+
export declare function trim<T>(cache: Map<string, T>, limit: number): void;
|
|
10
|
+
export declare function retainedEnvelope(window: Window, limit: number): Window;
|
|
11
|
+
export declare function recordStats(stats: ExpandStats): void;
|
|
12
|
+
export declare function expandStats(): ExpandStats;
|
|
13
|
+
export declare function resetExpandStats(): void;
|
|
14
|
+
export declare function clearExpandCache(): void;
|
|
15
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/adapters/rrule/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAC/D,eAAO,MAAM,WAAW,0BAAiC,CAAC;AAM1D,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAIxE;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAElE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAEpD;AAED,wBAAgB,WAAW,IAAI,WAAW,CAEzC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.occurrences = void 0;
|
|
4
|
+
exports.touch = touch;
|
|
5
|
+
exports.trim = trim;
|
|
6
|
+
exports.retainedEnvelope = retainedEnvelope;
|
|
7
|
+
exports.recordStats = recordStats;
|
|
8
|
+
exports.expandStats = expandStats;
|
|
9
|
+
exports.resetExpandStats = resetExpandStats;
|
|
10
|
+
exports.clearExpandCache = clearExpandCache;
|
|
11
|
+
const envelope_1 = require("./envelope");
|
|
12
|
+
exports.occurrences = new Map();
|
|
13
|
+
const envelopes = new Map();
|
|
14
|
+
const counts = { rules: 0, dates: 0, expanded: 0, cacheHits: 0, cacheMisses: 0 };
|
|
15
|
+
// Map insertion order is the LRU: reads move entries to the newest end.
|
|
16
|
+
// Envelope retention selects bounds only; no netted result is retained.
|
|
17
|
+
function touch(cache, key, value) {
|
|
18
|
+
cache.delete(key);
|
|
19
|
+
cache.set(key, value);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function trim(cache, limit) {
|
|
23
|
+
while (cache.size > limit)
|
|
24
|
+
cache.delete(cache.keys().next().value);
|
|
25
|
+
}
|
|
26
|
+
function retainedEnvelope(window, limit) {
|
|
27
|
+
trim(envelopes, limit);
|
|
28
|
+
for (const [id, envelope] of [...envelopes].reverse()) {
|
|
29
|
+
if (envelope.start <= window.start && envelope.end >= window.end) {
|
|
30
|
+
return touch(envelopes, id, envelope);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const envelope = (0, envelope_1.envelopeFor)(window);
|
|
34
|
+
touch(envelopes, JSON.stringify(envelope), envelope);
|
|
35
|
+
trim(envelopes, limit);
|
|
36
|
+
return envelope;
|
|
37
|
+
}
|
|
38
|
+
function recordStats(stats) {
|
|
39
|
+
for (const key of Object.keys(counts))
|
|
40
|
+
counts[key] += stats[key];
|
|
41
|
+
}
|
|
42
|
+
function expandStats() {
|
|
43
|
+
return { ...counts };
|
|
44
|
+
}
|
|
45
|
+
function resetExpandStats() {
|
|
46
|
+
for (const key of Object.keys(counts))
|
|
47
|
+
counts[key] = 0;
|
|
48
|
+
}
|
|
49
|
+
function clearExpandCache() {
|
|
50
|
+
exports.occurrences.clear();
|
|
51
|
+
envelopes.clear();
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/adapters/rrule/cache.ts"],"names":[],"mappings":";;;;;;;;;;AACA,yCAAyC;AAI5B,QAAA,WAAW,GAAG,IAAI,GAAG,EAAuB,CAAC;AAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;AAC5C,MAAM,MAAM,GAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAE9F,wEAAwE;AACxE,wEAAwE;AACxE,eAAyB,KAAqB,EAAE,GAAW,EAAE,KAAQ;IACnE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAwB,KAAqB,EAAE,KAAa;IAC1D,OAAO,KAAK,CAAC,IAAI,GAAG,KAAK;QAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;AAC/E,CAAC;AAED,0BAAiC,MAAc,EAAE,KAAa;IAC5D,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACvB,KAAK,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,IAAI,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACjE,OAAO,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,IAAA,sBAAW,EAAC,MAAM,CAAC,CAAC;IACrC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrD,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACvB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,qBAA4B,KAAkB;IAC5C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAA6B;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;AAC/F,CAAC;AAED;IACE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;AACvB,CAAC;AAED;IACE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAA6B;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrF,CAAC;AAED;IACE,QAAA,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../../src/adapters/rrule/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIzC,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.envelopeFor = envelopeFor;
|
|
4
|
+
// Absolute 48-hour padding exceeds the 26-hour difference between view zones.
|
|
5
|
+
// Includes, excludes, and dates share these bounds before subtraction.
|
|
6
|
+
function envelopeFor(window) {
|
|
7
|
+
return { start: window.start - 48 * 3_600_000, end: window.end + 48 * 3_600_000 };
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../../src/adapters/rrule/envelope.ts"],"names":[],"mappings":";;;AAEA,8EAA8E;AAC9E,uEAAuE;AACvE,qBAA4B,MAAc;IACxC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expand.d.ts","sourceRoot":"","sources":["../../../../src/adapters/rrule/expand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,MAAM,EAAE,MAAM,YAAY,CAAC;AAM3D,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAIZ,OAAO,EACR,MAAM,SAAS,CAAC;AAGjB,wBAAgB,aAAa,CAC3B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAgFd"}
|