soseki 0.0.5 → 0.0.7

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 (352) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/components/browser-router.d.ts +19 -0
  3. package/dist/src/components/browser-router.d.ts.map +1 -0
  4. package/dist/src/components/browser-router.jsx +15 -0
  5. package/dist/src/components/outlet.d.ts +8 -0
  6. package/dist/src/components/outlet.d.ts.map +1 -0
  7. package/dist/src/components/outlet.jsx +15 -0
  8. package/dist/src/components/router.d.ts +21 -0
  9. package/dist/src/components/router.d.ts.map +1 -0
  10. package/dist/src/components/router.jsx +138 -0
  11. package/dist/src/contexts/route-context.d.ts +19 -0
  12. package/dist/src/contexts/route-context.d.ts.map +1 -0
  13. package/dist/src/contexts/route-context.js +6 -0
  14. package/dist/src/contexts/router-context.d.ts +55 -0
  15. package/dist/src/contexts/router-context.d.ts.map +1 -0
  16. package/dist/src/contexts/router-context.js +8 -0
  17. package/dist/src/core/_compare-route-paths.d.ts +11 -0
  18. package/dist/src/core/_compare-route-paths.d.ts.map +1 -0
  19. package/dist/src/core/_compare-route-paths.js +92 -0
  20. package/dist/src/core/_match-route-path.d.ts +22 -0
  21. package/dist/src/core/_match-route-path.d.ts.map +1 -0
  22. package/dist/src/core/_match-route-path.js +26 -0
  23. package/dist/src/core/_process-routes.d.ts +14 -0
  24. package/dist/src/core/_process-routes.d.ts.map +1 -0
  25. package/dist/src/core/_process-routes.js +45 -0
  26. package/dist/src/core/_singleton.d.ts +12 -0
  27. package/dist/src/core/_singleton.d.ts.map +1 -0
  28. package/dist/src/core/_singleton.js +18 -0
  29. package/dist/src/core/_unreachable.d.ts +16 -0
  30. package/dist/src/core/_unreachable.d.ts.map +1 -0
  31. package/dist/src/core/_unreachable.js +8 -0
  32. package/dist/src/core/_valibot.d.ts +25 -0
  33. package/dist/src/core/_valibot.d.ts.map +1 -0
  34. package/dist/src/core/_valibot.js +30 -0
  35. package/dist/src/core/errors.d.ts +182 -0
  36. package/dist/src/core/errors.d.ts.map +1 -0
  37. package/dist/src/core/errors.js +166 -0
  38. package/dist/src/core/expect-history-entry.d.ts +59 -0
  39. package/dist/src/core/expect-history-entry.d.ts.map +1 -0
  40. package/dist/src/core/expect-history-entry.js +42 -0
  41. package/dist/src/core/form-data-to-html-form-element.d.ts +11 -0
  42. package/dist/src/core/form-data-to-html-form-element.d.ts.map +1 -0
  43. package/dist/src/core/form-data-to-html-form-element.js +31 -0
  44. package/dist/src/core/history-entry-id-schema.d.ts +17 -0
  45. package/dist/src/core/history-entry-id-schema.d.ts.map +1 -0
  46. package/dist/src/core/history-entry-id-schema.js +9 -0
  47. package/dist/src/core/history-entry-url-schema.d.ts +18 -0
  48. package/dist/src/core/history-entry-url-schema.d.ts.map +1 -0
  49. package/dist/src/core/history-entry-url-schema.js +20 -0
  50. package/dist/src/core/init-loaders.d.ts +28 -0
  51. package/dist/src/core/init-loaders.d.ts.map +1 -0
  52. package/dist/src/core/init-loaders.js +30 -0
  53. package/dist/src/core/match-routes.d.ts +28 -0
  54. package/dist/src/core/match-routes.d.ts.map +1 -0
  55. package/dist/src/core/match-routes.js +31 -0
  56. package/dist/src/core/readonly-form-data.types.d.ts +74 -0
  57. package/dist/src/core/readonly-form-data.types.d.ts.map +1 -0
  58. package/dist/src/core/readonly-url.types.d.ts +164 -0
  59. package/dist/src/core/readonly-url.types.d.ts.map +1 -0
  60. package/dist/src/core/redirect-response.d.ts +37 -0
  61. package/dist/src/core/redirect-response.d.ts.map +1 -0
  62. package/dist/src/core/redirect-response.js +19 -0
  63. package/dist/src/core/route-path.d.ts +57 -0
  64. package/dist/src/core/route-path.d.ts.map +1 -0
  65. package/dist/src/core/route-path.js +93 -0
  66. package/dist/src/core/route-request.d.ts +149 -0
  67. package/dist/src/core/route-request.d.ts.map +1 -0
  68. package/dist/src/core/route-request.js +41 -0
  69. package/dist/src/core/route.types.d.ts +296 -0
  70. package/dist/src/core/route.types.d.ts.map +1 -0
  71. package/dist/src/core/start-action.d.ts +53 -0
  72. package/dist/src/core/start-action.d.ts.map +1 -0
  73. package/dist/src/core/start-action.js +95 -0
  74. package/dist/src/core/start-loaders.d.ts +63 -0
  75. package/dist/src/core/start-loaders.d.ts.map +1 -0
  76. package/dist/src/core/start-loaders.js +138 -0
  77. package/dist/{core.d.ts → src/core.d.ts} +7 -11
  78. package/dist/src/core.d.ts.map +1 -0
  79. package/dist/{core.js → src/core.js} +2 -4
  80. package/dist/src/engines/engine.types.d.ts +216 -0
  81. package/dist/src/engines/engine.types.d.ts.map +1 -0
  82. package/dist/src/engines/navigation-api-engine.d.ts +50 -0
  83. package/dist/src/engines/navigation-api-engine.d.ts.map +1 -0
  84. package/dist/src/engines/navigation-api-engine.js +411 -0
  85. package/dist/src/engines.d.ts +4 -0
  86. package/dist/src/engines.d.ts.map +1 -0
  87. package/dist/src/engines.js +1 -0
  88. package/dist/src/hooks/_use-singleton.d.ts +11 -0
  89. package/dist/src/hooks/_use-singleton.d.ts.map +1 -0
  90. package/dist/src/hooks/_use-singleton.js +26 -0
  91. package/dist/src/hooks/use-action-data.d.ts +17 -0
  92. package/dist/src/hooks/use-action-data.d.ts.map +1 -0
  93. package/dist/src/hooks/use-action-data.js +16 -0
  94. package/dist/src/hooks/use-form-action.d.ts +7 -0
  95. package/dist/src/hooks/use-form-action.d.ts.map +1 -0
  96. package/dist/src/hooks/use-form-action.js +9 -0
  97. package/dist/src/hooks/use-loader-data.d.ts +9 -0
  98. package/dist/src/hooks/use-loader-data.d.ts.map +1 -0
  99. package/dist/src/hooks/use-loader-data.js +20 -0
  100. package/dist/src/hooks/use-navigate.d.ts +53 -0
  101. package/dist/src/hooks/use-navigate.d.ts.map +1 -0
  102. package/dist/src/hooks/use-navigate.js +43 -0
  103. package/dist/{hooks → src/hooks}/use-params.d.ts +2 -2
  104. package/dist/src/hooks/use-params.d.ts.map +1 -0
  105. package/dist/{hooks → src/hooks}/use-params.js +1 -1
  106. package/dist/src/hooks/use-route-context.d.ts +10 -0
  107. package/dist/src/hooks/use-route-context.d.ts.map +1 -0
  108. package/dist/src/hooks/use-route-context.js +17 -0
  109. package/dist/src/hooks/use-router-context.d.ts +12 -0
  110. package/dist/src/hooks/use-router-context.d.ts.map +1 -0
  111. package/dist/src/hooks/use-router-context.js +20 -0
  112. package/dist/src/hooks/use-submit.d.ts +59 -0
  113. package/dist/src/hooks/use-submit.d.ts.map +1 -0
  114. package/dist/src/hooks/use-submit.js +38 -0
  115. package/dist/src/soseki.d.ts +31 -0
  116. package/dist/src/soseki.d.ts.map +1 -0
  117. package/dist/src/soseki.js +12 -0
  118. package/dist/src/utils/redirect.d.ts +11 -0
  119. package/dist/src/utils/redirect.d.ts.map +1 -0
  120. package/dist/src/utils/redirect.js +12 -0
  121. package/package.json +47 -40
  122. package/src/components/browser-router.tsx +8 -11
  123. package/src/components/outlet.tsx +3 -2
  124. package/src/components/router.tsx +139 -145
  125. package/src/contexts/route-context.ts +6 -5
  126. package/src/contexts/router-context.ts +36 -19
  127. package/src/core/_compare-route-paths.ts +48 -34
  128. package/src/core/_match-route-path.ts +21 -15
  129. package/src/core/_process-routes.ts +44 -46
  130. package/src/core/_singleton.ts +13 -38
  131. package/src/core/_unreachable.ts +12 -7
  132. package/src/core/_valibot.ts +19 -116
  133. package/src/core/errors.ts +150 -495
  134. package/src/core/expect-history-entry.ts +40 -41
  135. package/src/core/form-data-to-html-form-element.ts +37 -0
  136. package/src/core/history-entry-id-schema.ts +6 -11
  137. package/src/core/history-entry-url-schema.ts +25 -18
  138. package/src/core/init-loaders.ts +35 -57
  139. package/src/core/match-routes.ts +33 -65
  140. package/src/core/readonly-form-data.types.ts +48 -28
  141. package/src/core/readonly-url.types.ts +57 -28
  142. package/src/core/redirect-response.ts +26 -15
  143. package/src/core/route-path.ts +114 -0
  144. package/src/core/route-request.ts +144 -32
  145. package/src/core/route.types.ts +250 -226
  146. package/src/core/start-action.ts +164 -0
  147. package/src/core/start-loaders.ts +190 -212
  148. package/src/core.ts +8 -15
  149. package/src/engines/engine.types.ts +204 -166
  150. package/src/engines/navigation-api-engine.ts +332 -233
  151. package/src/engines.ts +4 -0
  152. package/src/hooks/_use-singleton.ts +30 -0
  153. package/src/hooks/use-action-data.ts +21 -26
  154. package/src/hooks/use-form-action.ts +4 -5
  155. package/src/hooks/use-loader-data.ts +16 -18
  156. package/src/hooks/use-navigate.ts +69 -28
  157. package/src/hooks/use-params.ts +4 -4
  158. package/src/hooks/use-route-context.ts +20 -0
  159. package/src/hooks/use-router-context.ts +25 -0
  160. package/src/hooks/use-submit.ts +48 -53
  161. package/src/soseki.ts +27 -34
  162. package/src/utils/redirect.ts +5 -5
  163. package/dist/components/action-id.d.ts +0 -19
  164. package/dist/components/action-id.d.ts.map +0 -1
  165. package/dist/components/action-id.jsx +0 -14
  166. package/dist/components/browser-router.d.ts +0 -17
  167. package/dist/components/browser-router.d.ts.map +0 -1
  168. package/dist/components/browser-router.jsx +0 -13
  169. package/dist/components/hidden-input.d.ts +0 -20
  170. package/dist/components/hidden-input.d.ts.map +0 -1
  171. package/dist/components/hidden-input.jsx +0 -8
  172. package/dist/components/outlet.d.ts +0 -8
  173. package/dist/components/outlet.d.ts.map +0 -1
  174. package/dist/components/outlet.jsx +0 -15
  175. package/dist/components/router.d.ts +0 -23
  176. package/dist/components/router.d.ts.map +0 -1
  177. package/dist/components/router.jsx +0 -128
  178. package/dist/contexts/route-context.d.ts +0 -19
  179. package/dist/contexts/route-context.d.ts.map +0 -1
  180. package/dist/contexts/route-context.js +0 -6
  181. package/dist/contexts/router-context.d.ts +0 -46
  182. package/dist/contexts/router-context.d.ts.map +0 -1
  183. package/dist/contexts/router-context.js +0 -8
  184. package/dist/core/_action-id-registry.d.ts +0 -10
  185. package/dist/core/_action-id-registry.d.ts.map +0 -1
  186. package/dist/core/_action-id-registry.js +0 -8
  187. package/dist/core/_capture-stack-trace.d.ts +0 -8
  188. package/dist/core/_capture-stack-trace.d.ts.map +0 -1
  189. package/dist/core/_capture-stack-trace.js +0 -12
  190. package/dist/core/_compare-route-paths.d.ts +0 -11
  191. package/dist/core/_compare-route-paths.d.ts.map +0 -1
  192. package/dist/core/_compare-route-paths.js +0 -80
  193. package/dist/core/_create-html-form-element-form-form-data.d.ts +0 -9
  194. package/dist/core/_create-html-form-element-form-form-data.d.ts.map +0 -1
  195. package/dist/core/_create-html-form-element-form-form-data.js +0 -27
  196. package/dist/core/_encode-pathname.d.ts +0 -10
  197. package/dist/core/_encode-pathname.d.ts.map +0 -1
  198. package/dist/core/_encode-pathname.js +0 -16
  199. package/dist/core/_is-error.d.ts +0 -3
  200. package/dist/core/_is-error.d.ts.map +0 -1
  201. package/dist/core/_is-error.js +0 -13
  202. package/dist/core/_is-promise-like.d.ts +0 -8
  203. package/dist/core/_is-promise-like.d.ts.map +0 -1
  204. package/dist/core/_is-promise-like.js +0 -12
  205. package/dist/core/_match-route-path.d.ts +0 -19
  206. package/dist/core/_match-route-path.d.ts.map +0 -1
  207. package/dist/core/_match-route-path.js +0 -22
  208. package/dist/core/_process-routes.d.ts +0 -9
  209. package/dist/core/_process-routes.d.ts.map +0 -1
  210. package/dist/core/_process-routes.js +0 -47
  211. package/dist/core/_singleton.d.ts +0 -18
  212. package/dist/core/_singleton.d.ts.map +0 -1
  213. package/dist/core/_singleton.js +0 -37
  214. package/dist/core/_unreachable.d.ts +0 -12
  215. package/dist/core/_unreachable.d.ts.map +0 -1
  216. package/dist/core/_unreachable.js +0 -8
  217. package/dist/core/_use-singleton.d.ts +0 -11
  218. package/dist/core/_use-singleton.d.ts.map +0 -1
  219. package/dist/core/_use-singleton.js +0 -21
  220. package/dist/core/_valibot.d.ts +0 -52
  221. package/dist/core/_valibot.d.ts.map +0 -1
  222. package/dist/core/_valibot.js +0 -107
  223. package/dist/core/_weak-id-registry.d.ts +0 -76
  224. package/dist/core/_weak-id-registry.d.ts.map +0 -1
  225. package/dist/core/_weak-id-registry.js +0 -67
  226. package/dist/core/constants.d.ts +0 -5
  227. package/dist/core/constants.d.ts.map +0 -1
  228. package/dist/core/constants.js +0 -4
  229. package/dist/core/data-map.types.d.ts +0 -23
  230. package/dist/core/data-map.types.d.ts.map +0 -1
  231. package/dist/core/data-map.types.js +0 -1
  232. package/dist/core/data-store.types.d.ts +0 -22
  233. package/dist/core/data-store.types.d.ts.map +0 -1
  234. package/dist/core/data-store.types.js +0 -1
  235. package/dist/core/deferred-promise.d.ts +0 -203
  236. package/dist/core/deferred-promise.d.ts.map +0 -1
  237. package/dist/core/deferred-promise.js +0 -200
  238. package/dist/core/errors.d.ts +0 -303
  239. package/dist/core/errors.d.ts.map +0 -1
  240. package/dist/core/errors.js +0 -400
  241. package/dist/core/expect-history-entry.d.ts +0 -52
  242. package/dist/core/expect-history-entry.d.ts.map +0 -1
  243. package/dist/core/expect-history-entry.js +0 -38
  244. package/dist/core/history-entry-id-schema.d.ts +0 -17
  245. package/dist/core/history-entry-id-schema.d.ts.map +0 -1
  246. package/dist/core/history-entry-id-schema.js +0 -9
  247. package/dist/core/history-entry-url-schema.d.ts +0 -20
  248. package/dist/core/history-entry-url-schema.d.ts.map +0 -1
  249. package/dist/core/history-entry-url-schema.js +0 -16
  250. package/dist/core/init-loaders.d.ts +0 -37
  251. package/dist/core/init-loaders.d.ts.map +0 -1
  252. package/dist/core/init-loaders.js +0 -38
  253. package/dist/core/match-routes.d.ts +0 -31
  254. package/dist/core/match-routes.d.ts.map +0 -1
  255. package/dist/core/match-routes.js +0 -54
  256. package/dist/core/readonly-form-data.types.d.ts +0 -32
  257. package/dist/core/readonly-form-data.types.d.ts.map +0 -1
  258. package/dist/core/readonly-url.types.d.ts +0 -135
  259. package/dist/core/readonly-url.types.d.ts.map +0 -1
  260. package/dist/core/redirect-response.d.ts +0 -29
  261. package/dist/core/redirect-response.d.ts.map +0 -1
  262. package/dist/core/redirect-response.js +0 -17
  263. package/dist/core/route-request.d.ts +0 -52
  264. package/dist/core/route-request.d.ts.map +0 -1
  265. package/dist/core/route-request.js +0 -26
  266. package/dist/core/route.types.d.ts +0 -309
  267. package/dist/core/route.types.d.ts.map +0 -1
  268. package/dist/core/start-actions.d.ts +0 -60
  269. package/dist/core/start-actions.d.ts.map +0 -1
  270. package/dist/core/start-actions.js +0 -186
  271. package/dist/core/start-loaders.d.ts +0 -69
  272. package/dist/core/start-loaders.d.ts.map +0 -1
  273. package/dist/core/start-loaders.js +0 -154
  274. package/dist/core.d.ts.map +0 -1
  275. package/dist/engines/engine.types.d.ts +0 -190
  276. package/dist/engines/engine.types.d.ts.map +0 -1
  277. package/dist/engines/navigation-api-engine.d.ts +0 -48
  278. package/dist/engines/navigation-api-engine.d.ts.map +0 -1
  279. package/dist/engines/navigation-api-engine.js +0 -332
  280. package/dist/hooks/_use-route-context.d.ts +0 -10
  281. package/dist/hooks/_use-route-context.d.ts.map +0 -1
  282. package/dist/hooks/_use-route-context.js +0 -17
  283. package/dist/hooks/_use-router-context.d.ts +0 -10
  284. package/dist/hooks/_use-router-context.d.ts.map +0 -1
  285. package/dist/hooks/_use-router-context.js +0 -18
  286. package/dist/hooks/use-action-data.d.ts +0 -23
  287. package/dist/hooks/use-action-data.d.ts.map +0 -1
  288. package/dist/hooks/use-action-data.js +0 -16
  289. package/dist/hooks/use-form-action.d.ts +0 -7
  290. package/dist/hooks/use-form-action.d.ts.map +0 -1
  291. package/dist/hooks/use-form-action.js +0 -10
  292. package/dist/hooks/use-loader-data.d.ts +0 -11
  293. package/dist/hooks/use-loader-data.d.ts.map +0 -1
  294. package/dist/hooks/use-loader-data.js +0 -19
  295. package/dist/hooks/use-navigate.d.ts +0 -39
  296. package/dist/hooks/use-navigate.d.ts.map +0 -1
  297. package/dist/hooks/use-navigate.js +0 -26
  298. package/dist/hooks/use-params.d.ts.map +0 -1
  299. package/dist/hooks/use-pathname.d.ts +0 -7
  300. package/dist/hooks/use-pathname.d.ts.map +0 -1
  301. package/dist/hooks/use-pathname.js +0 -9
  302. package/dist/hooks/use-submit.d.ts +0 -66
  303. package/dist/hooks/use-submit.d.ts.map +0 -1
  304. package/dist/hooks/use-submit.js +0 -35
  305. package/dist/soseki.d.ts +0 -42
  306. package/dist/soseki.d.ts.map +0 -1
  307. package/dist/soseki.js +0 -19
  308. package/dist/utils/get-action-id.d.ts +0 -8
  309. package/dist/utils/get-action-id.d.ts.map +0 -1
  310. package/dist/utils/get-action-id.js +0 -11
  311. package/dist/utils/href.d.ts +0 -11
  312. package/dist/utils/href.d.ts.map +0 -1
  313. package/dist/utils/href.js +0 -12
  314. package/dist/utils/redirect.d.ts +0 -11
  315. package/dist/utils/redirect.d.ts.map +0 -1
  316. package/dist/utils/redirect.js +0 -12
  317. package/dist/utils/route-index.d.ts +0 -41
  318. package/dist/utils/route-index.d.ts.map +0 -1
  319. package/dist/utils/route-index.js +0 -12
  320. package/dist/utils/route-route.d.ts +0 -62
  321. package/dist/utils/route-route.d.ts.map +0 -1
  322. package/dist/utils/route-route.js +0 -25
  323. package/dist/utils/set-action-id.d.ts +0 -9
  324. package/dist/utils/set-action-id.d.ts.map +0 -1
  325. package/dist/utils/set-action-id.js +0 -12
  326. package/src/components/action-id.tsx +0 -35
  327. package/src/components/hidden-input.tsx +0 -39
  328. package/src/core/_action-id-registry.ts +0 -11
  329. package/src/core/_capture-stack-trace.ts +0 -12
  330. package/src/core/_create-html-form-element-form-form-data.ts +0 -32
  331. package/src/core/_encode-pathname.ts +0 -17
  332. package/src/core/_is-error.ts +0 -16
  333. package/src/core/_is-promise-like.ts +0 -14
  334. package/src/core/_use-singleton.ts +0 -24
  335. package/src/core/_weak-id-registry.ts +0 -125
  336. package/src/core/constants.ts +0 -4
  337. package/src/core/data-map.types.ts +0 -28
  338. package/src/core/data-store.types.ts +0 -25
  339. package/src/core/deferred-promise.ts +0 -408
  340. package/src/core/start-actions.ts +0 -274
  341. package/src/hooks/_use-route-context.ts +0 -19
  342. package/src/hooks/_use-router-context.ts +0 -25
  343. package/src/hooks/use-pathname.ts +0 -10
  344. package/src/utils/get-action-id.ts +0 -12
  345. package/src/utils/href.ts +0 -17
  346. package/src/utils/route-index.ts +0 -70
  347. package/src/utils/route-route.ts +0 -111
  348. package/src/utils/set-action-id.ts +0 -14
  349. /package/dist/{core → src/core}/readonly-form-data.types.js +0 -0
  350. /package/dist/{core → src/core}/readonly-url.types.js +0 -0
  351. /package/dist/{core → src/core}/route.types.js +0 -0
  352. /package/dist/{engines → src/engines}/engine.types.js +0 -0
