@robertlinde/react-tour-kit 0.8.8 → 1.0.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 (368) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/MIGRATION.md +205 -0
  3. package/README.md +401 -850
  4. package/dist/react-native-platform/hooks/use-tour-scroll-view.hook.d.ts +14 -0
  5. package/dist/react-native-platform/hooks/use-tour-scroll-view.hook.d.ts.map +1 -0
  6. package/dist/react-native-platform/hooks/use-tour-scroll-view.hook.js +21 -0
  7. package/dist/react-native-platform/hooks/use-tour-scroll-view.hook.js.map +1 -0
  8. package/dist/react-native-platform/hooks/use-tour-target.hook.d.ts +15 -0
  9. package/dist/react-native-platform/hooks/use-tour-target.hook.d.ts.map +1 -0
  10. package/dist/react-native-platform/hooks/use-tour-target.hook.js +28 -0
  11. package/dist/react-native-platform/hooks/use-tour-target.hook.js.map +1 -0
  12. package/dist/react-native-platform/host-store.d.ts +24 -0
  13. package/dist/react-native-platform/host-store.d.ts.map +1 -0
  14. package/dist/react-native-platform/host-store.js +63 -0
  15. package/dist/react-native-platform/host-store.js.map +1 -0
  16. package/dist/react-native-platform/insets.util.d.ts +11 -0
  17. package/dist/react-native-platform/insets.util.d.ts.map +1 -0
  18. package/dist/react-native-platform/insets.util.js +31 -0
  19. package/dist/react-native-platform/insets.util.js.map +1 -0
  20. package/dist/react-native-platform/layer/native-renderer.d.ts +7 -0
  21. package/dist/react-native-platform/layer/native-renderer.d.ts.map +1 -0
  22. package/dist/react-native-platform/layer/native-renderer.js +496 -0
  23. package/dist/react-native-platform/layer/native-renderer.js.map +1 -0
  24. package/dist/react-native-platform/layer/tour-host.d.ts +13 -0
  25. package/dist/react-native-platform/layer/tour-host.d.ts.map +1 -0
  26. package/dist/react-native-platform/layer/tour-host.js +70 -0
  27. package/dist/react-native-platform/layer/tour-host.js.map +1 -0
  28. package/dist/react-native-platform/measure.util.d.ts +20 -0
  29. package/dist/react-native-platform/measure.util.d.ts.map +1 -0
  30. package/dist/react-native-platform/measure.util.js +100 -0
  31. package/dist/react-native-platform/measure.util.js.map +1 -0
  32. package/dist/react-native-platform/native-context.d.ts +12 -0
  33. package/dist/react-native-platform/native-context.d.ts.map +1 -0
  34. package/dist/react-native-platform/native-context.js +4 -0
  35. package/dist/react-native-platform/native-context.js.map +1 -0
  36. package/dist/react-native-platform/native-environment.d.ts +14 -0
  37. package/dist/react-native-platform/native-environment.d.ts.map +1 -0
  38. package/dist/react-native-platform/native-environment.js +20 -0
  39. package/dist/react-native-platform/native-environment.js.map +1 -0
  40. package/dist/react-native-platform/native-platform.d.ts +19 -0
  41. package/dist/react-native-platform/native-platform.d.ts.map +1 -0
  42. package/dist/react-native-platform/native-platform.js +265 -0
  43. package/dist/react-native-platform/native-platform.js.map +1 -0
  44. package/dist/react-native-platform/reduced-motion.d.ts +4 -0
  45. package/dist/react-native-platform/reduced-motion.d.ts.map +1 -0
  46. package/dist/react-native-platform/reduced-motion.js +44 -0
  47. package/dist/react-native-platform/reduced-motion.js.map +1 -0
  48. package/dist/react-native-platform/registry.d.ts +18 -0
  49. package/dist/react-native-platform/registry.d.ts.map +1 -0
  50. package/dist/react-native-platform/registry.js +51 -0
  51. package/dist/react-native-platform/registry.js.map +1 -0
  52. package/dist/react-native-platform/tour-provider.d.ts +16 -3
  53. package/dist/react-native-platform/tour-provider.d.ts.map +1 -0
  54. package/dist/react-native-platform/tour-provider.js +92 -211
  55. package/dist/react-native-platform/tour-provider.js.map +1 -1
  56. package/dist/react-native.d.ts +14 -8
  57. package/dist/react-native.d.ts.map +1 -0
  58. package/dist/react-native.js +7 -6
  59. package/dist/react-native.js.map +1 -1
  60. package/dist/react-platform/dom/elements.util.d.ts +35 -0
  61. package/dist/react-platform/dom/elements.util.d.ts.map +1 -0
  62. package/dist/react-platform/dom/elements.util.js +155 -0
  63. package/dist/react-platform/dom/elements.util.js.map +1 -0
  64. package/dist/react-platform/dom/occluders.util.d.ts +13 -0
  65. package/dist/react-platform/dom/occluders.util.d.ts.map +1 -0
  66. package/dist/react-platform/dom/occluders.util.js +75 -0
  67. package/dist/react-platform/dom/occluders.util.js.map +1 -0
  68. package/dist/react-platform/dom/scroll-lock.util.d.ts +13 -0
  69. package/dist/react-platform/dom/scroll-lock.util.d.ts.map +1 -0
  70. package/dist/react-platform/dom/scroll-lock.util.js +219 -0
  71. package/dist/react-platform/dom/scroll-lock.util.js.map +1 -0
  72. package/dist/react-platform/dom/scroll.util.d.ts +44 -0
  73. package/dist/react-platform/dom/scroll.util.d.ts.map +1 -0
  74. package/dist/react-platform/dom/scroll.util.js +250 -0
  75. package/dist/react-platform/dom/scroll.util.js.map +1 -0
  76. package/dist/react-platform/dom/viewport.util.d.ts +16 -0
  77. package/dist/react-platform/dom/viewport.util.d.ts.map +1 -0
  78. package/dist/react-platform/dom/viewport.util.js +65 -0
  79. package/dist/react-platform/dom/viewport.util.js.map +1 -0
  80. package/dist/react-platform/dom/web-platform.d.ts +15 -0
  81. package/dist/react-platform/dom/web-platform.d.ts.map +1 -0
  82. package/dist/react-platform/dom/web-platform.js +169 -0
  83. package/dist/react-platform/dom/web-platform.js.map +1 -0
  84. package/dist/react-platform/layer/styles.d.ts +12 -0
  85. package/dist/react-platform/layer/styles.d.ts.map +1 -0
  86. package/dist/react-platform/layer/styles.js +285 -0
  87. package/dist/react-platform/layer/styles.js.map +1 -0
  88. package/dist/react-platform/layer/web-renderer.d.ts +4 -0
  89. package/dist/react-platform/layer/web-renderer.d.ts.map +1 -0
  90. package/dist/react-platform/layer/web-renderer.js +390 -0
  91. package/dist/react-platform/layer/web-renderer.js.map +1 -0
  92. package/dist/react-platform/tour-provider.d.ts +9 -3
  93. package/dist/react-platform/tour-provider.d.ts.map +1 -0
  94. package/dist/react-platform/tour-provider.js +28 -218
  95. package/dist/react-platform/tour-provider.js.map +1 -1
  96. package/dist/react.d.ts +10 -8
  97. package/dist/react.d.ts.map +1 -0
  98. package/dist/react.js +5 -6
  99. package/dist/react.js.map +1 -1
  100. package/dist/shared/engine/abort.util.d.ts +17 -0
  101. package/dist/shared/engine/abort.util.d.ts.map +1 -0
  102. package/dist/shared/engine/abort.util.js +72 -0
  103. package/dist/shared/engine/abort.util.js.map +1 -0
  104. package/dist/shared/engine/report.util.d.ts +12 -0
  105. package/dist/shared/engine/report.util.d.ts.map +1 -0
  106. package/dist/shared/engine/report.util.js +51 -0
  107. package/dist/shared/engine/report.util.js.map +1 -0
  108. package/dist/shared/engine/tour-adapter.type.d.ts +60 -0
  109. package/dist/shared/engine/tour-adapter.type.d.ts.map +1 -0
  110. package/dist/shared/engine/tour-adapter.type.js +2 -0
  111. package/dist/shared/engine/tour-adapter.type.js.map +1 -0
  112. package/dist/shared/engine/tour-engine.d.ts +92 -0
  113. package/dist/shared/engine/tour-engine.d.ts.map +1 -0
  114. package/dist/shared/engine/tour-engine.js +787 -0
  115. package/dist/shared/engine/tour-engine.js.map +1 -0
  116. package/dist/shared/geometry/box.util.d.ts +39 -0
  117. package/dist/shared/geometry/box.util.d.ts.map +1 -0
  118. package/dist/shared/geometry/box.util.js +146 -0
  119. package/dist/shared/geometry/box.util.js.map +1 -0
  120. package/dist/shared/geometry/compute-tooltip-layout.util.d.ts +60 -0
  121. package/dist/shared/geometry/compute-tooltip-layout.util.d.ts.map +1 -0
  122. package/dist/shared/geometry/compute-tooltip-layout.util.js +148 -0
  123. package/dist/shared/geometry/compute-tooltip-layout.util.js.map +1 -0
  124. package/dist/shared/geometry/geometry.type.d.ts +34 -0
  125. package/dist/shared/geometry/geometry.type.d.ts.map +1 -0
  126. package/dist/shared/geometry/geometry.type.js +2 -0
  127. package/dist/shared/geometry/geometry.type.js.map +1 -0
  128. package/dist/shared/geometry/reveal.util.d.ts +38 -0
  129. package/dist/shared/geometry/reveal.util.d.ts.map +1 -0
  130. package/dist/shared/geometry/reveal.util.js +135 -0
  131. package/dist/shared/geometry/reveal.util.js.map +1 -0
  132. package/dist/shared/geometry/target-visibility.util.d.ts +10 -0
  133. package/dist/shared/geometry/target-visibility.util.d.ts.map +1 -0
  134. package/dist/shared/geometry/target-visibility.util.js +29 -0
  135. package/dist/shared/geometry/target-visibility.util.js.map +1 -0
  136. package/dist/shared/platform/create-tour-adapter.d.ts +9 -0
  137. package/dist/shared/platform/create-tour-adapter.d.ts.map +1 -0
  138. package/dist/shared/platform/create-tour-adapter.js +130 -0
  139. package/dist/shared/platform/create-tour-adapter.js.map +1 -0
  140. package/dist/shared/platform/platform.type.d.ts +77 -0
  141. package/dist/shared/platform/platform.type.d.ts.map +1 -0
  142. package/dist/shared/platform/platform.type.js +2 -0
  143. package/dist/shared/platform/platform.type.js.map +1 -0
  144. package/dist/shared/platform/reveal-in-scroll-containers.d.ts +27 -0
  145. package/dist/shared/platform/reveal-in-scroll-containers.d.ts.map +1 -0
  146. package/dist/shared/platform/reveal-in-scroll-containers.js +49 -0
  147. package/dist/shared/platform/reveal-in-scroll-containers.js.map +1 -0
  148. package/dist/shared/react/tour-context.d.ts +7 -0
  149. package/dist/shared/react/tour-context.d.ts.map +1 -0
  150. package/dist/shared/react/tour-context.js +23 -0
  151. package/dist/shared/react/tour-context.js.map +1 -0
  152. package/dist/shared/react/tour-provider-core.d.ts +41 -0
  153. package/dist/shared/react/tour-provider-core.d.ts.map +1 -0
  154. package/dist/shared/react/tour-provider-core.js +24 -0
  155. package/dist/shared/react/tour-provider-core.js.map +1 -0
  156. package/dist/shared/react/tour-root.d.ts +14 -0
  157. package/dist/shared/react/tour-root.d.ts.map +1 -0
  158. package/dist/shared/react/tour-root.js +22 -0
  159. package/dist/shared/react/tour-root.js.map +1 -0
  160. package/dist/shared/react/use-isomorphic-layout-effect.hook.d.ts +4 -0
  161. package/dist/shared/react/use-isomorphic-layout-effect.hook.d.ts.map +1 -0
  162. package/dist/shared/react/use-isomorphic-layout-effect.hook.js +5 -0
  163. package/dist/shared/react/use-isomorphic-layout-effect.hook.js.map +1 -0
  164. package/dist/shared/react/use-tour-view.hook.d.ts +5 -0
  165. package/dist/shared/react/use-tour-view.hook.d.ts.map +1 -0
  166. package/dist/shared/react/use-tour-view.hook.js +14 -0
  167. package/dist/shared/react/use-tour-view.hook.js.map +1 -0
  168. package/dist/shared/react/use-tour.hook.d.ts +7 -0
  169. package/dist/shared/react/use-tour.hook.d.ts.map +1 -0
  170. package/dist/shared/react/use-tour.hook.js +10 -0
  171. package/dist/shared/react/use-tour.hook.js.map +1 -0
  172. package/dist/shared/renderer/default-tooltip.d.ts +5 -0
  173. package/dist/shared/renderer/default-tooltip.d.ts.map +1 -0
  174. package/dist/shared/renderer/default-tooltip.js +13 -0
  175. package/dist/shared/renderer/default-tooltip.js.map +1 -0
  176. package/dist/shared/renderer/motion.d.ts +29 -0
  177. package/dist/shared/renderer/motion.d.ts.map +1 -0
  178. package/dist/shared/renderer/motion.js +49 -0
  179. package/dist/shared/renderer/motion.js.map +1 -0
  180. package/dist/shared/renderer/renderer-context.d.ts +17 -0
  181. package/dist/shared/renderer/renderer-context.d.ts.map +1 -0
  182. package/dist/shared/renderer/renderer-context.js +16 -0
  183. package/dist/shared/renderer/renderer-context.js.map +1 -0
  184. package/dist/shared/renderer/renderer.type.d.ts +164 -0
  185. package/dist/shared/renderer/renderer.type.d.ts.map +1 -0
  186. package/dist/shared/renderer/renderer.type.js +2 -0
  187. package/dist/shared/renderer/renderer.type.js.map +1 -0
  188. package/dist/shared/renderer/tooltip-model.d.ts +32 -0
  189. package/dist/shared/renderer/tooltip-model.d.ts.map +1 -0
  190. package/dist/shared/renderer/tooltip-model.js +24 -0
  191. package/dist/shared/renderer/tooltip-model.js.map +1 -0
  192. package/dist/shared/renderer/tour-overlay.d.ts +24 -0
  193. package/dist/shared/renderer/tour-overlay.d.ts.map +1 -0
  194. package/dist/shared/renderer/tour-overlay.js +228 -0
  195. package/dist/shared/renderer/tour-overlay.js.map +1 -0
  196. package/dist/shared/types/tour-context.type.d.ts +21 -11
  197. package/dist/shared/types/tour-context.type.d.ts.map +1 -0
  198. package/dist/shared/types/tour-end-info.type.d.ts +19 -2
  199. package/dist/shared/types/tour-end-info.type.d.ts.map +1 -0
  200. package/dist/shared/types/tour-i18n.type.d.ts +8 -0
  201. package/dist/shared/types/tour-i18n.type.d.ts.map +1 -0
  202. package/dist/shared/types/tour-step.type.d.ts +35 -6
  203. package/dist/shared/types/tour-step.type.d.ts.map +1 -0
  204. package/dist/shared/types/tour-theme.type.d.ts +22 -2
  205. package/dist/shared/types/tour-theme.type.d.ts.map +1 -0
  206. package/dist/shared/types/tour-theme.type.js +1 -16
  207. package/dist/shared/types/tour-theme.type.js.map +1 -1
  208. package/dist/shared/types/tour-tooltip-props.type.d.ts +21 -17
  209. package/dist/shared/types/tour-tooltip-props.type.d.ts.map +1 -0
  210. package/dist/shared/utils/frame.util.d.ts +6 -0
  211. package/dist/shared/utils/frame.util.d.ts.map +1 -0
  212. package/dist/shared/utils/frame.util.js +20 -0
  213. package/dist/shared/utils/frame.util.js.map +1 -0
  214. package/dist/shared/utils/get-truncated-dots.util.d.ts +13 -7
  215. package/dist/shared/utils/get-truncated-dots.util.d.ts.map +1 -0
  216. package/dist/shared/utils/get-truncated-dots.util.js +30 -30
  217. package/dist/shared/utils/get-truncated-dots.util.js.map +1 -1
  218. package/dist/shared/utils/i18n.util.d.ts +7 -0
  219. package/dist/shared/utils/i18n.util.d.ts.map +1 -0
  220. package/dist/shared/utils/i18n.util.js +34 -0
  221. package/dist/shared/utils/i18n.util.js.map +1 -0
  222. package/dist/shared/utils/theme.util.d.ts +6 -0
  223. package/dist/shared/utils/theme.util.d.ts.map +1 -0
  224. package/dist/shared/utils/theme.util.js +31 -0
  225. package/dist/shared/utils/theme.util.js.map +1 -0
  226. package/package.json +72 -55
  227. package/src/react-native-platform/hooks/use-tour-scroll-view.hook.ts +24 -0
  228. package/src/react-native-platform/hooks/use-tour-target.hook.ts +30 -0
  229. package/src/react-native-platform/host-store.ts +92 -0
  230. package/src/react-native-platform/insets.util.ts +39 -0
  231. package/src/react-native-platform/layer/native-renderer.tsx +776 -0
  232. package/src/react-native-platform/layer/tour-host.tsx +105 -0
  233. package/src/react-native-platform/measure.util.ts +140 -0
  234. package/src/react-native-platform/native-context.ts +15 -0
  235. package/src/react-native-platform/native-environment.ts +33 -0
  236. package/src/react-native-platform/native-platform.ts +368 -0
  237. package/src/react-native-platform/reduced-motion.ts +47 -0
  238. package/src/react-native-platform/registry.ts +70 -0
  239. package/src/react-native-platform/tour-provider.tsx +148 -0
  240. package/src/react-native.ts +15 -0
  241. package/src/react-platform/dom/elements.util.ts +191 -0
  242. package/src/react-platform/dom/occluders.util.ts +88 -0
  243. package/src/react-platform/dom/scroll-lock.util.ts +261 -0
  244. package/src/react-platform/dom/scroll.util.ts +310 -0
  245. package/src/react-platform/dom/viewport.util.ts +74 -0
  246. package/src/react-platform/dom/web-platform.ts +208 -0
  247. package/src/react-platform/layer/styles.ts +286 -0
  248. package/src/react-platform/layer/web-renderer.tsx +594 -0
  249. package/src/react-platform/tour-provider.tsx +44 -0
  250. package/src/react.ts +13 -0
  251. package/src/shared/engine/abort.util.ts +84 -0
  252. package/src/shared/engine/report.util.ts +58 -0
  253. package/src/shared/engine/tour-adapter.type.ts +62 -0
  254. package/src/shared/engine/tour-engine.ts +1068 -0
  255. package/src/shared/geometry/box.util.ts +185 -0
  256. package/src/shared/geometry/compute-tooltip-layout.util.ts +238 -0
  257. package/src/shared/geometry/geometry.type.ts +38 -0
  258. package/src/shared/geometry/reveal.util.ts +190 -0
  259. package/src/shared/geometry/target-visibility.util.ts +44 -0
  260. package/src/shared/platform/create-tour-adapter.ts +151 -0
  261. package/src/shared/platform/platform.type.ts +81 -0
  262. package/src/shared/platform/reveal-in-scroll-containers.ts +78 -0
  263. package/src/shared/react/tour-context.ts +28 -0
  264. package/src/shared/react/tour-provider-core.ts +67 -0
  265. package/src/shared/react/tour-root.tsx +34 -0
  266. package/src/shared/react/use-isomorphic-layout-effect.hook.ts +7 -0
  267. package/src/shared/react/use-tour-view.hook.ts +17 -0
  268. package/src/shared/react/use-tour.hook.ts +11 -0
  269. package/src/shared/renderer/default-tooltip.tsx +52 -0
  270. package/src/shared/renderer/motion.ts +59 -0
  271. package/src/shared/renderer/renderer-context.ts +33 -0
  272. package/src/shared/renderer/renderer.type.ts +183 -0
  273. package/src/shared/renderer/tooltip-model.ts +44 -0
  274. package/src/shared/renderer/tour-overlay.tsx +453 -0
  275. package/src/shared/types/tour-context.type.ts +23 -0
  276. package/src/shared/types/tour-end-info.type.ts +32 -0
  277. package/src/shared/types/tour-i18n.type.ts +15 -0
  278. package/src/shared/types/tour-step.type.ts +40 -0
  279. package/src/shared/types/tour-theme.type.ts +28 -0
  280. package/src/shared/types/tour-tooltip-props.type.ts +27 -0
  281. package/src/shared/utils/frame.util.ts +21 -0
  282. package/src/shared/utils/get-truncated-dots.util.ts +46 -0
  283. package/src/shared/utils/i18n.util.ts +44 -0
  284. package/src/shared/utils/theme.util.ts +38 -0
  285. package/dist/react-native-platform/components/index.d.ts +0 -2
  286. package/dist/react-native-platform/components/index.js +0 -3
  287. package/dist/react-native-platform/components/index.js.map +0 -1
  288. package/dist/react-native-platform/components/tour-overlay.d.ts +0 -3
  289. package/dist/react-native-platform/components/tour-overlay.js +0 -26
  290. package/dist/react-native-platform/components/tour-overlay.js.map +0 -1
  291. package/dist/react-native-platform/components/tour-tooltip.d.ts +0 -3
  292. package/dist/react-native-platform/components/tour-tooltip.js +0 -167
  293. package/dist/react-native-platform/components/tour-tooltip.js.map +0 -1
  294. package/dist/react-native-platform/hooks/index.d.ts +0 -1
  295. package/dist/react-native-platform/hooks/index.js +0 -2
  296. package/dist/react-native-platform/hooks/index.js.map +0 -1
  297. package/dist/react-native-platform/hooks/use-tour-target.d.ts +0 -2
  298. package/dist/react-native-platform/hooks/use-tour-target.js +0 -13
  299. package/dist/react-native-platform/hooks/use-tour-target.js.map +0 -1
  300. package/dist/react-native-platform/index.d.ts +0 -7
  301. package/dist/react-native-platform/index.js +0 -7
  302. package/dist/react-native-platform/index.js.map +0 -1
  303. package/dist/react-native-platform/platform-adapter.d.ts +0 -2
  304. package/dist/react-native-platform/platform-adapter.js +0 -84
  305. package/dist/react-native-platform/platform-adapter.js.map +0 -1
  306. package/dist/react-native-platform/target-registry.d.ts +0 -10
  307. package/dist/react-native-platform/target-registry.js +0 -17
  308. package/dist/react-native-platform/target-registry.js.map +0 -1
  309. package/dist/react-native-platform/types/tour-provider.props.type.d.ts +0 -12
  310. package/dist/react-native-platform/types/tour-provider.props.type.js +0 -2
  311. package/dist/react-native-platform/types/tour-provider.props.type.js.map +0 -1
  312. package/dist/react-platform/components/index.d.ts +0 -2
  313. package/dist/react-platform/components/index.js +0 -3
  314. package/dist/react-platform/components/index.js.map +0 -1
  315. package/dist/react-platform/components/tour-overlay.d.ts +0 -3
  316. package/dist/react-platform/components/tour-overlay.js +0 -29
  317. package/dist/react-platform/components/tour-overlay.js.map +0 -1
  318. package/dist/react-platform/components/tour-tooltip.d.ts +0 -2
  319. package/dist/react-platform/components/tour-tooltip.js +0 -155
  320. package/dist/react-platform/components/tour-tooltip.js.map +0 -1
  321. package/dist/react-platform/index.d.ts +0 -6
  322. package/dist/react-platform/index.js +0 -6
  323. package/dist/react-platform/index.js.map +0 -1
  324. package/dist/react-platform/platform-adapter.d.ts +0 -2
  325. package/dist/react-platform/platform-adapter.js +0 -101
  326. package/dist/react-platform/platform-adapter.js.map +0 -1
  327. package/dist/react-platform/types/tour-provider.props.type.d.ts +0 -12
  328. package/dist/react-platform/types/tour-provider.props.type.js +0 -2
  329. package/dist/react-platform/types/tour-provider.props.type.js.map +0 -1
  330. package/dist/react-platform/utils/find-visible-element.util.d.ts +0 -1
  331. package/dist/react-platform/utils/find-visible-element.util.js +0 -11
  332. package/dist/react-platform/utils/find-visible-element.util.js.map +0 -1
  333. package/dist/react-platform/utils/index.d.ts +0 -1
  334. package/dist/react-platform/utils/index.js +0 -2
  335. package/dist/react-platform/utils/index.js.map +0 -1
  336. package/dist/shared/context/index.d.ts +0 -1
  337. package/dist/shared/context/index.js +0 -2
  338. package/dist/shared/context/index.js.map +0 -1
  339. package/dist/shared/context/tour-context.d.ts +0 -3
  340. package/dist/shared/context/tour-context.js +0 -14
  341. package/dist/shared/context/tour-context.js.map +0 -1
  342. package/dist/shared/hooks/index.d.ts +0 -1
  343. package/dist/shared/hooks/index.js +0 -2
  344. package/dist/shared/hooks/index.js.map +0 -1
  345. package/dist/shared/hooks/use-tour.hook.d.ts +0 -2
  346. package/dist/shared/hooks/use-tour.hook.js +0 -7
  347. package/dist/shared/hooks/use-tour.hook.js.map +0 -1
  348. package/dist/shared/index.d.ts +0 -5
  349. package/dist/shared/index.js +0 -5
  350. package/dist/shared/index.js.map +0 -1
  351. package/dist/shared/types/index.d.ts +0 -10
  352. package/dist/shared/types/index.js +0 -2
  353. package/dist/shared/types/index.js.map +0 -1
  354. package/dist/shared/types/platform-adapter.type.d.ts +0 -24
  355. package/dist/shared/types/platform-adapter.type.js +0 -2
  356. package/dist/shared/types/platform-adapter.type.js.map +0 -1
  357. package/dist/shared/types/rect.type.d.ts +0 -11
  358. package/dist/shared/types/rect.type.js +0 -2
  359. package/dist/shared/types/rect.type.js.map +0 -1
  360. package/dist/shared/types/tour-overlay-props.type.d.ts +0 -8
  361. package/dist/shared/types/tour-overlay-props.type.js +0 -2
  362. package/dist/shared/types/tour-overlay-props.type.js.map +0 -1
  363. package/dist/shared/utils/calculate-tooltip-position.util.d.ts +0 -14
  364. package/dist/shared/utils/calculate-tooltip-position.util.js +0 -49
  365. package/dist/shared/utils/calculate-tooltip-position.util.js.map +0 -1
  366. package/dist/shared/utils/index.d.ts +0 -3
  367. package/dist/shared/utils/index.js +0 -3
  368. package/dist/shared/utils/index.js.map +0 -1
