react-native-roster 0.0.0 → 0.0.1

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.
Files changed (362) hide show
  1. package/NOTICE.md +29 -0
  2. package/README.md +378 -2
  3. package/dist/src/adapters/rrule/cache.d.ts +15 -0
  4. package/dist/src/adapters/rrule/cache.d.ts.map +1 -0
  5. package/dist/src/adapters/rrule/cache.js +53 -0
  6. package/dist/src/adapters/rrule/cache.js.map +1 -0
  7. package/dist/src/adapters/rrule/envelope.d.ts +3 -0
  8. package/dist/src/adapters/rrule/envelope.d.ts.map +1 -0
  9. package/dist/src/adapters/rrule/envelope.js +9 -0
  10. package/dist/src/adapters/rrule/envelope.js.map +1 -0
  11. package/dist/src/adapters/rrule/expand.d.ts +4 -0
  12. package/dist/src/adapters/rrule/expand.d.ts.map +1 -0
  13. package/dist/src/adapters/rrule/expand.js +92 -0
  14. package/dist/src/adapters/rrule/expand.js.map +1 -0
  15. package/dist/src/adapters/rrule/hash.d.ts +3 -0
  16. package/dist/src/adapters/rrule/hash.d.ts.map +1 -0
  17. package/dist/src/adapters/rrule/hash.js +15 -0
  18. package/dist/src/adapters/rrule/hash.js.map +1 -0
  19. package/dist/src/adapters/rrule/index.d.ts +5 -0
  20. package/dist/src/adapters/rrule/index.d.ts.map +1 -0
  21. package/dist/src/adapters/rrule/index.js +12 -0
  22. package/dist/src/adapters/rrule/index.js.map +1 -0
  23. package/dist/src/adapters/rrule/net.d.ts +6 -0
  24. package/dist/src/adapters/rrule/net.d.ts.map +1 -0
  25. package/dist/src/adapters/rrule/net.js +31 -0
  26. package/dist/src/adapters/rrule/net.js.map +1 -0
  27. package/dist/src/adapters/rrule/occurrences.d.ts +6 -0
  28. package/dist/src/adapters/rrule/occurrences.d.ts.map +1 -0
  29. package/dist/src/adapters/rrule/occurrences.js +252 -0
  30. package/dist/src/adapters/rrule/occurrences.js.map +1 -0
  31. package/dist/src/adapters/rrule/types.d.ts +62 -0
  32. package/dist/src/adapters/rrule/types.d.ts.map +1 -0
  33. package/dist/src/adapters/rrule/types.js +3 -0
  34. package/dist/src/adapters/rrule/types.js.map +1 -0
  35. package/dist/src/adapters/rrule/validate.d.ts +6 -0
  36. package/dist/src/adapters/rrule/validate.d.ts.map +1 -0
  37. package/dist/src/adapters/rrule/validate.js +64 -0
  38. package/dist/src/adapters/rrule/validate.js.map +1 -0
  39. package/dist/src/components/layers/layers.types.d.ts +15 -0
  40. package/dist/src/components/layers/layers.types.d.ts.map +1 -0
  41. package/dist/src/components/layers/layers.types.js +3 -0
  42. package/dist/src/components/layers/layers.types.js.map +1 -0
  43. package/dist/src/components/layers/parts/gap.d.ts +3 -0
  44. package/dist/src/components/layers/parts/gap.d.ts.map +1 -0
  45. package/dist/src/components/layers/parts/gap.js +7 -0
  46. package/dist/src/components/layers/parts/gap.js.map +1 -0
  47. package/dist/src/components/layers/parts/interval.d.ts +3 -0
  48. package/dist/src/components/layers/parts/interval.d.ts.map +1 -0
  49. package/dist/src/components/layers/parts/interval.js +22 -0
  50. package/dist/src/components/layers/parts/interval.js.map +1 -0
  51. package/dist/src/components/layers/utils/styles.d.ts +7 -0
  52. package/dist/src/components/layers/utils/styles.d.ts.map +1 -0
  53. package/dist/src/components/layers/utils/styles.js +24 -0
  54. package/dist/src/components/layers/utils/styles.js.map +1 -0
  55. package/dist/src/components/primitives/press-point.d.ts +3 -0
  56. package/dist/src/components/primitives/press-point.d.ts.map +1 -0
  57. package/dist/src/components/primitives/press-point.js +7 -0
  58. package/dist/src/components/primitives/press-point.js.map +1 -0
  59. package/dist/src/components/primitives/press-point.types.d.ts +14 -0
  60. package/dist/src/components/primitives/press-point.types.d.ts.map +1 -0
  61. package/dist/src/components/primitives/press-point.types.js +3 -0
  62. package/dist/src/components/primitives/press-point.types.js.map +1 -0
  63. package/dist/src/components/primitives/press-point.web.d.ts +3 -0
  64. package/dist/src/components/primitives/press-point.web.d.ts.map +1 -0
  65. package/dist/src/components/primitives/press-point.web.js +17 -0
  66. package/dist/src/components/primitives/press-point.web.js.map +1 -0
  67. package/dist/src/components/primitives/region-style.d.ts +9 -0
  68. package/dist/src/components/primitives/region-style.d.ts.map +1 -0
  69. package/dist/src/components/primitives/region-style.js +20 -0
  70. package/dist/src/components/primitives/region-style.js.map +1 -0
  71. package/dist/src/components/roster/index.d.ts +3 -0
  72. package/dist/src/components/roster/index.d.ts.map +1 -0
  73. package/dist/src/components/roster/index.js +56 -0
  74. package/dist/src/components/roster/index.js.map +1 -0
  75. package/dist/src/components/roster/lanes/interval-hover.d.ts +3 -0
  76. package/dist/src/components/roster/lanes/interval-hover.d.ts.map +1 -0
  77. package/dist/src/components/roster/lanes/interval-hover.js +7 -0
  78. package/dist/src/components/roster/lanes/interval-hover.js.map +1 -0
  79. package/dist/src/components/roster/lanes/interval-hover.types.d.ts +15 -0
  80. package/dist/src/components/roster/lanes/interval-hover.types.d.ts.map +1 -0
  81. package/dist/src/components/roster/lanes/interval-hover.types.js +3 -0
  82. package/dist/src/components/roster/lanes/interval-hover.types.js.map +1 -0
  83. package/dist/src/components/roster/lanes/interval-hover.web.d.ts +3 -0
  84. package/dist/src/components/roster/lanes/interval-hover.web.d.ts.map +1 -0
  85. package/dist/src/components/roster/lanes/interval-hover.web.js +20 -0
  86. package/dist/src/components/roster/lanes/interval-hover.web.js.map +1 -0
  87. package/dist/src/components/roster/lanes/lane.d.ts +10 -0
  88. package/dist/src/components/roster/lanes/lane.d.ts.map +1 -0
  89. package/dist/src/components/roster/lanes/lane.js +37 -0
  90. package/dist/src/components/roster/lanes/lane.js.map +1 -0
  91. package/dist/src/components/roster/lanes/parts/incomplete.d.ts +8 -0
  92. package/dist/src/components/roster/lanes/parts/incomplete.d.ts.map +1 -0
  93. package/dist/src/components/roster/lanes/parts/incomplete.js +30 -0
  94. package/dist/src/components/roster/lanes/parts/incomplete.js.map +1 -0
  95. package/dist/src/components/roster/lanes/parts/lane-label.d.ts +3 -0
  96. package/dist/src/components/roster/lanes/parts/lane-label.d.ts.map +1 -0
  97. package/dist/src/components/roster/lanes/parts/lane-label.js +18 -0
  98. package/dist/src/components/roster/lanes/parts/lane-label.js.map +1 -0
  99. package/dist/src/components/roster/layout.d.ts +17 -0
  100. package/dist/src/components/roster/layout.d.ts.map +1 -0
  101. package/dist/src/components/roster/layout.js +24 -0
  102. package/dist/src/components/roster/layout.js.map +1 -0
  103. package/dist/src/components/roster/parts/body.d.ts +7 -0
  104. package/dist/src/components/roster/parts/body.d.ts.map +1 -0
  105. package/dist/src/components/roster/parts/body.js +29 -0
  106. package/dist/src/components/roster/parts/body.js.map +1 -0
  107. package/dist/src/components/roster/parts/corner.d.ts +2 -0
  108. package/dist/src/components/roster/parts/corner.d.ts.map +1 -0
  109. package/dist/src/components/roster/parts/corner.js +7 -0
  110. package/dist/src/components/roster/parts/corner.js.map +1 -0
  111. package/dist/src/components/roster/parts/empty.d.ts +2 -0
  112. package/dist/src/components/roster/parts/empty.d.ts.map +1 -0
  113. package/dist/src/components/roster/parts/empty.js +9 -0
  114. package/dist/src/components/roster/parts/empty.js.map +1 -0
  115. package/dist/src/components/roster/parts/grid.d.ts +3 -0
  116. package/dist/src/components/roster/parts/grid.d.ts.map +1 -0
  117. package/dist/src/components/roster/parts/grid.js +16 -0
  118. package/dist/src/components/roster/parts/grid.js.map +1 -0
  119. package/dist/src/components/roster/parts/header-cell.d.ts +5 -0
  120. package/dist/src/components/roster/parts/header-cell.d.ts.map +1 -0
  121. package/dist/src/components/roster/parts/header-cell.js +9 -0
  122. package/dist/src/components/roster/parts/header-cell.js.map +1 -0
  123. package/dist/src/components/roster/parts/header.d.ts +3 -0
  124. package/dist/src/components/roster/parts/header.d.ts.map +1 -0
  125. package/dist/src/components/roster/parts/header.js +13 -0
  126. package/dist/src/components/roster/parts/header.js.map +1 -0
  127. package/dist/src/components/roster/parts/lane-label-column.d.ts +3 -0
  128. package/dist/src/components/roster/parts/lane-label-column.d.ts.map +1 -0
  129. package/dist/src/components/roster/parts/lane-label-column.js +18 -0
  130. package/dist/src/components/roster/parts/lane-label-column.js.map +1 -0
  131. package/dist/src/components/roster/roster.types.d.ts +146 -0
  132. package/dist/src/components/roster/roster.types.d.ts.map +1 -0
  133. package/dist/src/components/roster/roster.types.js +3 -0
  134. package/dist/src/components/roster/roster.types.js.map +1 -0
  135. package/dist/src/components/roster/use-roster.d.ts +3 -0
  136. package/dist/src/components/roster/use-roster.d.ts.map +1 -0
  137. package/dist/src/components/roster/use-roster.js +106 -0
  138. package/dist/src/components/roster/use-roster.js.map +1 -0
  139. package/dist/src/components/roster/utils/body-content-key.d.ts +3 -0
  140. package/dist/src/components/roster/utils/body-content-key.d.ts.map +1 -0
  141. package/dist/src/components/roster/utils/body-content-key.js +29 -0
  142. package/dist/src/components/roster/utils/body-content-key.js.map +1 -0
  143. package/dist/src/components/roster/utils/ticks.d.ts +4 -0
  144. package/dist/src/components/roster/utils/ticks.d.ts.map +1 -0
  145. package/dist/src/components/roster/utils/ticks.js +60 -0
  146. package/dist/src/components/roster/utils/ticks.js.map +1 -0
  147. package/dist/src/components/schedule/days/day.d.ts +20 -0
  148. package/dist/src/components/schedule/days/day.d.ts.map +1 -0
  149. package/dist/src/components/schedule/days/day.js +26 -0
  150. package/dist/src/components/schedule/days/day.js.map +1 -0
  151. package/dist/src/components/schedule/days/header-layout.d.ts +9 -0
  152. package/dist/src/components/schedule/days/header-layout.d.ts.map +1 -0
  153. package/dist/src/components/schedule/days/header-layout.js +9 -0
  154. package/dist/src/components/schedule/days/header-layout.js.map +1 -0
  155. package/dist/src/components/schedule/days/layout.d.ts +18 -0
  156. package/dist/src/components/schedule/days/layout.d.ts.map +1 -0
  157. package/dist/src/components/schedule/days/layout.js +9 -0
  158. package/dist/src/components/schedule/days/layout.js.map +1 -0
  159. package/dist/src/components/schedule/days/parts/column.d.ts +3 -0
  160. package/dist/src/components/schedule/days/parts/column.d.ts.map +1 -0
  161. package/dist/src/components/schedule/days/parts/column.js +33 -0
  162. package/dist/src/components/schedule/days/parts/column.js.map +1 -0
  163. package/dist/src/components/schedule/days/parts/day-header.d.ts +5 -0
  164. package/dist/src/components/schedule/days/parts/day-header.d.ts.map +1 -0
  165. package/dist/src/components/schedule/days/parts/day-header.js +10 -0
  166. package/dist/src/components/schedule/days/parts/day-header.js.map +1 -0
  167. package/dist/src/components/schedule/days/parts/grid.d.ts +3 -0
  168. package/dist/src/components/schedule/days/parts/grid.d.ts.map +1 -0
  169. package/dist/src/components/schedule/days/parts/grid.js +14 -0
  170. package/dist/src/components/schedule/days/parts/grid.js.map +1 -0
  171. package/dist/src/components/schedule/days/parts/now-line.d.ts +5 -0
  172. package/dist/src/components/schedule/days/parts/now-line.d.ts.map +1 -0
  173. package/dist/src/components/schedule/days/parts/now-line.js +9 -0
  174. package/dist/src/components/schedule/days/parts/now-line.js.map +1 -0
  175. package/dist/src/components/schedule/days/parts/skipped-date.d.ts +4 -0
  176. package/dist/src/components/schedule/days/parts/skipped-date.d.ts.map +1 -0
  177. package/dist/src/components/schedule/days/parts/skipped-date.js +17 -0
  178. package/dist/src/components/schedule/days/parts/skipped-date.js.map +1 -0
  179. package/dist/src/components/schedule/days/parts/transition.d.ts +3 -0
  180. package/dist/src/components/schedule/days/parts/transition.d.ts.map +1 -0
  181. package/dist/src/components/schedule/days/parts/transition.js +42 -0
  182. package/dist/src/components/schedule/days/parts/transition.js.map +1 -0
  183. package/dist/src/components/schedule/index.d.ts +3 -0
  184. package/dist/src/components/schedule/index.d.ts.map +1 -0
  185. package/dist/src/components/schedule/index.js +45 -0
  186. package/dist/src/components/schedule/index.js.map +1 -0
  187. package/dist/src/components/schedule/layout.d.ts +15 -0
  188. package/dist/src/components/schedule/layout.d.ts.map +1 -0
  189. package/dist/src/components/schedule/layout.js +10 -0
  190. package/dist/src/components/schedule/layout.js.map +1 -0
  191. package/dist/src/components/schedule/parts/gutter.d.ts +3 -0
  192. package/dist/src/components/schedule/parts/gutter.d.ts.map +1 -0
  193. package/dist/src/components/schedule/parts/gutter.js +9 -0
  194. package/dist/src/components/schedule/parts/gutter.js.map +1 -0
  195. package/dist/src/components/schedule/parts/incomplete.d.ts +6 -0
  196. package/dist/src/components/schedule/parts/incomplete.d.ts.map +1 -0
  197. package/dist/src/components/schedule/parts/incomplete.js +9 -0
  198. package/dist/src/components/schedule/parts/incomplete.js.map +1 -0
  199. package/dist/src/components/schedule/schedule.types.d.ts +109 -0
  200. package/dist/src/components/schedule/schedule.types.d.ts.map +1 -0
  201. package/dist/src/components/schedule/schedule.types.js +3 -0
  202. package/dist/src/components/schedule/schedule.types.js.map +1 -0
  203. package/dist/src/components/schedule/use-schedule-viewport.d.ts +7 -0
  204. package/dist/src/components/schedule/use-schedule-viewport.d.ts.map +1 -0
  205. package/dist/src/components/schedule/use-schedule-viewport.js +15 -0
  206. package/dist/src/components/schedule/use-schedule-viewport.js.map +1 -0
  207. package/dist/src/components/schedule/use-schedule.d.ts +3 -0
  208. package/dist/src/components/schedule/use-schedule.d.ts.map +1 -0
  209. package/dist/src/components/schedule/use-schedule.js +71 -0
  210. package/dist/src/components/schedule/use-schedule.js.map +1 -0
  211. package/dist/src/components/schedule/utils/days.d.ts +17 -0
  212. package/dist/src/components/schedule/utils/days.d.ts.map +1 -0
  213. package/dist/src/components/schedule/utils/days.js +49 -0
  214. package/dist/src/components/schedule/utils/days.js.map +1 -0
  215. package/dist/src/core/axis.d.ts +18 -0
  216. package/dist/src/core/axis.d.ts.map +1 -0
  217. package/dist/src/core/axis.js +58 -0
  218. package/dist/src/core/axis.js.map +1 -0
  219. package/dist/src/core/cache.d.ts +29 -0
  220. package/dist/src/core/cache.d.ts.map +1 -0
  221. package/dist/src/core/cache.js +33 -0
  222. package/dist/src/core/cache.js.map +1 -0
  223. package/dist/src/core/columns.d.ts +3 -0
  224. package/dist/src/core/columns.d.ts.map +1 -0
  225. package/dist/src/core/columns.js +45 -0
  226. package/dist/src/core/columns.js.map +1 -0
  227. package/dist/src/core/coverage.d.ts +3 -0
  228. package/dist/src/core/coverage.d.ts.map +1 -0
  229. package/dist/src/core/coverage.js +60 -0
  230. package/dist/src/core/coverage.js.map +1 -0
  231. package/dist/src/core/flag.d.ts +3 -0
  232. package/dist/src/core/flag.d.ts.map +1 -0
  233. package/dist/src/core/flag.js +17 -0
  234. package/dist/src/core/flag.js.map +1 -0
  235. package/dist/src/core/hash.d.ts +5 -0
  236. package/dist/src/core/hash.d.ts.map +1 -0
  237. package/dist/src/core/hash.js +29 -0
  238. package/dist/src/core/hash.js.map +1 -0
  239. package/dist/src/core/hit-test.d.ts +6 -0
  240. package/dist/src/core/hit-test.d.ts.map +1 -0
  241. package/dist/src/core/hit-test.js +23 -0
  242. package/dist/src/core/hit-test.js.map +1 -0
  243. package/dist/src/core/index.d.ts +12 -0
  244. package/dist/src/core/index.d.ts.map +1 -0
  245. package/dist/src/core/index.js +30 -0
  246. package/dist/src/core/index.js.map +1 -0
  247. package/dist/src/core/layout.d.ts +3 -0
  248. package/dist/src/core/layout.d.ts.map +1 -0
  249. package/dist/src/core/layout.js +96 -0
  250. package/dist/src/core/layout.js.map +1 -0
  251. package/dist/src/core/order.d.ts +7 -0
  252. package/dist/src/core/order.d.ts.map +1 -0
  253. package/dist/src/core/order.js +12 -0
  254. package/dist/src/core/order.js.map +1 -0
  255. package/dist/src/core/scale.d.ts +9 -0
  256. package/dist/src/core/scale.d.ts.map +1 -0
  257. package/dist/src/core/scale.js +41 -0
  258. package/dist/src/core/scale.js.map +1 -0
  259. package/dist/src/core/snap.d.ts +10 -0
  260. package/dist/src/core/snap.d.ts.map +1 -0
  261. package/dist/src/core/snap.js +43 -0
  262. package/dist/src/core/snap.js.map +1 -0
  263. package/dist/src/core/spans.d.ts +3 -0
  264. package/dist/src/core/spans.d.ts.map +1 -0
  265. package/dist/src/core/spans.js +60 -0
  266. package/dist/src/core/spans.js.map +1 -0
  267. package/dist/src/core/types.d.ts +104 -0
  268. package/dist/src/core/types.d.ts.map +1 -0
  269. package/dist/src/core/types.js +3 -0
  270. package/dist/src/core/types.js.map +1 -0
  271. package/dist/src/core/zone.d.ts +10 -0
  272. package/dist/src/core/zone.d.ts.map +1 -0
  273. package/dist/src/core/zone.js +103 -0
  274. package/dist/src/core/zone.js.map +1 -0
  275. package/dist/src/index.d.ts +27 -0
  276. package/dist/src/index.d.ts.map +1 -0
  277. package/dist/src/index.js +63 -0
  278. package/dist/src/index.js.map +1 -0
  279. package/dist/src/nativewind/index.d.ts +61 -0
  280. package/dist/src/nativewind/index.d.ts.map +1 -0
  281. package/dist/src/nativewind/index.js +24 -0
  282. package/dist/src/nativewind/index.js.map +1 -0
  283. package/llms.txt +481 -0
  284. package/package.json +154 -8
  285. package/src/adapters/rrule/README.md +41 -0
  286. package/src/adapters/rrule/cache.ts +50 -0
  287. package/src/adapters/rrule/envelope.ts +7 -0
  288. package/src/adapters/rrule/expand.ts +105 -0
  289. package/src/adapters/rrule/hash.ts +13 -0
  290. package/src/adapters/rrule/index.ts +11 -0
  291. package/src/adapters/rrule/net.ts +30 -0
  292. package/src/adapters/rrule/occurrences.ts +288 -0
  293. package/src/adapters/rrule/types.ts +52 -0
  294. package/src/adapters/rrule/validate.ts +78 -0
  295. package/src/components/layers/README.md +11 -0
  296. package/src/components/layers/layers.types.ts +6 -0
  297. package/src/components/layers/parts/gap.tsx +5 -0
  298. package/src/components/layers/parts/interval.tsx +24 -0
  299. package/src/components/layers/utils/styles.ts +24 -0
  300. package/src/components/primitives/README.md +12 -0
  301. package/src/components/primitives/press-point.tsx +5 -0
  302. package/src/components/primitives/press-point.types.ts +5 -0
  303. package/src/components/primitives/press-point.web.tsx +19 -0
  304. package/src/components/primitives/region-style.ts +21 -0
  305. package/src/components/roster/README.md +18 -0
  306. package/src/components/roster/index.tsx +90 -0
  307. package/src/components/roster/lanes/interval-hover.tsx +5 -0
  308. package/src/components/roster/lanes/interval-hover.types.ts +11 -0
  309. package/src/components/roster/lanes/interval-hover.web.tsx +19 -0
  310. package/src/components/roster/lanes/lane.tsx +88 -0
  311. package/src/components/roster/lanes/parts/incomplete.tsx +44 -0
  312. package/src/components/roster/lanes/parts/lane-label.tsx +41 -0
  313. package/src/components/roster/layout.tsx +68 -0
  314. package/src/components/roster/parts/body.tsx +91 -0
  315. package/src/components/roster/parts/corner.tsx +3 -0
  316. package/src/components/roster/parts/empty.tsx +5 -0
  317. package/src/components/roster/parts/grid.tsx +26 -0
  318. package/src/components/roster/parts/header-cell.tsx +10 -0
  319. package/src/components/roster/parts/header.tsx +18 -0
  320. package/src/components/roster/parts/lane-label-column.tsx +31 -0
  321. package/src/components/roster/roster.types.ts +155 -0
  322. package/src/components/roster/use-roster.ts +133 -0
  323. package/src/components/roster/utils/body-content-key.ts +46 -0
  324. package/src/components/roster/utils/ticks.ts +62 -0
  325. package/src/components/schedule/README.md +18 -0
  326. package/src/components/schedule/days/day.tsx +76 -0
  327. package/src/components/schedule/days/header-layout.tsx +12 -0
  328. package/src/components/schedule/days/layout.tsx +38 -0
  329. package/src/components/schedule/days/parts/column.tsx +59 -0
  330. package/src/components/schedule/days/parts/day-header.tsx +18 -0
  331. package/src/components/schedule/days/parts/grid.tsx +21 -0
  332. package/src/components/schedule/days/parts/now-line.tsx +11 -0
  333. package/src/components/schedule/days/parts/skipped-date.tsx +22 -0
  334. package/src/components/schedule/days/parts/transition.tsx +70 -0
  335. package/src/components/schedule/index.tsx +109 -0
  336. package/src/components/schedule/layout.tsx +42 -0
  337. package/src/components/schedule/parts/gutter.tsx +16 -0
  338. package/src/components/schedule/parts/incomplete.tsx +13 -0
  339. package/src/components/schedule/schedule.types.ts +103 -0
  340. package/src/components/schedule/use-schedule-viewport.ts +13 -0
  341. package/src/components/schedule/use-schedule.ts +75 -0
  342. package/src/components/schedule/utils/days.ts +54 -0
  343. package/src/core/README.md +25 -0
  344. package/src/core/axis.ts +58 -0
  345. package/src/core/cache.ts +38 -0
  346. package/src/core/columns.ts +49 -0
  347. package/src/core/coverage.ts +56 -0
  348. package/src/core/flag.ts +14 -0
  349. package/src/core/hash.ts +28 -0
  350. package/src/core/hit-test.ts +27 -0
  351. package/src/core/index.ts +34 -0
  352. package/src/core/layout.ts +101 -0
  353. package/src/core/order.ts +18 -0
  354. package/src/core/scale.ts +45 -0
  355. package/src/core/snap.ts +52 -0
  356. package/src/core/spans.ts +58 -0
  357. package/src/core/types.ts +92 -0
  358. package/src/core/zone.ts +100 -0
  359. package/src/index.ts +49 -0
  360. package/src/nativewind/README.md +14 -0
  361. package/src/nativewind/index.ts +30 -0
  362. 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,381 @@
