@robertlinde/react-tour-kit 0.8.9 → 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 -10
  57. package/dist/react-native.d.ts.map +1 -0
  58. package/dist/react-native.js +7 -7
  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 -10
  97. package/dist/react.d.ts.map +1 -0
  98. package/dist/react.js +5 -7
  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 -7
  349. package/dist/shared/index.js +0 -6
  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,594 @@
1
+ import {
2
+ type CSSProperties,
3
+ type KeyboardEvent as ReactKeyboardEvent,
4
+ type ReactNode,
5
+ useEffect,
6
+ useInsertionEffect,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import {clamp} from '../../shared/geometry/box.util.js';
11
+ import type {Box} from '../../shared/geometry/geometry.type.js';
12
+ import {useIsomorphicLayoutEffect} from '../../shared/react/use-isomorphic-layout-effect.hook.js';
13
+ import {motion} from '../../shared/renderer/motion.js';
14
+ import type {
15
+ ArrowProps,
16
+ BackdropProps,
17
+ ButtonProps,
18
+ CardParts,
19
+ CardProps,
20
+ CloseButtonProps,
21
+ ContainerProps,
22
+ CounterProps,
23
+ DotProps,
24
+ DotsProps,
25
+ LayerProps,
26
+ MeasureFrameProps,
27
+ SpotlightProps,
28
+ TextPartProps,
29
+ TooltipFrameProps,
30
+ TourRenderer,
31
+ } from '../../shared/renderer/renderer.type.js';
32
+ import {handlesKey, pageDirection} from '../dom/elements.util.js';
33
+ import {lockScroll} from '../dom/scroll-lock.util.js';
34
+ import {injectTourStyles} from './styles.js';
35
+
36
+ /** Custom properties (`--rtk-*`) in inline styles. */
37
+ type StyleWithVariables = CSSProperties & Record<`--rtk-${string}`, string>;
38
+
39
+ const [x1, y1, x2, y2] = motion.easing;
40
+ const standardEasing = `cubic-bezier(${x1}, ${y1}, ${x2}, ${y2})`;
41
+
42
+ // ---------------------------------------------------------------------------------------------
43
+ // Layer: a modal <dialog> in the top layer
44
+ // ---------------------------------------------------------------------------------------------
45
+
46
+ /** Elements made inert by the fallback below, so they can be restored. */
47
+ const inertedByTour = new WeakMap<HTMLDialogElement, Element[]>();
48
+
49
+ /**
50
+ * Opens the dialog as a modal: top layer, rest of the page inert, focus restored on close.
51
+ * Without `showModal` (very old browsers, jsdom) the dialog is shown with a high z-index
52
+ * (`--rtk-z-index`) and the rest of the page is made inert manually.
53
+ */
54
+ function openModal(dialog: HTMLDialogElement): void {
55
+ if (dialog.open || dialog.hasAttribute('open')) {
56
+ return;
57
+ }
58
+
59
+ if (typeof dialog.showModal === 'function') {
60
+ try {
61
+ dialog.showModal();
62
+ return;
63
+ } catch {
64
+ // Not connected or not allowed: fall through to the fallback.
65
+ }
66
+ }
67
+
68
+ dialog.setAttribute('open', '');
69
+ const others = [...document.body.children].filter(
70
+ (element) => element !== dialog && !element.contains(dialog) && !element.hasAttribute('inert'),
71
+ );
72
+ for (const element of others) {
73
+ element.setAttribute('inert', '');
74
+ }
75
+
76
+ inertedByTour.set(dialog, others);
77
+ }
78
+
79
+ function closeModal(dialog: HTMLDialogElement): void {
80
+ if (typeof dialog.close === 'function' && dialog.open) {
81
+ dialog.close();
82
+ } else {
83
+ dialog.removeAttribute('open');
84
+ }
85
+
86
+ for (const element of inertedByTour.get(dialog) ?? []) {
87
+ element.removeAttribute('inert');
88
+ }
89
+
90
+ inertedByTour.delete(dialog);
91
+ }
92
+
93
+ function safeMatches(element: Element, selector: string): boolean {
94
+ try {
95
+ return element.matches(selector);
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ /** The tooltip on screen, to put focus on. */
102
+ function shownTooltip(dialog: HTMLDialogElement): HTMLElement | null {
103
+ return dialog.querySelector<HTMLElement>('[data-rtk-tooltip]:not([data-hidden])');
104
+ }
105
+
106
+ /**
107
+ * Returns focus to where it was when the tour opened. Browsers do this when a modal dialog closes,
108
+ * but forget where it was once the dialog has been re-opened over one of the app's own.
109
+ */
110
+ function restoreFocus(trigger: Element | null, dialog: HTMLDialogElement): void {
111
+ if (!(trigger instanceof HTMLElement) || trigger === document.body || !trigger.isConnected) {
112
+ return;
113
+ }
114
+
115
+ const active = document.activeElement;
116
+ if (!active || active === document.body || dialog.contains(active)) {
117
+ trigger.focus({preventScroll: true});
118
+ }
119
+ }
120
+
121
+ /**
122
+ * A modal `<dialog>` in the top layer: above any z-index, with the page inert, focus restored on
123
+ * close and the page kept from scrolling. Keys and the dialog's own close requests become intents.
124
+ */
125
+ function Layer({
126
+ children,
127
+ state,
128
+ isVisible,
129
+ fadeMs,
130
+ isInteractive,
131
+ theme,
132
+ titleId,
133
+ descriptionId,
134
+ fallbackLabel,
135
+ announcement,
136
+ stepKey,
137
+ onIntent,
138
+ }: LayerProps): ReactNode {
139
+ const layerRef = useRef<HTMLDialogElement | null>(null);
140
+ const liveRef = useRef<HTMLDivElement | null>(null);
141
+ const reopening = useRef(false);
142
+ const [direction] = useState(pageDirection);
143
+
144
+ useInsertionEffect(() => {
145
+ injectTourStyles(document);
146
+ }, []);
147
+
148
+ useIsomorphicLayoutEffect(() => {
149
+ const dialog = layerRef.current;
150
+ if (!dialog) {
151
+ return undefined;
152
+ }
153
+
154
+ const trigger = document.activeElement;
155
+ openModal(dialog);
156
+ const unlock = lockScroll(dialog);
157
+ return (): void => {
158
+ unlock();
159
+ reopening.current = true;
160
+ closeModal(dialog);
161
+ restoreFocus(trigger, dialog);
162
+ };
163
+ }, []);
164
+
165
+ // If the app opened its own modal (in onBeforeStep), move the tour back on top of it.
166
+ useEffect(() => {
167
+ const dialog = layerRef.current;
168
+ if (!dialog || stepKey === undefined) {
169
+ return;
170
+ }
171
+
172
+ const other = [...document.querySelectorAll('dialog')].find(
173
+ (element) => element !== dialog && element.open && safeMatches(element, ':modal'),
174
+ );
175
+ if (other && dialog.open && safeMatches(dialog, ':modal')) {
176
+ const focused = document.activeElement;
177
+ // `close` fires asynchronously; the handler consumes this flag.
178
+ reopening.current = true;
179
+ closeModal(dialog);
180
+ openModal(dialog);
181
+ // Opening focuses the first button: keep focus where it was in the tour.
182
+ const refocus = focused instanceof HTMLElement && dialog.contains(focused) ? focused : shownTooltip(dialog);
183
+ refocus?.focus({preventScroll: true});
184
+ }
185
+ }, [stepKey]);
186
+
187
+ // A custom tooltip may not render an element with the title id: then label the dialog directly.
188
+ useEffect(() => {
189
+ const dialog = layerRef.current;
190
+ if (!dialog || titleId === undefined) {
191
+ return;
192
+ }
193
+
194
+ // `getElementById`: ids from useId() contain characters that would need escaping in selectors.
195
+ // eslint-disable-next-line unicorn/prefer-query-selector
196
+ if (document.getElementById(titleId)) {
197
+ dialog.removeAttribute('aria-label');
198
+ } else {
199
+ dialog.setAttribute('aria-label', fallbackLabel);
200
+ }
201
+ }, [stepKey, titleId, fallbackLabel]);
202
+
203
+ useEffect(() => {
204
+ if (announcement && liveRef.current) {
205
+ liveRef.current.textContent = announcement;
206
+ }
207
+ }, [announcement, stepKey]);
208
+
209
+ const style: StyleWithVariables = {
210
+ '--rtk-primary': theme.primaryColor,
211
+ '--rtk-on-primary': theme.primaryTextColor,
212
+ '--rtk-bg': theme.tooltipBackground,
213
+ '--rtk-title': theme.titleColor,
214
+ '--rtk-text': theme.contentColor,
215
+ '--rtk-overlay': theme.overlayColor,
216
+ '--rtk-fade-duration': `${fadeMs}ms`,
217
+ };
218
+
219
+ const onKeyDown = (event: ReactKeyboardEvent<HTMLDialogElement>): void => {
220
+ const {nativeEvent, key} = event;
221
+ if (
222
+ !isInteractive ||
223
+ event.defaultPrevented ||
224
+ nativeEvent.isComposing ||
225
+ event.altKey ||
226
+ event.ctrlKey ||
227
+ event.metaKey
228
+ ) {
229
+ return;
230
+ }
231
+
232
+ if (key === 'Escape') {
233
+ event.preventDefault();
234
+ onIntent('escape');
235
+ return;
236
+ }
237
+
238
+ if ((key === 'ArrowRight' || key === 'ArrowLeft') && !handlesKey(event.target, key)) {
239
+ event.preventDefault();
240
+ // In right-to-left pages, the arrow pointing to the start goes forward.
241
+ const isForward = (key === 'ArrowRight') !== (direction === 'rtl');
242
+ onIntent(isForward ? 'next' : 'previous');
243
+ }
244
+ };
245
+
246
+ return (
247
+ <dialog
248
+ ref={layerRef}
249
+ className="rtk-root"
250
+ data-rtk-root=""
251
+ data-state={state}
252
+ data-visible={isVisible ? '' : undefined}
253
+ dir={direction === 'rtl' ? 'rtl' : undefined}
254
+ aria-labelledby={titleId}
255
+ aria-describedby={descriptionId}
256
+ style={style}
257
+ onKeyDown={onKeyDown}
258
+ onCancel={(event): void => {
259
+ // Escape (and the Android back gesture) fire `cancel`; the tour decides how to close.
260
+ event.preventDefault();
261
+ onIntent('escape');
262
+ }}
263
+ onClose={(): void => {
264
+ if (reopening.current) {
265
+ reopening.current = false;
266
+ return;
267
+ }
268
+
269
+ // The browser closed the dialog by force (for example a second Escape press).
270
+ onIntent('escape');
271
+ }}
272
+ >
273
+ {children}
274
+ <div ref={liveRef} className="rtk-sr-only" aria-live="polite" aria-atomic="true" />
275
+ </dialog>
276
+ );
277
+ }
278
+
279
+ function Backdrop({isDismissible, onPress}: BackdropProps): ReactNode {
280
+ return (
281
+ <div
282
+ className="rtk-backdrop"
283
+ data-rtk-backdrop=""
284
+ data-closable={isDismissible ? '' : undefined}
285
+ onClick={(event): void => {
286
+ onPress({x: event.clientX, y: event.clientY});
287
+ }}
288
+ />
289
+ );
290
+ }
291
+
292
+ const spotlightProperties = ['left', 'top', 'width', 'height', 'border-radius'];
293
+
294
+ /** How far off screen a hole may be: past the ring around it. */
295
+ const offScreenMargin = 16;
296
+
297
+ /**
298
+ * Keeps a hole that is far off screen (a target still to be scrolled to) just past the screen's
299
+ * edge: the dim is the hole's shadow, which only reaches so far.
300
+ */
301
+ function nearScreen(hole: Box): Box {
302
+ const width = document.documentElement.clientWidth || globalThis.innerWidth;
303
+ const height = document.documentElement.clientHeight || globalThis.innerHeight;
304
+ return {
305
+ ...hole,
306
+ x: clamp(hole.x, -offScreenMargin - hole.width, width + offScreenMargin),
307
+ y: clamp(hole.y, -offScreenMargin - hole.height, height + offScreenMargin),
308
+ };
309
+ }
310
+
311
+ /** The dimmed overlay with a rounded hole, drawn with a single box-shadow. */
312
+ function Spotlight({hole: requested, transition}: SpotlightProps): ReactNode {
313
+ const hole = requested ? nearScreen(requested) : undefined;
314
+ const style: CSSProperties = hole
315
+ ? {
316
+ left: hole.x,
317
+ top: hole.y,
318
+ width: hole.width,
319
+ height: hole.height,
320
+ borderRadius: `min(var(--rtk-spotlight-radius), ${hole.width / 2}px, ${hole.height / 2}px)`,
321
+ }
322
+ : {left: '50%', top: '50%', width: 0, height: 0, borderRadius: 0};
323
+ if (transition) {
324
+ const easing = transition.easing === 'linear' ? 'linear' : standardEasing;
325
+ style.transition = spotlightProperties
326
+ .map((property) => `${property} ${transition.durationMs}ms ${easing}`)
327
+ .join(', ');
328
+ }
329
+
330
+ return (
331
+ <div
332
+ aria-hidden="true"
333
+ className="rtk-spotlight"
334
+ data-rtk-spotlight=""
335
+ data-collapsed={hole ? undefined : ''}
336
+ style={style}
337
+ />
338
+ );
339
+ }
340
+
341
+ function isVerticalWritingMode(element: Element): boolean {
342
+ return getComputedStyle(element).writingMode.startsWith('vertical');
343
+ }
344
+
345
+ /**
346
+ * True when the tooltip's content is bigger than its frame (it reached the size limits), so the
347
+ * frame has to scroll. Decorations sticking out of the content (the arrow) do not count.
348
+ */
349
+ function overflowsFrame(frame: HTMLElement): boolean {
350
+ const children = [...frame.children].filter((child) => child instanceof HTMLElement);
351
+ if (children.length === 0 || children.length < frame.children.length) {
352
+ return frame.scrollHeight > frame.clientHeight + 1 || frame.scrollWidth > frame.clientWidth + 1;
353
+ }
354
+
355
+ let left = 0;
356
+ let top = 0;
357
+ let right = 0;
358
+ let bottom = 0;
359
+ for (const child of children) {
360
+ left = Math.min(left, child.offsetLeft);
361
+ top = Math.min(top, child.offsetTop);
362
+ right = Math.max(right, child.offsetLeft + child.offsetWidth);
363
+ bottom = Math.max(bottom, child.offsetTop + child.offsetHeight);
364
+ }
365
+
366
+ return left < -1 || top < -1 || right > frame.clientWidth + 1 || bottom > frame.clientHeight + 1;
367
+ }
368
+
369
+ /** Positions the tooltip (with `translate`, so the entrance's `transform` never moves it), reports its size and takes focus. */
370
+ function TooltipFrame({children, layout, entrance, isBusy, isHidden, onSize}: TooltipFrameProps): ReactNode {
371
+ const ref = useRef<HTMLDivElement | null>(null);
372
+ const [isEntering, setIsEntering] = useState(true);
373
+ const [isOverflowing, setIsOverflowing] = useState(false);
374
+
375
+ // Report size changes (late-loading fonts or images, content changes); keep scrolling available
376
+ // when the content does not fit. Sizes come from ResizeObserver's border box: unlike
377
+ // getBoundingClientRect it ignores the entrance animation's scale. The content is observed too:
378
+ // it can keep growing once the frame has reached its size limits.
379
+ useIsomorphicLayoutEffect(() => {
380
+ const element = ref.current;
381
+ if (!element) {
382
+ return undefined;
383
+ }
384
+
385
+ const report = (box: ResizeObserverSize | undefined): void => {
386
+ const isVertical = isVerticalWritingMode(element);
387
+ const width = box ? (isVertical ? box.blockSize : box.inlineSize) : element.offsetWidth;
388
+ const height = box ? (isVertical ? box.inlineSize : box.blockSize) : element.offsetHeight;
389
+ onSize({width, height});
390
+ };
391
+
392
+ if (typeof ResizeObserver !== 'function') {
393
+ // No ResizeObserver (jsdom): report the size once.
394
+ report(undefined);
395
+ return undefined;
396
+ }
397
+
398
+ const observer = new ResizeObserver((entries) => {
399
+ setIsOverflowing(overflowsFrame(element));
400
+ const own = entries.find((entry) => entry.target === element);
401
+ if (own) {
402
+ report(own.borderBoxSize?.[0]);
403
+ }
404
+ });
405
+ observer.observe(element);
406
+ for (const child of element.children) {
407
+ observer.observe(child);
408
+ }
409
+
410
+ return (): void => {
411
+ observer.disconnect();
412
+ };
413
+ }, [onSize]);
414
+
415
+ // Move focus into the tooltip so screen readers read it and keyboard users can act on it.
416
+ useEffect(() => {
417
+ ref.current?.focus({preventScroll: true});
418
+ }, []);
419
+
420
+ const style: StyleWithVariables = {
421
+ translate: `${layout.x}px ${layout.y}px`,
422
+ maxWidth: layout.maxWidth,
423
+ maxHeight: layout.maxHeight,
424
+ '--rtk-max-height': `${layout.maxHeight}px`,
425
+ '--rtk-enter-x': `${entrance.dx}px`,
426
+ '--rtk-enter-y': `${entrance.dy}px`,
427
+ '--rtk-enter-scale': String(entrance.scale),
428
+ '--rtk-enter-duration': `${entrance.durationMs}ms`,
429
+ '--rtk-enter-delay': `${entrance.delayMs}ms`,
430
+ };
431
+
432
+ return (
433
+ <div
434
+ ref={ref}
435
+ className="rtk-tooltip"
436
+ data-rtk-tooltip=""
437
+ data-placement={layout.placement}
438
+ data-entering={isEntering ? '' : undefined}
439
+ data-hidden={isHidden ? '' : undefined}
440
+ data-overflowing={isOverflowing ? '' : undefined}
441
+ aria-busy={isBusy ? 'true' : undefined}
442
+ tabIndex={-1}
443
+ style={style}
444
+ onAnimationEnd={(event): void => {
445
+ // Animations inside a custom tooltip bubble up here too.
446
+ if (event.target === event.currentTarget) {
447
+ setIsEntering(false);
448
+ }
449
+ }}
450
+ >
451
+ {children}
452
+ </div>
453
+ );
454
+ }
455
+
456
+ function MeasureFrame({children, maxWidth, maxHeight, onSize}: MeasureFrameProps): ReactNode {
457
+ const ref = useRef<HTMLDivElement | null>(null);
458
+ useIsomorphicLayoutEffect(() => {
459
+ const element = ref.current;
460
+ if (element) {
461
+ const rect = element.getBoundingClientRect();
462
+ onSize({width: rect.width, height: rect.height});
463
+ }
464
+ }, [onSize]);
465
+
466
+ const style: StyleWithVariables = {maxWidth, maxHeight, '--rtk-max-height': `${maxHeight}px`};
467
+ return (
468
+ <div ref={ref} aria-hidden="true" className="rtk-measure" style={style}>
469
+ {children}
470
+ </div>
471
+ );
472
+ }
473
+
474
+ // ---------------------------------------------------------------------------------------------
475
+ // Card parts
476
+ // ---------------------------------------------------------------------------------------------
477
+
478
+ function CloseIcon(): ReactNode {
479
+ return (
480
+ <svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16" fill="none" focusable="false">
481
+ <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" />
482
+ </svg>
483
+ );
484
+ }
485
+
486
+ function Card({placement, children}: CardProps): ReactNode {
487
+ return (
488
+ <div className="rtk-card" data-placement={placement}>
489
+ {children}
490
+ </div>
491
+ );
492
+ }
493
+
494
+ function Arrow({side, offset}: ArrowProps): ReactNode {
495
+ const style: StyleWithVariables = {'--rtk-arrow-offset': `${offset}px`};
496
+ return <div aria-hidden="true" className="rtk-arrow" data-side={side} style={style} />;
497
+ }
498
+
499
+ function Header({children}: ContainerProps): ReactNode {
500
+ return <div className="rtk-header">{children}</div>;
501
+ }
502
+
503
+ function Counter({text}: CounterProps): ReactNode {
504
+ return <span className="rtk-counter">{text}</span>;
505
+ }
506
+
507
+ function CloseButton({label, onPress}: CloseButtonProps): ReactNode {
508
+ return (
509
+ <button type="button" className="rtk-close" aria-label={label} onClick={onPress}>
510
+ <CloseIcon />
511
+ </button>
512
+ );
513
+ }
514
+
515
+ function Body({children}: ContainerProps): ReactNode {
516
+ return <div className="rtk-body">{children}</div>;
517
+ }
518
+
519
+ /** A heading by role rather than an `<h2>`: global heading styles (resets, typography) do not reach it. */
520
+ function Title({id, children}: TextPartProps): ReactNode {
521
+ return (
522
+ <div id={id} role="heading" aria-level={2} className="rtk-title">
523
+ {children}
524
+ </div>
525
+ );
526
+ }
527
+
528
+ function Content({id, children}: TextPartProps): ReactNode {
529
+ return (
530
+ <div id={id} className="rtk-content">
531
+ {children}
532
+ </div>
533
+ );
534
+ }
535
+
536
+ function Footer({children}: ContainerProps): ReactNode {
537
+ return <div className="rtk-footer">{children}</div>;
538
+ }
539
+
540
+ function Button({kind, label, isDisabled, onPress}: ButtonProps): ReactNode {
541
+ return (
542
+ <button
543
+ type="button"
544
+ className={kind === 'next' ? 'rtk-button rtk-button--next' : 'rtk-button rtk-button--prev'}
545
+ disabled={isDisabled}
546
+ onClick={onPress}
547
+ >
548
+ {label}
549
+ </button>
550
+ );
551
+ }
552
+
553
+ function Dots({label, children}: DotsProps): ReactNode {
554
+ return (
555
+ <div className="rtk-dots" role="group" aria-label={label}>
556
+ {children}
557
+ </div>
558
+ );
559
+ }
560
+
561
+ function Dot({label, isCurrent, onPress}: DotProps): ReactNode {
562
+ return (
563
+ <button
564
+ type="button"
565
+ className="rtk-dot"
566
+ aria-label={label}
567
+ aria-current={isCurrent ? 'step' : undefined}
568
+ onClick={onPress}
569
+ />
570
+ );
571
+ }
572
+
573
+ function Ellipsis(): ReactNode {
574
+ return <span aria-hidden="true" className="rtk-ellipsis" />;
575
+ }
576
+
577
+ const card: CardParts = {
578
+ Card,
579
+ Arrow,
580
+ Header,
581
+ Counter,
582
+ CloseButton,
583
+ Body,
584
+ Title,
585
+ Content,
586
+ Footer,
587
+ Button,
588
+ Dots,
589
+ Dot,
590
+ Ellipsis,
591
+ };
592
+
593
+ /** How the web draws the tour. */
594
+ export const webRenderer: TourRenderer = {Layer, Backdrop, Spotlight, TooltipFrame, MeasureFrame, card};
@@ -0,0 +1,44 @@
1
+ import {type ReactNode, useEffect, useState} from 'react';
2
+ import {createPortal} from 'react-dom';
3
+ import {TourRoot} from '../shared/react/tour-root.js';
4
+ import {type TourProviderBaseProps, useTourCore} from '../shared/react/tour-provider-core.js';
5
+ import {useIsomorphicLayoutEffect} from '../shared/react/use-isomorphic-layout-effect.hook.js';
6
+ import {TourOverlay, type TourOverlayProps} from '../shared/renderer/tour-overlay.js';
7
+ import {acquireSafeAreaProbe} from './dom/viewport.util.js';
8
+ import {createWebPlatform, type WebPlatform} from './dom/web-platform.js';
9
+ import {webRenderer} from './layer/web-renderer.js';
10
+
11
+ export type TourProviderProps = TourProviderBaseProps;
12
+
13
+ /**
14
+ * Provides `useTour()` to its children and renders the tour. Place it around your app, inside
15
+ * your router if steps navigate between pages.
16
+ */
17
+ export function TourProvider(props: TourProviderProps): ReactNode {
18
+ const [platform] = useState(createWebPlatform);
19
+ const {engine, overlay} = useTourCore(props, platform, webRenderer);
20
+ useEffect(() => acquireSafeAreaProbe(), []);
21
+ return (
22
+ <TourRoot engine={engine}>
23
+ {props.children}
24
+ <WebMount platform={platform} overlay={overlay} />
25
+ </TourRoot>
26
+ );
27
+ }
28
+
29
+ /** Draws the tour into its own element at the end of `<body>`, on the client only (after hydration). */
30
+ function WebMount({
31
+ platform,
32
+ overlay,
33
+ }: {
34
+ readonly platform: WebPlatform;
35
+ readonly overlay: TourOverlayProps;
36
+ }): ReactNode {
37
+ const [container, setContainer] = useState<HTMLElement | undefined>(undefined);
38
+ useIsomorphicLayoutEffect(() => {
39
+ const host = platform.mountHost();
40
+ setContainer(host.container);
41
+ return host.unmount;
42
+ }, [platform]);
43
+ return container ? createPortal(<TourOverlay {...overlay} />, container) : null;
44
+ }
package/src/react.ts ADDED
@@ -0,0 +1,13 @@
1
+ 'use client';
2
+
3
+ // Web entry point: import from '@robertlinde/react-tour-kit/react'.
4
+
5
+ export {TourProvider, type TourProviderProps} from './react-platform/tour-provider.js';
6
+ export {useTour} from './shared/react/use-tour.hook.js';
7
+ export {getTruncatedDots, type DotItem} from './shared/utils/get-truncated-dots.util.js';
8
+ export type {TourContextType} from './shared/types/tour-context.type.js';
9
+ export type {StartTourOptions, TourEndCallback, TourEndInfo, TourEndReason} from './shared/types/tour-end-info.type.js';
10
+ export type {TourI18n} from './shared/types/tour-i18n.type.js';
11
+ export type {TourPlacement, TourStep, TourStepContext, TourTarget} from './shared/types/tour-step.type.js';
12
+ export type {TourTheme} from './shared/types/tour-theme.type.js';
13
+ export type {TourTooltipProps} from './shared/types/tour-tooltip-props.type.js';