react-native-agenda-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +364 -0
  3. package/lib/commonjs/agenda/AgendaBackdrop.js +68 -0
  4. package/lib/commonjs/agenda/AgendaBackdrop.js.map +1 -0
  5. package/lib/commonjs/agenda/AgendaList.js +354 -0
  6. package/lib/commonjs/agenda/AgendaList.js.map +1 -0
  7. package/lib/commonjs/agenda/AgendaSlot.js +88 -0
  8. package/lib/commonjs/agenda/AgendaSlot.js.map +1 -0
  9. package/lib/commonjs/agenda/AgendaWindow.js +171 -0
  10. package/lib/commonjs/agenda/AgendaWindow.js.map +1 -0
  11. package/lib/commonjs/agenda/StickyHeaderOverlay.js +125 -0
  12. package/lib/commonjs/agenda/StickyHeaderOverlay.js.map +1 -0
  13. package/lib/commonjs/agenda/buildAgendaLayout.js +100 -0
  14. package/lib/commonjs/agenda/buildAgendaLayout.js.map +1 -0
  15. package/lib/commonjs/agenda/constants.js +29 -0
  16. package/lib/commonjs/agenda/constants.js.map +1 -0
  17. package/lib/commonjs/agenda/heights.js +49 -0
  18. package/lib/commonjs/agenda/heights.js.map +1 -0
  19. package/lib/commonjs/agenda/useAgendaScrollSync.js +204 -0
  20. package/lib/commonjs/agenda/useAgendaScrollSync.js.map +1 -0
  21. package/lib/commonjs/core/ArrowGlyph.js +65 -0
  22. package/lib/commonjs/core/ArrowGlyph.js.map +1 -0
  23. package/lib/commonjs/core/CalendarContext.js +32 -0
  24. package/lib/commonjs/core/CalendarContext.js.map +1 -0
  25. package/lib/commonjs/core/CalendarProvider.js +141 -0
  26. package/lib/commonjs/core/CalendarProvider.js.map +1 -0
  27. package/lib/commonjs/core/CalendarStore.js +70 -0
  28. package/lib/commonjs/core/CalendarStore.js.map +1 -0
  29. package/lib/commonjs/core/KitText.js +23 -0
  30. package/lib/commonjs/core/KitText.js.map +1 -0
  31. package/lib/commonjs/core/TodayButton.js +136 -0
  32. package/lib/commonjs/core/TodayButton.js.map +1 -0
  33. package/lib/commonjs/core/civil.js +101 -0
  34. package/lib/commonjs/core/civil.js.map +1 -0
  35. package/lib/commonjs/core/dateKey.js +56 -0
  36. package/lib/commonjs/core/dateKey.js.map +1 -0
  37. package/lib/commonjs/core/motion.js +56 -0
  38. package/lib/commonjs/core/motion.js.map +1 -0
  39. package/lib/commonjs/core/worklets.js +44 -0
  40. package/lib/commonjs/core/worklets.js.map +1 -0
  41. package/lib/commonjs/expandable/DayCell.js +120 -0
  42. package/lib/commonjs/expandable/DayCell.js.map +1 -0
  43. package/lib/commonjs/expandable/ExpandableCalendar.js +280 -0
  44. package/lib/commonjs/expandable/ExpandableCalendar.js.map +1 -0
  45. package/lib/commonjs/expandable/Knob.js +72 -0
  46. package/lib/commonjs/expandable/Knob.js.map +1 -0
  47. package/lib/commonjs/expandable/MonthPager.js +180 -0
  48. package/lib/commonjs/expandable/MonthPager.js.map +1 -0
  49. package/lib/commonjs/expandable/WeekStrip.js +451 -0
  50. package/lib/commonjs/expandable/WeekStrip.js.map +1 -0
  51. package/lib/commonjs/expandable/calendarCells.js +152 -0
  52. package/lib/commonjs/expandable/calendarCells.js.map +1 -0
  53. package/lib/commonjs/expandable/geometry.js +62 -0
  54. package/lib/commonjs/expandable/geometry.js.map +1 -0
  55. package/lib/commonjs/expandable/useExpandGesture.js +124 -0
  56. package/lib/commonjs/expandable/useExpandGesture.js.map +1 -0
  57. package/lib/commonjs/expandable/useHorizontalPager.js +97 -0
  58. package/lib/commonjs/expandable/useHorizontalPager.js.map +1 -0
  59. package/lib/commonjs/index.js +167 -0
  60. package/lib/commonjs/index.js.map +1 -0
  61. package/lib/commonjs/package.json +1 -0
  62. package/lib/commonjs/theme/ThemeProvider.js +73 -0
  63. package/lib/commonjs/theme/ThemeProvider.js.map +1 -0
  64. package/lib/commonjs/theme/index.js +75 -0
  65. package/lib/commonjs/theme/index.js.map +1 -0
  66. package/lib/commonjs/theme/theme.js +79 -0
  67. package/lib/commonjs/theme/theme.js.map +1 -0
  68. package/lib/commonjs/theme/tokens.js +54 -0
  69. package/lib/commonjs/theme/tokens.js.map +1 -0
  70. package/lib/commonjs/timeline/DayColumn.js +95 -0
  71. package/lib/commonjs/timeline/DayColumn.js.map +1 -0
  72. package/lib/commonjs/timeline/DayPager.js +250 -0
  73. package/lib/commonjs/timeline/DayPager.js.map +1 -0
  74. package/lib/commonjs/timeline/EventBlock.js +91 -0
  75. package/lib/commonjs/timeline/EventBlock.js.map +1 -0
  76. package/lib/commonjs/timeline/GridLines.js +47 -0
  77. package/lib/commonjs/timeline/GridLines.js.map +1 -0
  78. package/lib/commonjs/timeline/HourGrid.js +96 -0
  79. package/lib/commonjs/timeline/HourGrid.js.map +1 -0
  80. package/lib/commonjs/timeline/NowIndicator.js +132 -0
  81. package/lib/commonjs/timeline/NowIndicator.js.map +1 -0
  82. package/lib/commonjs/timeline/TimelineDay.js +126 -0
  83. package/lib/commonjs/timeline/TimelineDay.js.map +1 -0
  84. package/lib/commonjs/timeline/packEvents.js +102 -0
  85. package/lib/commonjs/timeline/packEvents.js.map +1 -0
  86. package/lib/commonjs/timeline/timelineGeometry.js +27 -0
  87. package/lib/commonjs/timeline/timelineGeometry.js.map +1 -0
  88. package/lib/commonjs/timeline/timelineMath.js +82 -0
  89. package/lib/commonjs/timeline/timelineMath.js.map +1 -0
  90. package/lib/commonjs/types.js +71 -0
  91. package/lib/commonjs/types.js.map +1 -0
  92. package/lib/module/agenda/AgendaBackdrop.js +63 -0
  93. package/lib/module/agenda/AgendaBackdrop.js.map +1 -0
  94. package/lib/module/agenda/AgendaList.js +349 -0
  95. package/lib/module/agenda/AgendaList.js.map +1 -0
  96. package/lib/module/agenda/AgendaSlot.js +84 -0
  97. package/lib/module/agenda/AgendaSlot.js.map +1 -0
  98. package/lib/module/agenda/AgendaWindow.js +167 -0
  99. package/lib/module/agenda/AgendaWindow.js.map +1 -0
  100. package/lib/module/agenda/StickyHeaderOverlay.js +120 -0
  101. package/lib/module/agenda/StickyHeaderOverlay.js.map +1 -0
  102. package/lib/module/agenda/buildAgendaLayout.js +95 -0
  103. package/lib/module/agenda/buildAgendaLayout.js.map +1 -0
  104. package/lib/module/agenda/constants.js +25 -0
  105. package/lib/module/agenda/constants.js.map +1 -0
  106. package/lib/module/agenda/heights.js +42 -0
  107. package/lib/module/agenda/heights.js.map +1 -0
  108. package/lib/module/agenda/useAgendaScrollSync.js +200 -0
  109. package/lib/module/agenda/useAgendaScrollSync.js.map +1 -0
  110. package/lib/module/core/ArrowGlyph.js +60 -0
  111. package/lib/module/core/ArrowGlyph.js.map +1 -0
  112. package/lib/module/core/CalendarContext.js +26 -0
  113. package/lib/module/core/CalendarContext.js.map +1 -0
  114. package/lib/module/core/CalendarProvider.js +136 -0
  115. package/lib/module/core/CalendarProvider.js.map +1 -0
  116. package/lib/module/core/CalendarStore.js +66 -0
  117. package/lib/module/core/CalendarStore.js.map +1 -0
  118. package/lib/module/core/KitText.js +19 -0
  119. package/lib/module/core/KitText.js.map +1 -0
  120. package/lib/module/core/TodayButton.js +133 -0
  121. package/lib/module/core/TodayButton.js.map +1 -0
  122. package/lib/module/core/civil.js +88 -0
  123. package/lib/module/core/civil.js.map +1 -0
  124. package/lib/module/core/dateKey.js +47 -0
  125. package/lib/module/core/dateKey.js.map +1 -0
  126. package/lib/module/core/motion.js +49 -0
  127. package/lib/module/core/motion.js.map +1 -0
  128. package/lib/module/core/worklets.js +38 -0
  129. package/lib/module/core/worklets.js.map +1 -0
  130. package/lib/module/expandable/DayCell.js +116 -0
  131. package/lib/module/expandable/DayCell.js.map +1 -0
  132. package/lib/module/expandable/ExpandableCalendar.js +275 -0
  133. package/lib/module/expandable/ExpandableCalendar.js.map +1 -0
  134. package/lib/module/expandable/Knob.js +67 -0
  135. package/lib/module/expandable/Knob.js.map +1 -0
  136. package/lib/module/expandable/MonthPager.js +175 -0
  137. package/lib/module/expandable/MonthPager.js.map +1 -0
  138. package/lib/module/expandable/WeekStrip.js +446 -0
  139. package/lib/module/expandable/WeekStrip.js.map +1 -0
  140. package/lib/module/expandable/calendarCells.js +142 -0
  141. package/lib/module/expandable/calendarCells.js.map +1 -0
  142. package/lib/module/expandable/geometry.js +58 -0
  143. package/lib/module/expandable/geometry.js.map +1 -0
  144. package/lib/module/expandable/useExpandGesture.js +118 -0
  145. package/lib/module/expandable/useExpandGesture.js.map +1 -0
  146. package/lib/module/expandable/useHorizontalPager.js +92 -0
  147. package/lib/module/expandable/useHorizontalPager.js.map +1 -0
  148. package/lib/module/index.js +35 -0
  149. package/lib/module/index.js.map +1 -0
  150. package/lib/module/package.json +1 -0
  151. package/lib/module/theme/ThemeProvider.js +65 -0
  152. package/lib/module/theme/ThemeProvider.js.map +1 -0
  153. package/lib/module/theme/index.js +6 -0
  154. package/lib/module/theme/index.js.map +1 -0
  155. package/lib/module/theme/theme.js +74 -0
  156. package/lib/module/theme/theme.js.map +1 -0
  157. package/lib/module/theme/tokens.js +50 -0
  158. package/lib/module/theme/tokens.js.map +1 -0
  159. package/lib/module/timeline/DayColumn.js +91 -0
  160. package/lib/module/timeline/DayColumn.js.map +1 -0
  161. package/lib/module/timeline/DayPager.js +245 -0
  162. package/lib/module/timeline/DayPager.js.map +1 -0
  163. package/lib/module/timeline/EventBlock.js +87 -0
  164. package/lib/module/timeline/EventBlock.js.map +1 -0
  165. package/lib/module/timeline/GridLines.js +43 -0
  166. package/lib/module/timeline/GridLines.js.map +1 -0
  167. package/lib/module/timeline/HourGrid.js +94 -0
  168. package/lib/module/timeline/HourGrid.js.map +1 -0
  169. package/lib/module/timeline/NowIndicator.js +126 -0
  170. package/lib/module/timeline/NowIndicator.js.map +1 -0
  171. package/lib/module/timeline/TimelineDay.js +122 -0
  172. package/lib/module/timeline/TimelineDay.js.map +1 -0
  173. package/lib/module/timeline/packEvents.js +97 -0
  174. package/lib/module/timeline/packEvents.js.map +1 -0
  175. package/lib/module/timeline/timelineGeometry.js +22 -0
  176. package/lib/module/timeline/timelineGeometry.js.map +1 -0
  177. package/lib/module/timeline/timelineMath.js +75 -0
  178. package/lib/module/timeline/timelineMath.js.map +1 -0
  179. package/lib/module/types.js +67 -0
  180. package/lib/module/types.js.map +1 -0
  181. package/lib/typescript/commonjs/agenda/AgendaBackdrop.d.ts +20 -0
  182. package/lib/typescript/commonjs/agenda/AgendaBackdrop.d.ts.map +1 -0
  183. package/lib/typescript/commonjs/agenda/AgendaList.d.ts +12 -0
  184. package/lib/typescript/commonjs/agenda/AgendaList.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/agenda/AgendaSlot.d.ts +45 -0
  186. package/lib/typescript/commonjs/agenda/AgendaSlot.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/agenda/AgendaWindow.d.ts +49 -0
  188. package/lib/typescript/commonjs/agenda/AgendaWindow.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/agenda/StickyHeaderOverlay.d.ts +39 -0
  190. package/lib/typescript/commonjs/agenda/StickyHeaderOverlay.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/agenda/buildAgendaLayout.d.ts +57 -0
  192. package/lib/typescript/commonjs/agenda/buildAgendaLayout.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/agenda/constants.d.ts +19 -0
  194. package/lib/typescript/commonjs/agenda/constants.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/agenda/heights.d.ts +20 -0
  196. package/lib/typescript/commonjs/agenda/heights.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/agenda/useAgendaScrollSync.d.ts +44 -0
  198. package/lib/typescript/commonjs/agenda/useAgendaScrollSync.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/core/ArrowGlyph.d.ts +14 -0
  200. package/lib/typescript/commonjs/core/ArrowGlyph.d.ts.map +1 -0
  201. package/lib/typescript/commonjs/core/CalendarContext.d.ts +35 -0
  202. package/lib/typescript/commonjs/core/CalendarContext.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/core/CalendarProvider.d.ts +41 -0
  204. package/lib/typescript/commonjs/core/CalendarProvider.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/core/CalendarStore.d.ts +28 -0
  206. package/lib/typescript/commonjs/core/CalendarStore.d.ts.map +1 -0
  207. package/lib/typescript/commonjs/core/KitText.d.ts +10 -0
  208. package/lib/typescript/commonjs/core/KitText.d.ts.map +1 -0
  209. package/lib/typescript/commonjs/core/TodayButton.d.ts +18 -0
  210. package/lib/typescript/commonjs/core/TodayButton.d.ts.map +1 -0
  211. package/lib/typescript/commonjs/core/civil.d.ts +26 -0
  212. package/lib/typescript/commonjs/core/civil.d.ts.map +1 -0
  213. package/lib/typescript/commonjs/core/dateKey.d.ts +21 -0
  214. package/lib/typescript/commonjs/core/dateKey.d.ts.map +1 -0
  215. package/lib/typescript/commonjs/core/motion.d.ts +18 -0
  216. package/lib/typescript/commonjs/core/motion.d.ts.map +1 -0
  217. package/lib/typescript/commonjs/core/worklets.d.ts +12 -0
  218. package/lib/typescript/commonjs/core/worklets.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/expandable/DayCell.d.ts +22 -0
  220. package/lib/typescript/commonjs/expandable/DayCell.d.ts.map +1 -0
  221. package/lib/typescript/commonjs/expandable/ExpandableCalendar.d.ts +40 -0
  222. package/lib/typescript/commonjs/expandable/ExpandableCalendar.d.ts.map +1 -0
  223. package/lib/typescript/commonjs/expandable/Knob.d.ts +19 -0
  224. package/lib/typescript/commonjs/expandable/Knob.d.ts.map +1 -0
  225. package/lib/typescript/commonjs/expandable/MonthPager.d.ts +35 -0
  226. package/lib/typescript/commonjs/expandable/MonthPager.d.ts.map +1 -0
  227. package/lib/typescript/commonjs/expandable/WeekStrip.d.ts +34 -0
  228. package/lib/typescript/commonjs/expandable/WeekStrip.d.ts.map +1 -0
  229. package/lib/typescript/commonjs/expandable/calendarCells.d.ts +52 -0
  230. package/lib/typescript/commonjs/expandable/calendarCells.d.ts.map +1 -0
  231. package/lib/typescript/commonjs/expandable/geometry.d.ts +43 -0
  232. package/lib/typescript/commonjs/expandable/geometry.d.ts.map +1 -0
  233. package/lib/typescript/commonjs/expandable/useExpandGesture.d.ts +35 -0
  234. package/lib/typescript/commonjs/expandable/useExpandGesture.d.ts.map +1 -0
  235. package/lib/typescript/commonjs/expandable/useHorizontalPager.d.ts +35 -0
  236. package/lib/typescript/commonjs/expandable/useHorizontalPager.d.ts.map +1 -0
  237. package/lib/typescript/commonjs/index.d.ts +26 -0
  238. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  239. package/lib/typescript/commonjs/package.json +1 -0
  240. package/lib/typescript/commonjs/theme/ThemeProvider.d.ts +27 -0
  241. package/lib/typescript/commonjs/theme/ThemeProvider.d.ts.map +1 -0
  242. package/lib/typescript/commonjs/theme/index.d.ts +4 -0
  243. package/lib/typescript/commonjs/theme/index.d.ts.map +1 -0
  244. package/lib/typescript/commonjs/theme/theme.d.ts +62 -0
  245. package/lib/typescript/commonjs/theme/theme.d.ts.map +1 -0
  246. package/lib/typescript/commonjs/theme/tokens.d.ts +46 -0
  247. package/lib/typescript/commonjs/theme/tokens.d.ts.map +1 -0
  248. package/lib/typescript/commonjs/timeline/DayColumn.d.ts +32 -0
  249. package/lib/typescript/commonjs/timeline/DayColumn.d.ts.map +1 -0
  250. package/lib/typescript/commonjs/timeline/DayPager.d.ts +32 -0
  251. package/lib/typescript/commonjs/timeline/DayPager.d.ts.map +1 -0
  252. package/lib/typescript/commonjs/timeline/EventBlock.d.ts +17 -0
  253. package/lib/typescript/commonjs/timeline/EventBlock.d.ts.map +1 -0
  254. package/lib/typescript/commonjs/timeline/GridLines.d.ts +5 -0
  255. package/lib/typescript/commonjs/timeline/GridLines.d.ts.map +1 -0
  256. package/lib/typescript/commonjs/timeline/HourGrid.d.ts +12 -0
  257. package/lib/typescript/commonjs/timeline/HourGrid.d.ts.map +1 -0
  258. package/lib/typescript/commonjs/timeline/NowIndicator.d.ts +28 -0
  259. package/lib/typescript/commonjs/timeline/NowIndicator.d.ts.map +1 -0
  260. package/lib/typescript/commonjs/timeline/TimelineDay.d.ts +14 -0
  261. package/lib/typescript/commonjs/timeline/TimelineDay.d.ts.map +1 -0
  262. package/lib/typescript/commonjs/timeline/packEvents.d.ts +25 -0
  263. package/lib/typescript/commonjs/timeline/packEvents.d.ts.map +1 -0
  264. package/lib/typescript/commonjs/timeline/timelineGeometry.d.ts +14 -0
  265. package/lib/typescript/commonjs/timeline/timelineGeometry.d.ts.map +1 -0
  266. package/lib/typescript/commonjs/timeline/timelineMath.d.ts +32 -0
  267. package/lib/typescript/commonjs/timeline/timelineMath.d.ts.map +1 -0
  268. package/lib/typescript/commonjs/types.d.ts +237 -0
  269. package/lib/typescript/commonjs/types.d.ts.map +1 -0
  270. package/lib/typescript/module/agenda/AgendaBackdrop.d.ts +20 -0
  271. package/lib/typescript/module/agenda/AgendaBackdrop.d.ts.map +1 -0
  272. package/lib/typescript/module/agenda/AgendaList.d.ts +12 -0
  273. package/lib/typescript/module/agenda/AgendaList.d.ts.map +1 -0
  274. package/lib/typescript/module/agenda/AgendaSlot.d.ts +45 -0
  275. package/lib/typescript/module/agenda/AgendaSlot.d.ts.map +1 -0
  276. package/lib/typescript/module/agenda/AgendaWindow.d.ts +49 -0
  277. package/lib/typescript/module/agenda/AgendaWindow.d.ts.map +1 -0
  278. package/lib/typescript/module/agenda/StickyHeaderOverlay.d.ts +39 -0
  279. package/lib/typescript/module/agenda/StickyHeaderOverlay.d.ts.map +1 -0
  280. package/lib/typescript/module/agenda/buildAgendaLayout.d.ts +57 -0
  281. package/lib/typescript/module/agenda/buildAgendaLayout.d.ts.map +1 -0
  282. package/lib/typescript/module/agenda/constants.d.ts +19 -0
  283. package/lib/typescript/module/agenda/constants.d.ts.map +1 -0
  284. package/lib/typescript/module/agenda/heights.d.ts +20 -0
  285. package/lib/typescript/module/agenda/heights.d.ts.map +1 -0
  286. package/lib/typescript/module/agenda/useAgendaScrollSync.d.ts +44 -0
  287. package/lib/typescript/module/agenda/useAgendaScrollSync.d.ts.map +1 -0
  288. package/lib/typescript/module/core/ArrowGlyph.d.ts +14 -0
  289. package/lib/typescript/module/core/ArrowGlyph.d.ts.map +1 -0
  290. package/lib/typescript/module/core/CalendarContext.d.ts +35 -0
  291. package/lib/typescript/module/core/CalendarContext.d.ts.map +1 -0
  292. package/lib/typescript/module/core/CalendarProvider.d.ts +41 -0
  293. package/lib/typescript/module/core/CalendarProvider.d.ts.map +1 -0
  294. package/lib/typescript/module/core/CalendarStore.d.ts +28 -0
  295. package/lib/typescript/module/core/CalendarStore.d.ts.map +1 -0
  296. package/lib/typescript/module/core/KitText.d.ts +10 -0
  297. package/lib/typescript/module/core/KitText.d.ts.map +1 -0
  298. package/lib/typescript/module/core/TodayButton.d.ts +18 -0
  299. package/lib/typescript/module/core/TodayButton.d.ts.map +1 -0
  300. package/lib/typescript/module/core/civil.d.ts +26 -0
  301. package/lib/typescript/module/core/civil.d.ts.map +1 -0
  302. package/lib/typescript/module/core/dateKey.d.ts +21 -0
  303. package/lib/typescript/module/core/dateKey.d.ts.map +1 -0
  304. package/lib/typescript/module/core/motion.d.ts +18 -0
  305. package/lib/typescript/module/core/motion.d.ts.map +1 -0
  306. package/lib/typescript/module/core/worklets.d.ts +12 -0
  307. package/lib/typescript/module/core/worklets.d.ts.map +1 -0
  308. package/lib/typescript/module/expandable/DayCell.d.ts +22 -0
  309. package/lib/typescript/module/expandable/DayCell.d.ts.map +1 -0
  310. package/lib/typescript/module/expandable/ExpandableCalendar.d.ts +40 -0
  311. package/lib/typescript/module/expandable/ExpandableCalendar.d.ts.map +1 -0
  312. package/lib/typescript/module/expandable/Knob.d.ts +19 -0
  313. package/lib/typescript/module/expandable/Knob.d.ts.map +1 -0
  314. package/lib/typescript/module/expandable/MonthPager.d.ts +35 -0
  315. package/lib/typescript/module/expandable/MonthPager.d.ts.map +1 -0
  316. package/lib/typescript/module/expandable/WeekStrip.d.ts +34 -0
  317. package/lib/typescript/module/expandable/WeekStrip.d.ts.map +1 -0
  318. package/lib/typescript/module/expandable/calendarCells.d.ts +52 -0
  319. package/lib/typescript/module/expandable/calendarCells.d.ts.map +1 -0
  320. package/lib/typescript/module/expandable/geometry.d.ts +43 -0
  321. package/lib/typescript/module/expandable/geometry.d.ts.map +1 -0
  322. package/lib/typescript/module/expandable/useExpandGesture.d.ts +35 -0
  323. package/lib/typescript/module/expandable/useExpandGesture.d.ts.map +1 -0
  324. package/lib/typescript/module/expandable/useHorizontalPager.d.ts +35 -0
  325. package/lib/typescript/module/expandable/useHorizontalPager.d.ts.map +1 -0
  326. package/lib/typescript/module/index.d.ts +26 -0
  327. package/lib/typescript/module/index.d.ts.map +1 -0
  328. package/lib/typescript/module/package.json +1 -0
  329. package/lib/typescript/module/theme/ThemeProvider.d.ts +27 -0
  330. package/lib/typescript/module/theme/ThemeProvider.d.ts.map +1 -0
  331. package/lib/typescript/module/theme/index.d.ts +4 -0
  332. package/lib/typescript/module/theme/index.d.ts.map +1 -0
  333. package/lib/typescript/module/theme/theme.d.ts +62 -0
  334. package/lib/typescript/module/theme/theme.d.ts.map +1 -0
  335. package/lib/typescript/module/theme/tokens.d.ts +46 -0
  336. package/lib/typescript/module/theme/tokens.d.ts.map +1 -0
  337. package/lib/typescript/module/timeline/DayColumn.d.ts +32 -0
  338. package/lib/typescript/module/timeline/DayColumn.d.ts.map +1 -0
  339. package/lib/typescript/module/timeline/DayPager.d.ts +32 -0
  340. package/lib/typescript/module/timeline/DayPager.d.ts.map +1 -0
  341. package/lib/typescript/module/timeline/EventBlock.d.ts +17 -0
  342. package/lib/typescript/module/timeline/EventBlock.d.ts.map +1 -0
  343. package/lib/typescript/module/timeline/GridLines.d.ts +5 -0
  344. package/lib/typescript/module/timeline/GridLines.d.ts.map +1 -0
  345. package/lib/typescript/module/timeline/HourGrid.d.ts +12 -0
  346. package/lib/typescript/module/timeline/HourGrid.d.ts.map +1 -0
  347. package/lib/typescript/module/timeline/NowIndicator.d.ts +28 -0
  348. package/lib/typescript/module/timeline/NowIndicator.d.ts.map +1 -0
  349. package/lib/typescript/module/timeline/TimelineDay.d.ts +14 -0
  350. package/lib/typescript/module/timeline/TimelineDay.d.ts.map +1 -0
  351. package/lib/typescript/module/timeline/packEvents.d.ts +25 -0
  352. package/lib/typescript/module/timeline/packEvents.d.ts.map +1 -0
  353. package/lib/typescript/module/timeline/timelineGeometry.d.ts +14 -0
  354. package/lib/typescript/module/timeline/timelineGeometry.d.ts.map +1 -0
  355. package/lib/typescript/module/timeline/timelineMath.d.ts +32 -0
  356. package/lib/typescript/module/timeline/timelineMath.d.ts.map +1 -0
  357. package/lib/typescript/module/types.d.ts +237 -0
  358. package/lib/typescript/module/types.d.ts.map +1 -0
  359. package/package.json +105 -0
  360. package/src/agenda/AgendaBackdrop.tsx +55 -0
  361. package/src/agenda/AgendaList.tsx +370 -0
  362. package/src/agenda/AgendaSlot.tsx +88 -0
  363. package/src/agenda/AgendaWindow.tsx +183 -0
  364. package/src/agenda/StickyHeaderOverlay.tsx +126 -0
  365. package/src/agenda/buildAgendaLayout.ts +110 -0
  366. package/src/agenda/constants.ts +22 -0
  367. package/src/agenda/heights.ts +44 -0
  368. package/src/agenda/useAgendaScrollSync.ts +251 -0
  369. package/src/core/ArrowGlyph.tsx +53 -0
  370. package/src/core/CalendarContext.ts +47 -0
  371. package/src/core/CalendarProvider.tsx +165 -0
  372. package/src/core/CalendarStore.ts +64 -0
  373. package/src/core/KitText.tsx +10 -0
  374. package/src/core/TodayButton.tsx +121 -0
  375. package/src/core/civil.ts +92 -0
  376. package/src/core/dateKey.ts +52 -0
  377. package/src/core/motion.ts +51 -0
  378. package/src/core/worklets.ts +37 -0
  379. package/src/expandable/DayCell.tsx +97 -0
  380. package/src/expandable/ExpandableCalendar.tsx +278 -0
  381. package/src/expandable/Knob.tsx +67 -0
  382. package/src/expandable/MonthPager.tsx +208 -0
  383. package/src/expandable/WeekStrip.tsx +439 -0
  384. package/src/expandable/calendarCells.ts +155 -0
  385. package/src/expandable/geometry.ts +51 -0
  386. package/src/expandable/useExpandGesture.ts +147 -0
  387. package/src/expandable/useHorizontalPager.ts +116 -0
  388. package/src/index.ts +62 -0
  389. package/src/theme/ThemeProvider.tsx +85 -0
  390. package/src/theme/index.ts +18 -0
  391. package/src/theme/theme.ts +110 -0
  392. package/src/theme/tokens.ts +50 -0
  393. package/src/timeline/DayColumn.tsx +84 -0
  394. package/src/timeline/DayPager.tsx +295 -0
  395. package/src/timeline/EventBlock.tsx +76 -0
  396. package/src/timeline/GridLines.tsx +36 -0
  397. package/src/timeline/HourGrid.tsx +90 -0
  398. package/src/timeline/NowIndicator.tsx +123 -0
  399. package/src/timeline/TimelineDay.tsx +112 -0
  400. package/src/timeline/packEvents.ts +118 -0
  401. package/src/timeline/timelineGeometry.ts +23 -0
  402. package/src/timeline/timelineMath.ts +86 -0
  403. package/src/types.ts +252 -0