@@ -1,233 +1,227 @@
1
+ import type { NinjaPromise } from "ninja-promise";
1
2
  import * as React from "react";
3
+
2
4
  import RouteContext from "../contexts/route-context.js";
3
5
  import RouterContext, {
4
- type RouterContextValue,
5
6
  type RouterRef,
7
+ type RouterContextValue,
6
8
  } from "../contexts/router-context.js";
7
9
  import processRoutes from "../core/_process-routes.js";
8
- import type { IDataStore } from "../core/data-store.types.js";
9
10
  import type { HistoryEntry } from "../core/expect-history-entry.js";
11
+ import type { HistoryEntryId } from "../core/history-entry-id-schema.js";
10
12
  import type { MatchedRoute } from "../core/match-routes.js";
11
- import type { IAction, ILoader, RouteDefinition } from "../core/route.types.js";
12
- import type { IEngine, RouterState, SubmitArgs } from "../engines/engine.types.js";
13
- import type { NavigateArgs } from "../engines/engine.types.js";
13
+ import type { ActionFunction, LoaderFunction, RouteDefinition } from "../core/route.types.js";
14
+ import type { IEngine, RouterState } from "../engines/engine.types.js";
14
15
 
15
16
  /**
16
- * ComponentRenderer コンポーネントに渡されるプロパティーの型定義です。
17
+ * `ComponentRenderer` コンポーネントに渡されるプロパティーの型定義です。
17
18
  */
