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/llms.txt ADDED
@@ -0,0 +1,481 @@
1
+ # react-native-roster
2
+
3
+ > React Native read surfaces over layered absolute intervals with provenance.
4
+ > Roster projects many lanes horizontally; Schedule projects one lane into day
5
+ > columns. The core owns geometry, coverage, axis math, and caches. Adapters own
6
+ > upstream conversion and recurrence. The gallery and integration guides describe
7
+ > the implemented surface; package distribution status is in README.md.
8
+
9
+ This file is for an agent integrating the package into a consumer app. Follow the
10
+ setup, contract, and cache rules below. You do not need the repository's issues
11
+ to render a roster. README.md is the human quick start; AGENTS.md is for modifying
12
+ this repository. The demo is the working integration example, not a dependency.
13
+
14
+ ## Setup and first render
15
+
16
+ Use Bun 1.4.2 and Node 22 for this checkout. Run at repository root:
17
+
18
+ ```sh
19
+ bun install --ignore-scripts --frozen-lockfile
20
+ bun run build
21
+ bun run demo:web
22
+ ```
23
+
24
+ The root install also installs demo dependencies. Use `EXPO_OFFLINE=1 bun run
25
+ demo:web` if Expo cannot write its online dependency-validation cache. To consume from another app,
26
+ `bun add react-native-roster`; for an unreleased checkout, run
27
+ `bun pm pack --destination .cache` here, then `bun add` the actual absolute
28
+ tarball path in your app. Add `@legendapp/list` and install the SDK's
29
+ compatible Reanimated with `bunx expo install react-native-reanimated --bun`.
30
+ Keep React, React Native, and Expo aligned with the app's SDK. The demo uses Expo
31
+ 54, React 19.1, RN 0.81.5, LegendList 2.0.19, and Reanimated 3.19.5. NativeWind is
32
+ an optional peer (>=4.1); import react-native-roster/nativewind once at the app
33
+ root to enable className props on Roster and Schedule. Web needs compatible
34
+ React DOM and React Native Web. See demo/babel.config.js for workspace presets.
35
+
36
+ Peer ranges: React >=18.2, React Native >=0.74, Expo >=51, LegendList >=2.
37
+ Reanimated >=3.19 is optional for core-only installs and required for Roster.
38
+ Tested dependency versions are not proof of every combination in those ranges.
39
+
40
+ Save this as a screen component, or as demo/app/gallery/readme-example.tsx with
41
+ `export default function Example` for Expo Router, and visit /gallery/readme-example:
42
+
43
+ ```tsx
44
+ import { Roster } from 'react-native-roster';
45
+ import type { Lane } from 'react-native-roster/core';
46
+
47
+ const lanes: Lane[] = [{
48
+ id: 'one', label: 'Lane one', layers: [{
49
+ id: 'open', role: 'availability', z: 0, style: { color: '#4f9478' },
50
+ intervals: [{
51
+ start: Date.UTC(2024, 0, 1, 9), end: Date.UTC(2024, 0, 1, 17),
52
+ sources: [{ kind: 'table', id: 'row-one' }],
53
+ }],
54
+ }],
55
+ }];
56
+ export function Example() {
57
+ return <Roster lanes={lanes} style={{ height: 480, flex: undefined }}
58
+ windowSpec={{ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' }}
59
+ onIntervalPress={(rect, lane) => console.log(lane.id, rect.sources)} />;
60
+ }
61
+ ```
62
+
63
+ Expect a green 09:00 to 17:00 interval on January 1, 2024. Scroll horizontally to
64
+ see the time range. A bounded viewport is required. Remove the scratch route
65
+ when finished. In a controlled app, own WindowSpec in your screen's hook; update
66
+ it in navigation handlers, and prepare adapter output for windowFor(spec).
67
+
68
+ ## Vocabulary
69
+
70
+ | Term | Meaning |
71
+ | --- | --- |
72
+ | roster | Whole read surface: shared time axis, lanes, and layers. |
73
+ | lane | One person or resource row containing layers and display metadata. |
74
+ | layer | Ordered intervals and gaps with role, z-order, and style. |
75
+ | interval | Covered end-exclusive absolute time with sources. |
76
+ | gap | Removed end-exclusive absolute time with sources; survives complete subtraction. |
77
+ | source | Provenance identity (kind, id); optional label is display metadata. |
78
+ | window | Bare absolute { start, end }; no span or resolution. |
79
+ | projection | Horizontal elapsed time or day columns using wall-clock hours. |
80
+ | adapter | External conversion from upstream data to lanes and layers. |
81
+ | schedule | One lane projected into days across and hours down. |
82
+
83
+ Use these words in integration code. The LayerRole strings availability and
84
+ booking, and their coverage-field names below, are exact contract identifiers.
85
+
86
+ ## Data contract
87
+
88
+ ```ts
89
+ type Source = { kind: string; id: string; label?: string };
90
+ type Interval = { start: number; end: number; sources: Source[] };
91
+ type Gap = { start: number; end: number; sources: Source[] };
92
+ type LayerRole = 'availability' | 'booking' | 'custom';
93
+ type LayerStyle = { color: string; highlightColor?: string; inset?: number; opacity?: number };
94
+ type Layer = {
95
+ id: string; role: LayerRole; z: number; style: LayerStyle;
96
+ intervals: Interval[]; gaps?: Gap[]; label?: string;
97
+ };
98
+ type LaneFlag = 'none' | 'never-set' | 'empty-in-window';
99
+ type Lane = {
100
+ id: string; version?: string | number; label: string; timezone?: string;
101
+ flag?: LaneFlag; complete?: boolean; layers: Layer[]; meta?: unknown;
102
+ };
103
+ type Window = { start: number; end: number };
104
+ type Weekday = 0 | 1 | 2 | 3 | 4 | 5 | 6;
105
+ type Span = 'day' | 'week' | 'month';
106
+ type WindowSpec =
107
+ | { span: Span; anchorDate: string; wkst?: Weekday; timezone: string }
108
+ | { span: 'custom'; window: Window; timezone: string };
109
+ type Transition = { at: number; deltaMinutes: number };
110
+ type DayColumn = {
111
+ start: number; end: number; localDate: string; label: string; transitions: Transition[];
112
+ };
113
+ type Projection =
114
+ | { orientation: 'horizontal'; viewTimezone: string; pxPerMinute: number; rowHeight: number }
115
+ | { orientation: 'columns'; viewTimezone: string; pxPerHour: number; columnWidth: number; days: DayColumn[] };
116
+ type Rect = {
117
+ x: number; y: number; width: number; height: number; layerId: string;
118
+ z: number; sources: Source[]; column?: number;
119
+ };
120
+ type Coverage = {
121
+ availabilityMinutes: number; bookingMinutes: number; availabilityMinusBookingMinutes: number;
122
+ };
123
+ type LaneGeometry = {
124
+ laneId: string; rects: Rect[]; gapRects: Rect[]; coverage: Coverage; flag: LaneFlag;
125
+ };
126
+ ```
127
+
128
+ All bounds are integer epoch milliseconds, [start, end). Preserve exact times;
129
+ minuteStep is only for ticks and pointer snapping. Source equality uses both
130
+ kind and id, not reference or label. Distinct labels do not create distinct
131
+ sources. Use stable lane ids and unique layer ids within a lane.
132
+
133
+ Role determines union coverage, not z-order. availabilityMinusBookingMinutes
134
+ subtracts the intersection of the two role unions. Gaps are not subtracted again;
135
+ the adapter must already have netted intervals. Layout splits source sets exactly:
136
+ A 09:00 to 11:00 and B 10:00 to 12:00 gives {A}, {A,B}, {B}.
137
+
138
+ Only upstream knowledge justifies never-set. With no explicit flag, intervals
139
+ outside the requested window infer empty-in-window; all other cases infer none.
140
+ complete defaults to true. Set false for capped or partially fetched output and
141
+ show the incompleteLabel; do not describe incomplete empty time as definitive.
142
+
143
+ ## Entry points
144
+
145
+ | Import | Runtime exports and purpose |
146
+ | --- | --- |
147
+ | react-native-roster | Roster, Schedule, useRoster, useSchedule, default zone fillers, and core re-exports. |
148
+ | react-native-roster/core | layoutLane, coverageFor, flagFor, windowFor, prev, next, today, dayColumnsFor, timeAtX, timeAtY, snapToStep, byLabel, byCoverage, and core counters/caches. |
149
+ | react-native-roster/rrule | expandRuleSet, envelopeFor, expandStats, resetExpandStats, clearExpandCache; RuleSet, RosterRule, RosterDate, ExpandOptions, ExpandResult, and ExpandStats types. |
150
+ | react-native-roster/nativewind | Side-effect registration of Roster and Schedule with NativeWind's cssInterop, plus the registered Roster and Schedule and the rosterClassNames/scheduleClassNames mappings. Imports the optional nativewind peer. |
151
+
152
+ No default exports. Root exports renderer inputs/models/zone types as well as
153
+ core types. Core imports standard JS and Intl only. Only /rrule imports
154
+ rrule-temporal 1.6.0 and @js-temporal/polyfill 0.5.1. Those are installed runtime
155
+ dependencies but cannot enter root/core bundles through library imports.
156
+
157
+ Metro selects TS source via exports' react-native condition. Keep package exports
158
+ enabled and one React copy in a workspace. Other resolvers load built CommonJS
159
+ from dist/src; declarations use the types condition. Build before Node export
160
+ tests. Root needs a native renderer or web bundler; direct Node use of root is
161
+ not a substitute for a React Native app. Core and /rrule work in Node/Bun.
162
+
163
+ ## Renderer contracts
164
+
165
+ Roster required props: lanes: Lane[], windowSpec: WindowSpec.
166
+ Optional: minuteStep (60), rowHeight (48), pxPerMinute (minimum 0.5, fits viewport),
167
+ sortLanes (byLabel), highlightSource, onNavigate, onIntervalPress, onGapPress,
168
+ onCellPress, onIntervalHover (web only), style, headerStyle, laneLabelColumnStyle,
169
+ bodyStyle, laneLabelWidth (180), neverSetLabel, incompleteLabel, and zones below.
170
+ Each style prop has a className twin (className, headerClassName,
171
+ laneLabelColumnClassName, bodyClassName) resolved only after importing
172
+ react-native-roster/nativewind. A class entry replaces the region's default
173
+ paint (background and border colors) and keeps its structure, because React
174
+ Native Web renders object styles inline where they would beat any class. Labels default to "No availability set" and "Availability may
175
+ be incomplete". Supply a bounded height; Roster waits for viewport measurement
176
+ before mounting LegendList. Reanimated keeps horizontal and vertical offsets
177
+ outside React state.
178
+
179
+ useRoster returns window, projection, orderedLanes, coverage, laneState,
180
+ geometryFor(lane), scroll, press(lane,x,y), ticks, contentWidth, viewport,
181
+ onLayout, navigate, and status ('empty' or 'ready'). There is no visibleRange
182
+ field in the shipped public model. Custom layouts must wire onLayout. Custom
183
+ bodies compute geometry only for mounted lanes, preserving virtualization.
184
+ A zero-duration window has contentWidth=0 and renders no Roster body. Positive
185
+ windows use their exact elapsed duration, including sub-minute spans. Cell times
186
+ are clamped up to window.start and rejected at or beyond window.end.
187
+
188
+ Schedule required props: lane: Lane, windowSpec: WindowSpec & {span:'day'|'week'}.
189
+ Optional: minuteStep (60), pxPerHour (48, positive finite), highlightSource,
190
+ onNavigate, onIntervalPress, onGapPress, onCellPress, style, headerStyle,
191
+ gutterStyle, daysStyle, incompleteLabel, and zones below. Class twins are
192
+ className, headerClassName, gutterClassName, and daysClassName. No month/custom
193
+ spec, sort, or interval-hover prop.
194
+
195
+ useSchedule returns window, days, projection, geometry, now (epoch ms or null),
196
+ press(columnIndex,x,y), and status:'ready'. The standalone hook uses a 280 px grid.
197
+ The chassis measures width, reserves a 48 px gutter, and fits all actual day
198
+ columns without horizontal scrolling; the body scrolls vertically. now updates
199
+ every minute and is null outside the selected window.
200
+
201
+ Zone props are optional render functions. Use exported fillers inside replacements
202
+ to preserve geometry, scrolling, and interaction. Types are exported from root.
203
+
204
+ ## Roster zones
205
+
206
+ | Zone | Receives | Default filler and behavior |
207
+ | --- | --- | --- |
208
+ | `emptyZone` | Nothing | `RosterEmpty`: No lanes. |
209
+ | `laneLabelZone` | `lane`, `flag`, `complete`, `viewTimezone`, localized labels | `RosterLaneLabel`: label, differing IANA zone badge, and notices. |
210
+ | `headerCellZone` | `tick` | `RosterHeaderCell`: tick label. |
211
+ | `intervalZone` | `rect`, `layer`, `lane`, `highlighted` | `RosterInterval`: positioned colored rect, with final inset bounds. |
212
+ | `gapZone` | `rect`, `layer`, `lane` | `RosterGap`: no visible content; the row supplies pressable bounds. |
213
+ | `gridZone` | `ticks`, `contentWidth` | `RosterGrid`: one hairline per tick behind every lane. |
214
+ | `cornerZone` | Nothing | `RosterCorner`: nothing; the cell above the labels, laneLabelWidth wide. |
215
+ | `headerZone` | `ticks`, `projection`, `scroll`, `contentWidth`, `headerCellZone` | `RosterHeader`: frozen header following horizontal offset. |
216
+ | `laneLabelColumnZone` | `labels: LaneLabelInput[]`, `projection`, `scroll`, `laneLabelZone` | `RosterLaneLabelColumn`: frozen labels following vertical offset. |
217
+ | `bodyZone` | Ordered `lanes`, `window`, `geometryFor`, `projection`, `scroll`, `press`, `ticks`, `viewport`, `contentWidth`, highlight/hover, incomplete label, and rect zones | `RosterBody`: virtualized lanes. |
218
+
219
+ ## Schedule zones
220
+
221
+ | Zone | Receives | Default filler and behavior |
222
+ | --- | --- | --- |
223
+ | `gutterZone` | `hours`, `pxPerHour` | `ScheduleGutter`: 24 frozen hour labels. |
224
+ | `gridZone` | `hours`, `pxPerHour` | `ScheduleGrid`: 24 bordered hour bands behind each day's rects. |
225
+ | `dayHeaderZone` | `day` | `ScheduleDayHeader`: weekday, localDate, and transition badge. |
226
+ | `skippedDateZone` | `localDate` | `ScheduleSkippedDate`: zero-width header marker for a wholly skipped date. |
227
+ | `columnZone` | `day`, `rects`, `gapRects`, `lane`, `highlightSource`, `press`, interval/gap zones | `ScheduleColumn`: final rect bounds in layer order. |
228
+ | `transitionZone` | `day`, `transition`, `y`, `dividerY`, `height`, `width` | `ScheduleTransition`: skipped-time hatch, or repeat divider and again label. |
229
+ | `nowLineZone` | `y`, `column` | `ScheduleNowLine`: line in the current day's column, updated each minute. |
230
+ | `intervalZone`, `gapZone` | Same inputs as Roster | Shared `RosterInterval` and `RosterGap`. |
231
+ | `incompleteZone` | `lane`, `label` | `ScheduleIncomplete`: notice in reserved space above the grid when incomplete. |
232
+
233
+ Position custom interval content at rect.x/y with width/height/z and
234
+ pointerEvents="none". Gap content already sits in a positioned pressable.
235
+ Column x coordinates are local; select the column through rect.column.
236
+ Zone fillers are plain React Native views; under NativeWind they take className
237
+ directly. The default RosterLaneLabel owns its row's bottom border, so a custom
238
+ laneLabelZone draws its own separators.
239
+
240
+ ## Navigation and zones
241
+
242
+ windowFor(spec) returns the absolute window. anchorDate is a local YYYY-MM-DD;
243
+ changing timezone preserves it. Week starts Monday unless wkst overrides it;
244
+ Weekday is Monday=0 through Sunday=6. prev/next move one span; custom moves by
245
+ its own absolute duration. today reanchors to the view zone's local today.
246
+ Month navigation clamps to the target month's final day when needed.
247
+ Consumer controls update the controlled spec; there is no automatic toolbar.
248
+
249
+ Rule/date timezone interprets local hours during expansion. Lane timezone only
250
+ controls the IANA badge. View timezone is windowSpec.timezone, becoming
251
+ projection.viewTimezone. No other view-timezone component prop exists.
252
+
253
+ Roster uses true elapsed width (Chicago transition weeks have 167/169 hours).
254
+ Schedule always uses 24 equal wall-hour bands. Positive deltaMinutes means a
255
+ skipped empty region; negative means two half-height repeat regions. Rects split
256
+ at column edges, source changes, and every scale boundary. For repeat at T with
257
+ magnitude d, boundaries are T-d, T, and T+d. A wholly skipped date produces no
258
+ column; skippedDateZone labels the header gap (Apia 2011-12-30).
259
+ Each column spans the first instant of its date to the first instant of the next.
260
+ Skipped wall spans belong to the date they interrupt. Its transitions include a
261
+ skip at the exclusive end when it empties that date's final wall bands (Nuuk
262
+ 2024-03-30, 23:00 to 24:00). Those bands are hatched; timeAtY returns null there,
263
+ and onCellPress does not fire.
264
+ For rollbacks across midnight (St_Johns 2009, Goose_Bay 1988), earlier-date instants
265
+ inside that span draw in a compressed repeat at the top edge, ending where
266
+ ordinary wall time resumes. timeAtY inverts this region to the absolute occurrence.
267
+ The repeat divider uses dividerY, the projected transition instant, even when
268
+ the surviving repeat regions have unequal heights.
269
+
270
+ timeAtX(projection,window,x) returns absolute time with origin from window.
271
+ timeAtY(projection,columnIndex,y) returns an absolute occurrence or null for
272
+ skipped time/outside bounds. Inverse times stay below each scale piece's exclusive
273
+ end, including immediately inside the bottom edge.
274
+ snapToStep(time,minuteStep,timezone) floors by wall clock and clamps to occurrence start if flooring would cross a transition.
275
+ minuteStep must be a positive integer divisor of 60.
276
+
277
+ ## Interaction and ordering
278
+
279
+ One press yields one callback. Hit-test final rect bounds at the original point:
280
+ intervals first, gaps second, empty space last. Highest z wins, then later layer
281
+ wins among equal z. A low-z interval therefore wins over a high-z gap. Skipped
282
+ schedule time fires nothing. Only empty-space times snap; 10:30 intervals stay
283
+ pressable on a 60-minute grid. onIntervalPress(rect,lane), onGapPress(rect,lane),
284
+ and onCellPress(lane,time) expose the outcome. Cell times clamp up to window.start
285
+ and are rejected at or beyond window.end. Roster onIntervalHover(rect,lane)
286
+ reports the winning web interval; native attaches no hover handler.
287
+
288
+ highlightSource matches a fresh {kind,id} across lanes, using highlightColor or
289
+ the normal layer color; it changes no geometry. byLabel is the default comparator.
290
+ byCoverage({measure:'availability'|'availabilityMinusBooking'}) sorts descending
291
+ with label ties. Custom LaneComparator is (a,b,coverage:ReadonlyMap<string,Coverage>)
292
+ => number. Coverage is assembled for all lanes before sorting; sorting does not
293
+ precompute geometry for offscreen lanes. Newly mounted target-cold lanes can run
294
+ layout. Scroll retains viewport offset, not a lane anchor.
295
+
296
+ ## Caches and counters
297
+
298
+ layoutLane(lane,window,projection) computes rects for visible lanes only.
299
+ coverageFor(lane,window) computes role unions for all lanes, projection-independent.
300
+ flagFor(lane,window) is cheap and uncached. Geometry assembly reads fresh flag and
301
+ coverage outside cached rects. Repeated complete inputs retain references; treat
302
+ all results as read-only.
303
+
304
+ Geometry key: lane.id + lane.version (or structural encoding of layers only) +
305
+ window bounds + every projection field. Coverage uses the same key without
306
+ projection. Bump any supplied version when layers change. Label, lane timezone,
307
+ flag, complete, and meta never invalidate rects. Clear retained windows explicitly
308
+ when a consumer no longer needs them. This cache lifetime belongs to the consumer.
309
+
310
+ | Function | Meaning |
311
+ | --- | --- |
312
+ | layoutStats() | Cumulative {runs, cacheHits}; runs are geometry computations. |
313
+ | coverageStats() | Cumulative {runs, cacheHits}; runs are coverage computations. |
314
+ | resetStats() | Zero layout and coverage counters, preserve keys. |
315
+ | clearLayoutCache(), clearCoverageCache() | Empty corresponding keys, preserve counters. |
316
+ | expandStats() | Cumulative {rules, dates, expanded, cacheHits, cacheMisses}; expanded counts occurrence computations. |
317
+ | resetExpandStats() | Zero expansion counters, preserve keys. |
318
+ | clearExpandCache() | Empty occurrence entries and retained envelopes, preserve counters. |
319
+
320
+ Target-warm means exact requested keys exist. Target-cold means they do not.
321
+ Neither describes the whole cache. A projection change can be target-cold for
322
+ layout and target-warm for coverage. Equal absolute windows reuse coverage even
323
+ when view zones differ. Reanchoring UTC to Chicago changes the absolute week and
324
+ requires coverage for all lanes, plus geometry for mounted lanes.
325
+
326
+ ## Recurrence adapter
327
+
328
+ expandRuleSet(set,window,options?) returns {intervals,gaps,envelope,complete,
329
+ truncated:[{id,droppedAtLeast}],stats}. It throws on invalid window, hours,
330
+ recurrence fields, timezone, or date input. Treat malformed upstream data as an
331
+ error; do not silently map errors to definitive empty lanes. A zero-duration window
332
+ (start=end) validates every rule and date, including date, dtstart, until, and
333
+ timezone, then returns empty intervals and gaps, complete=true, and expanded=0.
334
+
335
+ RuleSet is {rules:RosterRule[],dates:RosterDate[]}.
336
+ RosterRule requires id, kind:'include'|'exclude', frequency:'DAILY'|'WEEKLY'|'MONTHLY',
337
+ dtstart (ISO date/datetime), hourstart, hourend, and timezone (IANA).
338
+ Optional: until, count, interval, wkst, byweekday, bymonth, bymonthday, bysetpos.
339
+ RosterDate requires id, kind, date (local ISO date), and timezone; optional note
340
+ becomes Source.label. Hours are both present for partial day, both absent for
341
+ whole day. A wholly skipped local date has no occurrences for either kind, with
342
+ or without hours. Hours satisfy 0<=hourstart<hourend<=24 and may be fractional.
343
+ Unsupported fields: byyearday, byweekno, byhour, byminute, bysecond. Convert enums,
344
+ Date values, and nulls at the boundary; reject unsupported active semantics.
345
+
346
+ Expansion uses one absolute envelope for every include, exclude, and date:
347
+ envelopeFor(window) is window +/-48 absolute hours. The view zone is not an input.
348
+ Enumeration retains the original dtstart except for interval-1 rules without
349
+ COUNT whose anchor is exactly local midnight. Those rules may skip whole periods
350
+ in plain-date space, preserving the weekly weekday and monthly day, and stepping
351
+ back past nonexistent dates. Date-only and local-datetime dtstart preserve their
352
+ authored date and time, even inside a skipped date or hour. Explicit-offset dtstart
353
+ remains an instant, converted to wall fields and an offset in the rule's zone.
354
+ The engine iterates those wall fields in UTC calendar space.
355
+ Every rule enumerates from the period containing DTSTART at the anchor wall time,
356
+ aligned to WKST for WEEKLY and day 1 for MONTHLY, so interval phases follow the
357
+ DTSTART period rather than the first matching date. Dates before DTSTART are
358
+ rejected before COUNT and cap admission.
359
+ DAILY weekday filters are applied by the adapter to the authored daily sequence
360
+ because the engine otherwise re-anchors at the first matching date.
361
+ The engine uses the end of UNTIL's local date as a conservative UTC enumeration bound.
362
+ Explicit-offset UNTIL uses the end of the following local date instead; exact instant
363
+ admission is its only UNTIL admission test. Clamp either bound to the corresponding
364
+ UTC calendar bound of the envelope query.
365
+ The enumeration bound is conservative through the wall date after any cross-date rollback
366
+ at the envelope end, and envelope clipping discards the extra candidates.
367
+ The adapter owns BYSETPOS after every other BYxxx filter, grouping plain dates
368
+ by day, WKST week, or year-month before deduplication, UNTIL, COUNT, and cap admission.
369
+ Positional enumeration includes complete edge periods, then rejects dates before
370
+ DTSTART and spans outside the envelope. The engine iteration limit is the number
371
+ of authored periods from the enumeration anchor through the query bound, so empty
372
+ candidate periods terminate completely without an arbitrary cutoff. Only that
373
+ exact engine limit error signals completed enumeration; other failures propagate.
374
+ Replayed iterator passes stop before buffering positional candidates.
375
+ YEARLY is unsupported and rejected by input validation.
376
+ The adapter
377
+ drops wholly nonexistent dates before counting existing dates from the original
378
+ anchor for COUNT. A skipped date never becomes a different weekday or consumes
379
+ COUNT. The adapter admits each emitted date only when that date is at or before
380
+ the authored date-only UNTIL,
381
+ including when its final hour or the whole date is skipped. Local datetime UNTIL
382
+ compares plain date-times at the authored dtstart wall time, without normalizing
383
+ skipped hours. Explicit-offset UNTIL compares exact instants, preferring an
384
+ explicit-offset dtstart's offset in repeats and using compatible disambiguation
385
+ otherwise. A datetime UNTIL before DTSTART admits nothing.
386
+ This keeps UNTIL admission independent of anchor advancement and retained envelopes.
387
+ Occurrences outside the envelope never consume the occurrence cap.
388
+ Retained-envelope containment selects existing bounds before creating a new
389
+ padded envelope. One shared LRU spans all sets (default maxEnvelopes=4);
390
+ containment selects the most recently used matching envelope.
391
+ Per-item keys use occurrence body content + exact envelope + perRuleOccurrences.
392
+ Id and dated note attach freshly in assembly; include/exclude kind remains in the body key. Unchanged
393
+ bodies reuse occurrences only if those exact keys still exist (maxEntries=2000).
394
+ Editing a set reuses containing envelopes; unchanged item keys may still hit.
395
+ Envelope retention alone never guarantees expanded=0 after occurrence eviction.
396
+
397
+ Netting and total caps run fresh on every call, then clip to display window.
398
+ Includes supply interval sources; excludes supply gap sources. Fully excluded
399
+ includes leave gaps. No minute-step snapping. Defaults: caps.perRuleOccurrences=400,
400
+ caps.totalOccurrences=10000; options.cache.maxEntries=2000, maxEnvelopes=4.
401
+ All accept nonnegative integers. Zero cache budgets disable retention; zero caps
402
+ admit no occurrences. Both occurrence entries and retained envelopes are bounded
403
+ globally across sets; clear when discarding old windows.
404
+
405
+ Per-rule cap truncation reports droppedAtLeast=1 (unknown remainder). The total
406
+ cap admits whole lists in rule-id order, then date-id order. First list that
407
+ cannot fit and every later list are dropped; exact fully enumerated counts are
408
+ reported. Equality fits. Caps apply across the envelope, not only visible time.
409
+ Changing the total cap changes assembly, not occurrence keys; changing the
410
+ per-rule cap changes all requested occurrence keys. Incomplete output can omit
411
+ exclusions too; it is not necessarily a conservative subset. Always map
412
+ result.complete to Lane.complete.
413
+
414
+ ```ts
415
+ import type { Lane } from 'react-native-roster/core';
416
+ import { windowFor } from 'react-native-roster/core';
417
+ import { expandRuleSet } from 'react-native-roster/rrule';
418
+ import type { RuleSet } from 'react-native-roster/rrule';
419
+
420
+ export function laneFromRules(set: RuleSet): Lane {
421
+ const window = windowFor({ span: 'week', anchorDate: '2024-01-01', timezone: 'UTC' });
422
+ const result = expandRuleSet(set, window);
423
+ return { id: 'one', label: 'One', complete: result.complete, layers: [{
424
+ id: 'open', role: 'availability', z: 0, style: { color: '#4f9478' },
425
+ intervals: result.intervals, gaps: result.gaps,
426
+ }] };
427
+ }
428
+ ```
429
+
430
+ ## Gallery, evidence, and non-goals
431
+
432
+ The home page derives links from named roster and schedule fixture records.
433
+ Explicit routes cover each day/week/month at 15/30/60-minute steps, lane counts,
434
+ provenance, flags, timezones, Schedule transitions, and default/replaced zones.
435
+ Adapter weekly/override/cap routes render editable JSON beside the roster through
436
+ ruleSetEditorZone. useRuleSetDraft owns text, parse result, and the applied set;
437
+ Apply validates before updating the roster, keeping the last valid set on error.
438
+ These are demo hooks/zones, not library exports.
439
+
440
+ Every route exposes live counter functions on web window.__roster. Its identity
441
+ stays stable until unmount; on-screen snapshots sample every 500 ms. The 200-lane
442
+ route feeds real adapter output to workload W and includes cold-layout, rule-hour,
443
+ and unrelated-lane-zone controls for the browser/device protocol.
444
+
445
+ Web static export and Chromium checks complement iOS/Android implementations;
446
+ physical-device rendering and Hermes Intl behavior remain unverified here.
447
+ Production web Profiler callbacks are disabled. check:web also exports development
448
+ web and checks actual LegendList LaneRow commits on the second scroll pass, with
449
+ nonzero mount and highlight-update controls. The development 200-lane route exposes
450
+ profileStats() through window.__roster. Bun host tests remain complementary; a
451
+ native LaneRow profile is required for release. Pages deployment
452
+ is configured from main but cannot be proven by local export.
453
+
454
+ W: seed 1318, 200 lanes, week, two layers, 24-lane layout batch, 15-minute ticks;
455
+ 63 rects + 7 gap rects per lane. test/performance/baseline.json records layout
456
+ 2.070 ms and all-200-lane coverage 1.063 ms on GitHub Actions ubuntu-latest,
457
+ Bun 1.4.0, 2026-09-08T05:18:00Z, commit
458
+ 1c4ac0e8580b1d46c043f946aa7ebc1ee316d0fa. Median of 11 target-cold samples after
459
+ five runtime warmups. Each timing must stay below 16 ms; CI also enforces <=1.5x
460
+ its baseline. Size gates: core <15 kB, root <40 kB minified/uncompressed, peers
461
+ external. Phone fps and cold-layout numbers are not yet captured; the paired
462
+ react-big-scheduler comparison is not yet measured. Do not claim relative speed.
463
+
464
+ The package does not create, drag, resize, persist, or authorize intervals; it
465
+ is not a general calendar. Consumers implement their own interactions. A rule
466
+ editor in the gallery is an integration example, not a rule-authoring product.
467
+
468
+ ## Reference
469
+
470
+ - [README](./README.md): runnable quick starts, setup, zones, and measured evidence.
471
+ - [Adapter guide](./docs/adapters.md): table/feed conversion and memoization contract.
472
+ - Area landing pages: [core](./src/core/README.md), [Roster](./src/components/roster/README.md),
473
+ [Schedule](./src/components/schedule/README.md), [layers](./src/components/layers/README.md),
474
+ [primitives](./src/components/primitives/README.md), [rrule adapter](./src/adapters/rrule/README.md),
475
+ [nativewind](./src/nativewind/README.md), [gallery](./demo/components/gallery/README.md),
476
+ [showcase](./demo/components/team-roster/README.md), [theme](./demo/components/theme/README.md);
477
+ [adding an adapter](./docs/adding-an-adapter.md).
478
+ - [Design note](./docs/design.md): reasoning and non-goals.
479
+ - [Performance](./docs/performance.md): automated budgets and exact-commit device capture.
480
+ - [AGENTS.md](./AGENTS.md): repository conventions, not consumer API requirements.
481
+ - [CONTRIBUTING.md](./CONTRIBUTING.md): commands and release process.
package/package.json CHANGED
@@ -1,19 +1,165 @@
1
1
  {
2
2
  "name": "react-native-roster",
3
- "version": "0.0.0",
4
- "description": "Layered intervals with provenance across lanes and a shared time axis for React Native. Placeholder release; the API is unreleased.",
5
- "license": "MIT",
3
+ "version": "0.0.1",
4
+ "description": "Layered intervals with provenance across lanes and a shared time axis for React Native.",
5
+ "keywords": [
6
+ "react-native",
7
+ "expo",
8
+ "roster",
9
+ "lanes",
10
+ "intervals",
11
+ "provenance",
12
+ "nativewind"
13
+ ],
6
14
  "author": "Jesse Harlin (the-simian) <info@simiancraft.com>",
15
+ "license": "MIT",
16
+ "homepage": "https://simiancraft.github.io/react-native-roster/",
7
17
  "repository": {
8
18
  "type": "git",
9
19
  "url": "git+https://github.com/simiancraft/react-native-roster.git"
10
20
  },
11
- "homepage": "https://simiancraft.github.io/react-native-roster/",
12
21
  "bugs": {
13
22
  "url": "https://github.com/simiancraft/react-native-roster/issues"
14
23
  },
15
- "keywords": ["react-native", "expo", "roster", "schedule", "timeline", "availability", "nativewind"],
16
- "main": "index.js",
17
- "files": ["index.js", "README.md", "LICENSE"],
18
- "publishConfig": { "access": "public" }
24
+ "type": "commonjs",
25
+ "sideEffects": [
26
+ "./src/nativewind/index.ts",
27
+ "./dist/src/nativewind/index.js"
28
+ ],
29
+ "main": "./src/index.ts",
30
+ "react-native": "./src/index.ts",
31
+ "types": "./dist/src/index.d.ts",
32
+ "browser": {
33
+ "./dist/src/components/primitives/press-point.js": "./dist/src/components/primitives/press-point.web.js",
34
+ "./dist/src/components/roster/lanes/interval-hover.js": "./dist/src/components/roster/lanes/interval-hover.web.js"
35
+ },
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/src/index.d.ts",
39
+ "bun": "./src/index.ts",
40
+ "react-native": "./src/index.ts",
41
+ "default": "./dist/src/index.js"
42
+ },
43
+ "./core": {
44
+ "types": "./dist/src/core/index.d.ts",
45
+ "bun": "./src/core/index.ts",
46
+ "react-native": "./src/core/index.ts",
47
+ "default": "./dist/src/core/index.js"
48
+ },
49
+ "./rrule": {
50
+ "types": "./dist/src/adapters/rrule/index.d.ts",
51
+ "bun": "./src/adapters/rrule/index.ts",
52
+ "react-native": "./src/adapters/rrule/index.ts",
53
+ "default": "./dist/src/adapters/rrule/index.js"
54
+ },
55
+ "./nativewind": {
56
+ "types": "./dist/src/nativewind/index.d.ts",
57
+ "bun": "./src/nativewind/index.ts",
58
+ "react-native": "./src/nativewind/index.ts",
59
+ "default": "./dist/src/nativewind/index.js"
60
+ },
61
+ "./package.json": "./package.json"
62
+ },
63
+ "files": [
64
+ "src",
65
+ "dist",
66
+ "README.md",
67
+ "LICENSE",
68
+ "NOTICE.md",
69
+ "llms.txt"
70
+ ],
71
+ "scripts": {
72
+ "clean": "rm -rf dist",
73
+ "build": "bun run clean && tsgo -p tsconfig.build.json",
74
+ "lint": "biome check",
75
+ "lint:fix": "biome check --write",
76
+ "format": "biome format --write .",
77
+ "typecheck": "tsgo --noEmit",
78
+ "typecheck:test": "tsgo --noEmit -p tsconfig.test.json",
79
+ "check:react-compiler": "eslint 'src/components/**/*.{ts,tsx}' 'demo/components/**/*.{ts,tsx}' 'demo/app/**/*.tsx' --no-error-on-unmatched-pattern",
80
+ "check:knip": "knip",
81
+ "check:package": "publint --strict",
82
+ "test": "bun test --coverage",
83
+ "check": "bun run lint && bun run typecheck && bun run typecheck:test && bun run typecheck:demo && bun run check:react-compiler && bun run build:web && bun run test && bun run check:knip && bun run check:package && bun run check:size && bun run check:web",
84
+ "prepare": "if command -v lefthook >/dev/null 2>&1; then lefthook install; fi",
85
+ "prepack": "bun run build",
86
+ "typecheck:demo": "tsgo --noEmit -p demo/tsconfig.json",
87
+ "build:web": "bun run build && cd demo && bunx expo export -p web",
88
+ "demo": "cd demo && bun run start",
89
+ "demo:ios": "cd demo && bun run ios",
90
+ "demo:android": "cd demo && bun run android",
91
+ "demo:web": "cd demo && bun run web",
92
+ "check:size": "size-limit",
93
+ "build:web:dev": "cd demo && bunx expo export -p web --dev --output-dir .cache/dev-dist",
94
+ "check:web": "bun run build:web:dev && bun scripts/check-web-performance.ts",
95
+ "bench:update": "bun scripts/update-performance-baseline.ts"
96
+ },
97
+ "peerDependencies": {
98
+ "@legendapp/list": ">=2.0.0",
99
+ "expo": ">=51.0.0",
100
+ "nativewind": ">=4.1.0",
101
+ "react": ">=18.2.0",
102
+ "react-native": ">=0.74.0",
103
+ "react-native-reanimated": ">=3.19.0"
104
+ },
105
+ "peerDependenciesMeta": {
106
+ "expo": {
107
+ "optional": true
108
+ },
109
+ "nativewind": {
110
+ "optional": true
111
+ },
112
+ "react-native-reanimated": {
113
+ "optional": true
114
+ }
115
+ },
116
+ "dependencies": {
117
+ "@js-temporal/polyfill": "0.5.1",
118
+ "rrule-temporal": "1.6.0"
119
+ },
120
+ "devDependencies": {
121
+ "@biomejs/biome": "2.5.12",
122
+ "@legendapp/list": "2.0.19",
123
+ "@semantic-release/changelog": "^7.0.0",
124
+ "@semantic-release/commit-analyzer": "13.0.1",
125
+ "@semantic-release/exec": "^7.1.0",
126
+ "@semantic-release/git": "^11.0.1",
127
+ "@semantic-release/github": "12.0.9",
128
+ "@semantic-release/npm": "13.1.5",
129
+ "@semantic-release/release-notes-generator": "14.1.1",
130
+ "@size-limit/preset-small-lib": "^13.0.3",
131
+ "@types/bun": "^1.3.12",
132
+ "@types/react": "~19.1.10",
133
+ "@types/react-test-renderer": "^19.1.0",
134
+ "@types/semver": "^7.7.0",
135
+ "@typescript-eslint/parser": "^8.60.1",
136
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
137
+ "eslint": "^10.4.1",
138
+ "eslint-plugin-react-compiler": "^19.1.0-rc.2",
139
+ "expo": "~54.0.37",
140
+ "knip": "^6.5.0",
141
+ "lefthook": "^2.1.9",
142
+ "nativewind": "4.1.x",
143
+ "playwright": "^1.63.0",
144
+ "publint": "^0.3.18",
145
+ "react": "19.1.0",
146
+ "react-native": "0.81.5",
147
+ "react-native-reanimated": "~3.19.5",
148
+ "react-test-renderer": "19.1.0",
149
+ "semantic-release": "^25.0.3",
150
+ "semver": "^7.7.0",
151
+ "size-limit": "^13.0.3",
152
+ "temporal-spec": "1.0.1"
153
+ },
154
+ "publishConfig": {
155
+ "access": "public",
156
+ "provenance": true
157
+ },
158
+ "engines": {
159
+ "node": ">=20"
160
+ },
161
+ "packageManager": "bun@1.4.2",
162
+ "workspaces": [
163
+ "demo"
164
+ ]
19
165
  }