@@ -0,0 +1,370 @@
1
+ /**
2
+ * The agenda: one `Animated.ScrollView`, absolute slots over a declared layout,
3
+ * a skeleton backdrop behind it and the stuck header over it.
4
+ *
5
+ * Compat with the react-native-calendars screen's `AgendaList` JSX, plus two things the library
6
+ * only pretended to do: real sticky headers and real pull-to-refresh.
7
+ */
8
+
9
+ import {
10
+ memo,
11
+ useCallback,
12
+ useImperativeHandle,
13
+ useLayoutEffect,
14
+ useMemo,
15
+ useRef,
16
+ useState,
17
+ } from 'react';
18
+ import { RefreshControl, StyleSheet, View, type LayoutChangeEvent } from 'react-native';
19
+ import Animated, {
20
+ scrollTo,
21
+ useAnimatedReaction,
22
+ useAnimatedRef,
23
+ useSharedValue,
24
+ type AnimatedRef,
25
+ type SharedValue,
26
+ } from 'react-native-reanimated';
27
+ import { runOnJS, scheduleOnUI } from 'react-native-worklets';
28
+ import { useKitTheme } from '../theme';
29
+ import { useCalendarContext } from '../core/CalendarContext';
30
+ import { clampIndex, dayIndexOf } from '../core/dateKey';
31
+ import { bsearchLE } from '../core/worklets';
32
+ import type { AgendaListProps, DateString, MoveOrigin } from '../types';
33
+ import { AgendaBackdrop } from './AgendaBackdrop';
34
+ import { AgendaWindow } from './AgendaWindow';
35
+ import { buildAgendaLayout, type AgendaRowRef } from './buildAgendaLayout';
36
+ import { BUCKET_REST } from './constants';
37
+ import { StickyHeaderOverlay, type StickyInputs } from './StickyHeaderOverlay';
38
+ import { useAgendaScrollSync, type AgendaTables } from './useAgendaScrollSync';
39
+
40
+ const MY_ORIGIN: MoveOrigin = 'agenda';
41
+ const EMPTY_TABLES: AgendaTables = { offsets: [], sectionOffset: [], sectionStart: [], monthOfSection: [] };
42
+
43
+ const defaultGetItemType = (item: unknown): string =>
44
+ (item as { itemCustomHeightType?: string })?.itemCustomHeightType ?? 'Regular';
45
+
46
+ const defaultKeyExtractor = (item: unknown, index: number): string =>
47
+ (item as { id?: string })?.id ?? `row-${index}`;
48
+
49
+ /** Every scroll this list issues goes through here; see `programmaticY` in the sync. */
50
+ const scrollListTo = (
51
+ ref: AnimatedRef<Animated.ScrollView>,
52
+ programmaticY: SharedValue<number>,
53
+ moving: SharedValue<number>,
54
+ y: number,
55
+ animated: boolean,
56
+ ) => {
57
+ 'worklet';
58
+ moving.value = 0;
59
+ programmaticY.value = animated ? y : -1;
60
+ scrollTo(ref, 0, y, animated);
61
+ };
62
+
63
+ type Range = { first: number; last: number };
64
+ const AgendaListInner = <T,>({
65
+ sections,
66
+ renderItem,
67
+ renderSectionHeader,
68
+ itemHeightByType,
69
+ sectionHeaderHeight = 32,
70
+ getItemType = defaultGetItemType,
71
+ keyExtractor = defaultKeyExtractor,
72
+ stickySectionHeadersEnabled = false,
73
+ refreshing = false,
74
+ onRefresh,
75
+ decelerationRate = 0.985,
76
+ backdrop,
77
+ rowGroundColor,
78
+ ref,
79
+ onDragBegin,
80
+ onSettle,
81
+ }: AgendaListProps<T>) => {
82
+ const { colors } = useKitTheme();
83
+ const { range, store, dateRef, setDate, commitDate, reduceMotion } = useCalendarContext();
84
+ const listRef = useAnimatedRef<Animated.ScrollView>();
85
+
86
+ const headerIntern = useRef(new Map<DateString, Extract<AgendaRowRef<T>, { kind: 'header' }>>());
87
+ const heightForType = useCallback(
88
+ (type: string) => itemHeightByType[type] ?? itemHeightByType.Regular ?? 0,
89
+ [itemHeightByType],
90
+ );
91
+ const layout = useMemo(
92
+ () =>
93
+ buildAgendaLayout<T>({
94
+ sections,
95
+ sectionHeaderHeight,
96
+ heightForType,
97
+ getItemType,
98
+ keyExtractor,
99
+ headerIntern: headerIntern.current,
100
+ }),
101
+ [sections, sectionHeaderHeight, heightForType, getItemType, keyExtractor],
102
+ );
103
+ const layoutRef = useRef(layout);
104
+ layoutRef.current = layout;
105
+
106
+ const tablesSV = useSharedValue<AgendaTables>(EMPTY_TABLES);
107
+ const viewportSV = useSharedValue(0);
108
+
109
+ // Mount at the committed day with zero scroll: `contentOffset` is honoured on
110
+ // the first frame (M0), and the first window already holds its rows.
111
+ const [initialSection] = useState(() => clampIndex(range, dayIndexOf(range, dateRef.current)));
112
+ const [initialOffset] = useState(() => layout.sectionOffset[initialSection] ?? 0);
113
+ const [contentOffset] = useState(() => ({ x: 0, y: initialOffset }));
114
+ const [windowRange, setWindowRange] = useState<Range>(() => {
115
+ const row = layout.sectionStart[initialSection] ?? 0;
116
+ return { first: Math.max(0, row - BUCKET_REST), last: row + 4 * BUCKET_REST };
117
+ });
118
+ const [fastMotion, setFastMotion] = useState(false);
119
+
120
+ /**
121
+ * A long programmatic move lands on rows that are not mounted. The destination
122
+ * slice mounts first, beside the current rows; the jump happens once it exists
123
+ * and the slice is released by the next window update. No skeleton frames.
124
+ */
125
+ const [jumpRange, setJumpRange] = useState<Range | null>(null);
126
+ const pendingJumpY = useRef<number | null>(null);
127
+ const releaseJump = useRef(false);
128
+
129
+ const onWindowChange = useCallback((first: number, last: number) => {
130
+ setWindowRange((was) => (was.first === first && was.last === last ? was : { first, last }));
131
+ if (releaseJump.current) {
132
+ releaseJump.current = false;
133
+ setJumpRange(null);
134
+ }
135
+ }, []);
136
+
137
+ const onCommitDate = useCallback(
138
+ (idx: number) => commitDate(idx, 'listDrag', MY_ORIGIN),
139
+ [commitDate],
140
+ );
141
+
142
+ const { scrollY, currentSection, moving, fast, programmaticY, windowFirst, windowLast, scrollHandler, applyOffset } =
143
+ useAgendaScrollSync({
144
+ tablesSV,
145
+ viewportSV,
146
+ headerHeight: sectionHeaderHeight,
147
+ dayIndex: store.dayIndex,
148
+ listDragSeq: store.listDragSeq,
149
+ onWindowChange,
150
+ onCommitDate,
151
+ onFastChange: setFastMotion,
152
+ onDragBegin,
153
+ onSettle,
154
+ });
155
+
156
+ /**
157
+ * Publish the tables; if the content changed under a laid-out list, keep the
158
+ * doctor's day in place — the current section plus how far into it we were —
159
+ * in the same commit that resizes the content.
160
+ *
161
+ * The anchor is computed ON the UI thread, which owns `scrollY` and
162
+ * `currentSection`: read from JS they can predate a queued re-anchor or
163
+ * `onLayout`'s seeding, and a rebuild landing in that gap kept the wrong offset.
164
+ */
165
+ const prevSectionOffset = useRef<readonly number[] | null>(null);
166
+ useLayoutEffect(() => {
167
+ const prev = prevSectionOffset.current;
168
+ const next = layout.sectionOffset;
169
+ prevSectionOffset.current = next;
170
+ tablesSV.value = {
171
+ offsets: layout.offsets,
172
+ sectionOffset: layout.sectionOffset,
173
+ sectionStart: layout.sectionStart,
174
+ monthOfSection: layout.monthOfSection,
175
+ };
176
+ if (prev === null || (prev.length === next.length && prev.every((v, i) => v === next[i]))) return;
177
+ scheduleOnUI(() => {
178
+ 'worklet';
179
+ // No viewport yet means no position to keep: `onLayout` anchors on the day.
180
+ if (viewportSV.value === 0) return;
181
+ const s = currentSection.value;
182
+ const from = prev[s];
183
+ const to = next[s];
184
+ if (from === undefined || to === undefined) return;
185
+ const y = to + (scrollY.value - from);
186
+ if (Math.abs(y - scrollY.value) <= 1) return;
187
+ scrollListTo(listRef, programmaticY, moving, y, false);
188
+ // Owned now: the next rebuild may be queued before this scroll's event arrives.
189
+ scrollY.value = y;
190
+ });
191
+ }, [currentSection, layout, listRef, moving, programmaticY, scrollY, tablesSV, viewportSV]);
192
+
193
+ const prepareJump = useCallback(
194
+ (y: number) => {
195
+ const H = viewportSV.value || 800;
196
+ const { offsets, rows } = layoutRef.current;
197
+ pendingJumpY.current = y;
198
+ setJumpRange({
199
+ first: bsearchLE(offsets, y - 0.5 * H) & -BUCKET_REST,
200
+ last: Math.min(rows.length - 1, bsearchLE(offsets, y + 2 * H) | (BUCKET_REST - 1)),
201
+ });
202
+ },
203
+ [viewportSV],
204
+ );
205
+
206
+ // Moves from other surfaces. Our own are ignored: that is the echo-proofing.
207
+ useAnimatedReaction(
208
+ () => store.move.value,
209
+ (m, prev) => {
210
+ if (!prev || m.seq === prev.seq || m.origin === MY_ORIGIN || viewportSV.value === 0) return;
211
+ const { offsets, sectionOffset } = tablesSV.value;
212
+ const y = sectionOffset[m.idx];
213
+ if (y === undefined) return;
214
+ const top = offsets[windowFirst.value] ?? 0;
215
+ const bottom = offsets[windowLast.value + 1] ?? offsets[offsets.length - 1] ?? 0;
216
+ if (y >= top && y + viewportSV.value <= bottom) scrollListTo(listRef, programmaticY, moving, y, m.animated);
217
+ else runOnJS(prepareJump)(y);
218
+ },
219
+ [prepareJump],
220
+ );
221
+
222
+ useLayoutEffect(() => {
223
+ const y = pendingJumpY.current;
224
+ if (jumpRange === null || y === null) return;
225
+ pendingJumpY.current = null;
226
+ releaseJump.current = true;
227
+ scheduleOnUI(() => {
228
+ 'worklet';
229
+ scrollListTo(listRef, programmaticY, moving, y, false);
230
+ });
231
+ }, [jumpRange, listRef, moving, programmaticY]);
232
+
233
+ const scrollToY = useCallback(
234
+ (y: number, animated: boolean) => {
235
+ const anim = animated && !reduceMotion;
236
+ scheduleOnUI(() => {
237
+ 'worklet';
238
+ if (viewportSV.value > 0) scrollListTo(listRef, programmaticY, moving, y, anim);
239
+ });
240
+ },
241
+ [listRef, moving, programmaticY, reduceMotion, viewportSV],
242
+ );
243
+
244
+ useImperativeHandle(
245
+ ref,
246
+ () => ({
247
+ // Dates outside the window are dropped by design: the section list is a
248
+ // pure function of the window and must not grow.
249
+ scrollToDate: (date: DateString, animated = true) => {
250
+ const idx = layout.sectionByTitle.get(date);
251
+ if (idx === undefined) return;
252
+ setDate(date, 'propUpdate', MY_ORIGIN, animated);
253
+ scrollToY(layout.sectionOffset[idx], animated);
254
+ },
255
+ scrollToSection: (title: DateString, animated = true) => {
256
+ const idx = layout.sectionByTitle.get(title);
257
+ if (idx !== undefined) scrollToY(layout.sectionOffset[idx], animated);
258
+ },
259
+ scrollToOffset: ({ offset, animated = true }) => scrollToY(offset, animated),
260
+ }),
261
+ [layout, scrollToY, setDate],
262
+ );
263
+
264
+ const laidOut = useRef(false);
265
+ const onLayout = useCallback(
266
+ (e: LayoutChangeEvent) => {
267
+ viewportSV.value = e.nativeEvent.layout.height;
268
+ if (laidOut.current) return;
269
+ laidOut.current = true;
270
+ const fallback = initialOffset;
271
+ scheduleOnUI(() => {
272
+ 'worklet';
273
+ // Anchor on the committed DAY in the tables as they are now, not on the
274
+ // first render's pixel offset: rows that change between mount and first
275
+ // layout (shimmer → data) move that day, and the re-anchor above cannot
276
+ // act without a viewport. The list opened on the right pixel of the wrong
277
+ // day — 238 px early on the fixture (2026-09-11). Also covers a device
278
+ // that ignores `contentOffset` on mount.
279
+ const target = tablesSV.value.sectionOffset[store.dayIndex.value] ?? fallback;
280
+ if (Math.abs(scrollY.value - target) > 1) scrollListTo(listRef, programmaticY, moving, target, false);
281
+ // No scroll event follows when the native offset already matches.
282
+ scrollY.value = target;
283
+ applyOffset(target, 0);
284
+ });
285
+ },
286
+ [applyOffset, initialOffset, listRef, moving, programmaticY, scrollY, store, tablesSV, viewportSV],
287
+ );
288
+
289
+ const refreshControl = useMemo(
290
+ () =>
291
+ onRefresh ? (
292
+ <RefreshControl
293
+ refreshing={refreshing}
294
+ onRefresh={onRefresh}
295
+ tintColor={colors.accent}
296
+ colors={[colors.accent]}
297
+ progressBackgroundColor={colors.surface}
298
+ />
299
+ ) : undefined,
300
+ [colors.accent, colors.surface, onRefresh, refreshing],
301
+ );
302
+
303
+ const contentStyle = useMemo(() => ({ height: layout.totalHeight }), [layout.totalHeight]);
304
+ const sticky = useMemo<StickyInputs>(
305
+ () => ({ scrollY, currentSection, fast, tablesSV }),
306
+ [currentSection, fast, scrollY, tablesSV],
307
+ );
308
+ const titleAt = useCallback((s: number): DateString | undefined => {
309
+ const { rows, sectionStart } = layoutRef.current;
310
+ const row = rows[sectionStart[s]];
311
+ return row?.kind === 'header' ? row.title : undefined;
312
+ }, []);
313
+
314
+ return (
315
+ <View style={styles.host}>
316
+ {backdrop ? (
317
+ <AgendaBackdrop scrollY={scrollY} tileHeight={backdrop.tileHeight} renderTile={backdrop.renderTile} />
318
+ ) : null}
319
+ <Animated.ScrollView
320
+ ref={listRef}
321
+ onLayout={onLayout}
322
+ onScroll={scrollHandler}
323
+ scrollEventThrottle={16}
324
+ contentOffset={contentOffset}
325
+ decelerationRate={decelerationRate}
326
+ refreshControl={refreshControl}
327
+ removeClippedSubviews
328
+ >
329
+ <View style={contentStyle}>
330
+ <AgendaWindow
331
+ layout={layout}
332
+ first={windowRange.first}
333
+ last={windowRange.last}
334
+ extraFirst={jumpRange?.first}
335
+ extraLast={jumpRange?.last}
336
+ renderItem={renderItem}
337
+ renderSectionHeader={renderSectionHeader}
338
+ sections={sections}
339
+ getItemType={getItemType}
340
+ fastMotion={fastMotion}
341
+ deferRows={backdrop !== undefined}
342
+ groundColor={rowGroundColor}
343
+ scrollY={scrollY}
344
+ viewportSV={viewportSV}
345
+ />
346
+ </View>
347
+ </Animated.ScrollView>
348
+ {stickySectionHeadersEnabled ? (
349
+ <StickyHeaderOverlay
350
+ initialSection={initialSection}
351
+ sectionCount={sections.length}
352
+ titleAt={titleAt}
353
+ height={sectionHeaderHeight}
354
+ sticky={sticky}
355
+ renderSectionHeader={renderSectionHeader}
356
+ />
357
+ ) : null}
358
+ </View>
359
+ );
360
+ };
361
+
362
+ export const AgendaList = memo(AgendaListInner) as typeof AgendaListInner;
363
+
364
+ const styles = StyleSheet.create({
365
+ // Clips at the list's own top edge. The sticky overlay's push-up translates its
366
+ // host — clip and all — out of the list, and the calendar sits right above: an
367
+ // unclipped host drew the outgoing header over the calendar's knob at every day
368
+ // crossing, so the knob and its gap flickered (2026-09-11).
369
+ host: { flex: 1, overflow: 'hidden' },
370
+ });
@@ -0,0 +1,88 @@
1
+ /**
2
+ * One row or header, parked at its declared offset.
3
+ *
4
+ * Slots take the row's DATA plus a stable render function, never `children`: a
5
+ * child element is a new object every parent render, so `memo` would never bail
6
+ * out and every window commit would re-render every mounted row (M1: p90 69 ms).
7
+ *
8
+ * `overflow: 'hidden'` is the safety mechanism: a row taller than its declaration
9
+ * is clipped in place instead of shifting every offset below it, and the DEV
10
+ * drift check (`heights.ts`) makes the wrong number loud.
11
+ */
12
+
13
+ import { memo, useMemo, type ReactElement } from 'react';
14
+ import { StyleSheet, View, type LayoutChangeEvent } from 'react-native';
15
+ import { needsMeasure, reportHeight } from './heights';
16
+ import type { AgendaSection, DateString } from '../types';
17
+
18
+ type ItemSlotProps<T> = {
19
+ top: number;
20
+ height: number;
21
+ /** Row type — the drift check's key. */
22
+ type: string;
23
+ item: T;
24
+ index: number;
25
+ section: AgendaSection<T>;
26
+ renderItem: (info: { item: T; index: number; section: AgendaSection<T> }) => ReactElement | null;
27
+ /**
28
+ * Draw nothing: the backdrop shows through. A prop on the same component, never a
29
+ * different component — changing the element type under a key remounts the row.
30
+ */
31
+ deferred: boolean;
32
+ groundColor?: string;
33
+ };
34
+
35
+ const AgendaItemSlotInner = <T,>({
36
+ top,
37
+ height,
38
+ type,
39
+ item,
40
+ index,
41
+ section,
42
+ renderItem,
43
+ deferred,
44
+ groundColor,
45
+ }: ItemSlotProps<T>) => {
46
+ const style = useMemo(
47
+ () => [styles.slot, { top, height, backgroundColor: deferred ? undefined : groundColor }],
48
+ [deferred, groundColor, height, top],
49
+ );
50
+ if (deferred) return null;
51
+
52
+ const content = renderItem({ item, index, section });
53
+ if (__DEV__ && needsMeasure(type, height)) {
54
+ // Measure the CHILD: the slot is `height` by construction.
55
+ const onLayout = (e: LayoutChangeEvent) => reportHeight(type, height, e.nativeEvent.layout.height);
56
+ return (
57
+ <View style={style}>
58
+ <View onLayout={onLayout}>{content}</View>
59
+ </View>
60
+ );
61
+ }
62
+ return <View style={style}>{content}</View>;
63
+ };
64
+
65
+ export const AgendaItemSlot = memo(AgendaItemSlotInner) as typeof AgendaItemSlotInner;
66
+
67
+ type HeaderSlotProps = {
68
+ top: number;
69
+ height: number;
70
+ title: DateString;
71
+ renderSectionHeader: (title: DateString) => ReactElement | null;
72
+ groundColor?: string;
73
+ };
74
+
75
+ export const AgendaHeaderSlot = memo(
76
+ ({ top, height, title, renderSectionHeader, groundColor }: HeaderSlotProps) => {
77
+ const style = useMemo(
78
+ () => [styles.slot, { top, height, backgroundColor: groundColor }],
79
+ [groundColor, height, top],
80
+ );
81
+ return <View style={style}>{renderSectionHeader(title)}</View>;
82
+ },
83
+ );
84
+ AgendaHeaderSlot.displayName = 'AgendaHeaderSlot';
85
+
86
+ const styles = StyleSheet.create({
87
+ slot: { position: 'absolute', left: 0, right: 0, overflow: 'hidden' },
88
+ });
@@ -0,0 +1,183 @@
1
+ /**
2
+ * The mounted slice of the list, keyed by row.
3
+ *
4
+ * DO NOT RECYCLE. A slot pool was built twice and measured worse on the device
5
+ * (p99 300 → 1000–1550 ms): keyed by row, a row that stays in the window has
6
+ * identical props and `memo` makes it free; a pool hands slots new rows and forces
7
+ * a full prop diff across every card.
8
+ *
9
+ * DO NOT KEEP ROWS MOUNTED "to avoid recreating them". Measured in release on the
10
+ * SM-F415F (2026-09-11): a grow-only window doubled the mounted views and took slow
11
+ * draw frames from ~180 to ~900 per 12 flings (p50 27 → 37 ms); pre-mounting the
12
+ * whole range (5,000 views, +130 MB) put every frame above 60 ms. Every mounted row
13
+ * costs frame time, on screen or not — the window stays tight.
14
+ *
15
+ * Deferral (only with a backdrop): a row ENTERING the window while the list is
16
+ * fast renders nothing and the backdrop shows through; a row already drawn stays
17
+ * drawn. When fast motion ends, deferred rows are released nearest the viewport
18
+ * first — every visible row in one batch, then a batch per frame — as transitions,
19
+ * so a new drag's window commit never waits behind them.
20
+ */
21
+
22
+ import { memo, startTransition, useEffect, useLayoutEffect, useRef, useState, type ReactElement } from 'react';
23
+ import type { SharedValue } from 'react-native-reanimated';
24
+ import { bsearchLE } from '../core/worklets';
25
+ import type { AgendaSection, DateString } from '../types';
26
+ import { AgendaHeaderSlot, AgendaItemSlot } from './AgendaSlot';
27
+ import type { AgendaLayout } from './buildAgendaLayout';
28
+ import { UPGRADE_BATCH } from './constants';
29
+
30
+ const NO_KEYS: ReadonlySet<string> = new Set();
31
+
32
+ type Props<T> = {
33
+ layout: AgendaLayout<T>;
34
+ first: number;
35
+ last: number;
36
+ /** A second slice mounted while a long programmatic jump is pending — its rows exist before the list moves. */
37
+ extraFirst?: number;
38
+ extraLast?: number;
39
+ renderItem: (info: { item: T; index: number; section: AgendaSection<T> }) => ReactElement | null;
40
+ renderSectionHeader: (title: DateString) => ReactElement | null;
41
+ sections: AgendaSection<T>[];
42
+ getItemType: (item: T) => string;
43
+ fastMotion: boolean;
44
+ deferRows: boolean;
45
+ groundColor?: string;
46
+ scrollY: SharedValue<number>;
47
+ viewportSV: SharedValue<number>;
48
+ };
49
+
50
+ const AgendaWindowInner = <T,>({
51
+ layout,
52
+ first,
53
+ last,
54
+ extraFirst,
55
+ extraLast,
56
+ renderItem,
57
+ renderSectionHeader,
58
+ sections,
59
+ getItemType,
60
+ fastMotion,
61
+ deferRows,
62
+ groundColor,
63
+ scrollY,
64
+ viewportSV,
65
+ }: Props<T>) => {
66
+ const { rows, offsets, heights } = layout;
67
+ const start = Math.max(0, first);
68
+ const end = Math.min(last, rows.length - 1);
69
+
70
+ /** Rows deferred in the last commit, and the window that commit drew. */
71
+ const heldRef = useRef<ReadonlySet<string>>(NO_KEYS);
72
+ const drawnRef = useRef({ layout, start: 0, end: -1 });
73
+ const [released, setReleased] = useState<ReadonlySet<string>>(NO_KEYS);
74
+
75
+ const prev = drawnRef.current;
76
+ const sameLayout = prev.layout === layout;
77
+ const held = heldRef.current;
78
+ let nextHeld: Set<string> | null = null;
79
+ const slots: ReactElement[] = [];
80
+
81
+ const pushRow = (i: number) => {
82
+ const row = rows[i];
83
+ if (row.kind === 'header') {
84
+ slots.push(
85
+ <AgendaHeaderSlot
86
+ key={row.key}
87
+ top={offsets[i]}
88
+ // The layout's pixel-snapped height, not the declared constant: with the
89
+ // constant, a header ending a fraction short of the next row's top left a
90
+ // hairline of backdrop between them.
91
+ height={heights[i]}
92
+ title={row.title}
93
+ renderSectionHeader={renderSectionHeader}
94
+ groundColor={groundColor}
95
+ />,
96
+ );
97
+ return;
98
+ }
99
+ let deferred = false;
100
+ if (deferRows) {
101
+ deferred = held.has(row.key)
102
+ ? fastMotion || !released.has(row.key)
103
+ : fastMotion && !(sameLayout && i >= prev.start && i <= prev.end);
104
+ if (deferred) (nextHeld ??= new Set()).add(row.key);
105
+ }
106
+ slots.push(
107
+ <AgendaItemSlot
108
+ key={row.key}
109
+ top={offsets[i]}
110
+ height={heights[i]}
111
+ type={getItemType(row.item)}
112
+ item={row.item}
113
+ index={row.indexInSection}
114
+ section={sections[row.section]}
115
+ renderItem={renderItem}
116
+ deferred={deferred}
117
+ groundColor={groundColor}
118
+ />,
119
+ );
120
+ };
121
+
122
+ for (let i = start; i <= end; i += 1) pushRow(i);
123
+ if (extraFirst !== undefined && extraLast !== undefined) {
124
+ const xEnd = Math.min(extraLast, rows.length - 1);
125
+ for (let i = Math.max(0, extraFirst); i <= xEnd; i += 1) {
126
+ if (i < start || i > end) pushRow(i);
127
+ }
128
+ }
129
+
130
+ const heldNow: ReadonlySet<string> = nextHeld ?? NO_KEYS;
131
+ // Committed in a layout effect, so a render React discards cannot leave the
132
+ // refs describing rows that never mounted.
133
+ useLayoutEffect(() => {
134
+ heldRef.current = heldNow;
135
+ drawnRef.current = { layout, start, end };
136
+ });
137
+
138
+ const hasHeld = heldNow.size > 0;
139
+ useEffect(() => {
140
+ if (fastMotion || !hasHeld) return;
141
+ const { layout: l, start: s, end: e } = drawnRef.current;
142
+ const y = scrollY.value;
143
+ const top = bsearchLE(l.offsets, y);
144
+ const bottom = bsearchLE(l.offsets, y + viewportSV.value);
145
+ const focus = (top + bottom) >> 1;
146
+
147
+ // Sorted ONCE; each frame then only pops a batch.
148
+ const queue: string[] = [];
149
+ const distance: number[] = [];
150
+ let visible = 0;
151
+ for (let i = s; i <= e; i += 1) {
152
+ const row = l.rows[i];
153
+ if (row.kind !== 'item' || !heldRef.current.has(row.key)) continue;
154
+ queue.push(row.key);
155
+ distance.push(Math.abs(i - focus));
156
+ if (i >= top && i <= bottom) visible += 1;
157
+ }
158
+ const order = queue.map((_, k) => k).sort((a, b) => distance[a] - distance[b]);
159
+
160
+ let cursor = 0;
161
+ let frame = 0;
162
+ const releaseNext = () => {
163
+ const n = cursor === 0 ? Math.max(UPGRADE_BATCH, visible) : UPGRADE_BATCH;
164
+ const batch = order.slice(cursor, cursor + n).map((k) => queue[k]);
165
+ const isFirst = cursor === 0;
166
+ cursor += n;
167
+ startTransition(() => {
168
+ setReleased((was) => {
169
+ const next = new Set(isFirst ? NO_KEYS : was);
170
+ for (const key of batch) next.add(key);
171
+ return next;
172
+ });
173
+ });
174
+ if (cursor < order.length) frame = requestAnimationFrame(releaseNext);
175
+ };
176
+ frame = requestAnimationFrame(releaseNext);
177
+ return () => cancelAnimationFrame(frame);
178
+ }, [fastMotion, hasHeld, scrollY, viewportSV]);
179
+
180
+ return <>{slots}</>;
181
+ };
182
+
183
+ export const AgendaWindow = memo(AgendaWindowInner) as typeof AgendaWindowInner;