18
19
  type ComponentRendererProps = {
19
20
  /**
20
- * 現在のコンテキストでレンダリングされる、マッチしたルート情報です。
21
+ * レンダリング対象となる、マッチした単一のルート情報です。
21
22
  */
22
23
  route: MatchedRoute;
23
24
 
24
25
  /**
25
- * ネストされた下位のルート要素です。存在しない場合は null を指定します。
26
+ * このルートの配下に描画されるべき子コンポーネントの要素です。
26
27
  */
27
28
  outlet: React.ReactElement<RouteRendererProps, typeof RouteRenderer> | null;
28
29
  };
29
30
 
30
31
  /**
31
- * 個別のルートコンポーネントをレンダリングし、ルートコンテキストを提供する内部コンポーネントです。
32
+ * マッチした個々のルートコンポーネントを、固有の `RouteContext` で包み込みながら再帰的にマウント・展開していくための内部レンダラーコンポーネントです。
32
33
  */
33
34
  function ComponentRenderer(props: ComponentRendererProps): React.JSX.Element | null {
34
- const {
35
- route: {
36
- path,
37
- index,
38
- params,
39
- urlPath,
40
- component: Component,
41
- },
42
- outlet,
43
- } = props;
35
+ const parentRoute = React.use(RouteContext);
36
+ const { route, outlet } = props;
44
37
  const context = {
45
- path,
46
- index,
47
- params,
38
+ ...route,
48
39
  outlet,
49
- urlPath,
40
+ // 親ルートのアクションとローダーを引き継ぐことで、`useActionData` と `useLoaderData` がデータを参照できようにします。
41
+ action: route.action ?? parentRoute?.action,
42
+ loader: route.loader ?? parentRoute?.loader,
50
43
  };
44
+ const Comp = route.component;
51
45
 
52
46
  return (
53
- <RouteContext value={context}>
54
- {Component ? <Component /> : outlet}
55
- </RouteContext>
47
+ <RouteContext value={context}>{typeof Comp === "function" ? <Comp /> : outlet}</RouteContext>
56
48
  );
57
49
  }