1
1
  # react-native-roster
2
2
 
3
- Layered intervals with provenance across lanes and a shared time axis for React Native.
3
+ **Lanes, layers, and sources on one time axis.**
4
4
 
5
- This is a placeholder release that reserves the package name; it contains no usable code. The first usable version will be published from https://github.com/simiancraft/react-native-roster. A live demo runs at https://simiancraft.github.io/react-native-roster/.
5
+ [![Gallery](https://img.shields.io/badge/▶%20Gallery-lanes%2C%20layers%2C%20and%20sources-4f46e5?style=for-the-badge)](https://simiancraft.github.io/react-native-roster/)
6
+
7
+ [![CI](https://github.com/simiancraft/react-native-roster/actions/workflows/ci.yml/badge.svg)](https://github.com/simiancraft/react-native-roster/actions/workflows/ci.yml)
8
+ [![Coverage](https://img.shields.io/codecov/c/github/simiancraft/react-native-roster?logo=codecov)](https://codecov.io/github/simiancraft/react-native-roster)
9
+ [![Types: included](https://img.shields.io/badge/types-included-3178c6?logo=typescript)](#contract)
10
+ [![Core under 15 kB](https://img.shields.io/badge/core-%3C15%20kB-0f766e)](./.size-limit.json)
11
+ [![Expo SDK 54](https://img.shields.io/badge/Expo-SDK%2054-000020?logo=expo)](./demo/package.json)
12
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
13
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/simiancraft/react-native-roster/badge)](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.** Every visual region is an optional render function, 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 zone filler; 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`, zone fillers, 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
+ Every zone is an optional render function. Compose the exported default filler
207
+ inside a replacement to retain scrolling, geometry, or press behavior.
208
+
209
+ | Zone | Receives | Default filler and behavior |
210
+ | --- | --- | --- |
211
+ | `emptyZone` | Nothing | `RosterEmpty`: No lanes. |
212
+ | `cornerZone` | Nothing | `RosterCorner`: nothing; the cell above the labels, `laneLabelWidth` wide. |
213
+ | `laneLabelZone` | `lane`, `flag`, `complete`, `viewTimezone`, localized labels | `RosterLaneLabel`: label, differing IANA zone badge, and notices. |
214
+ | `headerCellZone` | `tick` | `RosterHeaderCell`: tick label. |
215
+ | `intervalZone` | `rect`, `layer`, `lane`, `highlighted` | `RosterInterval`: positioned colored rect, with final inset bounds. |
216
+ | `gapZone` | `rect`, `layer`, `lane` | `RosterGap`: no visible content; the row supplies pressable bounds. |
217
+ | `gridZone` | `ticks`, `contentWidth` | `RosterGrid`: one hairline per tick behind every lane. |
218
+ | `headerZone` | `ticks`, `projection`, `scroll`, `contentWidth`, `headerCellZone` | `RosterHeader`: frozen header following horizontal offset. |
219
+ | `laneLabelColumnZone` | `labels`, `projection`, `scroll`, `laneLabelZone` | `RosterLaneLabelColumn`: frozen labels following vertical offset. |
220
+ | `bodyZone` | Ordered `lanes`, `window`, `geometryFor`, `projection`, `scroll`, `press`, `ticks`, `viewport`, `contentWidth`, highlight and hover, incomplete label, and rect zones | `RosterBody`: virtualized lanes. |
221
+
222
+ A custom interval filler positions at `rect.x/y`, uses `rect.width/height/z`,
223
+ and sets `pointerEvents="none"` so the parent hit-test walk owns presses. Gap
224
+ fillers are already inside positioned pressables. `useRoster` exposes ordered
225
+ lanes, coverage, lane state, ticks, `geometryFor`, shared scrolling, `press`,
226
+ viewport measurement, navigation, and status for fully custom layouts.
227
+
228
+ Chrome regions take style props: `style`, `headerStyle` (the 40 px header row
229
+ holding the corner and ticks), `laneLabelColumnStyle`, and `bodyStyle`.
230
+ `laneLabelWidth` sizes the corner and label column, default 180. Each style
231
+ prop has a `className` twin; see [NativeWind](#nativewind).
232
+
233
+ ## Schedule and its zones
234
+
235
+ ```tsx
236
+ import { Schedule } from 'react-native-roster';
237
+ import type { Lane } from 'react-native-roster/core';
238
+
239
+ export function Week({ lane }: { lane: Lane }) {
240
+ return <Schedule lane={lane} minuteStep={60}
241
+ style={{ height: 600, flex: undefined }}
242
+ windowSpec={{ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' }}
243
+ onIntervalPress={(rect) => console.log(rect.sources)} />;
244
+ }
245
+ ```
246
+
247
+ Only day and week specs are accepted. The component measures its width,
248
+ reserves a 48 px gutter, and fits the day columns without horizontal scrolling.
249
+ `pxPerHour` defaults to 48. Chrome takes `style`, `headerStyle`, `gutterStyle`,
250
+ and `daysStyle`, each with a `className` twin.
251
+
252
+ | Zone | Receives | Default filler and behavior |
253
+ | --- | --- | --- |
254
+ | `gutterZone` | `hours`, `pxPerHour` | `ScheduleGutter`: 24 frozen hour labels. |
255
+ | `gridZone` | `hours`, `pxPerHour` | `ScheduleGrid`: 24 bordered hour bands behind each day's rects. |
256
+ | `dayHeaderZone` | `day` | `ScheduleDayHeader`: weekday, localDate, and transition badge. |
257
+ | `skippedDateZone` | `localDate` | `ScheduleSkippedDate`: zero-width header marker for a wholly skipped date. |
258
+ | `columnZone` | `day`, `rects`, `gapRects`, `lane`, `highlightSource`, `press`, interval and gap zones | `ScheduleColumn`: final rect bounds in layer order. |
259
+ | `transitionZone` | `day`, `transition`, `y`, `dividerY`, `height`, `width` | `ScheduleTransition`: skipped-time hatch, or repeat divider and again label. |
260
+ | `nowLineZone` | `y`, `column` | `ScheduleNowLine`: line in the current day's column, updated each minute. |
261
+ | `intervalZone`, `gapZone` | Same inputs as Roster | Shared `RosterInterval` and `RosterGap`. |
262
+ | `incompleteZone` | `lane`, `label` | `ScheduleIncomplete`: notice above the grid when the lane is incomplete. |
263
+
264
+ ## NativeWind
265
+
266
+ `className` is a first-class prop on `Roster` and `Schedule`, alongside `style`.
267
+ Every chrome style prop has a class twin: `className`, `headerClassName`,
268
+ `laneLabelColumnClassName`, and `bodyClassName` on Roster; `className`,
269
+ `headerClassName`, `gutterClassName`, and `daysClassName` on Schedule. A class
270
+ on a region replaces that region's default paint (background and border colors)
271
+ while its structure (size, flex, overflow) stays. This is deliberate: React
272
+ Native Web renders object styles inline, and inline paint would otherwise beat
273
+ any class.
274
+
275
+ Set up NativeWind 4 as usual (the demo's [babel.config.js](./demo/babel.config.js),
276
+ [metro.config.js](./demo/metro.config.js), [tailwind.config.js](./demo/tailwind.config.js),
277
+ and [global.css](./demo/global.css) are a working reference), add the optional
278
+ peer with `bun add nativewind`, and register the components once at your app
279
+ root:
280
+
281
+ ```tsx
282
+ // app/_layout.tsx
283
+ import '../global.css';
284
+ import 'react-native-roster/nativewind';
285
+ ```
286
+
287
+ ```tsx
288
+ import { Roster } from 'react-native-roster';
289
+
290
+ <Roster
291
+ lanes={lanes}
292
+ windowSpec={windowSpec}
293
+ className="flex-1 rounded-xl bg-background"
294
+ headerClassName="border-b border-border bg-card"
295
+ laneLabelColumnClassName="border-r border-border bg-card"
296
+ laneLabelWidth={220}
297
+ />
298
+ ```
299
+
300
+ Zone fillers are ordinary React Native views, so a custom `laneLabelZone` or
301
+ `intervalZone` uses `className` on `View` and `Text` directly. Without the
302
+ entry point, class props are ignored and style props still work. The entry
303
+ point is the package's only module with side effects and is listed in
304
+ `sideEffects`. The [showcase route](./demo/app/showcase.tsx) styles every region
305
+ and zone this way in light and dark palettes.
306
+
307
+ ## Gallery and platform support
308
+
309
+ The [Expo gallery](https://simiancraft.github.io/react-native-roster/) is the
310
+ demo; there is no Storybook. Run it locally with `bun install --frozen-lockfile`,
311
+ `bun run build`, and `bun run demo:web` (add `EXPO_OFFLINE=1` in a restricted
312
+ network). The home page lists every fixture route:
313
+
314
+ - Empty, one, 20, and 200 lanes; inset layers; default and replaced zones.
315
+ - Day, week, and month routes at 15, 30, and 60-minute steps.
316
+ - Full-day gaps, lane flags, equal-z precedence, highlight, coverage sorting,
317
+ and incomplete expansion.
318
+ - Chicago DST weeks, mixed rule, lane, and view zones, and editable adapter routes.
319
+ - Schedule empty, layered, excluded, spring, fall, Lord Howe, Apia, incomplete,
320
+ midnight, side-by-side projections, and every zone.
321
+ - The showcase at `/showcase`: twelve generated people across seven zones,
322
+ weekly hours and exclusions from the recurrence adapter, booked events, day
323
+ and week spans, sorting, filtering, and a per-person Schedule, styled with
324
+ NativeWind class props and zone fillers, with a sun and moon theme toggle.
325
+ Names, titles, and the organization come from `@faker-js/faker` with a fixed
326
+ seed; any resemblance to real people is coincidental.
327
+
328
+ | Platform | Support and evidence |
329
+ | --- | --- |
330
+ | Web via React Native Web | Static export and Chromium gallery checks; first-class target. |
331
+ | iOS | React Native implementation; device rendering and Hermes behavior not yet verified here. |
332
+ | Android | React Native implementation; device rendering and release performance not yet captured. |
333
+ | Node and Bun | Built core and adapter work without a renderer; root components require native peers or a web bundler. |
334
+
335
+ ## Performance
336
+
337
+ Workload W is 200 lanes, one week, two layers, a 24-lane viewport, and
338
+ 15-minute ticks: 63 interval rects and 7 gap rects per lane. The
339
+ [committed CI baseline](./test/performance/baseline.json) on GitHub Actions
340
+ ubuntu-latest records target-cold layout of 24 lanes at 2.070 ms and coverage of
341
+ all 200 lanes at 1.063 ms, gated below 16 ms everywhere and within 1.5 times the
342
+ baseline in CI. Size gates hold core under 15 kB and root under 44 kB. Device
343
+ captures and the paired comparison against other libraries are described, not
344
+ yet recorded, in the [performance guide](./docs/performance.md); CI timings are
345
+ not phone frame rates.
346
+
347
+ ## What this isn't
348
+
349
+ This is a read surface. Consumers own creation, dragging, resizing,
350
+ persistence, and permission checks through their own interactions. It is not a
351
+ month grid or an arbitrary event list, and it does not expand rules inside the
352
+ core. The short [design note](./docs/design.md) explains the reasoning.
353
+
354
+ ## Development and reference
355
+
356
+ ```sh
357
+ bunx playwright install chromium
358
+ bun run check
359
+ ```
360
+
361
+ `check` runs Biome, library, test, and demo typechecks, React Compiler safety,
362
+ the library build, the static web export, tests with coverage, knip, strict
363
+ publint, size-limit, and Playwright.
364
+
365
+ - [Adapter guide](./docs/adapters.md), [recurrence semantics](./docs/recurrence.md),
366
+ [timezones](./docs/timezones.md), [caches](./docs/caches.md), and the
367
+ [performance guide](./docs/performance.md).
368
+ - [Design note](./docs/design.md): precompute, then render geometry.
369
+ - Area landing pages: [core](./src/core/README.md), [Roster](./src/components/roster/README.md),
370
+ [Schedule](./src/components/schedule/README.md), [layers](./src/components/layers/README.md),
371
+ [primitives](./src/components/primitives/README.md), [rrule adapter](./src/adapters/rrule/README.md),
372
+ [nativewind](./src/nativewind/README.md), the [gallery](./demo/components/gallery/README.md), and the
373
+ [showcase](./demo/components/team-roster/README.md), and the [theme](./demo/components/theme/README.md);
374
+ [adding an adapter](./docs/adding-an-adapter.md)
375
+ is the contributor recipe.
376
+ - [llms.txt](./llms.txt): integration instructions for agents.
377
+ - [CONTRIBUTING.md](./CONTRIBUTING.md) and [AGENTS.md](./AGENTS.md): contributor workflow.
378
+ - [CHANGELOG.md](./CHANGELOG.md): release history, maintained by semantic-release.
379
+ - [SECURITY.md](./SECURITY.md), [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md), and [NOTICE.md](./NOTICE.md).
380
+
381
+ 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,3 @@
1
+ import type { Window } from '../../core';
2
+ export declare function envelopeFor(window: Window): Window;
3
+ //# sourceMappingURL=envelope.d.ts.map
@@ -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,4 @@
1
+ import type { Window } from '../../core';
2
+ import type { ExpandOptions, ExpandResult, RuleSet } from './types';
3
+ export declare function expandRuleSet(set: RuleSet, window: Window, options?: ExpandOptions): ExpandResult;
4
+ //# sourceMappingURL=expand.d.ts.map
@@ -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"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expandRuleSet = expandRuleSet;
4
+ const cache_1 = require("./cache");
5
+ const envelope_1 = require("./envelope");
6
+ const hash_1 = require("./hash");
7
+ const net_1 = require("./net");
8
+ const occurrences_1 = require("./occurrences");
9
+ const validate_1 = require("./validate");
10
+ function expandRuleSet(set, window, options = {}) {
11
+ (0, validate_1.validateWindow)(window);
12
+ const maxEntries = (0, validate_1.nonnegativeInteger)(options.cache?.maxEntries ?? 2000, 'cache.maxEntries');
13
+ const maxEnvelopes = (0, validate_1.nonnegativeInteger)(options.cache?.maxEnvelopes ?? 4, 'cache.maxEnvelopes');
14
+ const cap = (0, validate_1.nonnegativeInteger)(options.caps?.perRuleOccurrences ?? 400, 'caps.perRuleOccurrences');
15
+ let remaining = (0, validate_1.nonnegativeInteger)(options.caps?.totalOccurrences ?? 10000, 'caps.totalOccurrences');
16
+ const rules = [...set.rules].sort(byId);
17
+ const dates = [...set.dates].sort(byId);
18
+ const ordered = [...rules, ...dates];
19
+ for (const input of ordered) {
20
+ (0, validate_1.validateInput)(input);
21
+ (0, occurrences_1.validateDates)(input);
22
+ }
23
+ const stats = {
24
+ rules: set.rules.length,
25
+ dates: set.dates.length,
26
+ expanded: 0,
27
+ cacheHits: 0,
28
+ cacheMisses: 0,
29
+ };
30
+ if (window.start === window.end) {
31
+ (0, cache_1.recordStats)(stats);
32
+ return {
33
+ intervals: [],
34
+ gaps: [],
35
+ envelope: (0, envelope_1.envelopeFor)(window),
36
+ complete: true,
37
+ truncated: [],
38
+ stats,
39
+ };
40
+ }
41
+ const envelope = (0, cache_1.retainedEnvelope)(window, maxEnvelopes);
42
+ (0, cache_1.trim)(cache_1.occurrences, maxEntries);
43
+ const includes = [];
44
+ const excludes = [];
45
+ const truncated = [];
46
+ let dropped = false;
47
+ for (const input of ordered) {
48
+ const key = JSON.stringify([(0, hash_1.bodyKey)(input), envelope.start, envelope.end, cap]);
49
+ let list = cache_1.occurrences.get(key);
50
+ if (list) {
51
+ (0, cache_1.touch)(cache_1.occurrences, key, list);
52
+ stats.cacheHits++;
53
+ }
54
+ else {
55
+ list = (0, occurrences_1.enumerate)(input, envelope, cap);
56
+ (0, cache_1.touch)(cache_1.occurrences, key, list);
57
+ (0, cache_1.trim)(cache_1.occurrences, maxEntries);
58
+ stats.expanded++;
59
+ stats.cacheMisses++;
60
+ }
61
+ // No partial admission: the first list that cannot fit ends the admitted
62
+ // prefix. Fetch all later lists anyway to report their exact retained counts.
63
+ dropped ||= list.spans.length > remaining;
64
+ if (dropped || list.capped) {
65
+ truncated.push({
66
+ id: input.id,
67
+ droppedAtLeast: list.capped ? 1 : list.spans.length,
68
+ });
69
+ }
70
+ if (dropped)
71
+ continue;
72
+ remaining -= list.spans.length;
73
+ const source = { kind: 'date' in input ? 'date' : 'rule', id: input.id };
74
+ if ('date' in input && input.note !== undefined)
75
+ source.label = input.note;
76
+ const target = input.kind === 'include' ? includes : excludes;
77
+ for (const span of list.spans)
78
+ target.push({ ...span, sources: [source] });
79
+ }
80
+ (0, cache_1.recordStats)(stats);
81
+ return {
82
+ ...(0, net_1.net)(includes, excludes, window),
83
+ envelope: { ...envelope },
84
+ complete: truncated.length === 0,
85
+ truncated,
86
+ stats,
87
+ };
88
+ }
89
+ function byId(a, b) {
90
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
91
+ }
92
+ //# sourceMappingURL=expand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.js","sourceRoot":"","sources":["../../../../src/adapters/rrule/expand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RosterDate, RosterRule } from './types';
2
+ export declare function bodyKey(input: RosterRule | RosterDate): string;
3
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../../src/adapters/rrule/hash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAItD,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAO9D"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bodyKey = bodyKey;
4
+ const hash_1 = require("../../core/hash");
5
+ // Use the core's collision-free canonical encoding as the content hash.
6
+ // Identity and display notes are attached fresh, never cached in occurrence lists.
7
+ function bodyKey(input) {
8
+ const { id: _id, ...body } = input;
9
+ if ('date' in body) {
10
+ const { note: _note, ...date } = body;
11
+ return (0, hash_1.structuralKey)(date);
12
+ }
13
+ return (0, hash_1.structuralKey)(body);
14
+ }
15
+ //# sourceMappingURL=hash.js.map