@@ -0,0 +1,151 @@
1
+ import {nextFrame, nextFrameOrAfter} from '../engine/abort.util.js';
2
+ import type {TargetMeasurement, TourAdapter} from '../engine/tour-adapter.type.js';
3
+ import {boxesEqual} from '../geometry/box.util.js';
4
+ import type {Box} from '../geometry/geometry.type.js';
5
+ import type {TourTarget} from '../types/tour-step.type.js';
6
+ import {requestFrame} from '../utils/frame.util.js';
7
+ import type {PlatformAdapter} from './platform.type.js';
8
+ import {revealInScrollContainers} from './reveal-in-scroll-containers.js';
9
+
10
+ /** A found target counts as settled once it has not moved for this many frames (screens slide in, drawers expand)... */
11
+ const stableFramesNeeded = 2;
12
+ /** ...or after this many frames, so a target that never stops moving (a pulsing button) is still shown... */
13
+ const maxSettleFrames = 12;
14
+ /** ...or after this long: frames stop in background tabs, timers only slow down. */
15
+ const maxSettleMs = 300;
16
+ /** Longest wait for a frame while settling, for the same reason. */
17
+ const settleFrameMs = 50;
18
+
19
+ /**
20
+ * The tour's behaviour on top of a platform: waiting for targets, following them, and scrolling
21
+ * them into view. Shared by every platform, so they behave the same; platforms only provide the
22
+ * raw facts ({@link PlatformAdapter}).
23
+ */
24
+ export function createTourAdapter(platform: PlatformAdapter): TourAdapter {
25
+ return {
26
+ measure: platform.measure,
27
+
28
+ async waitForTarget(target, signal): Promise<TargetMeasurement | undefined> {
29
+ // Subscribed for the whole wait, so a change between measuring and waiting is never missed.
30
+ let hasChanged = false;
31
+ let wake: (() => void) | undefined;
32
+ const unsubscribe = platform.subscribe(target, () => {
33
+ hasChanged = true;
34
+ wake?.();
35
+ });
36
+ const onAbort = (): void => {
37
+ wake?.();
38
+ };
39
+
40
+ const sleepUntilChange = async (): Promise<void> =>
41
+ new Promise<void>((resolve) => {
42
+ wake = resolve;
43
+ });
44
+ signal.addEventListener('abort', onAbort);
45
+ try {
46
+ let previous: Box | undefined;
47
+ let stableFrames = 0;
48
+ let settleFrames = 0;
49
+ let firstSeenAt = 0;
50
+ while (!signal.aborted) {
51
+ hasChanged = false;
52
+ // eslint-disable-next-line no-await-in-loop -- measuring until the target is there and settled
53
+ const current = await platform.measure(target);
54
+ if (signal.aborted) {
55
+ return undefined;
56
+ }
57
+
58
+ if (current) {
59
+ stableFrames = previous && boxesEqual(current.rect, previous, 0.5) ? stableFrames + 1 : 0;
60
+ firstSeenAt = settleFrames === 0 ? Date.now() : firstSeenAt;
61
+ settleFrames++;
62
+ const isSettled =
63
+ stableFrames >= stableFramesNeeded ||
64
+ settleFrames > maxSettleFrames ||
65
+ Date.now() - firstSeenAt >= maxSettleMs;
66
+ if (isSettled) {
67
+ return current;
68
+ }
69
+
70
+ previous = current.rect;
71
+ // eslint-disable-next-line no-await-in-loop -- see above
72
+ await nextFrameOrAfter(signal, settleFrameMs);
73
+ continue;
74
+ }
75
+
76
+ previous = undefined;
77
+ stableFrames = 0;
78
+ settleFrames = 0;
79
+ if (platform.isAwaitingLayout(target)) {
80
+ // eslint-disable-next-line no-await-in-loop -- see above
81
+ await nextFrame(signal);
82
+ } else if (!hasChanged) {
83
+ // Not there yet: sleep until something changes instead of polling.
84
+ // eslint-disable-next-line no-await-in-loop -- see above
85
+ await sleepUntilChange();
86
+ wake = undefined;
87
+ }
88
+ }
89
+
90
+ return undefined;
91
+ } finally {
92
+ signal.removeEventListener('abort', onAbort);
93
+ unsubscribe();
94
+ }
95
+ },
96
+
97
+ getViewport: platform.getViewport,
98
+
99
+ measuresWhileScrolling: platform.measuresWhileScrolling,
100
+
101
+ async reveal(target, request): Promise<void> {
102
+ const containers = await platform.scrollContainers(target);
103
+ if (request.signal.aborted) {
104
+ return;
105
+ }
106
+
107
+ await revealInScrollContainers({
108
+ containers,
109
+ async measureTarget() {
110
+ const measurement = await platform.measure(target);
111
+ return measurement?.rect;
112
+ },
113
+ margins: request.margins,
114
+ animated: request.behavior === 'smooth' && !platform.reducedMotion.get(),
115
+ signal: request.signal,
116
+ onScrollStart: request.onScrollStart,
117
+ });
118
+ },
119
+
120
+ observe(target: TourTarget | undefined, onChange, signal): void {
121
+ if (signal.aborted) {
122
+ return;
123
+ }
124
+
125
+ // At most one call per frame, however many events arrive.
126
+ let cancelFrame: (() => void) | undefined;
127
+ const schedule = (): void => {
128
+ if (cancelFrame !== undefined || signal.aborted) {
129
+ return;
130
+ }
131
+
132
+ cancelFrame = requestFrame(() => {
133
+ cancelFrame = undefined;
134
+ if (!signal.aborted) {
135
+ onChange();
136
+ }
137
+ });
138
+ };
139
+
140
+ const unsubscribe = platform.subscribe(target, schedule);
141
+ signal.addEventListener('abort', () => {
142
+ cancelFrame?.();
143
+ unsubscribe();
144
+ });
145
+ },
146
+
147
+ getPixelRatio: platform.getPixelRatio,
148
+
149
+ nextFrame,
150
+ };
151
+ }
@@ -0,0 +1,81 @@
1
+ import type {TargetMeasurement} from '../engine/tour-adapter.type.js';
2
+ import type {Box, Point, Viewport} from '../geometry/geometry.type.js';
3
+ import type {TourTarget} from '../types/tour-step.type.js';
4
+
5
+ /**
6
+ * What the tour needs from a platform (web, React Native): raw facts about the screen and the
7
+ * app's views, and nothing else. Everything built on them — waiting for targets, following them,
8
+ * scrolling them into view, deciding when scrolling has finished — is shared (see
9
+ * `createTourAdapter`), so it behaves the same everywhere.
10
+ *
11
+ * Every member is required: a platform that lacks one does not compile.
12
+ */
13
+ export type PlatformAdapter = {
14
+ /** Where the target is, in the tour layer's coordinates, or `undefined` when it is not rendered. */
15
+ readonly measure: (target: TourTarget) => Promise<TargetMeasurement | undefined>;
16
+ /**
17
+ * Calls `onChange` whenever the target, the layout around it or the viewport may have changed.
18
+ * Event-driven: no calls while nothing changes. Calling too often is fine (calls are coalesced
19
+ * per frame and results compared). Returns the unsubscribe function.
20
+ */
21
+ readonly subscribe: (target: TourTarget | undefined, onChange: () => void) => () => void;
22
+ /**
23
+ * True when the target exists but cannot be measured yet, and no event will announce when it
24
+ * can (React Native: registered, but not laid out yet). The tour then checks every frame.
25
+ */
26
+ readonly isAwaitingLayout: (target: TourTarget) => boolean;
27
+ /** The scroll containers around the target, innermost first, including the page where it scrolls. */
28
+ readonly scrollContainers: (target: TourTarget) => Promise<readonly ScrollContainer[]>;
29
+ /**
30
+ * The visible area of the tour layer and what covers its edges (safe areas, the on-screen
31
+ * keyboard). Pass the step's target so that a bar containing it does not count as covering it.
32
+ */
33
+ readonly getViewport: (target?: TourTarget) => Viewport;
34
+ /** Whether the user asked the system to reduce motion. */
35
+ readonly reducedMotion: ExternalValue<boolean>;
36
+ /**
37
+ * Whether `measure` sees targets move while a scroll animation runs. When it does not (React
38
+ * Native: on the New Architecture, measurements only catch up once a scroll has finished), the
39
+ * highlight moves straight to where the target will end up instead of following it.
40
+ */
41
+ readonly measuresWhileScrolling: boolean;
42
+ /** Device pixel ratio, used to place the tooltip on whole device pixels. */
43
+ readonly getPixelRatio: () => number;
44
+ };
45
+
46
+ /** A value that can change outside React (a system setting), readable with `useSyncExternalStore`. */
47
+ export type ExternalValue<T> = {
48
+ readonly get: () => T;
49
+ readonly subscribe: (listener: () => void) => () => void;
50
+ };
51
+
52
+ /** One scrollable area between the target and the screen (a nested scroller, a list, or the page itself). */
53
+ export type ScrollContainer = {
54
+ /** Current geometry, or `undefined` when the container is not rendered. */
55
+ readonly measure: () => Promise<ScrollContainerMetrics | undefined>;
56
+ /**
57
+ * Scrolls to `offset` and resolves once this container has finished scrolling (or cannot get
58
+ * further). Stops waiting as soon as `signal` is aborted.
59
+ */
60
+ readonly scrollTo: (offset: Point, options: ScrollOptions) => Promise<void>;
61
+ };
62
+
63
+ export type ScrollOptions = {
64
+ readonly animated: boolean;
65
+ readonly signal: AbortSignal;
66
+ };
67
+
68
+ export type ScrollContainerMetrics = {
69
+ /** The part of the container's viewport content should be revealed in (scroll-padding already applied), in layer coordinates. */
70
+ readonly area: Box;
71
+ readonly offset: Point;
72
+ /**
73
+ * The range the tour may scroll in, per axis. Usually `0` to the end of the content; on an axis
74
+ * the tour must not scroll (the app's own `overflow: hidden`), both are the current offset. Offsets
75
+ * can be negative at rest (content insets, centred content).
76
+ */
77
+ readonly minOffset: Point;
78
+ readonly maxOffset: Point;
79
+ /** Elements over this area that do not scroll with its content (sticky headers, floating buttons), in layer coordinates. */
80
+ readonly obstacles?: readonly Box[];
81
+ };
@@ -0,0 +1,78 @@
1
+ import {withTimeout} from '../engine/abort.util.js';
2
+ import {clamp} from '../geometry/box.util.js';
3
+ import type {Box, Insets, Point} from '../geometry/geometry.type.js';
4
+ import {computeRevealDelta} from '../geometry/reveal.util.js';
5
+ import type {ScrollContainer} from './platform.type.js';
6
+
7
+ export type RevealOptions = {
8
+ /** Innermost container first. */
9
+ readonly containers: readonly ScrollContainer[];
10
+ readonly measureTarget: () => Promise<Box | undefined>;
11
+ /** Space to keep around the target, most generous first (see `buildRevealMargins`). */
12
+ readonly margins: readonly Insets[];
13
+ readonly animated: boolean;
14
+ readonly signal: AbortSignal;
15
+ /**
16
+ * Called once, right before the first container scrolls, with where the target will be once
17
+ * everything has scrolled. Not called if nothing needs to scroll.
18
+ */
19
+ readonly onScrollStart?: (destination: Box) => void;
20
+ };
21
+
22
+ const minimumScroll = 0.5;
23
+ /** Safety cap: a scroll that never reports finishing (interrupted, snapped elsewhere) does not hold the tour up longer. */
24
+ export const settleTimeoutMs = 1500;
25
+
26
+ /**
27
+ * Scrolls every container around the target just enough to bring it (plus margin) into view, all
28
+ * at once: each container's scroll is computed innermost first, on the position the target will
29
+ * have after the inner containers have scrolled (an inner scroll moves the target by exactly the
30
+ * scrolled distance), and then all containers scroll together as one movement. Resolves once every
31
+ * container has finished scrolling.
32
+ */
33
+ export async function revealInScrollContainers(options: RevealOptions): Promise<boolean> {
34
+ const metrics = await Promise.all(options.containers.map(async (container) => container.measure()));
35
+ let predicted = await options.measureTarget();
36
+ if (options.signal.aborted || !predicted) {
37
+ return false;
38
+ }
39
+
40
+ const moves: Array<{readonly container: ScrollContainer; readonly offset: Point}> = [];
41
+ for (const [index, container] of options.containers.entries()) {
42
+ const current = metrics[index];
43
+ if (!current) {
44
+ continue;
45
+ }
46
+
47
+ const delta = computeRevealDelta(predicted, current.area, options.margins, current.obstacles);
48
+ const offset: Point = {
49
+ x: clamp(current.offset.x + delta.x, current.minOffset.x, Math.max(current.minOffset.x, current.maxOffset.x)),
50
+ y: clamp(current.offset.y + delta.y, current.minOffset.y, Math.max(current.minOffset.y, current.maxOffset.y)),
51
+ };
52
+ const applied: Point = {x: offset.x - current.offset.x, y: offset.y - current.offset.y};
53
+ if (Math.abs(applied.x) < minimumScroll && Math.abs(applied.y) < minimumScroll) {
54
+ continue;
55
+ }
56
+
57
+ moves.push({container, offset});
58
+ // Scrolling by `applied` moves the content (and the target) the other way.
59
+ predicted = {...predicted, x: predicted.x - applied.x, y: predicted.y - applied.y};
60
+ }
61
+
62
+ if (moves.length === 0) {
63
+ return false;
64
+ }
65
+
66
+ options.onScrollStart?.(predicted);
67
+ await withTimeout(
68
+ async (signal) => {
69
+ await Promise.all(
70
+ moves.map(async (move) => move.container.scrollTo(move.offset, {animated: options.animated, signal})),
71
+ );
72
+ return true;
73
+ },
74
+ options.signal,
75
+ settleTimeoutMs,
76
+ );
77
+ return true;
78
+ }
@@ -0,0 +1,28 @@
1
+ import {createContext} from 'react';
2
+ import {devWarn} from '../engine/report.util.js';
3
+ import type {TourEngine} from '../engine/tour-engine.js';
4
+ import type {TourContextType} from '../types/tour-context.type.js';
5
+
6
+ function outsideProvider(): void {
7
+ devWarn('useTour() was called outside of <TourProvider>; the call has no effect.');
8
+ }
9
+
10
+ const defaultTourContext: TourContextType = {
11
+ isActive: false,
12
+ currentStep: 0,
13
+ steps: [],
14
+ currentTourId: undefined,
15
+ startTour: outsideProvider,
16
+ endTour: outsideProvider,
17
+ nextStep: outsideProvider,
18
+ prevStep: outsideProvider,
19
+ goToStep: outsideProvider,
20
+ };
21
+
22
+ /** Public tour state and actions (what `useTour()` returns). */
23
+ export const TourContext = createContext(defaultTourContext);
24
+ TourContext.displayName = 'TourContext';
25
+
26
+ /** The engine, for the built-in renderer and platform hooks. Not part of the public API. */
27
+ export const TourEngineContext = createContext<TourEngine | undefined>(undefined);
28
+ TourEngineContext.displayName = 'TourEngineContext';
@@ -0,0 +1,67 @@
1
+ import {type ComponentType, type ReactNode, useMemo, useState, useSyncExternalStore} from 'react';
2
+ import type {TourEngine} from '../engine/tour-engine.js';
3
+ import {createTourAdapter} from '../platform/create-tour-adapter.js';
4
+ import type {PlatformAdapter} from '../platform/platform.type.js';
5
+ import {DefaultTooltip} from '../renderer/default-tooltip.js';
6
+ import type {TourRenderer} from '../renderer/renderer.type.js';
7
+ import type {TourOverlayProps} from '../renderer/tour-overlay.js';
8
+ import type {TourEndCallback} from '../types/tour-end-info.type.js';
9
+ import type {TourI18n} from '../types/tour-i18n.type.js';
10
+ import type {TourTheme} from '../types/tour-theme.type.js';
11
+ import type {TourTooltipProps} from '../types/tour-tooltip-props.type.js';
12
+ import {resolveI18n} from '../utils/i18n.util.js';
13
+ import {resolveTheme} from '../utils/theme.util.js';
14
+ import {useTourEngine} from './tour-root.js';
15
+
16
+ /** Props of `TourProvider` on every platform. Platforms may add their own (React Native: `insets`). */
17
+ export type TourProviderBaseProps = {
18
+ readonly children?: ReactNode;
19
+ /** Colours of the built-in tooltip and overlay. */
20
+ readonly theme?: TourTheme;
21
+ /** Texts of the built-in tooltip. */
22
+ readonly i18n?: TourI18n;
23
+ /** Called once whenever a tour ends, after the tour's own `onTourEnd`. */
24
+ readonly onTourEnd?: TourEndCallback;
25
+ /**
26
+ * Whether clicking or tapping the dimmed area ends the tour (with the reason `'blur'`).
27
+ * @defaultValue `true`
28
+ */
29
+ readonly closeOnOverlayClick?: boolean;
30
+ /**
31
+ * Replaces the content of the tooltip card. The tour still measures, positions, animates and
32
+ * focuses it, and keeps it on screen.
33
+ */
34
+ readonly TooltipComponent?: ComponentType<TourTooltipProps>;
35
+ };
36
+
37
+ export type TourCore = {
38
+ readonly engine: TourEngine;
39
+ /** Everything the overlay needs; the platform renders `<TourOverlay {...overlay} />` where the tour is drawn. */
40
+ readonly overlay: TourOverlayProps;
41
+ };
42
+
43
+ const neverReduced = (): boolean => false;
44
+
45
+ /**
46
+ * What every `TourProvider` does, whatever the platform: creates the engine on top of the
47
+ * platform's facts, resolves theme and texts, and prepares the overlay. `platform` and `renderer`
48
+ * must keep their identity for the lifetime of the provider.
49
+ */
50
+ export function useTourCore(props: TourProviderBaseProps, platform: PlatformAdapter, renderer: TourRenderer): TourCore {
51
+ const [adapter] = useState(() => createTourAdapter(platform));
52
+ const engine = useTourEngine(adapter, props.onTourEnd);
53
+ const isReducedMotion = useSyncExternalStore(
54
+ platform.reducedMotion.subscribe,
55
+ platform.reducedMotion.get,
56
+ neverReduced,
57
+ );
58
+ const theme = useMemo(() => resolveTheme(props.theme), [props.theme]);
59
+ const i18n = useMemo(() => resolveI18n(props.i18n), [props.i18n]);
60
+ const Tooltip = props.TooltipComponent ?? DefaultTooltip;
61
+ const isOverlayDismissible = props.closeOnOverlayClick ?? true;
62
+ const overlay = useMemo<TourOverlayProps>(
63
+ () => ({engine, renderer, theme, i18n, Tooltip, isOverlayDismissible, isReducedMotion}),
64
+ [engine, renderer, theme, i18n, Tooltip, isOverlayDismissible, isReducedMotion],
65
+ );
66
+ return {engine, overlay};
67
+ }
@@ -0,0 +1,34 @@
1
+ import {type ReactNode, useEffect, useMemo, useState, useSyncExternalStore} from 'react';
2
+ import type {TourAdapter} from '../engine/tour-adapter.type.js';
3
+ import {createTourEngine, type TourEngine} from '../engine/tour-engine.js';
4
+ import type {TourContextType} from '../types/tour-context.type.js';
5
+ import type {TourEndCallback} from '../types/tour-end-info.type.js';
6
+ import {TourContext, TourEngineContext} from './tour-context.js';
7
+ import {useIsomorphicLayoutEffect} from './use-isomorphic-layout-effect.hook.js';
8
+
9
+ /** Creates the engine once and keeps its options in sync with the latest props. */
10
+ export function useTourEngine(adapter: TourAdapter, onTourEnd: TourEndCallback | undefined): TourEngine {
11
+ const [engine] = useState(() => createTourEngine({adapter, onTourEnd}));
12
+ // Latest props: callback identity never matters, so inline callbacks cannot restart anything.
13
+ useIsomorphicLayoutEffect(() => {
14
+ engine.configure({adapter, onTourEnd});
15
+ });
16
+ useEffect(() => engine.mount(), [engine]);
17
+ return engine;
18
+ }
19
+
20
+ type TourRootProps = {
21
+ readonly engine: TourEngine;
22
+ readonly children: ReactNode;
23
+ };
24
+
25
+ /** Provides the public tour context (for `useTour`) and the engine (for the renderer). */
26
+ export function TourRoot({engine, children}: TourRootProps): ReactNode {
27
+ const state = useSyncExternalStore(engine.subscribe, engine.getPublicState, engine.getPublicState);
28
+ const value = useMemo<TourContextType>(() => ({...state, ...engine.actions}), [state, engine]);
29
+ return (
30
+ <TourEngineContext.Provider value={engine}>
31
+ <TourContext.Provider value={value}>{children}</TourContext.Provider>
32
+ </TourEngineContext.Provider>
33
+ );
34
+ }
@@ -0,0 +1,7 @@
1
+ import {useEffect, useLayoutEffect} from 'react';
2
+
3
+ const canUseLayoutEffect =
4
+ typeof document !== 'undefined' || (typeof navigator !== 'undefined' && navigator.product === 'ReactNative');
5
+
6
+ /** `useLayoutEffect` in the browser and on React Native; `useEffect` during server rendering (avoids React 18's SSR warning). */
7
+ export const useIsomorphicLayoutEffect = canUseLayoutEffect ? useLayoutEffect : useEffect;
@@ -0,0 +1,17 @@
1
+ import {useContext, useSyncExternalStore} from 'react';
2
+ import type {TourEngine, TourViewState} from '../engine/tour-engine.js';
3
+ import {TourEngineContext} from './tour-context.js';
4
+
5
+ export function useTourEngineContext(): TourEngine {
6
+ const engine = useContext(TourEngineContext);
7
+ if (!engine) {
8
+ throw new Error('[react-tour-kit] This component must be rendered inside <TourProvider>.');
9
+ }
10
+
11
+ return engine;
12
+ }
13
+
14
+ /** What the renderer draws. Re-renders only on structural changes (step, phase, layout). */
15
+ export function useTourView(engine: TourEngine): TourViewState {
16
+ return useSyncExternalStore(engine.subscribe, engine.getViewState, engine.getViewState);
17
+ }
@@ -0,0 +1,11 @@
1
+ import {useContext} from 'react';
2
+ import type {TourContextType} from '../types/tour-context.type.js';
3
+ import {TourContext} from './tour-context.js';
4
+
5
+ /**
6
+ * The current tour's state and the functions to control it. The functions keep their identity for
7
+ * the lifetime of the `TourProvider`, so they are safe to use in effect dependencies.
8
+ */
9
+ export function useTour(): TourContextType {
10
+ return useContext(TourContext);
11
+ }
@@ -0,0 +1,52 @@
1
+ import type {ReactNode} from 'react';
2
+ import type {TourTooltipProps} from '../types/tour-tooltip-props.type.js';
3
+ import {useRendererContext} from './renderer-context.js';
4
+ import {tooltipModel} from './tooltip-model.js';
5
+
6
+ /** The built-in tooltip: the same structure and texts on every platform, drawn with the platform's card parts. */
7
+ export function DefaultTooltip(props: TourTooltipProps): ReactNode {
8
+ const {renderer, i18n} = useRendererContext();
9
+ const {Card, Arrow, Header, Counter, CloseButton, Body, Title, Content, Footer, Button, Dots, Dot, Ellipsis} =
10
+ renderer.card;
11
+ const model = tooltipModel(props, i18n);
12
+ return (
13
+ <Card placement={props.placement}>
14
+ {model.arrow ? <Arrow side={model.arrow.side} offset={model.arrow.offset} /> : null}
15
+ <Header>
16
+ <Counter text={model.counter} />
17
+ <CloseButton label={model.closeLabel} onPress={props.onClose} />
18
+ </Header>
19
+ <Body>
20
+ <Title id={props.titleId}>{props.step.title}</Title>
21
+ <Content id={props.descriptionId}>{props.step.content}</Content>
22
+ </Body>
23
+ <Footer>
24
+ <Button
25
+ kind="previous"
26
+ label={model.previous.label}
27
+ isDisabled={model.previous.isDisabled}
28
+ onPress={props.onPrev}
29
+ />
30
+ {model.dots ? (
31
+ <Dots label={model.counter}>
32
+ {model.dots.map((dot) =>
33
+ dot.kind === 'ellipsis' ? (
34
+ <Ellipsis key={dot.key} />
35
+ ) : (
36
+ <Dot
37
+ key={dot.index}
38
+ label={dot.label}
39
+ isCurrent={dot.isCurrent}
40
+ onPress={() => {
41
+ props.onGoToStep(dot.index);
42
+ }}
43
+ />
44
+ ),
45
+ )}
46
+ </Dots>
47
+ ) : null}
48
+ <Button kind="next" label={model.next.label} isDisabled={false} onPress={props.onNext} />
49
+ </Footer>
50
+ </Card>
51
+ );
52
+ }
@@ -0,0 +1,59 @@
1
+ import type {TourPlacement} from '../types/tour-step.type.js';
2
+ import type {Entrance} from './renderer.type.js';
3
+
4
+ /** Timing of every animation, the same on every platform. */
5
+ export const motion = {
6
+ fadeInMs: 200,
7
+ fadeOutMs: 150,
8
+ /** With reduced motion turned on: short fades, no movement. */
9
+ reducedMs: 100,
10
+ /** The spotlight moving from one target to the next. */
11
+ morphMs: 250,
12
+ /** The spotlight following a target that is being scrolled into view, frame by frame. */
13
+ chaseMs: 120,
14
+ enterMs: 200,
15
+ /** The tooltip starts entering while the spotlight is still on its way. */
16
+ enterDelayMs: 100,
17
+ /** Distance (from the target's side) and scale the tooltip enters from. */
18
+ enterOffset: 6,
19
+ enterScale: 0.96,
20
+ /** If the first step takes longer than this to prepare (navigation, data), the screen is dimmed meanwhile. */
21
+ waitingDimDelayMs: 300,
22
+ /** Control points of the standard easing curve (`cubic-bezier`). */
23
+ easing: [0.2, 0, 0, 1],
24
+ } as const;
25
+
26
+ export function fadeDuration(isClosing: boolean, isReducedMotion: boolean): number {
27
+ if (isReducedMotion) {
28
+ return motion.reducedMs;
29
+ }
30
+
31
+ return isClosing ? motion.fadeOutMs : motion.fadeInMs;
32
+ }
33
+
34
+ const entranceDirection: Record<TourPlacement | 'center', readonly [number, number]> = {
35
+ // Above the target: comes down towards it; below: comes up; and so on.
36
+ top: [0, 1],
37
+ bottom: [0, -1],
38
+ left: [1, 0],
39
+ right: [-1, 0],
40
+ center: [0, 0],
41
+ };
42
+
43
+ export function entranceFor(
44
+ placement: TourPlacement | 'center',
45
+ {isDelayed, isReducedMotion}: {readonly isDelayed: boolean; readonly isReducedMotion: boolean},
46
+ ): Entrance {
47
+ if (isReducedMotion) {
48
+ return {dx: 0, dy: 0, scale: 1, durationMs: motion.reducedMs, delayMs: 0};
49
+ }
50
+
51
+ const [x, y] = entranceDirection[placement];
52
+ return {
53
+ dx: x * motion.enterOffset,
54
+ dy: y * motion.enterOffset,
55
+ scale: motion.enterScale,
56
+ durationMs: motion.enterMs,
57
+ delayMs: isDelayed ? motion.enterDelayMs : 0,
58
+ };
59
+ }
@@ -0,0 +1,33 @@
1
+ import {createContext, useContext} from 'react';
2
+ import type {ResolvedI18n} from '../utils/i18n.util.js';
3
+ import type {ResolvedTheme} from '../utils/theme.util.js';
4
+ import type {TourRenderer} from './renderer.type.js';
5
+
6
+ export type RendererContextValue = {
7
+ readonly renderer: TourRenderer;
8
+ readonly theme: ResolvedTheme;
9
+ readonly i18n: ResolvedI18n;
10
+ };
11
+
12
+ /** The platform's primitives, the theme and the texts, for everything drawn inside the tour. Internal. */
13
+ export const RendererContext = createContext<RendererContextValue | undefined>(undefined);
14
+ RendererContext.displayName = 'TourRendererContext';
15
+
16
+ export function useRendererContext(): RendererContextValue {
17
+ const value = useContext(RendererContext);
18
+ if (!value) {
19
+ throw new Error('[react-tour-kit] The built-in tooltip can only be rendered by the tour.');
20
+ }
21
+
22
+ return value;
23
+ }
24
+
25
+ export type TooltipLimits = {
26
+ readonly maxWidth: number;
27
+ readonly maxHeight: number;
28
+ };
29
+
30
+ /** Size limits of the tooltip being rendered; platforms that cannot express them in styles size the card with them. */
31
+ const defaultLimits: TooltipLimits = {maxWidth: 380, maxHeight: 600};
32
+ export const TooltipLimitsContext = createContext(defaultLimits);
33
+ TooltipLimitsContext.displayName = 'TourTooltipLimitsContext';