mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
22 Commits
patch-test
...
sp/react-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f8643cade | ||
|
|
f83f4c03d5 | ||
|
|
ec69d340c9 | ||
|
|
02a2b393b8 | ||
|
|
6bbab525d0 | ||
|
|
bf1debb947 | ||
|
|
caf0e3fae1 | ||
|
|
0f00d63648 | ||
|
|
6a44a70372 | ||
|
|
9bef17d9c8 | ||
|
|
7d8204a0a7 | ||
|
|
7236dabdce | ||
|
|
faa553faf9 | ||
|
|
eca89a38bf | ||
|
|
b907726bbd | ||
|
|
bcfad4e6c6 | ||
|
|
b418632450 | ||
|
|
0936639f81 | ||
|
|
86a3d353d6 | ||
|
|
492921b649 | ||
|
|
1db7c5322c | ||
|
|
16c373f853 |
@@ -200,6 +200,8 @@ ion-toast-controller,
|
||||
|
||||
.ion-page-invisible {
|
||||
opacity: 0;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.can-go-back > ion-header ion-back-button {
|
||||
|
||||
396
packages/react-router/package-lock.json
generated
396
packages/react-router/package-lock.json
generated
@@ -17,18 +17,16 @@
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@rollup/plugin-node-resolve": "^8.1.0",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/react": "16.14.0",
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"@types/react-router": "^5.0.3",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"@typescript-eslint/parser": "^5.48.2",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.8.3",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.26.4",
|
||||
"rollup-plugin-sourcemaps": "^0.6.2",
|
||||
@@ -37,8 +35,8 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.6",
|
||||
"react-dom": ">=16.8.6",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1"
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@@ -144,17 +142,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.16.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
|
||||
@@ -449,6 +436,15 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.0.tgz",
|
||||
"integrity": "sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-node-resolve": {
|
||||
"version": "8.4.0",
|
||||
"dev": true,
|
||||
@@ -502,11 +498,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/history": {
|
||||
"version": "4.7.9",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
@@ -530,39 +521,23 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "16.14.0",
|
||||
"version": "17.0.44",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.44.tgz",
|
||||
"integrity": "sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "16.9.14",
|
||||
"version": "17.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz",
|
||||
"integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "^16"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.17",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router-dom": {
|
||||
"version": "5.3.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
"@types/react": "^17"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
@@ -573,6 +548,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
@@ -2097,27 +2078,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/history": {
|
||||
"version": "4.10.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^3.0.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0",
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
@@ -2441,11 +2401,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -2562,19 +2517,6 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-create-react-context": {
|
||||
"version": "0.4.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"tiny-warning": "^1.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.0.0",
|
||||
"react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -2733,14 +2675,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "1.8.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
@@ -2795,15 +2729,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.7.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz",
|
||||
@@ -2834,76 +2759,62 @@
|
||||
]
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "16.14.0",
|
||||
"license": "MIT",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "16.14.0",
|
||||
"license": "MIT",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
"scheduler": "^0.20.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0"
|
||||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "5.2.1",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.0.tgz",
|
||||
"integrity": "sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"hoist-non-react-statics": "^3.1.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"mini-create-react-context": "^0.4.0",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.6.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15"
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "5.3.0",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.0.tgz",
|
||||
"integrity": "sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-router": "5.2.1",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0",
|
||||
"react-router": "6.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15"
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.9",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
|
||||
@@ -2968,11 +2879,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pathname": {
|
||||
"version": "3.0.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
@@ -3070,8 +2976,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.19.1",
|
||||
"license": "MIT",
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -3311,16 +3218,6 @@
|
||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -3451,11 +3348,6 @@
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/value-equal": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -3613,13 +3505,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.16.3",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
|
||||
@@ -3821,6 +3706,12 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@remix-run/router": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.0.tgz",
|
||||
"integrity": "sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==",
|
||||
"dev": true
|
||||
},
|
||||
"@rollup/plugin-node-resolve": {
|
||||
"version": "8.4.0",
|
||||
"dev": true,
|
||||
@@ -3852,10 +3743,6 @@
|
||||
"version": "0.0.39",
|
||||
"dev": true
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.9",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
@@ -3877,35 +3764,23 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.14.0",
|
||||
"version": "17.0.44",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.44.tgz",
|
||||
"integrity": "sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "16.9.14",
|
||||
"version": "17.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz",
|
||||
"integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "^16"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.17",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router-dom": {
|
||||
"version": "5.3.2",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/history": "*",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
"@types/react": "^17"
|
||||
}
|
||||
},
|
||||
"@types/resolve": {
|
||||
@@ -3915,6 +3790,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
@@ -4974,25 +4855,6 @@
|
||||
"has-symbols": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^3.0.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0",
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
@@ -5212,10 +5074,6 @@
|
||||
"call-bind": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"dev": true
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -5309,14 +5167,6 @@
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"mini-create-react-context": {
|
||||
"version": "0.4.1",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"tiny-warning": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -5432,13 +5282,6 @@
|
||||
"version": "1.0.7",
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "1.8.0",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
@@ -5469,14 +5312,6 @@
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"dev": true
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz",
|
||||
@@ -5490,58 +5325,43 @@
|
||||
"dev": true
|
||||
},
|
||||
"react": {
|
||||
"version": "16.14.0",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.14.0",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
"scheduler": "^0.20.2"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1"
|
||||
},
|
||||
"react-router": {
|
||||
"version": "5.2.1",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.0.tgz",
|
||||
"integrity": "sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"hoist-non-react-statics": "^3.1.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"mini-create-react-context": "^0.4.0",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.6.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "5.3.0",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.0.tgz",
|
||||
"integrity": "sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-router": "5.2.1",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0",
|
||||
"react-router": "6.14.0"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.9",
|
||||
"dev": true
|
||||
},
|
||||
"regexp.prototype.flags": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
|
||||
@@ -5582,10 +5402,6 @@
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "3.0.0",
|
||||
"dev": true
|
||||
},
|
||||
"reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
@@ -5635,7 +5451,9 @@
|
||||
}
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.19.1",
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -5815,14 +5633,6 @@
|
||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"dev": true
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"dev": true
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"dev": true
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -5923,10 +5733,6 @@
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||
"dev": true
|
||||
},
|
||||
"value-equal": {
|
||||
"version": "1.0.1",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -43,26 +43,24 @@
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.6",
|
||||
"react-dom": ">=16.8.6",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1"
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@rollup/plugin-node-resolve": "^8.1.0",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/react": "16.14.0",
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"@types/react-router": "^5.0.3",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"@typescript-eslint/parser": "^5.48.2",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.8.3",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.26.4",
|
||||
"rollup-plugin-sourcemaps": "^0.6.2",
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import type { Action as HistoryAction, History, Location as HistoryLocation } from 'history';
|
||||
import { createHashHistory as createHistory } from 'history';
|
||||
import React from 'react';
|
||||
import type { BrowserRouterProps } from 'react-router-dom';
|
||||
import { Router } from 'react-router-dom';
|
||||
|
||||
import { IonRouter } from './IonRouter';
|
||||
|
||||
interface IonReactHashRouterProps extends BrowserRouterProps {
|
||||
history?: History;
|
||||
}
|
||||
|
||||
export class IonReactHashRouter extends React.Component<IonReactHashRouterProps> {
|
||||
history: History;
|
||||
historyListenHandler?: (location: HistoryLocation, action: HistoryAction) => void;
|
||||
|
||||
constructor(props: IonReactHashRouterProps) {
|
||||
super(props);
|
||||
const { history, ...rest } = props;
|
||||
this.history = history || createHistory(rest);
|
||||
this.history.listen(this.handleHistoryChange.bind(this));
|
||||
this.registerHistoryListener = this.registerHistoryListener.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* history@4.x passes separate location and action
|
||||
* params. history@5.x passes location and action
|
||||
* together as a single object.
|
||||
* TODO: If support for React Router <=5 is dropped
|
||||
* this logic is no longer needed. We can just assume
|
||||
* a single object with both location and action.
|
||||
*/
|
||||
handleHistoryChange(location: HistoryLocation, action: HistoryAction) {
|
||||
const locationValue = (location as any).location || location;
|
||||
const actionValue = (location as any).action || action;
|
||||
if (this.historyListenHandler) {
|
||||
this.historyListenHandler(locationValue, actionValue);
|
||||
}
|
||||
}
|
||||
|
||||
registerHistoryListener(cb: (location: HistoryLocation, action: HistoryAction) => void) {
|
||||
this.historyListenHandler = cb;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, ...props } = this.props;
|
||||
return (
|
||||
<Router history={this.history} {...props}>
|
||||
<IonRouter registerHistoryListener={this.registerHistoryListener}>{children}</IonRouter>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { Action as HistoryAction, Location as HistoryLocation, MemoryHistory } from 'history';
|
||||
import React from 'react';
|
||||
import type { MemoryRouterProps } from 'react-router';
|
||||
import { Router } from 'react-router';
|
||||
|
||||
import { IonRouter } from './IonRouter';
|
||||
|
||||
interface IonReactMemoryRouterProps extends MemoryRouterProps {
|
||||
history: MemoryHistory;
|
||||
}
|
||||
|
||||
export class IonReactMemoryRouter extends React.Component<IonReactMemoryRouterProps> {
|
||||
history: MemoryHistory;
|
||||
historyListenHandler?: (location: HistoryLocation, action: HistoryAction) => void;
|
||||
|
||||
constructor(props: IonReactMemoryRouterProps) {
|
||||
super(props);
|
||||
this.history = props.history;
|
||||
this.history.listen(this.handleHistoryChange.bind(this));
|
||||
this.registerHistoryListener = this.registerHistoryListener.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* history@4.x passes separate location and action
|
||||
* params. history@5.x passes location and action
|
||||
* together as a single object.
|
||||
* TODO: If support for React Router <=5 is dropped
|
||||
* this logic is no longer needed. We can just assume
|
||||
* a single object with both location and action.
|
||||
*/
|
||||
handleHistoryChange(location: HistoryLocation, action: HistoryAction) {
|
||||
const locationValue = (location as any).location || location;
|
||||
const actionValue = (location as any).action || action;
|
||||
if (this.historyListenHandler) {
|
||||
this.historyListenHandler(locationValue, actionValue);
|
||||
}
|
||||
}
|
||||
|
||||
registerHistoryListener(cb: (location: HistoryLocation, action: HistoryAction) => void) {
|
||||
this.historyListenHandler = cb;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, ...props } = this.props;
|
||||
return (
|
||||
<Router {...props}>
|
||||
<IonRouter registerHistoryListener={this.registerHistoryListener}>{children}</IonRouter>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,20 @@
|
||||
import type { Action as HistoryAction, History, Location as HistoryLocation } from 'history';
|
||||
import { createBrowserHistory as createHistory } from 'history';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React from 'react';
|
||||
import type { BrowserRouterProps } from 'react-router-dom';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import { IonRouter } from './IonRouter';
|
||||
import IonRouter from './IonRouter';
|
||||
|
||||
interface IonReactRouterProps extends BrowserRouterProps {
|
||||
history?: History;
|
||||
}
|
||||
|
||||
export class IonReactRouter extends React.Component<IonReactRouterProps> {
|
||||
historyListenHandler?: (location: HistoryLocation, action: HistoryAction) => void;
|
||||
history: History;
|
||||
|
||||
constructor(props: IonReactRouterProps) {
|
||||
super(props);
|
||||
const { history, ...rest } = props;
|
||||
this.history = history || createHistory(rest);
|
||||
this.history.listen(this.handleHistoryChange.bind(this));
|
||||
this.registerHistoryListener = this.registerHistoryListener.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* history@4.x passes separate location and action
|
||||
* params. history@5.x passes location and action
|
||||
* together as a single object.
|
||||
* TODO: If support for React Router <=5 is dropped
|
||||
* this logic is no longer needed. We can just assume
|
||||
* a single object with both location and action.
|
||||
*/
|
||||
handleHistoryChange(location: HistoryLocation, action: HistoryAction) {
|
||||
const locationValue = (location as any).location || location;
|
||||
const actionValue = (location as any).action || action;
|
||||
if (this.historyListenHandler) {
|
||||
this.historyListenHandler(locationValue, actionValue);
|
||||
}
|
||||
}
|
||||
|
||||
registerHistoryListener(cb: (location: HistoryLocation, action: HistoryAction) => void) {
|
||||
this.historyListenHandler = cb;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, ...props } = this.props;
|
||||
return (
|
||||
<Router history={this.history} {...props}>
|
||||
<IonRouter registerHistoryListener={this.registerHistoryListener}>{children}</IonRouter>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Wrapper around react-router-dom's BrowserRouter that provides a context for IonRouterOutlet.
|
||||
* Ionic developers should use IonReactRouter instead of BrowserRouter when using React Router.
|
||||
*/
|
||||
export function IonReactRouter({ children }: PropsWithChildren<BrowserRouterProps>) {
|
||||
// BrowserRouter is used so that the route state is kept in sync with the browser history.
|
||||
// This reflects the current route in the URL.
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<IonRouter>{children}</IonRouter>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,29 +2,6 @@ import type { IonRouteProps } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import { Route } from 'react-router';
|
||||
|
||||
export class IonRouteInner extends React.PureComponent<IonRouteProps> {
|
||||
render() {
|
||||
return (
|
||||
<Route
|
||||
path={this.props.path}
|
||||
exact={this.props.exact}
|
||||
render={this.props.render}
|
||||
{
|
||||
/**
|
||||
* `computedMatch` is a private API in react-router v5 that
|
||||
* has been removed in v6.
|
||||
*
|
||||
* This needs to be removed when we support v6.
|
||||
*
|
||||
* TODO: FW-647
|
||||
*/
|
||||
...((this.props as any).computedMatch !== undefined
|
||||
? {
|
||||
computedMatch: (this.props as any).computedMatch,
|
||||
}
|
||||
: {})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
export function IonRouteInner(props: IonRouteProps) {
|
||||
return <Route path={props.path} children={props.render} />;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import type {
|
||||
AnimationBuilder,
|
||||
RouteAction,
|
||||
RouteInfo,
|
||||
RouteManagerContextState,
|
||||
RouterDirection,
|
||||
ViewItem,
|
||||
} from '@ionic/react';
|
||||
import type { AnimationBuilder, RouteAction, RouteInfo, RouteManagerContextState, RouterDirection } from '@ionic/react';
|
||||
import { LocationHistory, NavManager, RouteManagerContext, generateId, getConfig } from '@ionic/react';
|
||||
import type { Action as HistoryAction, Location as HistoryLocation } from 'history';
|
||||
import React from 'react';
|
||||
import type { RouteComponentProps } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import type { Location, NavigationType } from 'react-router-dom';
|
||||
import { useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom';
|
||||
|
||||
import { IonRouteInner } from './IonRouteInner';
|
||||
import { ReactRouterViewStack } from './ReactRouterViewStack';
|
||||
@@ -21,158 +14,149 @@ export interface LocationState {
|
||||
routerOptions?: { as?: string; unmount?: boolean };
|
||||
}
|
||||
|
||||
interface IonRouteProps extends RouteComponentProps<{}, {}, LocationState> {
|
||||
registerHistoryListener: (cb: (location: HistoryLocation<any>, action: HistoryAction) => void) => void;
|
||||
}
|
||||
const IonRouter = ({ children }: PropsWithChildren<{}>) => {
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const navigationType = useNavigationType();
|
||||
|
||||
interface IonRouteState {
|
||||
routeInfo: RouteInfo;
|
||||
}
|
||||
const [currentTab, setCurrentTab] = useState<string>();
|
||||
const [incomingRouteParams, setIncomingRouteParams] = useState<Partial<RouteInfo>>({});
|
||||
const [routeInfo, setRouteInfo] = useState({
|
||||
id: generateId('routeInfo'),
|
||||
pathname: location.pathname,
|
||||
search: location.search,
|
||||
});
|
||||
const locationHistory = useRef(new LocationHistory());
|
||||
|
||||
class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
||||
currentTab?: string;
|
||||
exitViewFromOtherOutletHandlers: ((pathname: string) => ViewItem | undefined)[] = [];
|
||||
incomingRouteParams?: Partial<RouteInfo>;
|
||||
locationHistory = new LocationHistory();
|
||||
viewStack = new ReactRouterViewStack();
|
||||
routeMangerContextState: RouteManagerContextState = {
|
||||
canGoBack: () => this.locationHistory.canGoBack(),
|
||||
clearOutlet: this.viewStack.clear,
|
||||
findViewItemByPathname: this.viewStack.findViewItemByPathname,
|
||||
getChildrenToRender: this.viewStack.getChildrenToRender,
|
||||
goBack: () => this.handleNavigateBack(),
|
||||
createViewItem: this.viewStack.createViewItem,
|
||||
findViewItemByRouteInfo: this.viewStack.findViewItemByRouteInfo,
|
||||
findLeavingViewItemByRouteInfo: this.viewStack.findLeavingViewItemByRouteInfo,
|
||||
addViewItem: this.viewStack.add,
|
||||
unMountViewItem: this.viewStack.remove,
|
||||
};
|
||||
const viewStack = useRef(new ReactRouterViewStack());
|
||||
|
||||
constructor(props: IonRouteProps) {
|
||||
super(props);
|
||||
useEffect(() => {
|
||||
locationHistory.current.add(routeInfo);
|
||||
}, []);
|
||||
|
||||
const routeInfo = {
|
||||
id: generateId('routeInfo'),
|
||||
pathname: this.props.location.pathname,
|
||||
search: this.props.location.search,
|
||||
};
|
||||
useEffect(() => {
|
||||
handleHistoryChange(location, navigationType);
|
||||
}, [location, navigationType]);
|
||||
|
||||
this.locationHistory.add(routeInfo);
|
||||
this.handleChangeTab = this.handleChangeTab.bind(this);
|
||||
this.handleResetTab = this.handleResetTab.bind(this);
|
||||
this.handleNativeBack = this.handleNativeBack.bind(this);
|
||||
this.handleNavigate = this.handleNavigate.bind(this);
|
||||
this.handleNavigateBack = this.handleNavigateBack.bind(this);
|
||||
this.props.registerHistoryListener(this.handleHistoryChange.bind(this));
|
||||
this.handleSetCurrentTab = this.handleSetCurrentTab.bind(this);
|
||||
|
||||
this.state = {
|
||||
routeInfo,
|
||||
};
|
||||
}
|
||||
|
||||
handleChangeTab(tab: string, path?: string, routeOptions?: any) {
|
||||
const handleChangeTab = (tab: string, path?: string, routeOptions?: any) => {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
const routeInfo = this.locationHistory.getCurrentRouteInfoForTab(tab);
|
||||
const routeInfo = locationHistory.current.getCurrentRouteInfoForTab(tab);
|
||||
const [pathname, search] = path.split('?');
|
||||
if (routeInfo) {
|
||||
this.incomingRouteParams = { ...routeInfo, routeAction: 'push', routeDirection: 'none' };
|
||||
if (routeInfo.pathname === pathname) {
|
||||
this.incomingRouteParams.routeOptions = routeOptions;
|
||||
this.props.history.push(routeInfo.pathname + (routeInfo.search || ''));
|
||||
} else {
|
||||
this.incomingRouteParams.pathname = pathname;
|
||||
this.incomingRouteParams.search = search ? '?' + search : undefined;
|
||||
this.incomingRouteParams.routeOptions = routeOptions;
|
||||
this.props.history.push(pathname + (search ? '?' + search : ''));
|
||||
}
|
||||
} else {
|
||||
this.handleNavigate(pathname, 'push', 'none', undefined, routeOptions, tab);
|
||||
}
|
||||
}
|
||||
|
||||
handleHistoryChange(location: HistoryLocation<LocationState>, action: HistoryAction) {
|
||||
let leavingLocationInfo: RouteInfo;
|
||||
if (this.incomingRouteParams) {
|
||||
if (this.incomingRouteParams.routeAction === 'replace') {
|
||||
leavingLocationInfo = this.locationHistory.previous();
|
||||
if (routeInfo) {
|
||||
const routeParams = {
|
||||
...incomingRouteParams,
|
||||
routeAction: 'push' as RouteAction,
|
||||
routeDirection: 'none' as RouterDirection,
|
||||
};
|
||||
if (routeInfo.pathname === pathname) {
|
||||
routeParams.routeOptions = routeOptions;
|
||||
setIncomingRouteParams({
|
||||
...routeParams,
|
||||
routeOptions,
|
||||
});
|
||||
navigate(routeInfo.pathname + (routeInfo.search || ''));
|
||||
} else {
|
||||
leavingLocationInfo = this.locationHistory.current();
|
||||
setIncomingRouteParams({
|
||||
...routeParams,
|
||||
pathname,
|
||||
search: search ? '?' + search : undefined,
|
||||
routeOptions,
|
||||
});
|
||||
navigate(pathname + (search ? '?' + search : ''));
|
||||
}
|
||||
} else {
|
||||
leavingLocationInfo = this.locationHistory.current();
|
||||
handleNavigate(pathname, 'push', 'none', undefined, routeOptions, tab);
|
||||
}
|
||||
};
|
||||
|
||||
const handleHistoryChange = (location: Location, action: NavigationType) => {
|
||||
let leavingLocationInfo: RouteInfo;
|
||||
if (incomingRouteParams) {
|
||||
if (incomingRouteParams.routeAction === 'replace') {
|
||||
leavingLocationInfo = locationHistory.current.previous();
|
||||
} else {
|
||||
leavingLocationInfo = locationHistory.current.current();
|
||||
}
|
||||
} else {
|
||||
leavingLocationInfo = locationHistory.current.current();
|
||||
}
|
||||
|
||||
const leavingUrl = leavingLocationInfo.pathname + leavingLocationInfo.search;
|
||||
if (leavingUrl !== location.pathname) {
|
||||
if (!this.incomingRouteParams) {
|
||||
if (!incomingRouteParams) {
|
||||
if (action === 'REPLACE') {
|
||||
this.incomingRouteParams = {
|
||||
routeAction: 'replace',
|
||||
routeDirection: 'none',
|
||||
tab: this.currentTab,
|
||||
};
|
||||
setIncomingRouteParams({
|
||||
routeAction: 'replace' as RouteAction,
|
||||
routeDirection: 'none' as RouterDirection,
|
||||
tab: currentTab,
|
||||
});
|
||||
}
|
||||
if (action === 'POP') {
|
||||
const currentRoute = this.locationHistory.current();
|
||||
const currentRoute = locationHistory.current.current();
|
||||
if (currentRoute && currentRoute.pushedByRoute) {
|
||||
const prevInfo = this.locationHistory.findLastLocation(currentRoute);
|
||||
this.incomingRouteParams = { ...prevInfo, routeAction: 'pop', routeDirection: 'back' };
|
||||
const prevInfo = locationHistory.current.findLastLocation(currentRoute);
|
||||
setIncomingRouteParams({
|
||||
...prevInfo,
|
||||
routeAction: 'pop' as RouteAction,
|
||||
routeDirection: 'back' as RouterDirection,
|
||||
});
|
||||
} else {
|
||||
this.incomingRouteParams = {
|
||||
routeAction: 'pop',
|
||||
routeDirection: 'none',
|
||||
tab: this.currentTab,
|
||||
};
|
||||
setIncomingRouteParams({
|
||||
routeAction: 'pop' as RouteAction,
|
||||
routeDirection: 'back' as RouterDirection,
|
||||
tab: currentTab,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!this.incomingRouteParams) {
|
||||
this.incomingRouteParams = {
|
||||
routeAction: 'push',
|
||||
if (!incomingRouteParams) {
|
||||
setIncomingRouteParams({
|
||||
routeAction: 'push' as RouteAction,
|
||||
routeDirection: location.state?.direction || 'forward',
|
||||
routeOptions: location.state?.routerOptions,
|
||||
tab: this.currentTab,
|
||||
};
|
||||
routeOptions: location.state?.routerOptions, // todo @sean review this routeOptions vs. routerOptions
|
||||
tab: currentTab,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let routeInfo: RouteInfo;
|
||||
|
||||
if (this.incomingRouteParams?.id) {
|
||||
if (incomingRouteParams?.id) {
|
||||
routeInfo = {
|
||||
...(this.incomingRouteParams as RouteInfo),
|
||||
...(incomingRouteParams as RouteInfo),
|
||||
lastPathname: leavingLocationInfo.pathname,
|
||||
};
|
||||
this.locationHistory.add(routeInfo);
|
||||
locationHistory.current.add(routeInfo);
|
||||
} else {
|
||||
const isPushed =
|
||||
this.incomingRouteParams.routeAction === 'push' && this.incomingRouteParams.routeDirection === 'forward';
|
||||
const isPushed = incomingRouteParams.routeAction === 'push' && incomingRouteParams.routeDirection === 'forward';
|
||||
|
||||
routeInfo = {
|
||||
id: generateId('routeInfo'),
|
||||
...this.incomingRouteParams,
|
||||
...incomingRouteParams,
|
||||
lastPathname: leavingLocationInfo.pathname,
|
||||
pathname: location.pathname,
|
||||
search: location.search,
|
||||
params: this.props.match.params,
|
||||
params: params as any, // TODO @sean fix type of route info for params
|
||||
prevRouteLastPathname: leavingLocationInfo.lastPathname,
|
||||
};
|
||||
|
||||
if (isPushed) {
|
||||
routeInfo.tab = leavingLocationInfo.tab;
|
||||
routeInfo.pushedByRoute = leavingLocationInfo.pathname;
|
||||
} else if (routeInfo.routeAction === 'pop') {
|
||||
const r = this.locationHistory.findLastLocation(routeInfo);
|
||||
const r = locationHistory.current.findLastLocation(routeInfo);
|
||||
routeInfo.pushedByRoute = r?.pushedByRoute;
|
||||
} else if (routeInfo.routeAction === 'push' && routeInfo.tab !== leavingLocationInfo.tab) {
|
||||
// If we are switching tabs grab the last route info for the tab and use its pushedByRoute
|
||||
const lastRoute = this.locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
|
||||
const lastRoute = locationHistory.current.getCurrentRouteInfoForTab(routeInfo.tab);
|
||||
routeInfo.pushedByRoute = lastRoute?.pushedByRoute;
|
||||
} else if (routeInfo.routeAction === 'replace') {
|
||||
// Make sure to set the lastPathname, etc.. to the current route so the page transitions out
|
||||
const currentRouteInfo = this.locationHistory.current();
|
||||
|
||||
const currentRouteInfo = locationHistory.current.current();
|
||||
/**
|
||||
* If going from /home to /child, then replacing from
|
||||
* /child to /home, we don't want the route info to
|
||||
@@ -190,39 +174,28 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
||||
routeInfo.routeDirection = currentRouteInfo?.routeDirection || routeInfo.routeDirection;
|
||||
routeInfo.routeAnimation = currentRouteInfo?.routeAnimation || routeInfo.routeAnimation;
|
||||
}
|
||||
|
||||
this.locationHistory.add(routeInfo);
|
||||
locationHistory.current.add(routeInfo);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
routeInfo,
|
||||
});
|
||||
setRouteInfo(routeInfo);
|
||||
}
|
||||
|
||||
this.incomingRouteParams = undefined;
|
||||
}
|
||||
setIncomingRouteParams({});
|
||||
};
|
||||
|
||||
/**
|
||||
* history@4.x uses goBack(), history@5.x uses back()
|
||||
* TODO: If support for React Router <=5 is dropped
|
||||
* this logic is no longer needed. We can just
|
||||
* assume back() is available.
|
||||
*/
|
||||
handleNativeBack() {
|
||||
const history = this.props.history as any;
|
||||
const goBack = history.goBack || history.back;
|
||||
goBack();
|
||||
}
|
||||
const handleNativeBack = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
|
||||
handleNavigate(
|
||||
const handleNavigate = (
|
||||
path: string,
|
||||
routeAction: RouteAction,
|
||||
routeDirection?: RouterDirection,
|
||||
routeAnimation?: AnimationBuilder,
|
||||
routeOptions?: any,
|
||||
tab?: string
|
||||
) {
|
||||
this.incomingRouteParams = Object.assign(this.incomingRouteParams || {}, {
|
||||
) => {
|
||||
setIncomingRouteParams({
|
||||
...incomingRouteParams,
|
||||
routeAction,
|
||||
routeDirection,
|
||||
routeOptions,
|
||||
@@ -230,26 +203,28 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
||||
tab,
|
||||
});
|
||||
|
||||
if (routeAction === 'push') {
|
||||
this.props.history.push(path);
|
||||
} else {
|
||||
this.props.history.replace(path);
|
||||
}
|
||||
}
|
||||
navigate(path, { replace: routeAction !== 'push' });
|
||||
};
|
||||
|
||||
handleNavigateBack(defaultHref: string | RouteInfo = '/', routeAnimation?: AnimationBuilder) {
|
||||
const handleNavigateBack = (defaultHref: string | RouteInfo = '/', routeAnimation?: AnimationBuilder) => {
|
||||
const config = getConfig();
|
||||
defaultHref = defaultHref ? defaultHref : config && config.get('backButtonDefaultHref' as any);
|
||||
const routeInfo = this.locationHistory.current();
|
||||
|
||||
if (!defaultHref && config) {
|
||||
// If the defaultHref wasn't passed in, then we should use the configured defaultHref.
|
||||
// Developers can set this on their IonicConfig.
|
||||
defaultHref = config.get('backButtonDefaultHref');
|
||||
}
|
||||
|
||||
const routeInfo = locationHistory.current.current();
|
||||
if (routeInfo && routeInfo.pushedByRoute) {
|
||||
const prevInfo = this.locationHistory.findLastLocation(routeInfo);
|
||||
const prevInfo = locationHistory.current.findLastLocation(routeInfo);
|
||||
if (prevInfo) {
|
||||
this.incomingRouteParams = {
|
||||
setIncomingRouteParams({
|
||||
...prevInfo,
|
||||
routeAction: 'pop',
|
||||
routeDirection: 'back',
|
||||
routeAction: 'pop' as RouteAction,
|
||||
routeDirection: 'back' as RouterDirection,
|
||||
routeAnimation: routeAnimation || routeInfo.routeAnimation,
|
||||
};
|
||||
});
|
||||
if (
|
||||
routeInfo.lastPathname === routeInfo.pushedByRoute ||
|
||||
/**
|
||||
@@ -260,68 +235,74 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
||||
*/
|
||||
(prevInfo.pathname === routeInfo.pushedByRoute && routeInfo.tab === '' && prevInfo.tab === '')
|
||||
) {
|
||||
/**
|
||||
* history@4.x uses goBack(), history@5.x uses back()
|
||||
* TODO: If support for React Router <=5 is dropped
|
||||
* this logic is no longer needed. We can just
|
||||
* assume back() is available.
|
||||
*/
|
||||
const history = this.props.history as any;
|
||||
const goBack = history.goBack || history.back;
|
||||
goBack();
|
||||
navigate(-1);
|
||||
} else {
|
||||
this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back');
|
||||
handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back');
|
||||
}
|
||||
} else {
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
}
|
||||
} else {
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleResetTab(tab: string, originalHref: string, originalRouteOptions: any) {
|
||||
const routeInfo = this.locationHistory.getFirstRouteInfoForTab(tab);
|
||||
if (routeInfo) {
|
||||
const newRouteInfo = { ...routeInfo };
|
||||
newRouteInfo.pathname = originalHref;
|
||||
newRouteInfo.routeOptions = originalRouteOptions;
|
||||
this.incomingRouteParams = { ...newRouteInfo, routeAction: 'pop', routeDirection: 'back' };
|
||||
this.props.history.push(newRouteInfo.pathname + (newRouteInfo.search || ''));
|
||||
const handleResetTab = (tab: string, originalHref: string, originalRouteOptions: any) => {
|
||||
const firstRouteForTab = locationHistory.current.getFirstRouteInfoForTab(tab);
|
||||
if (firstRouteForTab) {
|
||||
const routeInfo = {
|
||||
...firstRouteForTab,
|
||||
pathName: originalHref,
|
||||
routeOptions: originalRouteOptions,
|
||||
routeAction: 'pop' as RouteAction,
|
||||
routeDirection: 'back' as RouterDirection,
|
||||
};
|
||||
setIncomingRouteParams(routeInfo);
|
||||
navigate(routeInfo.pathname + (routeInfo.search || ''));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleSetCurrentTab(tab: string) {
|
||||
this.currentTab = tab;
|
||||
const ri = { ...this.locationHistory.current() };
|
||||
if (ri.tab !== tab) {
|
||||
ri.tab = tab;
|
||||
this.locationHistory.update(ri);
|
||||
const handleSetCurrentTab = (tab: string) => {
|
||||
setCurrentTab(tab);
|
||||
const currentRoute = locationHistory.current.current();
|
||||
if (currentRoute && currentRoute.tab !== tab) {
|
||||
const updatedRoute = { ...currentRoute, tab };
|
||||
locationHistory.current.update(updatedRoute);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RouteManagerContext.Provider value={this.routeMangerContextState}>
|
||||
<NavManager
|
||||
ionRoute={IonRouteInner}
|
||||
ionRedirect={{}}
|
||||
stackManager={StackManager}
|
||||
routeInfo={this.state.routeInfo!}
|
||||
onNativeBack={this.handleNativeBack}
|
||||
onNavigateBack={this.handleNavigateBack}
|
||||
onNavigate={this.handleNavigate}
|
||||
onSetCurrentTab={this.handleSetCurrentTab}
|
||||
onChangeTab={this.handleChangeTab}
|
||||
onResetTab={this.handleResetTab}
|
||||
locationHistory={this.locationHistory}
|
||||
>
|
||||
{this.props.children}
|
||||
</NavManager>
|
||||
</RouteManagerContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
const routeManagerContextValue: RouteManagerContextState = {
|
||||
canGoBack: () => locationHistory.current.canGoBack(),
|
||||
clearOutlet: viewStack.current.clear,
|
||||
findViewItemByPathname: viewStack.current.findViewItemByPathname,
|
||||
getChildrenToRender: viewStack.current.getChildrenToRender,
|
||||
goBack: () => handleNavigateBack(),
|
||||
createViewItem: viewStack.current.createViewItem,
|
||||
findViewItemByRouteInfo: viewStack.current.findViewItemByRouteInfo,
|
||||
findLeavingViewItemByRouteInfo: viewStack.current.findLeavingViewItemByRouteInfo,
|
||||
addViewItem: viewStack.current.add,
|
||||
unMountViewItem: viewStack.current.remove,
|
||||
};
|
||||
|
||||
export const IonRouter = withRouter(IonRouterInner);
|
||||
IonRouter.displayName = 'IonRouter';
|
||||
return (
|
||||
<RouteManagerContext.Provider value={routeManagerContextValue}>
|
||||
<NavManager
|
||||
ionRoute={IonRouteInner}
|
||||
ionRedirect={{}}
|
||||
stackManager={StackManager}
|
||||
routeInfo={routeInfo}
|
||||
onNativeBack={handleNativeBack}
|
||||
onNavigateBack={handleNavigateBack}
|
||||
onNavigate={handleNavigate}
|
||||
onSetCurrentTab={handleSetCurrentTab}
|
||||
onChangeTab={handleChangeTab}
|
||||
onResetTab={handleResetTab}
|
||||
locationHistory={locationHistory.current}
|
||||
>
|
||||
{children}
|
||||
</NavManager>
|
||||
</RouteManagerContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default IonRouter;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { RouteInfo, ViewItem } from '@ionic/react';
|
||||
import { IonRoute, ViewLifeCycleManager, ViewStacks, generateId } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import { matchPath } from 'react-router';
|
||||
import { Route, Routes, matchPath } from 'react-router';
|
||||
|
||||
export class ReactRouterViewStack extends ViewStacks {
|
||||
constructor() {
|
||||
@@ -23,13 +23,11 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
ionRoute: false,
|
||||
};
|
||||
|
||||
const matchProps = {
|
||||
exact: reactElement.props.exact,
|
||||
path: reactElement.props.path || reactElement.props.from,
|
||||
component: reactElement.props.component,
|
||||
};
|
||||
if (reactElement.type !== Route) {
|
||||
console.warn('something is wrong, reactElement is not a Route', reactElement);
|
||||
}
|
||||
|
||||
const match = matchPath(routeInfo.pathname, matchProps);
|
||||
const match = matchPath(reactElement.props, routeInfo.pathname);
|
||||
|
||||
if (reactElement.type === IonRoute) {
|
||||
viewItem.ionRoute = true;
|
||||
@@ -47,8 +45,10 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
getChildrenToRender(outletId: string, ionRouterOutlet: React.ReactElement, routeInfo: RouteInfo) {
|
||||
const viewItems = this.getViewItemsForOutlet(outletId);
|
||||
|
||||
const routesNode = findRoutesNode(ionRouterOutlet.props.children);
|
||||
|
||||
// Sync latest routes with viewItems
|
||||
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
|
||||
React.Children.forEach(routesNode, (child: React.ReactElement) => {
|
||||
const viewItem = viewItems.find((v) => {
|
||||
return matchComponent(child, v.routeData.childProps.path || v.routeData.childProps.from);
|
||||
});
|
||||
@@ -58,32 +58,8 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
});
|
||||
|
||||
const children = viewItems.map((viewItem) => {
|
||||
let clonedChild;
|
||||
if (viewItem.ionRoute && !viewItem.disableIonPageManagement) {
|
||||
clonedChild = (
|
||||
<ViewLifeCycleManager
|
||||
key={`view-${viewItem.id}`}
|
||||
mount={viewItem.mount}
|
||||
removeView={() => this.remove(viewItem)}
|
||||
>
|
||||
{React.cloneElement(viewItem.reactElement, {
|
||||
computedMatch: viewItem.routeData.match,
|
||||
})}
|
||||
</ViewLifeCycleManager>
|
||||
);
|
||||
} else {
|
||||
if (!viewItem.ionRoute || viewItem.disableIonPageManagement) {
|
||||
const match = matchComponent(viewItem.reactElement, routeInfo.pathname);
|
||||
clonedChild = (
|
||||
<ViewLifeCycleManager
|
||||
key={`view-${viewItem.id}`}
|
||||
mount={viewItem.mount}
|
||||
removeView={() => this.remove(viewItem)}
|
||||
>
|
||||
{React.cloneElement(viewItem.reactElement, {
|
||||
computedMatch: viewItem.routeData.match,
|
||||
})}
|
||||
</ViewLifeCycleManager>
|
||||
);
|
||||
|
||||
if (!match && viewItem.routeData.match) {
|
||||
viewItem.routeData.match = undefined;
|
||||
@@ -91,6 +67,20 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
}
|
||||
}
|
||||
|
||||
const clonedChild = (
|
||||
<ViewLifeCycleManager
|
||||
key={`view-${viewItem.id}`}
|
||||
mount={viewItem.mount}
|
||||
removeView={() => this.remove(viewItem)}
|
||||
>
|
||||
{/*
|
||||
TODO @sean it is currently required to render a <Routes /> or you will get:
|
||||
Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
|
||||
*/}
|
||||
<Routes>{React.cloneElement(viewItem.reactElement)}</Routes>
|
||||
</ViewLifeCycleManager>
|
||||
);
|
||||
|
||||
return clonedChild;
|
||||
});
|
||||
return children;
|
||||
@@ -140,12 +130,20 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
if (mustBeIonRoute && !v.ionRoute) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pathname === undefined) {
|
||||
// This wasn't needed in react router v5
|
||||
// it is possible we are re-rendering or calling something too early.
|
||||
return false;
|
||||
}
|
||||
|
||||
const matchProps = {
|
||||
exact: forceExact ? true : v.routeData.childProps.exact,
|
||||
path: v.routeData.childProps.path || v.routeData.childProps.from,
|
||||
component: v.routeData.childProps.component,
|
||||
// component: v.routeData.childProps.component, // TODO removed in v6
|
||||
element: v.routeData.childProps.element,
|
||||
};
|
||||
const myMatch = matchPath(pathname, matchProps);
|
||||
const myMatch = matchPath(matchProps, pathname);
|
||||
if (myMatch) {
|
||||
viewItem = v;
|
||||
match = myMatch;
|
||||
@@ -158,11 +156,12 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
// try to find a route that doesn't have a path or from prop, that will be our default route
|
||||
if (!v.routeData.childProps.path && !v.routeData.childProps.from) {
|
||||
match = {
|
||||
path: pathname,
|
||||
url: pathname,
|
||||
isExact: true,
|
||||
pathname,
|
||||
params: {},
|
||||
};
|
||||
// url: pathname,
|
||||
// isExact: true,
|
||||
// params: {},
|
||||
} as any; // TODO @sean review what this is doing
|
||||
viewItem = v;
|
||||
return true;
|
||||
}
|
||||
@@ -171,13 +170,27 @@ export class ReactRouterViewStack extends ViewStacks {
|
||||
}
|
||||
}
|
||||
|
||||
const findRoutesNode = (node: React.ReactNode) => {
|
||||
// Finds the <Routes /> component node
|
||||
let routesNode: React.ReactNode;
|
||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||
if (child.type === Routes) {
|
||||
routesNode = child;
|
||||
}
|
||||
});
|
||||
if (routesNode) {
|
||||
return (routesNode as React.ReactElement).props.children;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function matchComponent(node: React.ReactElement, pathname: string, forceExact?: boolean) {
|
||||
const matchProps = {
|
||||
exact: forceExact ? true : node.props.exact,
|
||||
path: node.props.path || node.props.from,
|
||||
component: node.props.component,
|
||||
element: node.props.element,
|
||||
};
|
||||
const match = matchPath(pathname, matchProps);
|
||||
const match = matchPath(matchProps, pathname);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
|
||||
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { cloneElement, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
||||
import { Route, Routes, matchPath } from 'react-router-dom';
|
||||
|
||||
import { clonePageElement } from './clonePageElement';
|
||||
|
||||
@@ -11,76 +12,91 @@ interface StackManagerProps {
|
||||
routeInfo: RouteInfo;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface StackManagerState {}
|
||||
|
||||
const isViewVisible = (el: HTMLElement) =>
|
||||
!el.classList.contains('ion-page-invisible') && !el.classList.contains('ion-page-hidden');
|
||||
|
||||
export class StackManager extends React.PureComponent<StackManagerProps, StackManagerState> {
|
||||
id: string;
|
||||
context!: React.ContextType<typeof RouteManagerContext>;
|
||||
ionRouterOutlet?: React.ReactElement;
|
||||
routerOutletElement: HTMLIonRouterOutletElement | undefined;
|
||||
prevProps?: StackManagerProps;
|
||||
skipTransition: boolean;
|
||||
export const StackManager = ({ children, ...props }: PropsWithChildren<StackManagerProps>) => {
|
||||
const { routeInfo } = props;
|
||||
const {
|
||||
findViewItemByRouteInfo,
|
||||
findLeavingViewItemByRouteInfo,
|
||||
findViewItemByPathname,
|
||||
createViewItem,
|
||||
addViewItem,
|
||||
goBack,
|
||||
getChildrenToRender,
|
||||
clearOutlet,
|
||||
} = useContext(RouteManagerContext);
|
||||
|
||||
stackContextValue: StackContextState = {
|
||||
registerIonPage: this.registerIonPage.bind(this),
|
||||
isInOutlet: () => true,
|
||||
};
|
||||
const routerOutletRef = useRef<HTMLIonRouterOutletElement>();
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
const ionRouterOutletRef = useRef<React.ReactElement>();
|
||||
const skipTransitionRef = useRef(false);
|
||||
const clearOutletTimeout = useRef(null);
|
||||
const pendingPageTransitionRef = useRef(false);
|
||||
const prevProps = useRef<{ routeInfo: RouteInfo }>();
|
||||
|
||||
private clearOutletTimeout: any;
|
||||
private pendingPageTransition = false;
|
||||
const forceUpdate = useReducer((x) => x + 1, 0)[1];
|
||||
|
||||
constructor(props: StackManagerProps) {
|
||||
super(props);
|
||||
this.registerIonPage = this.registerIonPage.bind(this);
|
||||
this.transitionPage = this.transitionPage.bind(this);
|
||||
this.handlePageTransition = this.handlePageTransition.bind(this);
|
||||
this.id = generateId('routerOutlet');
|
||||
this.prevProps = undefined;
|
||||
this.skipTransition = false;
|
||||
}
|
||||
const [id] = useState(generateId('routerOutlet'));
|
||||
|
||||
componentDidMount() {
|
||||
if (this.clearOutletTimeout) {
|
||||
/**
|
||||
* The clearOutlet integration with React Router is a bit hacky.
|
||||
* It uses a timeout to clear the outlet after a transition.
|
||||
* In React v18, components are mounted and unmounted in development mode
|
||||
* to check for side effects.
|
||||
*
|
||||
* This clearTimeout prevents the outlet from being cleared when the component is re-mounted,
|
||||
* which should only happen in development mode and as a result of a hot reload.
|
||||
*/
|
||||
clearTimeout(this.clearOutletTimeout);
|
||||
const stackContextValue: StackContextState = useMemo(
|
||||
() => ({
|
||||
isInOutlet: () => true,
|
||||
registerIonPage: (page: HTMLElement, routeInfo: RouteInfo) => {
|
||||
const foundView = findViewItemByRouteInfo(routeInfo, id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
*/
|
||||
if (oldPageElement === page) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
handlePageTransition(routeInfo);
|
||||
},
|
||||
}),
|
||||
[routerOutletElement]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (routerOutletElement) {
|
||||
// Mount behavior for the initial route
|
||||
setupRouterOutlet(routerOutletElement);
|
||||
handlePageTransition(routeInfo);
|
||||
}
|
||||
if (this.routerOutletElement) {
|
||||
this.setupRouterOutlet(this.routerOutletElement);
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
}, [routerOutletElement]);
|
||||
|
||||
useEffect(() => {
|
||||
const { pathname } = routeInfo;
|
||||
|
||||
if (pathname !== prevProps.current?.routeInfo.pathname) {
|
||||
prevProps.current = props;
|
||||
handlePageTransition(routeInfo);
|
||||
} else if (pendingPageTransitionRef.current) {
|
||||
handlePageTransition(routeInfo);
|
||||
pendingPageTransitionRef.current = false;
|
||||
}
|
||||
}
|
||||
}, [routeInfo]);
|
||||
|
||||
componentDidUpdate(prevProps: StackManagerProps) {
|
||||
const { pathname } = this.props.routeInfo;
|
||||
const { pathname: prevPathname } = prevProps.routeInfo;
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearOutlet(id);
|
||||
if (clearOutletTimeout.current) {
|
||||
clearTimeout(clearOutletTimeout.current);
|
||||
clearOutletTimeout.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (pathname !== prevPathname) {
|
||||
this.prevProps = prevProps;
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
} else if (this.pendingPageTransition) {
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
this.pendingPageTransition = false;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearOutletTimeout = this.context.clearOutlet(this.id);
|
||||
}
|
||||
|
||||
async handlePageTransition(routeInfo: RouteInfo) {
|
||||
if (!this.routerOutletElement || !this.routerOutletElement.commit) {
|
||||
const handlePageTransition = (routeInfo: RouteInfo) => {
|
||||
if (!routerOutletElement || !routerOutletElement.commit) {
|
||||
/**
|
||||
* The route outlet has not mounted yet. We need to wait for it to render
|
||||
* before we can transition the page.
|
||||
@@ -88,16 +104,16 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* Set a flag to indicate that we should transition the page after
|
||||
* the component has updated.
|
||||
*/
|
||||
this.pendingPageTransition = true;
|
||||
pendingPageTransitionRef.current = true;
|
||||
} else {
|
||||
let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id);
|
||||
let enteringViewItem = findViewItemByRouteInfo(routeInfo, id);
|
||||
let leavingViewItem = findLeavingViewItemByRouteInfo(routeInfo, id);
|
||||
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id);
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
// Check if leavingViewItem should be unmounted
|
||||
// Check if the leavingViewItem should be unmounted
|
||||
if (leavingViewItem) {
|
||||
if (routeInfo.routeAction === 'replace') {
|
||||
leavingViewItem.mount = false;
|
||||
@@ -110,13 +126,15 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
}
|
||||
}
|
||||
|
||||
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
||||
const enteringRoute = matchRoute(ionRouterOutletRef.current?.props.children, routeInfo) as React.ReactElement; // TODO @sean can we return React.ReactElement so we don't need to cast?
|
||||
|
||||
if (enteringViewItem) {
|
||||
// If the entering view is already in the stack, then we need to clone it
|
||||
enteringViewItem.reactElement = enteringRoute;
|
||||
} else if (enteringRoute) {
|
||||
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
|
||||
this.context.addViewItem(enteringViewItem);
|
||||
// Otherwise we need to create a new view item
|
||||
enteringViewItem = createViewItem(id, enteringRoute, routeInfo);
|
||||
addViewItem(enteringViewItem);
|
||||
}
|
||||
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
||||
@@ -143,8 +161,8 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* that the user has routed from a previous path, then we need
|
||||
* to find the leaving view item to transition between.
|
||||
*/
|
||||
if (!leavingViewItem && this.props.routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(this.props.routeInfo.prevRouteLastPathname, this.id);
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,57 +191,39 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* route or on an initial page load (i.e. refreshing). In cases when loading
|
||||
* /tabs/tab-1, we need to transition the /tabs page element into the view.
|
||||
*/
|
||||
this.transitionPage(routeInfo, enteringViewItem, leavingViewItem);
|
||||
transitionPage(routeInfo, enteringViewItem, leavingViewItem!); // TODO @sean why do we need to use ! on the leavingViewItem here? Didn't need to originally.
|
||||
} else if (leavingViewItem && !enteringRoute && !enteringViewItem) {
|
||||
// If we have a leavingView but no entering view/route, we are probably leaving to
|
||||
// another outlet, so hide this leavingView. We do it in a timeout to give time for a
|
||||
// transition to finish.
|
||||
// setTimeout(() => {
|
||||
// another outlet, so hide this leavingView.
|
||||
if (leavingViewItem.ionPageElement) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
// }, 250);
|
||||
}
|
||||
|
||||
this.forceUpdate();
|
||||
// This causes the router outlet to re-render with the updated view items.
|
||||
// Without it, a push navigation will remove the previous route's view item,
|
||||
// but will not render the new route's view item.
|
||||
// this.forceUpdate();
|
||||
forceUpdate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
registerIonPage(page: HTMLElement, routeInfo: RouteInfo) {
|
||||
const foundView = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
*/
|
||||
if (oldPageElement === page) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.handlePageTransition(routeInfo);
|
||||
}
|
||||
|
||||
async setupRouterOutlet(routerOutlet: HTMLIonRouterOutletElement) {
|
||||
const canStart = () => {
|
||||
const setupRouterOutlet = (routerOutlet: HTMLIonRouterOutletElement) => {
|
||||
const canStart = (): boolean => {
|
||||
const config = getConfig();
|
||||
const swipeEnabled = config && config.get('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
const swipeEnabled = config?.getBoolean('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
|
||||
if (!swipeEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any); // TODO figure out what this does
|
||||
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
|
||||
return (
|
||||
!!enteringViewItem &&
|
||||
@@ -247,14 +247,12 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
};
|
||||
|
||||
const onStart = async () => {
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any); // TODO figure out what this does
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
|
||||
/**
|
||||
* When the gesture starts, kick off
|
||||
@@ -262,30 +260,28 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* via a swipe gesture.
|
||||
*/
|
||||
if (enteringViewItem && leavingViewItem) {
|
||||
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
await transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const onEnd = (shouldContinue: boolean) => {
|
||||
if (shouldContinue) {
|
||||
this.skipTransition = true;
|
||||
|
||||
this.context.goBack();
|
||||
skipTransitionRef.current = true;
|
||||
goBack();
|
||||
} else {
|
||||
/**
|
||||
* In the event that the swipe
|
||||
* gesture was aborted, we should
|
||||
* re-hide the page that was going to enter.
|
||||
*/
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any); // TODO figure out what this does
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
|
||||
/**
|
||||
* Ionic React has a design defect where it
|
||||
@@ -309,17 +305,17 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
onStart,
|
||||
onEnd,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
async transitionPage(
|
||||
const transitionPage = async (
|
||||
routeInfo: RouteInfo,
|
||||
enteringViewItem: ViewItem,
|
||||
leavingViewItem?: ViewItem,
|
||||
leavingViewItem: ViewItem,
|
||||
direction?: 'forward' | 'back',
|
||||
progressAnimation = false
|
||||
) {
|
||||
) => {
|
||||
const runCommit = async (enteringEl: HTMLElement, leavingEl?: HTMLElement) => {
|
||||
const skipTransition = this.skipTransition;
|
||||
const skipTransition = skipTransitionRef.current;
|
||||
|
||||
/**
|
||||
* If the transition was handled
|
||||
@@ -342,105 +338,112 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* transition triggered by handlePageTransition
|
||||
* in componentDidUpdate.
|
||||
*/
|
||||
this.skipTransition = false;
|
||||
skipTransitionRef.current = false;
|
||||
} else {
|
||||
enteringEl.classList.add('ion-page');
|
||||
enteringEl.classList.add('ion-page-invisible');
|
||||
enteringEl.classList.add('ion-page', 'ion-page-invisible');
|
||||
}
|
||||
|
||||
await routerOutlet.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransition || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
if (routerOutletElement) {
|
||||
await routerOutletElement.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransitionRef.current || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const routerOutlet = this.routerOutletElement!;
|
||||
|
||||
const routeInfoFallbackDirection =
|
||||
const routerInfoFallbackDirection =
|
||||
routeInfo.routeDirection === 'none' || routeInfo.routeDirection === 'root' ? undefined : routeInfo.routeDirection;
|
||||
const directionToUse = direction ?? routeInfoFallbackDirection;
|
||||
const directionToUse = direction ?? routerInfoFallbackDirection;
|
||||
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement && this.routerOutletElement) {
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
if (enteringViewItem?.ionPageElement && routerOutletElement) {
|
||||
if (leavingViewItem?.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
// If a page is transitioning to another version of itself
|
||||
// we clone it so we can have an animation to show
|
||||
|
||||
const match = matchComponent(leavingViewItem.reactElement, routeInfo.pathname, true);
|
||||
if (match) {
|
||||
const newLeavingElement = clonePageElement(leavingViewItem.ionPageElement.outerHTML);
|
||||
if (newLeavingElement) {
|
||||
this.routerOutletElement.appendChild(newLeavingElement);
|
||||
routerOutletElement.appendChild(newLeavingElement);
|
||||
await runCommit(enteringViewItem.ionPageElement, newLeavingElement);
|
||||
this.routerOutletElement.removeChild(newLeavingElement);
|
||||
routerOutletElement.removeChild(newLeavingElement);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, undefined);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, leavingViewItem?.ionPageElement);
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && !progressAnimation) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
if (leavingViewItem?.ionPageElement && !progressAnimation) {
|
||||
const { ionPageElement } = leavingViewItem;
|
||||
ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
ionPageElement.classList.add('ion-page-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
|
||||
this.ionRouterOutlet = ionRouterOutlet;
|
||||
const renderComponents = () => {
|
||||
const ionRouterOutlet = React.Children.only<React.ReactElement>(children as React.ReactElement);
|
||||
ionRouterOutletRef.current = ionRouterOutlet;
|
||||
|
||||
const components = this.context.getChildrenToRender(this.id, this.ionRouterOutlet, this.props.routeInfo, () => {
|
||||
this.forceUpdate();
|
||||
const components = getChildrenToRender(id, ionRouterOutlet, routeInfo, () => {
|
||||
forceUpdate();
|
||||
});
|
||||
|
||||
return (
|
||||
<StackContext.Provider value={this.stackContextValue}>
|
||||
{React.cloneElement(
|
||||
ionRouterOutlet as any,
|
||||
{
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
this.routerOutletElement = node;
|
||||
const { ref } = ionRouterOutlet as any;
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
},
|
||||
components
|
||||
)}
|
||||
</StackContext.Provider>
|
||||
);
|
||||
}
|
||||
return cloneElement(ionRouterOutlet, {
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
routerOutletRef.current = node;
|
||||
const { ref } = ionRouterOutlet as any; // TODO @sean why do we need to cast any here? Is there a better type?
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
children: components,
|
||||
});
|
||||
};
|
||||
|
||||
static get contextType() {
|
||||
return RouteManagerContext;
|
||||
}
|
||||
}
|
||||
return <StackContext.Provider value={stackContextValue}>{renderComponents()}</StackContext.Provider>;
|
||||
};
|
||||
|
||||
export default StackManager;
|
||||
|
||||
const findRoutesNode = (node: React.ReactNode) => {
|
||||
// Finds the <Routes /> component node
|
||||
let routesNode: React.ReactNode;
|
||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||
if (child.type === Routes) {
|
||||
routesNode = child;
|
||||
}
|
||||
});
|
||||
if (routesNode) {
|
||||
return (routesNode as React.ReactElement).props.children;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
||||
let matchedNode: React.ReactNode;
|
||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||
const matchProps = {
|
||||
exact: child.props.exact,
|
||||
path: child.props.path || child.props.from,
|
||||
component: child.props.component,
|
||||
};
|
||||
const match = matchPath(routeInfo.pathname, matchProps);
|
||||
if (match) {
|
||||
matchedNode = child;
|
||||
|
||||
const routesNode = findRoutesNode(node);
|
||||
|
||||
if (!routesNode) {
|
||||
console.error('No <Routes /> component found in the stack');
|
||||
}
|
||||
|
||||
React.Children.forEach(routesNode as React.ReactElement, (child: React.ReactElement) => {
|
||||
if (child.type === Route) {
|
||||
const match = matchPath(child.props, routeInfo.pathname);
|
||||
if (match) {
|
||||
matchedNode = child;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -464,7 +467,7 @@ function matchComponent(node: React.ReactElement, pathname: string, forceExact?:
|
||||
path: node.props.path || node.props.from,
|
||||
component: node.props.component,
|
||||
};
|
||||
const match = matchPath(pathname, matchProps);
|
||||
const match = matchPath(matchProps, pathname);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
export { IonReactRouter } from './ReactRouter/IonReactRouter';
|
||||
export { IonReactMemoryRouter } from './ReactRouter/IonReactMemoryRouter';
|
||||
export { IonReactHashRouter } from './ReactRouter/IonReactHashRouter';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { JSX as LocalJSX } from '@ionic/core/components';
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import { NavContext } from '../contexts/NavContext';
|
||||
import OutletPageManager from '../routing/OutletPageManager';
|
||||
@@ -18,43 +19,35 @@ interface InternalProps extends Props {
|
||||
forwardedRef?: React.ForwardedRef<HTMLIonRouterOutletElement>;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface InternalState {}
|
||||
const IonRouterOutletContainer = (props: PropsWithChildren<InternalProps>) => {
|
||||
const { hasIonicRouter, routeInfo, getStackManager } = useContext(NavContext);
|
||||
const { children, forwardedRef, ...restProps } = props;
|
||||
|
||||
class IonRouterOutletContainer extends React.Component<InternalProps, InternalState> {
|
||||
context!: React.ContextType<typeof NavContext>;
|
||||
if (hasIonicRouter()) {
|
||||
const StackManager = getStackManager();
|
||||
|
||||
constructor(props: InternalProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const StackManager = this.context.getStackManager();
|
||||
const { children, forwardedRef, ...props } = this.props;
|
||||
|
||||
return this.context.hasIonicRouter() ? (
|
||||
props.ionPage ? (
|
||||
<OutletPageManager StackManager={StackManager} routeInfo={this.context.routeInfo} {...props}>
|
||||
if (restProps.ionPage) {
|
||||
return (
|
||||
<OutletPageManager StackManager={StackManager} routeInfo={routeInfo} {...restProps}>
|
||||
{children}
|
||||
</OutletPageManager>
|
||||
) : (
|
||||
<StackManager routeInfo={this.context.routeInfo}>
|
||||
<IonRouterOutletInner {...props} forwardedRef={forwardedRef}>
|
||||
{children}
|
||||
</IonRouterOutletInner>
|
||||
</StackManager>
|
||||
)
|
||||
) : (
|
||||
<IonRouterOutletInner ref={forwardedRef} {...this.props}>
|
||||
{this.props.children}
|
||||
</IonRouterOutletInner>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<StackManager routeInfo={routeInfo}>
|
||||
<IonRouterOutletInner {...restProps} forwardedRef={forwardedRef}>
|
||||
{children}
|
||||
</IonRouterOutletInner>
|
||||
</StackManager>
|
||||
);
|
||||
}
|
||||
|
||||
static get contextType() {
|
||||
return NavContext;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<IonRouterOutletInner ref={forwardedRef} {...restProps}>
|
||||
{children}
|
||||
</IonRouterOutletInner>
|
||||
);
|
||||
};
|
||||
|
||||
export const IonRouterOutlet = createForwardRef<Props & IonicReactProps, HTMLIonRouterOutletElement>(
|
||||
IonRouterOutletContainer,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { JSX as LocalJSX } from '@ionic/core/components';
|
||||
import React, { Fragment } from 'react';
|
||||
import React, { Fragment, cloneElement, useContext, useEffect, useRef } from 'react';
|
||||
|
||||
import { NavContext } from '../../contexts/NavContext';
|
||||
import PageManager from '../../routing/PageManager';
|
||||
@@ -60,123 +60,102 @@ const tabsInner: React.CSSProperties = {
|
||||
contain: 'layout size style',
|
||||
};
|
||||
|
||||
export const IonTabs = /*@__PURE__*/ (() =>
|
||||
class extends React.Component<Props> {
|
||||
context!: React.ContextType<typeof NavContext>;
|
||||
routerOutletRef: React.Ref<HTMLIonRouterOutletElement> = React.createRef();
|
||||
selectTabHandler?: (tag: string) => boolean;
|
||||
tabBarRef = React.createRef<any>();
|
||||
export const IonTabs = (props: Props) => {
|
||||
const { hasIonicRouter, routeInfo } = useContext(NavContext);
|
||||
const tabBarRef = useRef<any>(null); // TODO @sean find the type for this
|
||||
|
||||
ionTabContextState: IonTabsContextState = {
|
||||
activeTab: undefined,
|
||||
selectTab: () => false,
|
||||
const ionTabContextState: IonTabsContextState = {
|
||||
activeTab: undefined,
|
||||
selectTab: () => false,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (tabBarRef.current) {
|
||||
ionTabContextState.activeTab = tabBarRef.current.state.activeTab;
|
||||
// Overrides the web component implementation of this method
|
||||
tabBarRef.current.setActiveTabOnContext = (tab: string) => {
|
||||
ionTabContextState.activeTab = tab;
|
||||
};
|
||||
ionTabContextState.selectTab = tabBarRef.current.selectTab;
|
||||
}
|
||||
}, []);
|
||||
|
||||
let outlet: React.ReactElement | undefined;
|
||||
let tabBar: React.ReactElement | undefined;
|
||||
const { className, onIonTabsDidChange, onIonTabsWillChange, ...restProps } = props;
|
||||
|
||||
const children =
|
||||
typeof props.children === 'function' ? (props.children as ChildFunction)(ionTabContextState) : props.children;
|
||||
|
||||
React.Children.forEach(children, (child: any) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
|
||||
return;
|
||||
}
|
||||
if (child.type === IonRouterOutlet || child.type.isRouterOutlet) {
|
||||
outlet = cloneElement(child);
|
||||
} else if (child.type === Fragment && child.props.children[0].type === IonRouterOutlet) {
|
||||
outlet = child.props.children[0]; // TODO @sean why do we cloneElement everywhere but here?
|
||||
}
|
||||
|
||||
let childProps: any = {
|
||||
ref: tabBarRef,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
/**
|
||||
* Only pass these props down from IonTabs to
|
||||
* IonTabsBar if they are defined. Otherwise if you have
|
||||
* a handler set on IonTabBar it will be overridden.
|
||||
*/
|
||||
if (onIonTabsDidChange !== undefined) {
|
||||
childProps = {
|
||||
...childProps,
|
||||
onIonTabsDidChange,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.tabBarRef.current) {
|
||||
// Grab initial value
|
||||
this.ionTabContextState.activeTab = this.tabBarRef.current.state.activeTab;
|
||||
// Override method
|
||||
this.tabBarRef.current.setActiveTabOnContext = (tab: string) => {
|
||||
this.ionTabContextState.activeTab = tab;
|
||||
};
|
||||
this.ionTabContextState.selectTab = this.tabBarRef.current.selectTab;
|
||||
}
|
||||
if (onIonTabsWillChange !== undefined) {
|
||||
childProps = {
|
||||
...childProps,
|
||||
onIonTabsWillChange,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let outlet: React.ReactElement<{}> | undefined;
|
||||
let tabBar: React.ReactElement | undefined;
|
||||
const { className, onIonTabsDidChange, onIonTabsWillChange, ...props } = this.props;
|
||||
if (child.type === IonTabBar || child.type.isTabBar) {
|
||||
tabBar = cloneElement(child, childProps);
|
||||
} else if (child.type === Fragment && child.props.children[1].type === IonTabBar) {
|
||||
tabBar = cloneElement(child.props.children[1], childProps);
|
||||
}
|
||||
});
|
||||
|
||||
const children =
|
||||
typeof this.props.children === 'function'
|
||||
? (this.props.children as ChildFunction)(this.ionTabContextState)
|
||||
: this.props.children;
|
||||
if (!outlet) {
|
||||
throw new Error('[Ionic Error]: IonTabs must contain an <IonRouterOutlet />');
|
||||
}
|
||||
|
||||
React.Children.forEach(children, (child: any) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) {
|
||||
return;
|
||||
}
|
||||
if (child.type === IonRouterOutlet || child.type.isRouterOutlet) {
|
||||
outlet = React.cloneElement(child);
|
||||
} else if (child.type === Fragment && child.props.children[0].type === IonRouterOutlet) {
|
||||
outlet = child.props.children[0];
|
||||
}
|
||||
|
||||
let childProps: any = {
|
||||
ref: this.tabBarRef,
|
||||
};
|
||||
|
||||
/**
|
||||
* Only pass these props
|
||||
* down from IonTabs to IonTabBar
|
||||
* if they are defined, otherwise
|
||||
* if you have a handler set on
|
||||
* IonTabBar it will be overridden.
|
||||
*/
|
||||
if (onIonTabsDidChange !== undefined) {
|
||||
childProps = {
|
||||
...childProps,
|
||||
onIonTabsDidChange,
|
||||
};
|
||||
}
|
||||
|
||||
if (onIonTabsWillChange !== undefined) {
|
||||
childProps = {
|
||||
...childProps,
|
||||
onIonTabsWillChange,
|
||||
};
|
||||
}
|
||||
|
||||
if (child.type === IonTabBar || child.type.isTabBar) {
|
||||
tabBar = React.cloneElement(child, childProps);
|
||||
} else if (
|
||||
child.type === Fragment &&
|
||||
(child.props.children[1].type === IonTabBar || child.props.children[1].type.isTabBar)
|
||||
) {
|
||||
tabBar = React.cloneElement(child.props.children[1], childProps);
|
||||
}
|
||||
});
|
||||
|
||||
if (!outlet) {
|
||||
throw new Error('IonTabs must contain an IonRouterOutlet');
|
||||
}
|
||||
if (!tabBar) {
|
||||
throw new Error('IonTabs needs a IonTabBar');
|
||||
}
|
||||
|
||||
return (
|
||||
<IonTabsContext.Provider value={this.ionTabContextState}>
|
||||
{this.context.hasIonicRouter() ? (
|
||||
<PageManager className={className ? `${className}` : ''} routeInfo={this.context.routeInfo} {...props}>
|
||||
<ion-tabs className="ion-tabs" style={hostStyles}>
|
||||
{tabBar.props.slot === 'top' ? tabBar : null}
|
||||
<div style={tabsInner} className="tabs-inner">
|
||||
{outlet}
|
||||
</div>
|
||||
{tabBar.props.slot === 'bottom' ? tabBar : null}
|
||||
</ion-tabs>
|
||||
</PageManager>
|
||||
) : (
|
||||
<div className={className ? `${className}` : 'ion-tabs'} {...props} style={hostStyles}>
|
||||
{tabBar.props.slot === 'top' ? tabBar : null}
|
||||
<div style={tabsInner} className="tabs-inner">
|
||||
{outlet}
|
||||
</div>
|
||||
{tabBar.props.slot === 'bottom' ? tabBar : null}
|
||||
if (!tabBar) {
|
||||
throw new Error('[Ionic Error]: IonTabs must contain an <IonTabBar />');
|
||||
}
|
||||
return (
|
||||
<IonTabsContext.Provider value={ionTabContextState}>
|
||||
{hasIonicRouter() ? (
|
||||
<PageManager className={className ? `${className}` : ''} routeInfo={routeInfo} {...restProps}>
|
||||
<ion-tabs className="ion-tabs" style={hostStyles}>
|
||||
{tabBar.props.slot === 'top' ? tabBar : null}
|
||||
<div style={tabsInner} className="tabs-inner">
|
||||
{outlet}
|
||||
</div>
|
||||
)}
|
||||
</IonTabsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
static get contextType() {
|
||||
return NavContext;
|
||||
}
|
||||
})();
|
||||
{tabBar.props.slot === 'bottom' ? tabBar : null}
|
||||
</ion-tabs>
|
||||
</PageManager>
|
||||
) : (
|
||||
<div className={className ? `${className}` : 'ion-tabs'} {...restProps} style={hostStyles}>
|
||||
{tabBar.props.slot === 'top' ? tabBar : null}
|
||||
<div style={tabsInner} className="tabs-inner">
|
||||
{outlet}
|
||||
</div>
|
||||
{tabBar.props.slot === 'bottom' ? tabBar : null}
|
||||
</div>
|
||||
)}
|
||||
</IonTabsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { createContext } from 'react';
|
||||
|
||||
export interface IonTabsContextState {
|
||||
activeTab: string | undefined;
|
||||
selectTab: (tab: string) => boolean;
|
||||
}
|
||||
|
||||
export const IonTabsContext = React.createContext<IonTabsContextState>({
|
||||
export const IonTabsContext = createContext<IonTabsContextState>({
|
||||
activeTab: undefined,
|
||||
selectTab: () => false,
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { AnimationBuilder } from '@ionic/core/components';
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
||||
import type { IonRouterContextState } from '../components/IonRouterContext';
|
||||
import { IonRouterContext } from '../components/IonRouterContext';
|
||||
import type { NavContextState } from '../contexts/NavContext';
|
||||
import { NavContext } from '../contexts/NavContext';
|
||||
import type { RouteAction } from '../models/RouteAction';
|
||||
import type { RouteInfo } from '../models/RouteInfo';
|
||||
@@ -36,8 +36,27 @@ interface NavManagerProps {
|
||||
locationHistory: LocationHistory;
|
||||
}
|
||||
|
||||
export class NavManager extends React.PureComponent<NavManagerProps, NavContextState> {
|
||||
ionRouterContextValue: IonRouterContextState = {
|
||||
export const NavManager = ({ children, ...props }: PropsWithChildren<NavManagerProps>) => {
|
||||
const {
|
||||
routeInfo,
|
||||
onNativeBack,
|
||||
onNavigateBack,
|
||||
onNavigate,
|
||||
onSetCurrentTab,
|
||||
onChangeTab,
|
||||
onResetTab,
|
||||
stackManager,
|
||||
ionRedirect,
|
||||
ionRoute,
|
||||
locationHistory,
|
||||
} = props;
|
||||
|
||||
const getPageManager = useCallback(() => PageManager, []);
|
||||
const getIonRedirect = useCallback(() => ionRedirect, []);
|
||||
const getIonRoute = useCallback(() => ionRoute, []);
|
||||
const getStackManager = useCallback(() => stackManager, []);
|
||||
|
||||
const ionRouterContextValue: IonRouterContextState = {
|
||||
push: (
|
||||
pathname: string,
|
||||
routerDirection?: RouterDirection,
|
||||
@@ -45,95 +64,67 @@ export class NavManager extends React.PureComponent<NavManagerProps, NavContextS
|
||||
routerOptions?: RouterOptions,
|
||||
animationBuilder?: AnimationBuilder
|
||||
) => {
|
||||
this.navigate(pathname, routerDirection, routeAction, animationBuilder, routerOptions);
|
||||
navigate(pathname, routerDirection, routeAction, animationBuilder, routerOptions);
|
||||
},
|
||||
back: (animationBuilder?: AnimationBuilder) => {
|
||||
this.goBack(undefined, animationBuilder);
|
||||
goBack(undefined, animationBuilder);
|
||||
},
|
||||
canGoBack: () => this.props.locationHistory.canGoBack(),
|
||||
nativeBack: () => this.props.onNativeBack(),
|
||||
routeInfo: this.props.routeInfo,
|
||||
canGoBack: () => locationHistory.canGoBack(),
|
||||
nativeBack: () => onNativeBack(),
|
||||
routeInfo,
|
||||
};
|
||||
|
||||
constructor(props: NavManagerProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
goBack: this.goBack.bind(this),
|
||||
hasIonicRouter: () => true,
|
||||
navigate: this.navigate.bind(this),
|
||||
getIonRedirect: this.getIonRedirect.bind(this),
|
||||
getIonRoute: this.getIonRoute.bind(this),
|
||||
getStackManager: this.getStackManager.bind(this),
|
||||
getPageManager: this.getPageManager.bind(this),
|
||||
routeInfo: this.props.routeInfo,
|
||||
setCurrentTab: this.props.onSetCurrentTab,
|
||||
changeTab: this.props.onChangeTab,
|
||||
resetTab: this.props.onResetTab,
|
||||
useEffect(() => {
|
||||
const handleHardwareBackButton = (e: any) => {
|
||||
e.detail.register(0, (processNextHandler: () => void) => {
|
||||
onNativeBack();
|
||||
processNextHandler();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (typeof document !== 'undefined') {
|
||||
this.handleHardwareBackButton = this.handleHardwareBackButton.bind(this);
|
||||
document.addEventListener('ionBackButton', this.handleHardwareBackButton);
|
||||
document.addEventListener('ionBackButton', handleHardwareBackButton);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.removeEventListener('ionBackButton', this.handleHardwareBackButton);
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.removeEventListener('ionBackButton', handleHardwareBackButton);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
handleHardwareBackButton(e: any) {
|
||||
e.detail.register(0, (processNextHandler: () => void) => {
|
||||
this.nativeGoBack();
|
||||
processNextHandler();
|
||||
});
|
||||
}
|
||||
const goBack = (route?: string | RouteInfo, animationBuilder?: AnimationBuilder) => {
|
||||
onNavigateBack(route, animationBuilder);
|
||||
};
|
||||
|
||||
goBack(route?: string | RouteInfo, animationBuilder?: AnimationBuilder) {
|
||||
this.props.onNavigateBack(route, animationBuilder);
|
||||
}
|
||||
|
||||
nativeGoBack() {
|
||||
this.props.onNativeBack();
|
||||
}
|
||||
|
||||
navigate(
|
||||
const navigate = (
|
||||
path: string,
|
||||
direction: RouterDirection = 'forward',
|
||||
action: RouteAction = 'push',
|
||||
animationBuilder?: AnimationBuilder,
|
||||
options?: any,
|
||||
tab?: string
|
||||
) {
|
||||
this.props.onNavigate(path, action, direction, animationBuilder, options, tab);
|
||||
}
|
||||
) => {
|
||||
onNavigate(path, action, direction, animationBuilder, options, tab);
|
||||
};
|
||||
|
||||
getPageManager() {
|
||||
return PageManager;
|
||||
}
|
||||
|
||||
getIonRedirect() {
|
||||
return this.props.ionRedirect;
|
||||
}
|
||||
|
||||
getIonRoute() {
|
||||
return this.props.ionRoute;
|
||||
}
|
||||
|
||||
getStackManager() {
|
||||
return this.props.stackManager;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NavContext.Provider value={{ ...this.state, routeInfo: this.props.routeInfo }}>
|
||||
<IonRouterContext.Provider value={{ ...this.ionRouterContextValue, routeInfo: this.props.routeInfo }}>
|
||||
{this.props.children}
|
||||
</IonRouterContext.Provider>
|
||||
</NavContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<NavContext.Provider
|
||||
value={{
|
||||
goBack,
|
||||
hasIonicRouter: () => true,
|
||||
navigate,
|
||||
getIonRedirect,
|
||||
getIonRoute,
|
||||
getStackManager,
|
||||
getPageManager,
|
||||
routeInfo,
|
||||
setCurrentTab: onSetCurrentTab,
|
||||
changeTab: onChangeTab,
|
||||
resetTab: onResetTab,
|
||||
}}
|
||||
>
|
||||
<IonRouterContext.Provider value={{ ...ionRouterContextValue, routeInfo }}>{children}</IonRouterContext.Provider>
|
||||
</NavContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { componentOnReady } from '@ionic/core/components';
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { IonRouterOutletInner } from '../components/inner-proxies';
|
||||
import type { IonLifeCycleContextInterface } from '../contexts/IonLifeCycleContext';
|
||||
import { IonLifeCycleContext } from '../contexts/IonLifeCycleContext';
|
||||
import type { RouteInfo } from '../models';
|
||||
|
||||
@@ -11,89 +13,81 @@ interface OutletPageManagerProps {
|
||||
className?: string;
|
||||
forwardedRef?: React.ForwardedRef<HTMLIonRouterOutletElement>;
|
||||
routeInfo?: RouteInfo;
|
||||
// TODO @sean I don't think we can get the type, it comes from @ionic/react, but we don't have a dep against it for react-router
|
||||
StackManager: any; // TODO(FW-2959): type
|
||||
}
|
||||
|
||||
export class OutletPageManager extends React.Component<OutletPageManagerProps> {
|
||||
ionLifeCycleContext!: React.ContextType<typeof IonLifeCycleContext>;
|
||||
context!: React.ContextType<typeof StackContext>;
|
||||
ionRouterOutlet: HTMLIonRouterOutletElement | undefined;
|
||||
outletIsReady: boolean;
|
||||
const OutletPageManager = ({ children, ...props }: PropsWithChildren<OutletPageManagerProps>) => {
|
||||
const { registerIonPage } = useContext(StackContext);
|
||||
|
||||
constructor(props: OutletPageManagerProps) {
|
||||
super(props);
|
||||
const ionRouterOutlet = useRef<HTMLIonRouterOutletElement>(null);
|
||||
const ionLifeCycleContext = useRef<IonLifeCycleContextInterface>();
|
||||
|
||||
this.outletIsReady = false;
|
||||
}
|
||||
const [outletIsReady, setOutletIsReady] = useState(false);
|
||||
|
||||
componentDidMount() {
|
||||
if (this.ionRouterOutlet) {
|
||||
const { routeInfo, StackManager } = props;
|
||||
|
||||
useEffect(() => {
|
||||
const routerOutlet = ionRouterOutlet.current;
|
||||
|
||||
if (routerOutlet) {
|
||||
/**
|
||||
* This avoids multiple raf calls
|
||||
* when React unmounts + remounts components.
|
||||
*/
|
||||
if (!this.outletIsReady) {
|
||||
componentOnReady(this.ionRouterOutlet, () => {
|
||||
this.outletIsReady = true;
|
||||
this.context.registerIonPage(this.ionRouterOutlet!, this.props.routeInfo!);
|
||||
if (!outletIsReady) {
|
||||
componentOnReady(routerOutlet, () => {
|
||||
registerIonPage(routerOutlet!, routeInfo!);
|
||||
setOutletIsReady(true);
|
||||
});
|
||||
}
|
||||
|
||||
this.ionRouterOutlet.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this));
|
||||
this.ionRouterOutlet.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this));
|
||||
this.ionRouterOutlet.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this));
|
||||
this.ionRouterOutlet.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this));
|
||||
routerOutlet.addEventListener('ionViewWillEnter', ionViewWillEnterHandler);
|
||||
routerOutlet.addEventListener('ionViewDidEnter', ionViewDidEnterHandler);
|
||||
routerOutlet.addEventListener('ionViewWillLeave', ionViewWillLeaveHandler);
|
||||
routerOutlet.addEventListener('ionViewDidLeave', ionViewDidLeaveHandler);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.ionRouterOutlet) {
|
||||
this.ionRouterOutlet.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this));
|
||||
this.ionRouterOutlet.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this));
|
||||
this.ionRouterOutlet.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this));
|
||||
this.ionRouterOutlet.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this));
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
if (routerOutlet) {
|
||||
routerOutlet.removeEventListener('ionViewWillEnter', ionViewWillEnterHandler);
|
||||
routerOutlet.removeEventListener('ionViewDidEnter', ionViewDidEnterHandler);
|
||||
routerOutlet.removeEventListener('ionViewWillLeave', ionViewWillLeaveHandler);
|
||||
routerOutlet.removeEventListener('ionViewDidLeave', ionViewDidLeaveHandler);
|
||||
}
|
||||
};
|
||||
}, [ionRouterOutlet, outletIsReady, routeInfo]);
|
||||
|
||||
ionViewWillEnterHandler() {
|
||||
this.ionLifeCycleContext.ionViewWillEnter();
|
||||
}
|
||||
const ionViewWillEnterHandler = () => {
|
||||
ionLifeCycleContext.current!.ionViewWillEnter();
|
||||
};
|
||||
|
||||
ionViewDidEnterHandler() {
|
||||
this.ionLifeCycleContext.ionViewDidEnter();
|
||||
}
|
||||
const ionViewDidEnterHandler = () => {
|
||||
ionLifeCycleContext.current!.ionViewDidEnter();
|
||||
};
|
||||
|
||||
ionViewWillLeaveHandler() {
|
||||
this.ionLifeCycleContext.ionViewWillLeave();
|
||||
}
|
||||
const ionViewWillLeaveHandler = () => {
|
||||
ionLifeCycleContext.current!.ionViewWillLeave();
|
||||
};
|
||||
|
||||
ionViewDidLeaveHandler() {
|
||||
this.ionLifeCycleContext.ionViewDidLeave();
|
||||
}
|
||||
const ionViewDidLeaveHandler = () => {
|
||||
ionLifeCycleContext.current!.ionViewDidLeave();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { StackManager, children, routeInfo, ...props } = this.props;
|
||||
return (
|
||||
<IonLifeCycleContext.Consumer>
|
||||
{(context) => {
|
||||
this.ionLifeCycleContext = context;
|
||||
return (
|
||||
<StackManager routeInfo={routeInfo}>
|
||||
<IonRouterOutletInner
|
||||
setRef={(val: HTMLIonRouterOutletElement) => (this.ionRouterOutlet = val)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</IonRouterOutletInner>
|
||||
</StackManager>
|
||||
);
|
||||
}}
|
||||
</IonLifeCycleContext.Consumer>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<IonLifeCycleContext.Consumer>
|
||||
{(context) => {
|
||||
ionLifeCycleContext.current = context;
|
||||
return (
|
||||
<StackManager routeInfo={routeInfo}>
|
||||
<IonRouterOutletInner ref={ionRouterOutlet} {...props}>
|
||||
{children}
|
||||
</IonRouterOutletInner>
|
||||
</StackManager>
|
||||
);
|
||||
}}
|
||||
</IonLifeCycleContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
static get contextType() {
|
||||
return StackContext;
|
||||
}
|
||||
}
|
||||
export default OutletPageManager;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useContext, useEffect, useRef } from 'react';
|
||||
|
||||
import { mergeRefs } from '../components/react-component-lib/utils';
|
||||
import { IonLifeCycleContext } from '../contexts/IonLifeCycleContext';
|
||||
@@ -12,77 +13,68 @@ interface PageManagerProps {
|
||||
routeInfo?: RouteInfo;
|
||||
}
|
||||
|
||||
export class PageManager extends React.PureComponent<PageManagerProps> {
|
||||
ionLifeCycleContext!: React.ContextType<typeof IonLifeCycleContext>;
|
||||
context!: React.ContextType<typeof StackContext>;
|
||||
ionPageElementRef: React.RefObject<HTMLDivElement>;
|
||||
stableMergedRefs: React.RefCallback<HTMLDivElement>;
|
||||
const PageManager = ({ children, ...props }: PropsWithChildren<PageManagerProps>) => {
|
||||
const { className, forwardedRef, routeInfo, ...restProps } = props;
|
||||
|
||||
constructor(props: PageManagerProps) {
|
||||
super(props);
|
||||
this.ionPageElementRef = React.createRef();
|
||||
// React refs must be stable (not created inline).
|
||||
this.stableMergedRefs = mergeRefs(this.ionPageElementRef, this.props.forwardedRef);
|
||||
}
|
||||
const ionLifeCycleContext = useContext(IonLifeCycleContext);
|
||||
const context = useContext(StackContext);
|
||||
|
||||
componentDidMount() {
|
||||
if (this.ionPageElementRef.current) {
|
||||
if (this.context.isInOutlet()) {
|
||||
this.ionPageElementRef.current.classList.add('ion-page-invisible');
|
||||
const ionPageElementRef = useRef<HTMLDivElement>(null);
|
||||
const stableMergedRefs = mergeRefs(ionPageElementRef, forwardedRef);
|
||||
|
||||
useEffect(() => {
|
||||
const ionPageElement = ionPageElementRef.current;
|
||||
|
||||
if (ionPageElement) {
|
||||
if (context.isInOutlet()) {
|
||||
ionPageElement.classList.add('ion-page-invisible');
|
||||
}
|
||||
this.context.registerIonPage(this.ionPageElementRef.current, this.props.routeInfo!);
|
||||
this.ionPageElementRef.current.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this));
|
||||
this.ionPageElementRef.current.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this));
|
||||
this.ionPageElementRef.current.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this));
|
||||
this.ionPageElementRef.current.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this));
|
||||
|
||||
context.registerIonPage(ionPageElement, routeInfo!);
|
||||
|
||||
ionPageElement.addEventListener('ionViewWillEnter', ionViewWillEnterHandler);
|
||||
ionPageElement.addEventListener('ionViewDidEnter', ionViewDidEnterHandler);
|
||||
ionPageElement.addEventListener('ionViewWillLeave', ionViewWillLeaveHandler);
|
||||
ionPageElement.addEventListener('ionViewDidLeave', ionViewDidLeaveHandler);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.ionPageElementRef.current) {
|
||||
this.ionPageElementRef.current.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this));
|
||||
this.ionPageElementRef.current.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this));
|
||||
this.ionPageElementRef.current.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this));
|
||||
this.ionPageElementRef.current.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this));
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
if (ionPageElement) {
|
||||
ionPageElement.removeEventListener('ionViewWillEnter', ionViewWillEnterHandler);
|
||||
ionPageElement.removeEventListener('ionViewDidEnter', ionViewDidEnterHandler);
|
||||
ionPageElement.removeEventListener('ionViewWillLeave', ionViewWillLeaveHandler);
|
||||
ionPageElement.removeEventListener('ionViewDidLeave', ionViewDidLeaveHandler);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
ionViewWillEnterHandler() {
|
||||
this.ionLifeCycleContext.ionViewWillEnter();
|
||||
}
|
||||
const ionViewWillEnterHandler = () => {
|
||||
ionLifeCycleContext.ionViewWillEnter();
|
||||
};
|
||||
|
||||
ionViewDidEnterHandler() {
|
||||
this.ionLifeCycleContext.ionViewDidEnter();
|
||||
}
|
||||
const ionViewDidEnterHandler = () => {
|
||||
ionLifeCycleContext.ionViewDidEnter();
|
||||
};
|
||||
|
||||
ionViewWillLeaveHandler() {
|
||||
this.ionLifeCycleContext.ionViewWillLeave();
|
||||
}
|
||||
const ionViewWillLeaveHandler = () => {
|
||||
ionLifeCycleContext.ionViewWillLeave();
|
||||
};
|
||||
|
||||
ionViewDidLeaveHandler() {
|
||||
this.ionLifeCycleContext.ionViewDidLeave();
|
||||
}
|
||||
const ionViewDidLeaveHandler = () => {
|
||||
ionLifeCycleContext.ionViewDidLeave();
|
||||
};
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { className, children, routeInfo, forwardedRef, ...props } = this.props;
|
||||
return (
|
||||
<IonLifeCycleContext.Consumer>
|
||||
{() => {
|
||||
return (
|
||||
<div className={className ? `${className} ion-page` : 'ion-page'} ref={stableMergedRefs} {...restProps}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</IonLifeCycleContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<IonLifeCycleContext.Consumer>
|
||||
{(context) => {
|
||||
this.ionLifeCycleContext = context;
|
||||
return (
|
||||
<div className={className ? `${className} ion-page` : `ion-page`} ref={this.stableMergedRefs} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</IonLifeCycleContext.Consumer>
|
||||
);
|
||||
}
|
||||
|
||||
static get contextType() {
|
||||
return StackContext;
|
||||
}
|
||||
}
|
||||
export default PageManager;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { DefaultIonLifeCycleContext, IonLifeCycleContext } from '../contexts/IonLifeCycleContext';
|
||||
|
||||
@@ -7,49 +8,32 @@ interface ViewTransitionManagerProps {
|
||||
mount: boolean;
|
||||
}
|
||||
|
||||
interface ViewTransitionManagerState {
|
||||
show: boolean;
|
||||
}
|
||||
export const ViewLifeCycleManager = ({ children, ...props }: PropsWithChildren<ViewTransitionManagerProps>) => {
|
||||
const ionLifeCycleContext = useRef(new DefaultIonLifeCycleContext());
|
||||
|
||||
export class ViewLifeCycleManager extends React.Component<ViewTransitionManagerProps, ViewTransitionManagerState> {
|
||||
ionLifeCycleContext = new DefaultIonLifeCycleContext();
|
||||
private _isMounted = false;
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const [show, setShow] = useState(true);
|
||||
|
||||
constructor(props: ViewTransitionManagerProps) {
|
||||
super(props);
|
||||
const { mount, removeView } = props;
|
||||
|
||||
this.ionLifeCycleContext.onComponentCanBeDestroyed(() => {
|
||||
if (!this.props.mount) {
|
||||
if (this._isMounted) {
|
||||
this.setState(
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
() => this.props.removeView()
|
||||
);
|
||||
}
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
|
||||
return () => {
|
||||
setIsMounted(false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
ionLifeCycleContext.current.onComponentCanBeDestroyed(() => {
|
||||
if (!mount && isMounted) {
|
||||
setShow(false);
|
||||
removeView();
|
||||
}
|
||||
});
|
||||
}, [mount, isMounted, removeView]);
|
||||
|
||||
this.state = {
|
||||
show: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { show } = this.state;
|
||||
return (
|
||||
<IonLifeCycleContext.Provider value={this.ionLifeCycleContext}>
|
||||
{show && this.props.children}
|
||||
</IonLifeCycleContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<IonLifeCycleContext.Provider value={ionLifeCycleContext.current}>{show && children}</IonLifeCycleContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
409
packages/react/test/apps/react18/package-lock.json
generated
409
packages/react/test/apps/react18/package-lock.json
generated
@@ -8,17 +8,15 @@
|
||||
"name": "test-app",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@ionic/react": "^6.6.1",
|
||||
"@ionic/react-router": "^6.6.1",
|
||||
"@ionic/react": "^7.0.0",
|
||||
"@ionic/react-router": "^7.0.0",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"ionicons": "^6.0.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^5.3.4",
|
||||
"react-router-dom": "^5.3.4",
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
"react-scripts": "^5.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
@@ -33,6 +31,9 @@
|
||||
"serve": "^14.0.1",
|
||||
"wait-on": "^6.0.0",
|
||||
"webpack-cli": "^4.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
@@ -2367,22 +2368,54 @@
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.6.1.tgz",
|
||||
"integrity": "sha512-+LMBk7kUX55rvYQ35AiAXPNzbNm3zNx9ginvuCzByguMjl+N63lpdPzIEfeRURkmq7NByD1VqpodMj5c6Oq2KQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.1.tgz",
|
||||
"integrity": "sha512-5tdOSUiAkAfCtaP94ADugRskVxdwjRl+lRmOQnInkHnbUmA9eo2sCLCAO2UHfSL6VCP8BOw41NGlz4ad+Ivijw==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^2.18.0",
|
||||
"ionicons": "^6.1.3",
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-6.6.1.tgz",
|
||||
"integrity": "sha512-gq8FzC0CAPt6MpOFethe9+zIU7jg1JyWPWRANJ/UudlF05f2eFOzLgqe/EH0uIIsuDjeoM50hrqfuvg6x2j3UQ==",
|
||||
"node_modules/@ionic/core/node_modules/@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.10.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core/node_modules/ionicons": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.1.0.tgz",
|
||||
"integrity": "sha512-iE4GuEdEHARJpp0sWL7WJZCzNCf5VxpNRhAjW0fLnZPnNL5qZOJUcfup2Z2Ty7Jk8Q5hacrHfGEB1lCwOdXqGg==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "6.6.1",
|
||||
"ionicons": "^6.1.3",
|
||||
"@stencil/core": "^2.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core/node_modules/ionicons/node_modules/@stencil/core": {
|
||||
"version": "2.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
||||
"integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.10.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.1.1.tgz",
|
||||
"integrity": "sha512-XMuXtC6HZXf5dBHkfbH0qzTAbvT/cbC+A69NbtOWI9BzxJOUUM3QLhmO7DMfYEdKjAEAfJxQ1vi+iOrz9wQ5Pw==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "7.1.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -2391,11 +2424,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react-router": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-6.6.1.tgz",
|
||||
"integrity": "sha512-9bHlz3MdzvkUyZ9QfxzcAGDtbRhZ7R5uMjm3UHvGhYS1Rdx4KIc8E5q31IQf7H6j2ULU9YcB7UeyW5ORxBX18Q==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-7.1.1.tgz",
|
||||
"integrity": "sha512-ncu5nEmCDEvVf++4MpfrZKf+XDTBLa9IJyrPYpDYi/U3iaCdNLUwGYqKbY5Q78O69T/mjYh94fZg7gTbYM+/ZA==",
|
||||
"dependencies": {
|
||||
"@ionic/react": "6.6.1",
|
||||
"@ionic/react": "7.1.1",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -2405,6 +2438,14 @@
|
||||
"react-router-dom": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react/node_modules/ionicons": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.1.2.tgz",
|
||||
"integrity": "sha512-zZ4njAqSP39H8RRvZhJvkHsv7cBjYE/VfInH218Osf2UVxJITSOutTTd25MW+tAXKN5fheYzclUXUsF55JHUDg==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^2.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
@@ -2957,6 +2998,14 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.0.tgz",
|
||||
"integrity": "sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
@@ -3541,11 +3590,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/history": {
|
||||
"version": "4.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
|
||||
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="
|
||||
},
|
||||
"node_modules/@types/html-minifier-terser": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
||||
@@ -3658,25 +3702,6 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
|
||||
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router-dom": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
|
||||
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
|
||||
@@ -8977,32 +9002,6 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^3.0.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0",
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/hoopy": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||
@@ -9816,11 +9815,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -12349,14 +12343,6 @@
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||
"dependencies": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
@@ -14054,46 +14040,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
||||
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.0.tgz",
|
||||
"integrity": "sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"hoist-non-react-statics": "^3.1.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.6.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15"
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz",
|
||||
"integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.0.tgz",
|
||||
"integrity": "sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-router": "5.3.4",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0",
|
||||
"react-router": "6.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15"
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
@@ -14466,11 +14441,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pathname": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
|
||||
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
|
||||
},
|
||||
"node_modules/resolve-url-loader": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
|
||||
@@ -15893,16 +15863,6 @@
|
||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
||||
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
|
||||
"integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
@@ -16328,11 +16288,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/value-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
|
||||
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@@ -18924,31 +18879,63 @@
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.6.1.tgz",
|
||||
"integrity": "sha512-+LMBk7kUX55rvYQ35AiAXPNzbNm3zNx9ginvuCzByguMjl+N63lpdPzIEfeRURkmq7NByD1VqpodMj5c6Oq2KQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.1.tgz",
|
||||
"integrity": "sha512-5tdOSUiAkAfCtaP94ADugRskVxdwjRl+lRmOQnInkHnbUmA9eo2sCLCAO2UHfSL6VCP8BOw41NGlz4ad+Ivijw==",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.18.0",
|
||||
"ionicons": "^6.1.3",
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g=="
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.1.0.tgz",
|
||||
"integrity": "sha512-iE4GuEdEHARJpp0sWL7WJZCzNCf5VxpNRhAjW0fLnZPnNL5qZOJUcfup2Z2Ty7Jk8Q5hacrHfGEB1lCwOdXqGg==",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.18.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stencil/core": {
|
||||
"version": "2.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
||||
"integrity": "sha512-kmVA0M/HojwsfkeHsifvHVIYe4l5tin7J5+DLgtl8h6WWfiMClND5K3ifCXXI2ETDNKiEk21p6jql3Fx9o2rng=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic/react": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-6.6.1.tgz",
|
||||
"integrity": "sha512-gq8FzC0CAPt6MpOFethe9+zIU7jg1JyWPWRANJ/UudlF05f2eFOzLgqe/EH0uIIsuDjeoM50hrqfuvg6x2j3UQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.1.1.tgz",
|
||||
"integrity": "sha512-XMuXtC6HZXf5dBHkfbH0qzTAbvT/cbC+A69NbtOWI9BzxJOUUM3QLhmO7DMfYEdKjAEAfJxQ1vi+iOrz9wQ5Pw==",
|
||||
"requires": {
|
||||
"@ionic/core": "6.6.1",
|
||||
"ionicons": "^6.1.3",
|
||||
"@ionic/core": "7.1.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"ionicons": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.1.2.tgz",
|
||||
"integrity": "sha512-zZ4njAqSP39H8RRvZhJvkHsv7cBjYE/VfInH218Osf2UVxJITSOutTTd25MW+tAXKN5fheYzclUXUsF55JHUDg==",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.18.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic/react-router": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-6.6.1.tgz",
|
||||
"integrity": "sha512-9bHlz3MdzvkUyZ9QfxzcAGDtbRhZ7R5uMjm3UHvGhYS1Rdx4KIc8E5q31IQf7H6j2ULU9YcB7UeyW5ORxBX18Q==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-7.1.1.tgz",
|
||||
"integrity": "sha512-ncu5nEmCDEvVf++4MpfrZKf+XDTBLa9IJyrPYpDYi/U3iaCdNLUwGYqKbY5Q78O69T/mjYh94fZg7gTbYM+/ZA==",
|
||||
"requires": {
|
||||
"@ionic/react": "6.6.1",
|
||||
"@ionic/react": "7.1.1",
|
||||
"tslib": "*"
|
||||
}
|
||||
},
|
||||
@@ -19357,6 +19344,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@remix-run/router": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.0.tgz",
|
||||
"integrity": "sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw=="
|
||||
},
|
||||
"@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
@@ -19779,11 +19771,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/history": {
|
||||
"version": "4.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
|
||||
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="
|
||||
},
|
||||
"@types/html-minifier-terser": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
||||
@@ -19896,25 +19883,6 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
|
||||
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
|
||||
"requires": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router-dom": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
|
||||
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
|
||||
"requires": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"@types/resolve": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
|
||||
@@ -23784,34 +23752,6 @@
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^3.0.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0",
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"hoopy": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||
@@ -24364,11 +24304,6 @@
|
||||
"is-docker": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -26251,14 +26186,6 @@
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
@@ -27341,40 +27268,20 @@
|
||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
||||
},
|
||||
"react-router": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
||||
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.0.tgz",
|
||||
"integrity": "sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"hoist-non-react-statics": "^3.1.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.6.0",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
}
|
||||
"@remix-run/router": "1.7.0"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz",
|
||||
"integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.0.tgz",
|
||||
"integrity": "sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-router": "5.3.4",
|
||||
"tiny-invariant": "^1.0.2",
|
||||
"tiny-warning": "^1.0.0"
|
||||
"@remix-run/router": "1.7.0",
|
||||
"react-router": "6.14.0"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
@@ -27669,11 +27576,6 @@
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
|
||||
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
|
||||
},
|
||||
"resolve-url-loader": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
|
||||
@@ -28734,16 +28636,6 @@
|
||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
||||
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
|
||||
},
|
||||
"tiny-invariant": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
|
||||
"integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
@@ -29068,11 +28960,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"value-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
|
||||
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
||||
@@ -3,17 +3,15 @@
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ionic/react": "^6.6.1",
|
||||
"@ionic/react-router": "^6.6.1",
|
||||
"@ionic/react": "^7.0.0",
|
||||
"@ionic/react-router": "^7.0.0",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"ionicons": "^6.0.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^5.3.4",
|
||||
"react-router-dom": "^5.3.4",
|
||||
"react-router": "^6.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
"react-scripts": "^5.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
|
||||
import { IonReactRouter } from '@ionic/react-router';
|
||||
import React from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
|
||||
/* Core CSS required for Ionic components to work properly */
|
||||
import '@ionic/react/css/core.css';
|
||||
@@ -21,18 +21,18 @@ import '@ionic/react/css/display.css';
|
||||
|
||||
/* Theme variables */
|
||||
import './theme/variables.css';
|
||||
import Main from './pages/Main';
|
||||
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
||||
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
||||
import KeepContentsMounted from './pages/overlay-components/KeepContentsMounted';
|
||||
import Tabs from './pages/Tabs';
|
||||
import Icons from './pages/Icons';
|
||||
import Main from './pages/Main';
|
||||
import Tabs from './pages/Tabs';
|
||||
import NavComponent from './pages/navigation/NavComponent';
|
||||
import IonModalConditionalSibling from './pages/overlay-components/IonModalConditionalSibling';
|
||||
import IonModalConditional from './pages/overlay-components/IonModalConditional';
|
||||
import IonModalConditionalSibling from './pages/overlay-components/IonModalConditionalSibling';
|
||||
import IonModalDatetimeButton from './pages/overlay-components/IonModalDatetimeButton';
|
||||
import IonPopoverNested from './pages/overlay-components/IonPopoverNested';
|
||||
import IonModalMultipleChildren from './pages/overlay-components/IonModalMultipleChildren';
|
||||
import IonPopoverNested from './pages/overlay-components/IonPopoverNested';
|
||||
import KeepContentsMounted from './pages/overlay-components/KeepContentsMounted';
|
||||
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
||||
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
||||
|
||||
setupIonicReact();
|
||||
|
||||
@@ -40,27 +40,20 @@ const App: React.FC = () => (
|
||||
<IonApp>
|
||||
<IonReactRouter>
|
||||
<IonRouterOutlet>
|
||||
<Route path="/" component={Main} />
|
||||
<Route path="/overlay-hooks" component={OverlayHooks} />
|
||||
<Route path="/overlay-components" component={OverlayComponents} />
|
||||
<Route path="/overlay-components/nested-popover" component={IonPopoverNested} />
|
||||
<Route
|
||||
path="/overlay-components/modal-conditional-sibling"
|
||||
component={IonModalConditionalSibling}
|
||||
/>
|
||||
<Route path="/overlay-components/modal-conditional" component={IonModalConditional} />
|
||||
<Route
|
||||
path="/overlay-components/modal-datetime-button"
|
||||
component={IonModalDatetimeButton}
|
||||
/>
|
||||
<Route
|
||||
path="/overlay-components/modal-multiple-children"
|
||||
component={IonModalMultipleChildren}
|
||||
/>
|
||||
<Route path="/keep-contents-mounted" component={KeepContentsMounted} />
|
||||
<Route path="/navigation" component={NavComponent} />
|
||||
<Route path="/tabs" component={Tabs} />
|
||||
<Route path="/icons" component={Icons} />
|
||||
<Routes>
|
||||
<Route path="/" element={<Main />} />
|
||||
<Route path="/overlay-hooks" element={<OverlayHooks />} />
|
||||
<Route path="/overlay-components" element={<OverlayComponents />} />
|
||||
<Route path="/overlay-components/nested-popover" element={<IonPopoverNested />} />
|
||||
<Route path="/overlay-components/modal-conditional-sibling" element={<IonModalConditionalSibling />} />
|
||||
<Route path="/overlay-components/modal-conditional" element={<IonModalConditional />} />
|
||||
<Route path="/overlay-components/modal-datetime-button" element={<IonModalDatetimeButton />} />
|
||||
<Route path="/overlay-components/modal-multiple-children" element={<IonModalMultipleChildren />} />
|
||||
<Route path="/keep-contents-mounted" element={<KeepContentsMounted />} />
|
||||
<Route path="/navigation" element={<NavComponent />} />
|
||||
<Route path="/tabs" element={<Tabs />} />
|
||||
<Route path="/icons" element={<Icons />} />
|
||||
</Routes>
|
||||
</IonRouterOutlet>
|
||||
</IonReactRouter>
|
||||
</IonApp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
import React from 'react';
|
||||
import { Route, Navigate } from 'react-router';
|
||||
|
||||
interface TabsProps {}
|
||||
|
||||
@@ -8,8 +8,10 @@ const Tabs: React.FC<TabsProps> = () => {
|
||||
return (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
<Redirect from="/tabs" to="/tabs/tab1" exact />
|
||||
<Route path="/tabs/tab1" render={() => <IonLabel>Tab 1</IonLabel>} />
|
||||
<Route path="/tabs/tab1">
|
||||
<IonLabel>Tab 1</IonLabel>
|
||||
</Route>
|
||||
<Route path="/tabs" element={<Navigate to="/tabs/tab1" />} />
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom">
|
||||
<IonTabButton tab="tab1" onClick={() => window.alert('Tab was clicked')}>
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import React from 'react';
|
||||
import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
import {
|
||||
addCircleOutline,
|
||||
alarm,
|
||||
alertCircle,
|
||||
logoGoogle,
|
||||
logoIonic,
|
||||
newspaper,
|
||||
star,
|
||||
} from 'ionicons/icons';
|
||||
import { addCircleOutline, alarm, alertCircle, logoGoogle, logoIonic, newspaper, star } from 'ionicons/icons';
|
||||
import React from 'react';
|
||||
import { Route, Routes, Navigate } from 'react-router';
|
||||
|
||||
import ActionSheetComponent from './ActionSheetComponent';
|
||||
import AlertComponent from './AlertComponent';
|
||||
import LoadingComponent from './LoadingComponent';
|
||||
@@ -24,14 +17,16 @@ const OverlayHooks: React.FC<OverlayHooksProps> = () => {
|
||||
return (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
<Redirect from="/overlay-components" to="/overlay-components/actionsheet" exact />
|
||||
<Route path="/overlay-components/actionsheet" component={ActionSheetComponent} />
|
||||
<Route path="/overlay-components/alert" component={AlertComponent} />
|
||||
<Route path="/overlay-components/loading" component={LoadingComponent} />
|
||||
<Route path="/overlay-components/modal" component={ModalComponent} />
|
||||
<Route path="/overlay-components/picker" component={PickerComponent} />
|
||||
<Route path="/overlay-components/popover" component={PopoverComponent} />
|
||||
<Route path="/overlay-components/toast" component={ToastComponent} />
|
||||
<Routes>
|
||||
<Route path="/overlay-components/actionsheet" element={<ActionSheetComponent />} />
|
||||
<Route path="/overlay-components/alert" element={<AlertComponent />} />
|
||||
<Route path="/overlay-components/loading" element={<LoadingComponent />} />
|
||||
<Route path="/overlay-components/modal" element={<ModalComponent />} />
|
||||
<Route path="/overlay-components/picker" element={<PickerComponent />} />
|
||||
<Route path="/overlay-components/popover" element={<PopoverComponent />} />
|
||||
<Route path="/overlay-components/toast" element={<ToastComponent />} />
|
||||
<Route path="/overlay-components/*" element={<Navigate to="/overlay-components/actionsheet" />} />
|
||||
</Routes>
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom">
|
||||
<IonTabButton tab="actionsheet" href="/overlay-components/actionsheet">
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import React from 'react';
|
||||
import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
import { addCircleOutline, alarm, alertCircle, logoGoogle, logoIonic, newspaper, star } from 'ionicons/icons';
|
||||
import React from 'react';
|
||||
import { Route, Navigate, Routes } from 'react-router';
|
||||
|
||||
import ActionSheetHook from './ActionSheetHook';
|
||||
import {
|
||||
addCircleOutline,
|
||||
alarm,
|
||||
alertCircle,
|
||||
logoGoogle,
|
||||
logoIonic,
|
||||
newspaper,
|
||||
star,
|
||||
} from 'ionicons/icons';
|
||||
import AlertHook from './AlertHook';
|
||||
import LoadingHook from './LoadingHook';
|
||||
import ModalHook from './ModalHook';
|
||||
@@ -24,14 +17,16 @@ const OverlayHooks: React.FC<OverlayHooksProps> = () => {
|
||||
return (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
<Redirect from="/overlay-hooks" to="/overlay-hooks/actionsheet" exact />
|
||||
<Route path="/overlay-hooks/actionsheet" component={ActionSheetHook} />
|
||||
<Route path="/overlay-hooks/alert" component={AlertHook} />
|
||||
<Route path="/overlay-hooks/loading" component={LoadingHook} />
|
||||
<Route path="/overlay-hooks/modal" component={ModalHook} />
|
||||
<Route path="/overlay-hooks/picker" component={PickerHook} />
|
||||
<Route path="/overlay-hooks/popover" component={PopoverHook} />
|
||||
<Route path="/overlay-hooks/toast" component={ToastHook} />
|
||||
<Routes>
|
||||
<Route path="/overlay-hooks/actionsheet" element={<ActionSheetHook />} />
|
||||
<Route path="/overlay-hooks/alert" element={<AlertHook />} />
|
||||
<Route path="/overlay-hooks/loading" element={<LoadingHook />} />
|
||||
<Route path="/overlay-hooks/modal" element={<ModalHook />} />
|
||||
<Route path="/overlay-hooks/picker" element={<PickerHook />} />
|
||||
<Route path="/overlay-hooks/popover" element={<PopoverHook />} />
|
||||
<Route path="/overlay-hooks/toast" element={<ToastHook />} />
|
||||
<Route path="/overlay-hooks/*" element={<Navigate to="/overlay-hooks/actionsheet" />} />
|
||||
</Routes>
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom">
|
||||
<IonTabButton tab="actionsheet" href="/overlay-hooks/actionsheet">
|
||||
|
||||
Reference in New Issue
Block a user