@kaspernj/api-maker 1.0.396 → 1.0.398

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaspernj/api-maker",
3
- "version": "1.0.396",
3
+ "version": "1.0.398",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "index.js",
@@ -35,7 +35,7 @@
35
35
  "on-location-changed": ">= 1.0.13",
36
36
  "qs": ">= 6.9.3",
37
37
  "replaceall": ">= 0.1.6",
38
- "set-state-compare": "^1.0.46",
38
+ "set-state-compare": "^1.0.49",
39
39
  "spark-md5": "^3.0.2",
40
40
  "stacktrace-parser": "^0.1.10",
41
41
  "strftime": ">= 0.10.0",
@@ -0,0 +1,224 @@
1
+ import BaseComponent from "../base-component"
2
+ import {createContext, useContext, useMemo} from "react"
3
+ import memo from "set-state-compare/src/memo"
4
+ import PropTypes from "prop-types"
5
+ import propTypesExact from "prop-types-exact"
6
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
7
+ import Switch, {CurrentSwitchContext} from "./switch"
8
+
9
+ const CurrentPathContext = createContext([])
10
+ const ParamsContext = createContext({})
11
+ const RequireComponentContext = createContext(null)
12
+ const RouteContext = createContext(null)
13
+ const useParams = () => useContext(ParamsContext)
14
+
15
+ const Route = memo(shapeComponent(class Route extends BaseComponent {
16
+ static defaultProps = {
17
+ exact: false,
18
+ fallback: false,
19
+ includeInPath: true
20
+ }
21
+
22
+ static propTypes = propTypesExact({
23
+ component: PropTypes.string,
24
+ componentPath: PropTypes.string,
25
+ exact: PropTypes.bool.isRequired,
26
+ fallback: PropTypes.bool.isRequired,
27
+ includeInPath: PropTypes.bool.isRequired,
28
+ onMatch: PropTypes.func,
29
+ path: PropTypes.string
30
+ })
31
+
32
+ match = null
33
+ newParams = null
34
+ pathParts = null
35
+
36
+ setup() {
37
+ const {path} = this.props
38
+ const {pathsMatched, switchGroup} = useContext(CurrentSwitchContext)
39
+ const givenRoute = useContext(RouteContext)
40
+ const {pathShown} = switchGroup.s
41
+
42
+ this.requireComponent = useContext(RequireComponentContext)
43
+ this.currentParams = useContext(ParamsContext)
44
+ this.currentPath = useContext(CurrentPathContext)
45
+ this.switchGroup = switchGroup
46
+
47
+ this.routeParts = useMemo(() => {
48
+ let routeParts = givenRoute?.split("/")
49
+
50
+ return routeParts
51
+ }, [path, givenRoute])
52
+
53
+ this.pathParts = useMemo(() => path?.split("/"), [path])
54
+
55
+ this.newRouteParts = useMemo(
56
+ () => {
57
+ if (!path) {
58
+ if (givenRoute == "") {
59
+ return []
60
+ } else {
61
+ return this.routeParts
62
+ }
63
+ }
64
+
65
+ return this.routeParts.slice(this.pathParts.length, this.routeParts.length)
66
+ },
67
+ [givenRoute].concat(this.pathParts)
68
+ )
69
+
70
+ this.useStates({Component: null, componentNotFound: null, matches: false})
71
+
72
+ useMemo(() => {
73
+ this.loadMatches()
74
+ }, [givenRoute, path, pathsMatched])
75
+
76
+ useMemo(() => {
77
+ if (this.hasSwitchMatch() && !this.s.Component && this.s.matches) {
78
+ if (this.props.onMatch) {
79
+ this.props.onMatch()
80
+ }
81
+
82
+ this.loadComponent()
83
+ }
84
+ }, [path, pathShown, this.s.matches])
85
+ }
86
+
87
+ hasSwitchMatch = () => this.switchGroup.s.pathShown && this.switchGroup.s.pathShown == this.pathId()
88
+
89
+ pathId() {
90
+ const {fallback} = this.p
91
+ const {path} = this.props
92
+ let pathId
93
+
94
+ if (fallback) {
95
+ pathId = "[FALLBACK]"
96
+ } else if (!path) {
97
+ pathId = "[PATH-EMPTY]"
98
+ } else {
99
+ pathId = path
100
+ }
101
+
102
+ return pathId
103
+ }
104
+
105
+ loadMatches() {
106
+ const {newRouteParts} = this.tt
107
+ const {component, path} = this.props
108
+ const {exact, includeInPath, fallback} = this.p
109
+
110
+ let matches = true
111
+ const params = {}
112
+ const componentPathParts = [...this.currentPath]
113
+
114
+ for (const pathPartIndex in this.pathParts) {
115
+ const pathPart = this.pathParts[pathPartIndex]
116
+ const translatedPathPart = I18n.t(`routes.${pathPart}`, {defaultValue: pathPart})
117
+
118
+ if (!(pathPartIndex in this.routeParts)) {
119
+ matches = false
120
+ break
121
+ }
122
+
123
+ const routePart = this.routeParts[pathPartIndex]
124
+
125
+ if (pathPart.startsWith(":") && routePart) {
126
+ const paramName = pathPart.slice(1, pathPart.length)
127
+
128
+ params[paramName] = routePart
129
+ } else if (translatedPathPart != routePart) {
130
+ matches = false
131
+ break
132
+ } else if (!component && includeInPath) {
133
+ componentPathParts.push(pathPart)
134
+ }
135
+ }
136
+
137
+ if (exact && newRouteParts.length > 0) {
138
+ matches = false
139
+ } else if (matches && path) {
140
+ matches = true
141
+ } else if (this.routeParts.length == 0) {
142
+ matches = true
143
+ }
144
+
145
+ const matchId = this.pathId()
146
+
147
+ if (!matches && fallback) {
148
+ matches = true
149
+ }
150
+
151
+ if (matches) {
152
+ if (component && includeInPath) {
153
+ componentPathParts.push(component)
154
+ }
155
+
156
+ const newParams = Object.assign({}, this.currentParams, params)
157
+
158
+ this.setInstance({componentPathParts, match: {params}, newParams})
159
+ this.setState({matches})
160
+ this.switchGroup?.setPathMatched(matchId, true)
161
+ } else {
162
+ this.setInstance({componentPathParts: null, match: null, newParams: null})
163
+ this.setState({matches})
164
+ this.switchGroup?.setPathMatched(matchId, false)
165
+ }
166
+ }
167
+
168
+ async loadComponent() {
169
+ const actualComponentPath = this.props.componentPath || this.tt.componentPathParts.join("/")
170
+ let Component
171
+
172
+ try {
173
+ const componentImport = await this.tt.requireComponent({routeDefinition: {component: actualComponentPath}})
174
+
175
+ Component = componentImport.default
176
+ } catch (error) {
177
+ console.error(`Couldn't find component: ${actualComponentPath}`)
178
+
179
+ throw error
180
+ }
181
+
182
+ this.setState({Component, componentNotFound: !Component})
183
+ }
184
+
185
+ render() {
186
+ const {componentPathParts, match, newParams, newRouteParts} = this.tt
187
+ const {component, path} = this.props
188
+ const {Component, componentNotFound, matches} = this.s
189
+
190
+ if (!matches || !this.hasSwitchMatch()) {
191
+ // Route isn't matching and shouldn't be rendered at all.
192
+ return null
193
+ }
194
+
195
+ if (!Component && !componentNotFound) {
196
+ // Route is matching but hasn't been loaded yet.
197
+ return (
198
+ <div>
199
+ Loading {component || this.props.componentPath || componentPathParts.join("/")}
200
+ </div>
201
+ )
202
+ }
203
+
204
+ if (!Component && componentNotFound) {
205
+ // Don't render anything if the component couldn't be found.
206
+ return null
207
+ }
208
+
209
+ return (
210
+ <CurrentPathContext.Provider value={componentPathParts}>
211
+ <RouteContext.Provider value={newRouteParts.join("/")}>
212
+ <ParamsContext.Provider value={newParams}>
213
+ <Switch name={`route-group-${path}`} single={false}>
214
+ <Component match={match} />
215
+ </Switch>
216
+ </ParamsContext.Provider>
217
+ </RouteContext.Provider>
218
+ </CurrentPathContext.Provider>
219
+ )
220
+ }
221
+ }))
222
+
223
+ export {RequireComponentContext, RouteContext, Switch, useParams}
224
+ export default Route
@@ -0,0 +1,76 @@
1
+ import BaseComponent from "../base-component"
2
+ import {createContext} from "react"
3
+ import memo from "set-state-compare/src/memo"
4
+ import PropTypes from "prop-types"
5
+ import propTypesExact from "prop-types-exact"
6
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
7
+
8
+ const CurrentSwitchContext = createContext([])
9
+
10
+ const Switch = memo(shapeComponent(class Switch extends BaseComponent {
11
+ static defaultProps = {
12
+ name: "[no name]",
13
+ single: true
14
+ }
15
+
16
+ static propTypes = propTypesExact({
17
+ children: PropTypes.node,
18
+ name: PropTypes.string,
19
+ single: PropTypes.bool
20
+ })
21
+
22
+ pathsMatchedKeys = []
23
+
24
+ setup() {
25
+ this.useStates({
26
+ lastUpdate: new Date(),
27
+ pathShown: undefined,
28
+ pathsMatched: {}
29
+ })
30
+ }
31
+
32
+ render() {
33
+ const {pathShown, pathsMatched} = this.s
34
+
35
+ return (
36
+ <CurrentSwitchContext.Provider value={{pathShown, pathsMatched, switchGroup: this}}>
37
+ {this.props.children}
38
+ </CurrentSwitchContext.Provider>
39
+ )
40
+ }
41
+
42
+ pathShown(pathsMatched) {
43
+ for (const pathMatched of this.tt.pathsMatchedKeys) {
44
+ const isPathMatched = pathsMatched[pathMatched]
45
+
46
+ if (isPathMatched) {
47
+ return pathMatched
48
+ }
49
+ }
50
+ }
51
+
52
+ setPathMatched(path, matched) {
53
+ const {pathsMatchedKeys} = this.tt
54
+ const {pathsMatched} = this.s
55
+
56
+ if (!path) throw new Error("No 'path' given")
57
+ if (pathsMatched[path] == matched) return
58
+
59
+ if (!pathsMatchedKeys.includes(path)) {
60
+ pathsMatchedKeys.push(path)
61
+ }
62
+
63
+ const newPathsMatched = {...this.s.pathsMatched}
64
+
65
+ newPathsMatched[path] = matched
66
+
67
+ this.setState({
68
+ lastUpdate: Math.random() + new Date().getTime(),
69
+ pathShown: this.pathShown(newPathsMatched),
70
+ pathsMatched: newPathsMatched
71
+ })
72
+ }
73
+ }))
74
+
75
+ export {CurrentSwitchContext}
76
+ export default Switch
package/src/router.jsx CHANGED
@@ -1,38 +1,46 @@
1
+ import BaseComponent from "./base-component"
1
2
  import PropTypes from "prop-types"
