soseki 0.0.4 → 0.0.6
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.
- package/LICENSE +21 -0
- package/dist/src/components/browser-router.d.ts +19 -0
- package/dist/src/components/browser-router.d.ts.map +1 -0
- package/dist/src/components/browser-router.jsx +15 -0
- package/dist/src/components/outlet.d.ts +8 -0
- package/dist/src/components/outlet.d.ts.map +1 -0
- package/dist/src/components/outlet.jsx +15 -0
- package/dist/src/components/router.d.ts +21 -0
- package/dist/src/components/router.d.ts.map +1 -0
- package/dist/src/components/router.jsx +138 -0
- package/dist/src/contexts/route-context.d.ts +19 -0
- package/dist/src/contexts/route-context.d.ts.map +1 -0
- package/dist/src/contexts/route-context.js +6 -0
- package/dist/src/contexts/router-context.d.ts +55 -0
- package/dist/src/contexts/router-context.d.ts.map +1 -0
- package/dist/src/contexts/router-context.js +8 -0
- package/dist/src/core/_compare-route-paths.d.ts +11 -0
- package/dist/src/core/_compare-route-paths.d.ts.map +1 -0
- package/dist/src/core/_compare-route-paths.js +92 -0
- package/dist/src/core/_match-route-path.d.ts +22 -0
- package/dist/src/core/_match-route-path.d.ts.map +1 -0
- package/dist/src/core/_match-route-path.js +26 -0
- package/dist/src/core/_process-routes.d.ts +14 -0
- package/dist/src/core/_process-routes.d.ts.map +1 -0
- package/dist/src/core/_process-routes.js +45 -0
- package/dist/src/core/_singleton.d.ts +12 -0
- package/dist/src/core/_singleton.d.ts.map +1 -0
- package/dist/src/core/_singleton.js +18 -0
- package/dist/src/core/_unreachable.d.ts +16 -0
- package/dist/src/core/_unreachable.d.ts.map +1 -0
- package/dist/src/core/_unreachable.js +8 -0
- package/dist/src/core/_valibot.d.ts +25 -0
- package/dist/src/core/_valibot.d.ts.map +1 -0
- package/dist/src/core/_valibot.js +30 -0
- package/dist/src/core/errors.d.ts +182 -0
- package/dist/src/core/errors.d.ts.map +1 -0
- package/dist/src/core/errors.js +166 -0
- package/dist/src/core/expect-history-entry.d.ts +59 -0
- package/dist/src/core/expect-history-entry.d.ts.map +1 -0
- package/dist/src/core/expect-history-entry.js +42 -0
- package/dist/src/core/form-data-to-html-form-element.d.ts +11 -0
- package/dist/src/core/form-data-to-html-form-element.d.ts.map +1 -0
- package/dist/src/core/form-data-to-html-form-element.js +31 -0
- package/dist/src/core/history-entry-id-schema.d.ts +17 -0
- package/dist/src/core/history-entry-id-schema.d.ts.map +1 -0
- package/dist/src/core/history-entry-id-schema.js +9 -0
- package/dist/src/core/history-entry-url-schema.d.ts +18 -0
- package/dist/src/core/history-entry-url-schema.d.ts.map +1 -0
- package/dist/src/core/history-entry-url-schema.js +20 -0
- package/dist/src/core/init-loaders.d.ts +28 -0
- package/dist/src/core/init-loaders.d.ts.map +1 -0
- package/dist/src/core/init-loaders.js +30 -0
- package/dist/src/core/match-routes.d.ts +28 -0
- package/dist/src/core/match-routes.d.ts.map +1 -0
- package/dist/src/core/match-routes.js +31 -0
- package/dist/src/core/readonly-form-data.types.d.ts +74 -0
- package/dist/src/core/readonly-form-data.types.d.ts.map +1 -0
- package/dist/src/core/readonly-url.types.d.ts +164 -0
- package/dist/src/core/readonly-url.types.d.ts.map +1 -0
- package/dist/src/core/redirect-response.d.ts +37 -0
- package/dist/src/core/redirect-response.d.ts.map +1 -0
- package/dist/src/core/redirect-response.js +19 -0
- package/dist/src/core/route-path.d.ts +57 -0
- package/dist/src/core/route-path.d.ts.map +1 -0
- package/dist/src/core/route-path.js +93 -0
- package/dist/src/core/route-request.d.ts +149 -0
- package/dist/src/core/route-request.d.ts.map +1 -0
- package/dist/src/core/route-request.js +41 -0
- package/dist/src/core/route.types.d.ts +296 -0
- package/dist/src/core/route.types.d.ts.map +1 -0
- package/dist/src/core/start-action.d.ts +53 -0
- package/dist/src/core/start-action.d.ts.map +1 -0
- package/dist/src/core/start-action.js +95 -0
- package/dist/src/core/start-loaders.d.ts +63 -0
- package/dist/src/core/start-loaders.d.ts.map +1 -0
- package/dist/src/core/start-loaders.js +138 -0
- package/dist/{core.d.ts → src/core.d.ts} +7 -11
- package/dist/src/core.d.ts.map +1 -0
- package/dist/{core.js → src/core.js} +2 -4
- package/dist/src/engines/engine.types.d.ts +216 -0
- package/dist/src/engines/engine.types.d.ts.map +1 -0
- package/dist/src/engines/navigation-api-engine.d.ts +50 -0
- package/dist/src/engines/navigation-api-engine.d.ts.map +1 -0
- package/dist/src/engines/navigation-api-engine.js +411 -0
- package/dist/src/engines.d.ts +4 -0
- package/dist/src/engines.d.ts.map +1 -0
- package/dist/src/engines.js +1 -0
- package/dist/src/hooks/_use-singleton.d.ts +11 -0
- package/dist/src/hooks/_use-singleton.d.ts.map +1 -0
- package/dist/src/hooks/_use-singleton.js +26 -0
- package/dist/src/hooks/use-action-data.d.ts +17 -0
- package/dist/src/hooks/use-action-data.d.ts.map +1 -0
- package/dist/src/hooks/use-action-data.js +16 -0
- package/dist/src/hooks/use-form-action.d.ts +7 -0
- package/dist/src/hooks/use-form-action.d.ts.map +1 -0
- package/dist/src/hooks/use-form-action.js +9 -0
- package/dist/src/hooks/use-loader-data.d.ts +9 -0
- package/dist/src/hooks/use-loader-data.d.ts.map +1 -0
- package/dist/src/hooks/use-loader-data.js +20 -0
- package/dist/src/hooks/use-navigate.d.ts +53 -0
- package/dist/src/hooks/use-navigate.d.ts.map +1 -0
- package/dist/src/hooks/use-navigate.js +43 -0
- package/dist/{hooks → src/hooks}/use-params.d.ts +2 -2
- package/dist/src/hooks/use-params.d.ts.map +1 -0
- package/dist/{hooks → src/hooks}/use-params.js +1 -1
- package/dist/src/hooks/use-route-context.d.ts +10 -0
- package/dist/src/hooks/use-route-context.d.ts.map +1 -0
- package/dist/src/hooks/use-route-context.js +17 -0
- package/dist/src/hooks/use-router-context.d.ts +12 -0
- package/dist/src/hooks/use-router-context.d.ts.map +1 -0
- package/dist/src/hooks/use-router-context.js +20 -0
- package/dist/src/hooks/use-submit.d.ts +59 -0
- package/dist/src/hooks/use-submit.d.ts.map +1 -0
- package/dist/src/hooks/use-submit.js +38 -0
- package/dist/src/soseki.d.ts +31 -0
- package/dist/src/soseki.d.ts.map +1 -0
- package/dist/src/soseki.js +12 -0
- package/dist/src/utils/redirect.d.ts +11 -0
- package/dist/src/utils/redirect.d.ts.map +1 -0
- package/dist/src/utils/redirect.js +12 -0
- package/package.json +48 -30
- package/src/components/browser-router.tsx +8 -11
- package/src/components/outlet.tsx +3 -2
- package/src/components/router.tsx +139 -145
- package/src/contexts/route-context.ts +6 -5
- package/src/contexts/router-context.ts +36 -19
- package/src/core/_compare-route-paths.ts +48 -34
- package/src/core/_match-route-path.ts +21 -15
- package/src/core/_process-routes.ts +44 -46
- package/src/core/_singleton.ts +13 -38
- package/src/core/_unreachable.ts +12 -7
- package/src/core/_valibot.ts +19 -116
- package/src/core/errors.ts +150 -495
- package/src/core/expect-history-entry.ts +40 -41
- package/src/core/form-data-to-html-form-element.ts +37 -0
- package/src/core/history-entry-id-schema.ts +6 -11
- package/src/core/history-entry-url-schema.ts +25 -18
- package/src/core/init-loaders.ts +35 -57
- package/src/core/match-routes.ts +33 -65
- package/src/core/readonly-form-data.types.ts +48 -28
- package/src/core/readonly-url.types.ts +57 -28
- package/src/core/redirect-response.ts +26 -15
- package/src/core/route-path.ts +114 -0
- package/src/core/route-request.ts +144 -32
- package/src/core/route.types.ts +250 -226
- package/src/core/start-action.ts +164 -0
- package/src/core/start-loaders.ts +190 -212
- package/src/core.ts +8 -15
- package/src/engines/engine.types.ts +204 -166
- package/src/engines/navigation-api-engine.ts +332 -233
- package/src/engines.ts +4 -0
- package/src/hooks/_use-singleton.ts +30 -0
- package/src/hooks/use-action-data.ts +21 -26
- package/src/hooks/use-form-action.ts +4 -5
- package/src/hooks/use-loader-data.ts +16 -18
- package/src/hooks/use-navigate.ts +69 -28
- package/src/hooks/use-params.ts +4 -4
- package/src/hooks/use-route-context.ts +20 -0
- package/src/hooks/use-router-context.ts +25 -0
- package/src/hooks/use-submit.ts +48 -53
- package/src/soseki.ts +27 -34
- package/src/utils/redirect.ts +5 -5
- package/dist/components/action-id.d.ts +0 -19
- package/dist/components/action-id.d.ts.map +0 -1
- package/dist/components/action-id.jsx +0 -14
- package/dist/components/browser-router.d.ts +0 -17
- package/dist/components/browser-router.d.ts.map +0 -1
- package/dist/components/browser-router.jsx +0 -13
- package/dist/components/hidden-input.d.ts +0 -20
- package/dist/components/hidden-input.d.ts.map +0 -1
- package/dist/components/hidden-input.jsx +0 -8
- package/dist/components/outlet.d.ts +0 -8
- package/dist/components/outlet.d.ts.map +0 -1
- package/dist/components/outlet.jsx +0 -15
- package/dist/components/router.d.ts +0 -23
- package/dist/components/router.d.ts.map +0 -1
- package/dist/components/router.jsx +0 -128
- package/dist/contexts/route-context.d.ts +0 -19
- package/dist/contexts/route-context.d.ts.map +0 -1
- package/dist/contexts/route-context.js +0 -6
- package/dist/contexts/router-context.d.ts +0 -46
- package/dist/contexts/router-context.d.ts.map +0 -1
- package/dist/contexts/router-context.js +0 -8
- package/dist/core/_action-id-registry.d.ts +0 -10
- package/dist/core/_action-id-registry.d.ts.map +0 -1
- package/dist/core/_action-id-registry.js +0 -8
- package/dist/core/_capture-stack-trace.d.ts +0 -8
- package/dist/core/_capture-stack-trace.d.ts.map +0 -1
- package/dist/core/_capture-stack-trace.js +0 -12
- package/dist/core/_compare-route-paths.d.ts +0 -11
- package/dist/core/_compare-route-paths.d.ts.map +0 -1
- package/dist/core/_compare-route-paths.js +0 -80
- package/dist/core/_create-html-form-element-form-form-data.d.ts +0 -9
- package/dist/core/_create-html-form-element-form-form-data.d.ts.map +0 -1
- package/dist/core/_create-html-form-element-form-form-data.js +0 -27
- package/dist/core/_encode-pathname.d.ts +0 -10
- package/dist/core/_encode-pathname.d.ts.map +0 -1
- package/dist/core/_encode-pathname.js +0 -16
- package/dist/core/_is-error.d.ts +0 -3
- package/dist/core/_is-error.d.ts.map +0 -1
- package/dist/core/_is-error.js +0 -13
- package/dist/core/_is-promise-like.d.ts +0 -8
- package/dist/core/_is-promise-like.d.ts.map +0 -1
- package/dist/core/_is-promise-like.js +0 -12
- package/dist/core/_match-route-path.d.ts +0 -19
- package/dist/core/_match-route-path.d.ts.map +0 -1
- package/dist/core/_match-route-path.js +0 -22
- package/dist/core/_process-routes.d.ts +0 -9
- package/dist/core/_process-routes.d.ts.map +0 -1
- package/dist/core/_process-routes.js +0 -47
- package/dist/core/_singleton.d.ts +0 -18
- package/dist/core/_singleton.d.ts.map +0 -1
- package/dist/core/_singleton.js +0 -37
- package/dist/core/_unreachable.d.ts +0 -12
- package/dist/core/_unreachable.d.ts.map +0 -1
- package/dist/core/_unreachable.js +0 -8
- package/dist/core/_use-singleton.d.ts +0 -11
- package/dist/core/_use-singleton.d.ts.map +0 -1
- package/dist/core/_use-singleton.js +0 -21
- package/dist/core/_valibot.d.ts +0 -52
- package/dist/core/_valibot.d.ts.map +0 -1
- package/dist/core/_valibot.js +0 -107
- package/dist/core/_weak-id-registry.d.ts +0 -76
- package/dist/core/_weak-id-registry.d.ts.map +0 -1
- package/dist/core/_weak-id-registry.js +0 -67
- package/dist/core/constants.d.ts +0 -5
- package/dist/core/constants.d.ts.map +0 -1
- package/dist/core/constants.js +0 -4
- package/dist/core/data-map.types.d.ts +0 -23
- package/dist/core/data-map.types.d.ts.map +0 -1
- package/dist/core/data-map.types.js +0 -1
- package/dist/core/data-store.types.d.ts +0 -22
- package/dist/core/data-store.types.d.ts.map +0 -1
- package/dist/core/data-store.types.js +0 -1
- package/dist/core/deferred-promise.d.ts +0 -203
- package/dist/core/deferred-promise.d.ts.map +0 -1
- package/dist/core/deferred-promise.js +0 -200
- package/dist/core/errors.d.ts +0 -303
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -400
- package/dist/core/expect-history-entry.d.ts +0 -52
- package/dist/core/expect-history-entry.d.ts.map +0 -1
- package/dist/core/expect-history-entry.js +0 -38
- package/dist/core/history-entry-id-schema.d.ts +0 -17
- package/dist/core/history-entry-id-schema.d.ts.map +0 -1
- package/dist/core/history-entry-id-schema.js +0 -9
- package/dist/core/history-entry-url-schema.d.ts +0 -20
- package/dist/core/history-entry-url-schema.d.ts.map +0 -1
- package/dist/core/history-entry-url-schema.js +0 -16
- package/dist/core/init-loaders.d.ts +0 -37
- package/dist/core/init-loaders.d.ts.map +0 -1
- package/dist/core/init-loaders.js +0 -38
- package/dist/core/match-routes.d.ts +0 -31
- package/dist/core/match-routes.d.ts.map +0 -1
- package/dist/core/match-routes.js +0 -54
- package/dist/core/readonly-form-data.types.d.ts +0 -32
- package/dist/core/readonly-form-data.types.d.ts.map +0 -1
- package/dist/core/readonly-url.types.d.ts +0 -135
- package/dist/core/readonly-url.types.d.ts.map +0 -1
- package/dist/core/redirect-response.d.ts +0 -29
- package/dist/core/redirect-response.d.ts.map +0 -1
- package/dist/core/redirect-response.js +0 -17
- package/dist/core/route-request.d.ts +0 -52
- package/dist/core/route-request.d.ts.map +0 -1
- package/dist/core/route-request.js +0 -26
- package/dist/core/route.types.d.ts +0 -309
- package/dist/core/route.types.d.ts.map +0 -1
- package/dist/core/start-actions.d.ts +0 -60
- package/dist/core/start-actions.d.ts.map +0 -1
- package/dist/core/start-actions.js +0 -186
- package/dist/core/start-loaders.d.ts +0 -69
- package/dist/core/start-loaders.d.ts.map +0 -1
- package/dist/core/start-loaders.js +0 -154
- package/dist/core.d.ts.map +0 -1
- package/dist/engines/engine.types.d.ts +0 -190
- package/dist/engines/engine.types.d.ts.map +0 -1
- package/dist/engines/navigation-api-engine.d.ts +0 -48
- package/dist/engines/navigation-api-engine.d.ts.map +0 -1
- package/dist/engines/navigation-api-engine.js +0 -332
- package/dist/hooks/_use-route-context.d.ts +0 -10
- package/dist/hooks/_use-route-context.d.ts.map +0 -1
- package/dist/hooks/_use-route-context.js +0 -17
- package/dist/hooks/_use-router-context.d.ts +0 -10
- package/dist/hooks/_use-router-context.d.ts.map +0 -1
- package/dist/hooks/_use-router-context.js +0 -18
- package/dist/hooks/use-action-data.d.ts +0 -23
- package/dist/hooks/use-action-data.d.ts.map +0 -1
- package/dist/hooks/use-action-data.js +0 -16
- package/dist/hooks/use-form-action.d.ts +0 -7
- package/dist/hooks/use-form-action.d.ts.map +0 -1
- package/dist/hooks/use-form-action.js +0 -10
- package/dist/hooks/use-loader-data.d.ts +0 -11
- package/dist/hooks/use-loader-data.d.ts.map +0 -1
- package/dist/hooks/use-loader-data.js +0 -19
- package/dist/hooks/use-navigate.d.ts +0 -39
- package/dist/hooks/use-navigate.d.ts.map +0 -1
- package/dist/hooks/use-navigate.js +0 -26
- package/dist/hooks/use-params.d.ts.map +0 -1
- package/dist/hooks/use-pathname.d.ts +0 -7
- package/dist/hooks/use-pathname.d.ts.map +0 -1
- package/dist/hooks/use-pathname.js +0 -9
- package/dist/hooks/use-submit.d.ts +0 -66
- package/dist/hooks/use-submit.d.ts.map +0 -1
- package/dist/hooks/use-submit.js +0 -35
- package/dist/soseki.d.ts +0 -42
- package/dist/soseki.d.ts.map +0 -1
- package/dist/soseki.js +0 -19
- package/dist/utils/get-action-id.d.ts +0 -8
- package/dist/utils/get-action-id.d.ts.map +0 -1
- package/dist/utils/get-action-id.js +0 -11
- package/dist/utils/href.d.ts +0 -11
- package/dist/utils/href.d.ts.map +0 -1
- package/dist/utils/href.js +0 -12
- package/dist/utils/redirect.d.ts +0 -11
- package/dist/utils/redirect.d.ts.map +0 -1
- package/dist/utils/redirect.js +0 -12
- package/dist/utils/route-index.d.ts +0 -41
- package/dist/utils/route-index.d.ts.map +0 -1
- package/dist/utils/route-index.js +0 -12
- package/dist/utils/route-route.d.ts +0 -62
- package/dist/utils/route-route.d.ts.map +0 -1
- package/dist/utils/route-route.js +0 -25
- package/dist/utils/set-action-id.d.ts +0 -9
- package/dist/utils/set-action-id.d.ts.map +0 -1
- package/dist/utils/set-action-id.js +0 -12
- package/src/components/action-id.tsx +0 -35
- package/src/components/hidden-input.tsx +0 -39
- package/src/core/_action-id-registry.ts +0 -11
- package/src/core/_capture-stack-trace.ts +0 -12
- package/src/core/_create-html-form-element-form-form-data.ts +0 -32
- package/src/core/_encode-pathname.ts +0 -17
- package/src/core/_is-error.ts +0 -16
- package/src/core/_is-promise-like.ts +0 -14
- package/src/core/_use-singleton.ts +0 -24
- package/src/core/_weak-id-registry.ts +0 -125
- package/src/core/constants.ts +0 -4
- package/src/core/data-map.types.ts +0 -28
- package/src/core/data-store.types.ts +0 -25
- package/src/core/deferred-promise.ts +0 -408
- package/src/core/start-actions.ts +0 -274
- package/src/hooks/_use-route-context.ts +0 -19
- package/src/hooks/_use-router-context.ts +0 -25
- package/src/hooks/use-pathname.ts +0 -10
- package/src/utils/get-action-id.ts +0 -12
- package/src/utils/href.ts +0 -17
- package/src/utils/route-index.ts +0 -70
- package/src/utils/route-route.ts +0 -111
- package/src/utils/set-action-id.ts +0 -14
- /package/dist/{core → src/core}/readonly-form-data.types.js +0 -0
- /package/dist/{core → src/core}/readonly-url.types.js +0 -0
- /package/dist/{core → src/core}/route.types.js +0 -0
- /package/dist/{engines → src/engines}/engine.types.js +0 -0
|
@@ -1,96 +1,92 @@
|
|
|
1
|
-
import
|
|
2
|
-
import createHtmlFormElementFormFormData from "../core/_create-html-form-element-form-form-data.js";
|
|
1
|
+
import unreachable from "../core/_unreachable.js";
|
|
3
2
|
import * as v from "../core/_valibot.js";
|
|
4
|
-
import { ACTION_ID_FORM_DATA_NAME } from "../core/constants.js";
|
|
5
3
|
import { NavigationApiNotSupportedError } from "../core/errors.js";
|
|
6
4
|
import expectHistoryEntry from "../core/expect-history-entry.js";
|
|
7
|
-
import
|
|
5
|
+
import createHtmlFormElementFormFormData from "../core/form-data-to-html-form-element.js";
|
|
6
|
+
import type { HistoryEntryId } from "../core/history-entry-id-schema.js";
|
|
7
|
+
import HistoryEntryIdSchema from "../core/history-entry-id-schema.js";
|
|
8
8
|
import HistoryEntryUrlSchema from "../core/history-entry-url-schema.js";
|
|
9
9
|
import initLoaders from "../core/init-loaders.js";
|
|
10
10
|
import matchRoutes from "../core/match-routes.js";
|
|
11
|
-
import
|
|
12
|
-
import
|
|
11
|
+
import RoutePath from "../core/route-path.js";
|
|
12
|
+
import startAction from "../core/start-action.js";
|
|
13
13
|
import startLoaders from "../core/start-loaders.js";
|
|
14
|
-
import type {
|
|
15
|
-
IEngine,
|
|
16
|
-
InitEngineArgs,
|
|
17
|
-
NavigateArgs,
|
|
18
|
-
RouterState,
|
|
19
|
-
StartEngineArgs,
|
|
20
|
-
SubmitArgs,
|
|
21
|
-
} from "./engine.types.js";
|
|
14
|
+
import type { IEngine } from "./engine.types.js";
|
|
22
15
|
|
|
23
16
|
/**
|
|
24
|
-
* Navigation API
|
|
17
|
+
* モダンブラウザーに搭載されている標準の `Navigation API` を活用し、クライアントサイドにおける高度な SPA ルーティングを制御するエンジンクラスです。
|
|
25
18
|
*/
|
|
26
19
|
export default class NavigationApiEngine implements IEngine {
|
|
27
20
|
/**
|
|
28
|
-
*
|
|
21
|
+
* ブラウザー標準の `navigation` オブジェクトへの参照を保持します。
|
|
29
22
|
*/
|
|
30
|
-
private
|
|
23
|
+
private navigation: Navigation;
|
|
31
24
|
|
|
32
25
|
/**
|
|
33
|
-
*
|
|
26
|
+
* メモリーリークを防ぐため、すでに dispose リスナーを登録済みの履歴エントリー ID を追跡するセットです。
|
|
34
27
|
*/
|
|
35
28
|
private subscribedEntryIds: Set<HistoryEntryId>;
|
|
36
29
|
|
|
37
30
|
/**
|
|
38
|
-
*
|
|
31
|
+
* 連続して発生した画面遷移を適切にキャンセルするための、最新ナビゲーション用の中断コントローラーです。
|
|
39
32
|
*/
|
|
40
33
|
private navAbortController: AbortController | null;
|
|
41
34
|
|
|
42
35
|
/**
|
|
43
|
-
* NavigationApiEngine
|
|
36
|
+
* `NavigationApiEngine` クラスのインスタンスを初期化します。
|
|
37
|
+
*
|
|
38
|
+
* 実行環境が `Navigation API` をサポートしていない場合はエラーを投げます。
|
|
44
39
|
*/
|
|
45
40
|
public constructor() {
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
let navigation_: Navigation | undefined;
|
|
42
|
+
|
|
43
|
+
// グローバル環境または window オブジェクトから navigation インスタンスの回収を試みます。
|
|
44
|
+
for (const getNav of [() => navigation, () => window.navigation]) {
|
|
50
45
|
try {
|
|
51
|
-
|
|
46
|
+
navigation_ = getNav();
|
|
47
|
+
if (typeof navigation_ !== "undefined") {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
52
50
|
} catch {}
|
|
53
51
|
}
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
|
|
53
|
+
// オブジェクトとして存在しない場合はサポート外の環境とみなします。
|
|
54
|
+
if (typeof navigation_ !== "object") {
|
|
56
55
|
throw new NavigationApiNotSupportedError();
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
this.
|
|
58
|
+
this.navigation = navigation_;
|
|
60
59
|
this.subscribedEntryIds = new Set();
|
|
61
60
|
this.navAbortController = null;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
|
-
*
|
|
64
|
+
* 現在のページ URL に基づき、ルーターの初期状態を構築・登録します。
|
|
66
65
|
*
|
|
67
|
-
* @param args
|
|
68
|
-
* @returns
|
|
66
|
+
* @param args ルート定義配列、共通データストア、初期化用のアボートシグナルを含むオブジェクトです。
|
|
67
|
+
* @returns 構築された初期の `RouterState`。適合するルートがないか、履歴が無い場合は `null` を返します。
|
|
69
68
|
*/
|
|
70
|
-
|
|
71
|
-
const currentEntry = expectHistoryEntry(this.
|
|
69
|
+
init(args: IEngine.InitArgs): IEngine.InitReturn {
|
|
70
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
72
71
|
if (!currentEntry) {
|
|
73
72
|
return null;
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
const {
|
|
77
|
-
|
|
78
|
-
getSignal,
|
|
79
|
-
loaderDataStore,
|
|
80
|
-
} = args;
|
|
81
|
-
const currentRoutes = matchRoutes(routes, currentEntry.url.pathname);
|
|
75
|
+
const { routes, getSignal, loaderDataStore } = args;
|
|
76
|
+
const currentRoutes = matchRoutes(routes, currentEntry.url);
|
|
82
77
|
if (!currentRoutes) {
|
|
83
78
|
return null;
|
|
84
79
|
}
|
|
85
80
|
|
|
86
|
-
//
|
|
87
|
-
initLoaders({
|
|
88
|
-
|
|
89
|
-
routes: currentRoutes,
|
|
81
|
+
// 初期表示に必要なすべてのローダーを一斉に並行起動します。
|
|
82
|
+
const dataMap = initLoaders(currentRoutes, {
|
|
83
|
+
url: currentEntry.url,
|
|
90
84
|
signal: getSignal(),
|
|
91
|
-
dataStore: loaderDataStore,
|
|
92
85
|
});
|
|
93
86
|
|
|
87
|
+
// 起動したローダーの結果(NinjaPromise)のマップを、現在の履歴 ID をキーとしてキャッシュします。
|
|
88
|
+
loaderDataStore.set(currentEntry.id, dataMap);
|
|
89
|
+
|
|
94
90
|
return {
|
|
95
91
|
entry: currentEntry,
|
|
96
92
|
routes: currentRoutes,
|
|
@@ -98,169 +94,244 @@ export default class NavigationApiEngine implements IEngine {
|
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
/**
|
|
101
|
-
*
|
|
97
|
+
* ブラウザーの継続的なナビゲーションイベント(リンククリック、フォーム送信、履歴移動)の監視を開始します。
|
|
102
98
|
*
|
|
103
|
-
* @param args
|
|
99
|
+
* @param args ルート配列、UI側への状態反映関数、各種ストア、シグナル取得関数を含むオブジェクトです。
|
|
104
100
|
*/
|
|
105
|
-
|
|
106
|
-
const {
|
|
107
|
-
routes,
|
|
108
|
-
update,
|
|
109
|
-
getSignal,
|
|
110
|
-
actionDataStore,
|
|
111
|
-
loaderDataStore,
|
|
112
|
-
} = args;
|
|
101
|
+
start(args: IEngine.StartArgs): IEngine.StartReturn {
|
|
102
|
+
const { routes, update, getSignal, actionDataStore, loaderDataStore } = args;
|
|
113
103
|
|
|
114
104
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* @param event ナビゲーションイベントです。
|
|
105
|
+
* ユーザーのアクションによって発生したすべての遷移要求をインターセプトして処理する、ルーティングの中枢ハンドラーです。
|
|
118
106
|
*/
|
|
119
107
|
const handleNavigate = (event: NavigateEvent): void => {
|
|
120
|
-
//
|
|
108
|
+
// 処理すべきでない通常のブラウザー固有のナビゲーション(ハッシュ変更、ファイルのダウンロードなど)は、
|
|
109
|
+
// 標準の挙動を妨げないようにインターセプトせず即座にスルーします。
|
|
121
110
|
// 参照: https://developer.mozilla.org/docs/Web/API/Navigation_API#handling_a_navigation_using_intercept
|
|
122
111
|
if (
|
|
123
|
-
!event.isTrusted
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
112
|
+
!event.isTrusted ||
|
|
113
|
+
!event.canIntercept ||
|
|
114
|
+
event.hashChange ||
|
|
115
|
+
event.downloadRequest !== null
|
|
127
116
|
) {
|
|
128
117
|
return;
|
|
129
118
|
}
|
|
130
119
|
|
|
131
|
-
const currentEntry = expectHistoryEntry(this.
|
|
120
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
132
121
|
if (!currentEntry) {
|
|
122
|
+
// 現在のエントリーが存在しない場合は、ルーターを未マッチ状態(null)にリセットして制御をブラウザーに返します。
|
|
133
123
|
event.intercept({
|
|
134
124
|
async handler() {
|
|
135
125
|
update(null);
|
|
136
126
|
},
|
|
137
127
|
});
|
|
128
|
+
|
|
138
129
|
return;
|
|
139
130
|
}
|
|
140
131
|
|
|
132
|
+
// 移動先の URL を検証し、適合するルート定義があるかを探索します。
|
|
141
133
|
const destUrl = v.expect(HistoryEntryUrlSchema(), event.destination.url);
|
|
142
|
-
const destRoutes = matchRoutes(routes, destUrl
|
|
134
|
+
const destRoutes = matchRoutes(routes, destUrl);
|
|
143
135
|
if (!destRoutes) {
|
|
136
|
+
// 移動先のルート定義が見つからない場合は、ルーターを未マッチ状態(null)にリセットして制御をブラウザーに返します。
|
|
144
137
|
event.intercept({
|
|
145
138
|
async handler() {
|
|
146
139
|
update(null);
|
|
147
140
|
},
|
|
148
141
|
});
|
|
142
|
+
|
|
149
143
|
return;
|
|
150
144
|
}
|
|
151
145
|
|
|
152
|
-
//
|
|
146
|
+
// 前回の遷移から短時間で遷移する場合を考慮し、進行中だった以前の古い非同期処理をすべて安全に中断します。
|
|
153
147
|
this.navAbortController?.abort();
|
|
154
|
-
|
|
148
|
+
this.navAbortController = new AbortController();
|
|
149
|
+
const { signal } = this.navAbortController;
|
|
155
150
|
const { formData } = event;
|
|
156
151
|
const prevEntryInHandler = currentEntry;
|
|
152
|
+
|
|
153
|
+
// 分岐 A: フォームデータが伴う場合 = データ変更要求(HTTP POST / Action 契機)
|
|
157
154
|
if (formData) {
|
|
158
155
|
const { sourceElement } = event;
|
|
156
|
+
|
|
157
|
+
// submit メソッドによってプログラムから動的生成されたフォーム要素であれば、用済みのため DOM から削除します。
|
|
159
158
|
if (sourceElement?.hasAttribute("data-sosekisubmit")) {
|
|
160
159
|
document.body.removeChild(sourceElement);
|
|
161
160
|
}
|
|
162
161
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
162
|
+
/**
|
|
163
|
+
* A-1: URL が書き換わる直前の段階で割り込んでアクション関数を実行するハンドラーです。
|
|
164
|
+
*/
|
|
165
|
+
const precommitHandler = async (controller: NavigationPrecommitController) => {
|
|
166
|
+
const action = startAction(destRoutes, {
|
|
167
|
+
url: destUrl,
|
|
168
|
+
signal,
|
|
169
|
+
formData,
|
|
170
|
+
});
|
|
171
|
+
if (!action) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// アクションの実行状態を現在の履歴 ID に紐づけてストアへ保存します。
|
|
176
|
+
actionDataStore
|
|
177
|
+
.getOrInsertComputed(currentEntry.id, () => new Map())
|
|
178
|
+
.set(action.func, action.data);
|
|
179
|
+
|
|
180
|
+
// アクションの開始に伴い、UI 層へローディング状態などの再描画を伝播します。
|
|
181
|
+
update();
|
|
182
|
+
|
|
183
|
+
// 全アクションの処理が完了するまで待機します。
|
|
184
|
+
const actionResponse = await action.idle();
|
|
185
|
+
const redirectUrl = new URL(currentEntry.url.href);
|
|
186
|
+
|
|
187
|
+
switch (action.data.status) {
|
|
188
|
+
case "rejected": {
|
|
189
|
+
// アクションがエラーで失敗した場合は、URL を変更せず現在の元のページに強制リダイレクトさせます。
|
|
190
|
+
const { pathname, search, hash } = currentEntry.url;
|
|
191
|
+
controller.redirect(pathname + search + hash);
|
|
192
|
+
|
|
193
|
+
break;
|
|
180
194
|
}
|
|
181
195
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
redirectUrl.pathname = redirect;
|
|
189
|
-
controller.redirect(redirect);
|
|
190
|
-
},
|
|
191
|
-
handler: async () => {
|
|
192
|
-
if (!actionResultMap) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
196
|
+
case "fulfilled": {
|
|
197
|
+
// アクションが正常終了した場合、返り値にリダイレクト指示が含まれていればその目的地へ遷移させます。
|
|
198
|
+
// リダイレクトがなければそのまま本来の目的地へとブラウザーのコミット先を書き換えます。
|
|
199
|
+
const { redirectTo = currentEntry.url } = actionResponse;
|
|
200
|
+
const { pathname, search, hash } = redirectTo;
|
|
201
|
+
controller.redirect(pathname + search + hash);
|
|
195
202
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (currentEntry.url.href !== redirectUrl.href) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
203
|
+
redirectUrl.pathname = pathname;
|
|
204
|
+
redirectUrl.search = search;
|
|
205
|
+
redirectUrl.hash = hash;
|
|
204
206
|
|
|
205
|
-
|
|
206
|
-
if (!currentRoutes) {
|
|
207
|
-
update(null);
|
|
208
|
-
return;
|
|
207
|
+
break;
|
|
209
208
|
}
|
|
210
209
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
default:
|
|
211
|
+
unreachable(action.data.status as never);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 次の描画確定フェーズへコンテキスト情報を引き継ぎます。
|
|
215
|
+
return {
|
|
216
|
+
action: action.func,
|
|
217
|
+
actionData: action.data,
|
|
218
|
+
redirectUrl,
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* A-2: アクションが完了し、ブラウザーの URL コミットが確定した後に画面表示を同期させるハンドラーです。
|
|
224
|
+
*/
|
|
225
|
+
const handler = async (args: Awaited<ReturnType<typeof precommitHandler>>) => {
|
|
226
|
+
if (!args) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const { action, actionData, redirectUrl } = args;
|
|
231
|
+
|
|
232
|
+
// 履歴エントリーを再度取得します。
|
|
233
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
234
|
+
if (!currentEntry) {
|
|
235
|
+
// 現在のエントリーが存在しない場合は、ルーターを未マッチ状態(null)にリセットして制御をブラウザーに返します。
|
|
236
|
+
update(null);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// コミットされた実際のブラウザー URL が、想定しているリダイレクト先と一致しない場合は処理を中断します。
|
|
241
|
+
if (currentEntry.url.href !== redirectUrl.href) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 確定した新しい履歴 ID に改めてアクション結果をキャッシュします。
|
|
246
|
+
actionDataStore
|
|
247
|
+
.getOrInsertComputed(currentEntry.id, () => new Map())
|
|
248
|
+
.set(action, actionData);
|
|
249
|
+
|
|
250
|
+
const currentRoutes = matchRoutes(routes, currentEntry.url);
|
|
251
|
+
if (!currentRoutes) {
|
|
252
|
+
// 現在のルート定義が見つからない場合は、ルーターを未マッチ状態(null)にリセットして制御をブラウザーに返します。
|
|
253
|
+
update(null);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// アクションの処理結果を反映させるために、該当するルートのローダーを実行します。
|
|
258
|
+
const prevEntry = prevEntryInHandler;
|
|
259
|
+
const prevRoutes = matchRoutes(routes, prevEntry.url);
|
|
260
|
+
const startedLoaders = startLoaders(
|
|
261
|
+
{
|
|
214
262
|
signal,
|
|
215
|
-
formData,
|
|
216
263
|
prevEntry,
|
|
217
264
|
prevRoutes,
|
|
218
265
|
currentEntry,
|
|
219
266
|
currentRoutes,
|
|
220
|
-
actionResultMap,
|
|
221
|
-
actionDataStore,
|
|
222
267
|
loaderDataStore,
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
formData,
|
|
271
|
+
actionData,
|
|
272
|
+
},
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
// 最新の確定状態を UI に通知して画面を再描画します。ローダーの結果の中には実行中のものもありますが、それらの待機処理(描画)は各コンポーネントに任せます。
|
|
276
|
+
update({
|
|
277
|
+
entry: currentEntry,
|
|
278
|
+
routes: currentRoutes,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// 全ローダーの完了を待機します。ここで待機することで、全ローダーの実行が完了するまでブラウザーのタブにはローディングスピーナーが表示されます。
|
|
282
|
+
await startedLoaders?.idle();
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// Navigation API のインターセプト機構に、二段階の処理をバインドします。
|
|
286
|
+
let precommitResult: Awaited<ReturnType<typeof precommitHandler>>;
|
|
287
|
+
event.intercept({
|
|
288
|
+
async precommitHandler(controller) {
|
|
289
|
+
precommitResult = await precommitHandler(controller);
|
|
290
|
+
},
|
|
291
|
+
async handler() {
|
|
292
|
+
await handler(precommitResult);
|
|
233
293
|
},
|
|
234
294
|
});
|
|
235
295
|
} else {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
296
|
+
// 分岐 B: フォームデータがない場合 = 通常の画面遷移(HTTP GET / リンククリック・戻る進む契機)
|
|
297
|
+
const handler = async () => {
|
|
298
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
299
|
+
if (!currentEntry) {
|
|
300
|
+
update(null);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// 同期がズレている場合はガードします。
|
|
304
|
+
if (currentEntry.url.href !== destUrl.href) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const prevEntry = prevEntryInHandler;
|
|
309
|
+
const prevRoutes = matchRoutes(routes, prevEntry.url);
|
|
310
|
+
const currentRoutes = destRoutes;
|
|
311
|
+
|
|
312
|
+
// キャッシュの再利用判定を含めて、移動先のローダー関数群を精査・起動します。
|
|
313
|
+
const startedLoaders = startLoaders({
|
|
314
|
+
signal,
|
|
315
|
+
prevEntry,
|
|
316
|
+
prevRoutes,
|
|
317
|
+
currentEntry,
|
|
318
|
+
currentRoutes,
|
|
319
|
+
loaderDataStore,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// 最新の確定状態を UI に通知して画面を再描画します。ローダーの結果の中には実行中のものもありますが、それらの待機処理(描画)は各コンポーネントに任せます。
|
|
323
|
+
update({
|
|
324
|
+
entry: currentEntry,
|
|
325
|
+
routes: currentRoutes,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// 全ローダーの完了を待機します。ここで待機することで、全ローダーの実行が完了するまでブラウザーのタブにはローディングスピーナーが表示されます。
|
|
329
|
+
await startedLoaders?.idle();
|
|
330
|
+
};
|
|
246
331
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const waitForComplete = startLoaders({
|
|
251
|
-
signal,
|
|
252
|
-
prevEntry,
|
|
253
|
-
prevRoutes,
|
|
254
|
-
currentEntry,
|
|
255
|
-
currentRoutes,
|
|
256
|
-
actionDataStore,
|
|
257
|
-
loaderDataStore,
|
|
258
|
-
});
|
|
259
|
-
update({
|
|
260
|
-
entry: currentEntry,
|
|
261
|
-
routes: currentRoutes,
|
|
262
|
-
});
|
|
263
|
-
await waitForComplete?.();
|
|
332
|
+
event.intercept({
|
|
333
|
+
async handler() {
|
|
334
|
+
await handler();
|
|
264
335
|
},
|
|
265
336
|
});
|
|
266
337
|
}
|
|
@@ -268,23 +339,24 @@ export default class NavigationApiEngine implements IEngine {
|
|
|
268
339
|
|
|
269
340
|
const signal = getSignal();
|
|
270
341
|
|
|
271
|
-
|
|
342
|
+
// 外部からルーター全体の監視終了シグナルを受け取った際、中断処理を連動させます。
|
|
343
|
+
const handleAbort = (): void => {
|
|
272
344
|
this.navAbortController?.abort();
|
|
273
345
|
this.navAbortController = null;
|
|
274
346
|
};
|
|
275
347
|
signal.addEventListener("abort", handleAbort, { once: true });
|
|
276
348
|
|
|
277
|
-
|
|
278
|
-
|
|
349
|
+
// Navigation API の navigate イベントの購読を開始します。
|
|
350
|
+
this.navigation.addEventListener("navigate", handleNavigate, { signal });
|
|
279
351
|
|
|
280
|
-
//
|
|
281
|
-
for (const entry of this.
|
|
352
|
+
// セッション履歴から溢れて破棄された古い履歴エントリーのデータ(アクション・ローダーのキャッシュ)を自動削除します。
|
|
353
|
+
for (const entry of this.navigation.entries()) {
|
|
282
354
|
const entryId = v.expect(HistoryEntryIdSchema(), entry.id);
|
|
283
355
|
if (this.subscribedEntryIds.has(entryId)) {
|
|
284
356
|
continue;
|
|
285
357
|
}
|
|
286
358
|
|
|
287
|
-
const handleDispose = () => {
|
|
359
|
+
const handleDispose = (): void => {
|
|
288
360
|
this.subscribedEntryIds.delete(entryId);
|
|
289
361
|
actionDataStore.delete(entryId);
|
|
290
362
|
loaderDataStore.delete(entryId);
|
|
@@ -293,11 +365,9 @@ export default class NavigationApiEngine implements IEngine {
|
|
|
293
365
|
this.subscribedEntryIds.add(entryId);
|
|
294
366
|
}
|
|
295
367
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const handleCurrentEntryChange = () => {
|
|
300
|
-
const currentEntry = expectHistoryEntry(this.nav.currentEntry);
|
|
368
|
+
// ナビゲーションの進行に伴い、新しく生成される履歴エントリーに対しても、動的に破棄イベントの監視網を広げます。
|
|
369
|
+
const handleCurrentEntryChange = (): void => {
|
|
370
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
301
371
|
if (!currentEntry) {
|
|
302
372
|
return;
|
|
303
373
|
}
|
|
@@ -305,102 +375,131 @@ export default class NavigationApiEngine implements IEngine {
|
|
|
305
375
|
return;
|
|
306
376
|
}
|
|
307
377
|
|
|
308
|
-
const handleDispose = () => {
|
|
378
|
+
const handleDispose = (): void => {
|
|
309
379
|
this.subscribedEntryIds.delete(currentEntry.id);
|
|
310
380
|
actionDataStore.delete(currentEntry.id);
|
|
311
381
|
loaderDataStore.delete(currentEntry.id);
|
|
312
382
|
};
|
|
313
|
-
this.
|
|
383
|
+
this.navigation.currentEntry!.addEventListener("dispose", handleDispose, { signal });
|
|
314
384
|
this.subscribedEntryIds.add(currentEntry.id);
|
|
315
385
|
};
|
|
316
|
-
this.
|
|
386
|
+
this.navigation.addEventListener("currententrychange", handleCurrentEntryChange, { signal });
|
|
317
387
|
}
|
|
318
388
|
|
|
319
389
|
/**
|
|
320
|
-
*
|
|
390
|
+
* フォームデータまたはクエリーパラメータを、ブラウザーの Navigation API のライフサイクルに載せて命令的に送信します。
|
|
321
391
|
*
|
|
322
|
-
* @param args
|
|
392
|
+
* @param args 送信データの種類に応じたサブミット引数です。
|
|
323
393
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
target
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
394
|
+
submit(args: IEngine.SubmitArgs): void {
|
|
395
|
+
switch (args.type) {
|
|
396
|
+
case "FORM_DATA": {
|
|
397
|
+
const { action, target } = args;
|
|
398
|
+
const form = createHtmlFormElementFormFormData(target);
|
|
399
|
+
form.method = "POST";
|
|
400
|
+
form.action = action;
|
|
401
|
+
form.enctype = "multipart/form-data";
|
|
402
|
+
form.dataset["sosekisubmit"] = ""; // 後で削除できるように目印を付与します。
|
|
403
|
+
|
|
404
|
+
// 実際のフォーム送信を行うために DOM へ一時配置して実行します。
|
|
405
|
+
// ハンドラーがこの要素を使用した後に DOM から削除します。
|
|
406
|
+
document.body.appendChild(form);
|
|
407
|
+
form.submit();
|
|
408
|
+
|
|
409
|
+
break;
|
|
338
410
|
}
|
|
339
411
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
u.search = target.toString();
|
|
354
|
-
this.navigate({
|
|
355
|
-
to: u.href.slice("x://y".length),
|
|
356
|
-
history,
|
|
357
|
-
});
|
|
412
|
+
case "URL_SEARCH_PARAMS": {
|
|
413
|
+
const { action, target, history } = args;
|
|
414
|
+
const path = new RoutePath(action);
|
|
415
|
+
path.search = target.toString();
|
|
416
|
+
|
|
417
|
+
// Navigation API を用いて、クエリーが上書きされた新しいアドレスへ遷移させます。
|
|
418
|
+
this.navigation.navigate(path.toString(), { history });
|
|
419
|
+
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
default:
|
|
424
|
+
unreachable(args);
|
|
358
425
|
}
|
|
359
426
|
}
|
|
360
427
|
|
|
361
428
|
/**
|
|
362
|
-
*
|
|
429
|
+
* 命令的なページ遷移を処理します。
|
|
363
430
|
*
|
|
364
|
-
* @param args
|
|
431
|
+
* @param args 遷移タイプに応じたナビゲーション引数です。
|
|
365
432
|
*/
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
433
|
+
navigate(args: IEngine.NavigateArgs): void {
|
|
434
|
+
switch (args.type) {
|
|
435
|
+
case "LINK": {
|
|
436
|
+
const { to, history } = args;
|
|
437
|
+
switch (to.type) {
|
|
438
|
+
case "PATH": {
|
|
439
|
+
// 完全なパス文字列の余分なスラッシュなどをエンコードして直接遷移します。
|
|
440
|
+
|
|
441
|
+
const path = RoutePath.encode(to.path);
|
|
442
|
+
this.navigation.navigate(path, { history });
|
|
443
|
+
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
case "PARTIAL": {
|
|
448
|
+
// 現在のロケーション情報をベースに、指定されたパーツ(パス名、クエリー、ハッシュのみなど)を部分的にパッチ(上書き)したマージ URL を算出します。
|
|
449
|
+
|
|
450
|
+
const currentPath = new RoutePath(window.location);
|
|
451
|
+
const nextPath = new RoutePath(window.location);
|
|
452
|
+
if (typeof to.pathname === "string") {
|
|
453
|
+
nextPath.pathname = to.pathname;
|
|
454
|
+
}
|
|
455
|
+
if (typeof to.search === "string") {
|
|
456
|
+
nextPath.search = to.search;
|
|
457
|
+
}
|
|
458
|
+
if (typeof to.hash === "string") {
|
|
459
|
+
nextPath.hash = to.hash;
|
|
460
|
+
}
|
|
372
461
|
|
|
373
|
-
|
|
374
|
-
const index = currentEntry.index + delta;
|
|
375
|
-
const entry = this.nav.entries().find(e => e.index === index);
|
|
376
|
-
if (!entry) {
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
462
|
+
const nextPathString = nextPath.toString();
|
|
379
463
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const u = new URL(href);
|
|
391
|
-
if (to.pathname !== undefined) {
|
|
392
|
-
u.pathname = to.pathname;
|
|
393
|
-
}
|
|
394
|
-
if (to.search !== undefined) {
|
|
395
|
-
u.search = to.search;
|
|
464
|
+
// 無駄な遷移履歴を作らないように、URL に実際の変化がある場合のみ navigate を実行します。
|
|
465
|
+
if (nextPathString !== currentPath.toString()) {
|
|
466
|
+
this.navigation.navigate(nextPathString, { history });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
default:
|
|
473
|
+
unreachable(to);
|
|
396
474
|
}
|
|
397
|
-
|
|
398
|
-
|
|
475
|
+
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
case "MOVE": {
|
|
480
|
+
const currentEntry = expectHistoryEntry(this.navigation.currentEntry);
|
|
481
|
+
if (!currentEntry) {
|
|
482
|
+
return;
|
|
399
483
|
}
|
|
400
|
-
|
|
401
|
-
|
|
484
|
+
|
|
485
|
+
const { delta } = args;
|
|
486
|
+
|
|
487
|
+
// 現在のインデックスから相対位置(例: -1 なら 1 つ戻る)を計算し、履歴スタックに該当するインデックスが存在するか探索します。
|
|
488
|
+
const index = currentEntry.index + delta;
|
|
489
|
+
const entry = this.navigation.entries().find((e) => e.index === index);
|
|
490
|
+
if (!entry) {
|
|
491
|
+
// スタックの限界を超える移動要求の場合は何もしません。
|
|
492
|
+
return;
|
|
402
493
|
}
|
|
494
|
+
|
|
495
|
+
// Navigation API の traverseTo メソッドを使用し、一意の識別キーを指定して目的地へジャンプします。
|
|
496
|
+
this.navigation.traverseTo(entry.key);
|
|
497
|
+
|
|
498
|
+
break;
|
|
403
499
|
}
|
|
500
|
+
|
|
501
|
+
default:
|
|
502
|
+
unreachable(args);
|
|
404
503
|
}
|
|
405
504
|
}
|
|
406
505
|
}
|