58
50
 
59
51
  /**
60
- * マッチしたルートを再帰的にレンダリングするためのプロパティーです。
52
+ * `RouteRenderer` コンポーネントに渡されるプロパティーの型定義です。
61
53
  */
62
54
  type RouteRendererProps = {
63
55
  /**
64
- * 現在のパスにマッチしたルートの配列です。
56
+ * マッチしたルートの階層配列です。
65
57
  */
66
58
  routes: readonly MatchedRoute[];
67
59
 
68
60
  /**
69
- * 現在レンダリング対象となっているルートのインデックス番号です。
61
+ * 現在処理しているルート配列のインデックス(深さ)です。
70
62
  */
71
63
  index?: number;
72
64
  };
73
65
 
74
66
  /**
75
- * マッチしたルートの階層を順番にレンダリングする内部コンポーネントです。
67
+ * マッチしたルート配列を親から子の順番へと正しく巡回し、各階層を入れ子状の React エレメントツリーへと再帰的にビルドするコンポーネントです。
76
68
  */
77
69
  function RouteRenderer(props: RouteRendererProps): React.ReactElement {
78
- const {
79
- index = 0,
80
- routes,
81
- } = props;
70
+ const { index = 0, routes } = props;
82
71
  const route = routes[index]!;
83
- const outlet = index < routes.length - 1
84
- ? <RouteRenderer routes={routes} index={index + 1} />
85
- : null;
86
72
 
87
- return (
88
- <ComponentRenderer
89
- route={route}
90
- outlet={outlet}
91
- />
92
- );
73
+ // 配列の終端に達していない場合はインデックスを 1 進めて自身を再帰的に呼び出し、ネストされる子要素を生成します。
74
+ const outlet =
75
+ index < routes.length - 1 ? <RouteRenderer routes={routes} index={index + 1} /> : null;
76
+
77
+ return <ComponentRenderer route={route} outlet={outlet} />;
93
78
  }