3
+ import propTypesExact from "prop-types-exact"
2
4
  import React, {memo} from "react"
5
+ import {shapeComponent} from "set-state-compare/src/shape-component.js"
3
6
  import {Suspense} from "react"
4
- import withRouter from "./with-router"
7
+ import useRouter from "./use-router"
5
8
 
6
- const ApiMakerRouter = (props) => {
7
- const {match, ...restProps} = props
8
- const {matchingRoute} = match
9
+ export default memo(shapeComponent(class ApiMakerRouter extends BaseComponent {
10
+ static propTypes = propTypesExact({
11
+ history: PropTypes.object,
12
+ notFoundComponent: PropTypes.elementType,
13
+ path: PropTypes.string,
14
+ requireComponent: PropTypes.func.isRequired,
15
+ routeDefinitions: PropTypes.object,
16
+ routes: PropTypes.object
17
+ })
9
18
 
10
- if (!matchingRoute) {
11
- if (props.notFoundComponent) {
12
- const NotFoundComponent = props.notFoundComponent
19
+ render() {
20
+ const {notFoundComponent, path, requireComponent, routeDefinitions, routes} = this.props
21
+ const {match} = useRouter({path, routes, routeDefinitions})
22
+ const {matchingRoute} = match
13
23
 
14
- return (
15
- <Suspense fallback={<div />}>
16
- <NotFoundComponent match={match} />
17
- </Suspense>
18
- )
19
- } else {
20
- return null
21
- }
22
- }
23
-
24
- const Component = props.requireComponent({routeDefinition: matchingRoute.parsedRouteDefinition.routeDefinition})
24
+ if (!matchingRoute) {
25
+ if (notFoundComponent) {
26
+ const NotFoundComponent = notFoundComponent
25
27
 
26
- return (
27
- <Suspense fallback={<div />}>
28
- <Component match={match} {...restProps} />
29
- </Suspense>
30
- )
31
- }
28
+ return (
29
+ <Suspense fallback={<div />}>
30
+ <NotFoundComponent match={match} />
31
+ </Suspense>
32
+ )
33
+ } else {
34
+ return null
35
+ }
36
+ }
32
37
 
33
- ApiMakerRouter.propTypes = {
34
- notFoundComponent: PropTypes.elementType,
35
- requireComponent: PropTypes.func.isRequired
36
- }
38
+ const Component = requireComponent({routeDefinition: matchingRoute.parsedRouteDefinition.routeDefinition})
37
39
 
38
- export default withRouter(memo(ApiMakerRouter))
40
+ return (
41
+ <Suspense fallback={<div />}>
42
+ <Component match={match} />
43
+ </Suspense>
44
+ )
45
+ }
46
+ }))
@@ -103,8 +103,6 @@ export default memo(shapeComponent(class ApiMakerSuperAdminEditPage extends Base
103
103
  const {model} = this.tt
104
104
  const formObject = this.s.form.asObject()
105
105
 
106
- console.log({formObject})
107
-
108
106
  model.assignAttributes(formObject)
109
107
  await model.save()
110
108
  Params.changeParams({mode: undefined, model_id: model.id()})