94
79
 
95
80
  /**
96
- * Router コンポーネントに渡されるプロパティーの型定義です。
81
+ * `Router` コンポーネントに渡されるルートプロパティーの型定義です。
97
82
  */
98
83
  export type RouterProps = {
99
84
  /**
100
- * ルーティングのロジックを制御するエンジンインスタンスです。
85
+ * プラグイン形式で差し込まれる、ルーティングの実装です。
101
86
  */
102
87
  engine: IEngine;
103
88
 
104
89
  /**
105
- * アプリケーションのルート定義の配列です。
90
+ * ユーザーがアプリケーションに定義したルート定義の配列です。
106
91
  */
107
92
  routes: readonly RouteDefinition[];
108
93
  };
109
94
 
110
95
  /**
111
- * ルーティング機能を提供するメインのコンポーネントです。
112
- *
113
- * エンジンの管理、状態の同期、およびルートのレンダリングを担います。
96
+ * 宣言的なルート定義と、命令的なルーティング実行エンジンを仲介・統合し、アプリケーションの最上位でルーティングのライフサイクルと状態管理を司るプロバイダーコンポーネントです。
114
97
  */
115
98
  export default function Router(props: RouterProps) {
116
- const {
117
- engine,
118
- routes: routesProp,
119
- } = props;
120
- const routerRef = React.useRef({} as {
121
- submit(args: SubmitArgs): void;
122
- navigate(args: NavigateArgs): void;
123
- currentEntry: HistoryEntry;
124
- actionDataStore: IDataStore<IAction>;
125
- loaderDataStore: IDataStore<ILoader>;
126
- });
99
+ const { engine, routes: routesProp } = props;
100
+
101
+ // レンダリングを跨いで常に同一参照を維持し、かつ子コンポーネントから不要な再レンダリングなしでメソッドを叩けるように、ルーターコアの外部参照実体を useRef で永続管理します。
102
+ const routerRef = React.useRef(
103
+ {} as {
104
+ submit(args: IEngine.SubmitArgs): void;
105
+ navigate(args: IEngine.NavigateArgs): void;
106
+ currentEntry: HistoryEntry;
107
+ actionDataStore: Map<HistoryEntryId, Map<ActionFunction, NinjaPromise<unknown>>>;
108
+ loaderDataStore: Map<HistoryEntryId, Map<LoaderFunction, NinjaPromise<unknown>>>;
109
+ },
110
+ );
111
+
112
+ // エンジン、ストア、イベント購読メカニズムのセットアップを一元化し、useMemo でインスタンス化します。
127
113
  const router = React.useMemo<{
128
- start(): () => void;
129
- context: RouterContextValue;
130
- getRoutes(): readonly MatchedRoute[] | undefined;
131
- }>(
132
- () => {
133
- const actionDataStore: IDataStore<IAction> = new Map();
134
- const loaderDataStore: IDataStore<ILoader> = new Map();
135
- const subscribers = new Set<() => void>();
136
- const routes = processRoutes(routesProp);
137
- let ac: AbortController | null = null;
138
-
139
- function getAbortSignal(): AbortSignal {
140
- return (ac ||= new AbortController()).signal;
114
+ readonly start: () => () => void;
115
+ readonly context: RouterContextValue;
116
+ readonly getRoutes: () => readonly MatchedRoute[] | undefined;
117
+ }>(() => {
118
+ const actionDataStore = new Map<HistoryEntryId, Map<ActionFunction, NinjaPromise<unknown>>>();
119
+ const loaderDataStore = new Map<HistoryEntryId, Map<LoaderFunction, NinjaPromise<unknown>>>();
120
+ const subscribers = new Set<() => void>();
121
+ const routes = processRoutes(routesProp);
122
+ let ac: AbortController | null = null;
123
+
124
+ /**
125
+ * 現在のフェーズで有効な、シングルトン構造の中断シグナルをオンデマンドで生成・回収します。
126
+ */
127
+ function getAbortSignal(): AbortSignal {
128
+ return (ac ||= new AbortController()).signal;
129
+ }
130
+
131
+ // エンジンを初期化し、初期ロード時のマッチングルートおよび解決済みのデータマップを取得・登録します。
132
+ const initialState = engine.init({
133
+ routes,
134
+ getSignal: getAbortSignal,
135
+ loaderDataStore,
136
+ });
137
+ let currentRoutes = initialState?.routes;
138
+
139
+ /**
140
+ * エンジン内部での遷移確定時に、状態を React 側へ通知・マージするための状態更新関数です。
141
+ */
142
+ function updateRouter(newState?: RouterState | null) {
143
+ if (newState !== undefined) {
144
+ currentRoutes = newState?.routes;
141
145
  }
142
-
143
- const initialState = engine.init({
144
- routes,
145
- getSignal: getAbortSignal,
146
- loaderDataStore,
147
- });
148
- let currentRoutes = initialState?.routes;
149
-
150
- function updateRouter(newState?: RouterState | null) {
151
- if (newState !== undefined) {
152
- currentRoutes = newState?.routes;
153
- }
154
- if (newState) {
155
- routerRef.current.currentEntry = newState.entry;
156
- }
157
-
158
- // 登録されているすべてのサブスクライバーに通知します。
159
- subscribers.forEach(notify => notify());
146
+ if (newState) {
147
+ routerRef.current.currentEntry = newState.entry;
160
148
  }
161
149
 
162
- function startRouterEngine() {
163
- const stop = engine.start({
164
- routes,
165
- update: updateRouter,
166
- getSignal: getAbortSignal,
167
- actionDataStore,
168
- loaderDataStore,
169
- });
170
-
171
- return function stopRouterEngine() {
172
- try {
173
- // エンジンの動作を停止します。
174
- stop?.();
175
- } finally {
176
- // 進行中のすべての非同期処理を中断します。
177
- try {
178
- ac?.abort();
179
- } catch {
180
- }
181
-
182
- // 中断後は次回の呼び出しに備えてコントローラーを破棄します。
183
- ac = null;
184
- }
185
- };
186
- }
150
+ // 状態変更の発生を、React の useSyncExternalStore などのすべての購読者に一斉通知して再描画を促します。
151
+ subscribers.forEach((notify) => notify());
152
+ }
187
153
 
188
- Object.assign<RouterRef["current"], RouterRef["current"]>(routerRef.current, {
189
- submit(args) {
190
- return engine.submit(args);
191
- },
192
- navigate(args) {
193
- return engine.navigate(args);
194
- },
195
- currentEntry: initialState?.entry!,
154
+ /**
155
+ * エンジンによるイベントのリアルタイム監視を開始するトリガー関数です。
156
+ */
157
+ function startRouterEngine() {
158
+ const stop = engine.start({
159
+ routes,
160
+ update: updateRouter,
161
+ getSignal: getAbortSignal,
196
162
  actionDataStore,
197
163
  loaderDataStore,
198
164
  });
199
165
 
200
- return {
201
- start: startRouterEngine,
202
- context: {
203
- routerRef,
204
- subscribe(cb) {
205
- subscribers.add(cb);
206
- return () => {
207
- subscribers.delete(cb);
208
- };
209
- },
210
- },
211
- getRoutes() {
212
- return currentRoutes;
213
- },
166
+ return function stopRouterEngine() {
167
+ try {
168
+ if (typeof stop === "function") {
169
+ stop();
170
+ }
171
+ } finally {
172
+ try {
173
+ ac?.abort();
174
+ } catch {}
175
+ ac = null;
176
+ }
214
177
  };
215
- },
216
- [
217
- engine,
218
- routesProp,
219
- ],
220
- );
178
+ }
179
+
180
+ // 作成した各種ストアや命令型メソッドの参照を、永続化 Ref オブジェクトへと安全にマージします。
181
+ Object.assign<RouterRef["current"], RouterRef["current"]>(routerRef.current, {
182
+ submit(args) {
183
+ return engine.submit(args);
184
+ },
185
+ navigate(args) {
186
+ return engine.navigate(args);
187
+ },
188
+ currentEntry: initialState?.entry as HistoryEntry,
189
+ actionDataStore,
190
+ loaderDataStore,
191
+ });
192
+
193
+ return {
194
+ start: startRouterEngine,
195
+ context: {
196
+ routerRef,
197
+ subscribe(cb) {
198
+ subscribers.add(cb);
199
+ return () => {
200
+ subscribers.delete(cb);
201
+ };
202
+ },
203
+ },
204
+ getRoutes() {
205
+ return currentRoutes;
206
+ },
207
+ };
208
+ }, [engine, routesProp]);
221
209
 
222
- React.useEffect(router.start, [router]);
210
+ // コンポーネントのマウント時にルーターエンジンを始動させ、アンマウント時には自動的に破棄タスクを連動させます。
211
+ React.useEffect(() => router.start(), [router]);
223
212
 
213
+ // マッチしたルート階層配列をリアクティブに常時監視します。
224
214
  const routes = React.useSyncExternalStore(router.context.subscribe, router.getRoutes);
215
+
216
+ // 有効なルートマッチングがない場合は何も描画しません。
225
217
  if (!routes) {
218
+ // TODO(tai-kun): 404 Not Found ページを表示できるようにします。
226
219
  return null;
227
220
  }
228
221
 
229
222
  return (
230
223
  <RouterContext value={router.context}>
224
+ {/* マッチルート配列は詳細度の高い「子 -> 親」の順で並んでいるため、React のネストレイアウト構造(親の中に子を入れる)に適合させるために `.toReversed()` で「親 -> 子」の順に反転させてからレンダラーへ投入します。*/}
231
225
  <RouteRenderer routes={routes.toReversed()} />
232
226
  </RouterContext>
233
227
  );
@@ -1,20 +1,21 @@
1
1
  import * as React from "react";
2
+
2
3
  import type { MatchedRoute } from "../core/match-routes.js";
3
4
 
4
5
  /**
5
- * 各ルートのコンテキストで共有される値の型定義です。
6
+ * 現在のコンポーネント階層に紐づいている個別ルートのコンテキスト形状定義です。
6
7
  */
7
- export type RouteContextValue = Pick<MatchedRoute, "path" | "index" | "params" | "urlPath"> & {
8
+ export type RouteContextValue = MatchedRoute & {
8
9
  /**
9
- * 子ルートを描画するための React 要素です。
10
+ * 現在のルートの下位に位置する子ルートを表示するための React 要素です。
10
11
  *
11
- * 子ルートが存在しない場合は `null` となります。
12
+ * これ以上下位にマッチする子ルートが存在しない場合は `null` になります。
12
13
  */
13
14
  readonly outlet: React.ReactElement | null;
14
15
  };
15
16
 
16
17
  /**
17
- * 個別のルート情報やアウトレット(子ルートの挿入場所)を保持するための React コンテキストです。
18
+ * 階層的にネストされたルーターのレイアウト構造において、親ルートから子ルートへそれぞれの階層固有のルート情報伝播させるための React コンテキストです。
18
19
  */
19
20
  const RouteContext = /*#__PURE__*/ React.createContext<RouteContextValue | null>(null);
20
21
 
@@ -1,54 +1,71 @@
1
+ import type { NinjaPromise } from "ninja-promise";
1
2
  import * as React from "react";
2
- import type { IReadonlyDataStore } from "../core/data-store.types.js";
3
+
3
4
  import type { HistoryEntry } from "../core/expect-history-entry.js";
4
- import type { IAction, ILoader } from "../core/route.types.js";
5
- import type { NavigateArgs, SubmitArgs } from "../engines/engine.types.js";
5
+ import type { HistoryEntryId } from "../core/history-entry-id-schema.js";
6
+ import type { ActionFunction, LoaderFunction } from "../core/route.types.js";
7
+ import type { IEngine } from "../engines/engine.types.js";
6
8
 
9
+ /**
10
+ * ルーターの実体へのアクセスを提供する、読み取り専用の Ref オブジェクト型です。
11
+ */
7
12
  export type RouterRef = Readonly<
8
13
  React.RefObject<{
9
14
  /**
10
- * フォームデータやクエリーパラメーターを送信します。
11
- *
12
- * @param args 送信内容と送信先を含む引数です。
15
+ * フォームデータやクエリーパラメーターをルーターに送信するための関数です。
13
16
  */
14
- readonly submit: (args: SubmitArgs) => void;
17
+ readonly submit: (args: IEngine.SubmitArgs) => void;
15
18
 
16
19
  /**
17
- * 指定されたパスへ遷移します。
18
- *
19
- * @param args 遷移先と遷移オプションを含む引数です。
20
+ * URL 遷移や履歴スタックの相対移動をルーターに命令するための関数です。
20
21
  */
21
- readonly navigate: (args: NavigateArgs) => void;
22
+ readonly navigate: (args: IEngine.NavigateArgs) => void;
22
23
 
23
24
  /**
24
- * 現在の履歴エントリー情報(ID、URL、インデックスなど)です。
25
+ * 現在ブラウザー上でアクティブになっている履歴エントリーの情報です。
25
26
  */
26
27
  readonly currentEntry: HistoryEntry;
27
28
 
28
29
  /**
29
- * 履歴 ID ごとに管理されているアクションデータのマップです。
30
+ * 履歴エントリーの ID ごとにアクションの実行状態を管理するデータストアです。
30
31
  */
31
- readonly actionDataStore: IReadonlyDataStore<IAction>;
32
+ readonly actionDataStore: ReadonlyMap<
33
+ HistoryEntryId,
34
+ ReadonlyMap<ActionFunction, NinjaPromise<unknown>>
35
+ >;
32
36
 
33
37
  /**
34
- * 履歴 ID ごとに管理されているローダーデータのマップです。
38
+ * 履歴エントリーの ID ごとにローダーの実行状態を管理するデータストアです。
35
39
  */
36
- readonly loaderDataStore: IReadonlyDataStore<ILoader>;
40
+ readonly loaderDataStore: ReadonlyMap<
41
+ HistoryEntryId,
42
+ ReadonlyMap<LoaderFunction, NinjaPromise<unknown>>
43
+ >;
37
44
  }>
38
45
  >;
39
46
 
40
47
  /**
41
- * ルーターコンテキストで共有される値の型定義です。
48
+ * `RouterContext` がコンポーネントツリーの配下に供給するオブジェクトの型定義です。
42
49
  */
43
50
  export type RouterContextValue = {
51
+ /**
52
+ * ルーターの最新実体への参照を保持する Ref オブジェクトです。
53
+ */
44
54
  readonly routerRef: RouterRef;
55
+
56
+ /**
57
+ * ルーターの状態変更を監視するための購読関数です。
58
+ *
59
+ * @param onRouterChange ルーターの内部状態が変化した際に実行されるコールバック関数です。
60
+ * @returns 監視を安全に解除するためのクリーンアップ関数を返します。
61
+ */
45
62
  readonly subscribe: (onRouterChange: () => void) => () => void;
46
63
  };
47
64
 
48
65
  /**
49
- * ルーターの状態や操作関数をコンポーネントツリー全体で共有するための React コンテキストです。
66
+ * アプリケーションの最上位からルーターのグローバル状態を子コンポーネントへ一元的に伝播させるための React コンテキストです。
50
67
  *
51
- * 初期値は `null` であり、通常は Provider を介して値が提供されます。
68
+ * パフォーマンス最適化のためにプロバイダー自体は基本的に更新されず、子コンポーネントは `subscribe` `useSyncExternalStore`を使って必要な部分データだけを購読します。
52
69
  */
53
70
  const RouterContext = /*#__PURE__*/ React.createContext<RouterContextValue | null>(null);
54
71
 
@@ -1,60 +1,74 @@
1
1
  /**
2
2
  * セグメントの種類に応じたスコア定数です。
3
3
  *
4
- * 数値が大きいほど優先順位(具体性)が高いです。
4
+ * 数値が大きいほど優先順位(詳細度)が高いです。
5
+ *
6
+ * 詳細度(regexparam の README より):
7
+ * | 順位 | 種別 | 例 |
8
+ * | --: | :-- | :-- |
9
+ * | 1 | Static | `/foo`, `/foo/bar` |
10
+ * | 2 | Parameter with suffix | `/movies/:title.mp4`, `/movies/:title.(mp4\|mov)` |
11
+ * | 3 | Parameter | `/:title`, `/books/:title`, `/books/:genre/:title` |
12
+ * | 4 | Optional Parameters | `/:title?`, `/books/:title?`, `/books/:genre/:title?` |
13
+ * | 5 | Wildcards | `*`, `/books/*`, `/books/:genre/*` |
14
+ * | 6 | Optional Wildcard | `/books/*?` |
15
+ *
16
+ * @see https://github.com/lukeed/regexparam
5
17
  */
6
18
  const SCORE = {
7
- /**
8
- * 静的なパスセグメントのスコアです。
9
- */
10
- STATIC: 4,
11
-
12
- /**
13
- * 必須のパラメーターセグメントのスコアです。
14
- */
15
- PARAMETER: 3,
16
-
17
- /**
18
- * 任意のパラメーターセグメントのスコアです。
19
- */
20
- OPTIONAL_PARAM: 2,
21
-
22
- /**
23
- * ワイルドカードセグメントのスコアです。
24
- */
25
- WILDCARD: 1,
19
+ PARAM: 4,
20
+ STATIC: 6,
21
+ WILDCARD: 2,
22
+ OPTIONAL_PARAM: 3,
23
+ OPTIONAL_WILDCARD: 1,
24
+ PARAM_WITH_SUFFIX: 5,
26
25
  } as const;
27
26
 
28
27
  /**
29
- * 指定されたパスセグメントの文字列から、その種類に応じたスコアを計算します。
28
+ * 与えられた単一のセグメント文字列を解析し、その特性に応じた詳細度スコアを算出します。
30
29
  *
31
- * @param s 解析対象のパスセグメント文字列です。
32
- * @returns セグメントの種類に基づいた数値スコアを返します。
30
+ * @param s 解析対象となるセグメント文字列です。
31
+ * @returns セグメントの種別に対応する、`SCORE` 定数から抽出された数値スコアです。
33
32
  */
34
33
  function getSegmentScore(s: string): number {
35
- if (s.includes("*")) {
34
+ if (s === "*?") {
35
+ return SCORE.OPTIONAL_WILDCARD;
36
+ }
37
+
38
+ if (s === "*") {
36
39
  return SCORE.WILDCARD;
37
40
  }
38
41
 
39
- if (s.startsWith(":")) {
40
- if (s.endsWith("?")) {
42
+ if (s[0] === ":") {
43
+ if (s[s.length - 1] === "?") {
41
44
  return SCORE.OPTIONAL_PARAM;
42
- } else {
43
- return SCORE.PARAMETER;
44
45
  }
46
+
47
+ if (s.indexOf(".") < 0) {
48
+ return SCORE.PARAM;
49
+ }
50
+
51
+ return SCORE.PARAM_WITH_SUFFIX;
45
52
  }
46
53
 
47
54
  return SCORE.STATIC;
48
55
  }
49
56
 
50
57
  /**
51
- * 2 つのパスを比較し、ルーティングの優先順位に基づいたソート順を決定します。
58
+ * 英語のロケール設定に基づき、大文字小文字などを標準化した文字列比較を行うための `Intl.Collator` インスタンスです。
59
+ *
60
+ * 決定論的な辞書順ソートを保証するために使用します。
61
+ */
62
+ const enCollator = new Intl.Collator("en");
63
+
64
+ /**
65
+ * 2つのルートパスの優先順位を比較し、ソート順を決定するための比較関数です。
52
66
  *
53
- * より具体的で深いパスが前方に配置されるように比較を行います。
67
+ * より具体的で制限の厳しいパス(詳細度スコアが高いパス)が、ソート結果においてより前方に配置されるように負の値を返します。
54
68
  *
55
- * @param pathA 比較対象のパス A です。
56
- * @param pathB 比較対象のパス B です。
57
- * @returns 比較結果を示す数値です(負数は pathA が優先、正数は pathB が優先)。
69
+ * @param pathA 比較対象となる1つ目のパス文字列です。
70
+ * @param pathB 比較対象となる2つ目のパス文字列です。
71
+ * @returns `pathA` を優先する場合は負の数、`pathB` を優先する場合は正の数、等価である場合は `0` を返します。
58
72
  */
59
73
  export default function compareRoutePaths(pathA: string, pathB: string): number {
60
74
  const partsA = pathA.split("/").filter(Boolean);
@@ -82,7 +96,7 @@ export default function compareRoutePaths(pathA: string, pathB: string): number
82
96
  }
83
97
  // スコアが同じ場合は、文字列の辞書順で比較します。
84
98
  if (a !== b) {
85
- return a.localeCompare(b);
99
+ return enCollator.compare(a, b);
86
100
  }
87
101
  }
88
102