@thoughtbot/superglue 0.0.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # Superglue
2
+
3
+ Use classic Rails to build rich React Redux applications with **NO APIs** and
4
+ **NO client-side routing**.
5
+
6
+ [![Build Status](https://circleci.com/gh/thoughtbot/superglue.svg?style=shield)](https://circleci.com/gh/thoughtbot/superglue)
7
+
8
+ Superglue is a React Redux starter and library inspired by Turbolinks and designed
9
+ to complement classic Rails. You can enjoy the benefits of Redux state
10
+ management and React components without giving up the productivity of Rails form
11
+ helpers, UJS, tag helpers, the flash, cookie auth, and more.
12
+
13
+ ## Caution
14
+
15
+ This project is in its early phases of development. Its interface, behavior,
16
+ and name are likely to change drastically before a major version release.
17
+
18
+ ### No APIs
19
+
20
+ Instead of APIs, Superglue leans on Rail's ability to respond to different
21
+ [mime types](https://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to)
22
+ on the same route. In a Superglue application, if you direct your browser to
23
+ `/dashboard.html`, you would see the HTML version of the content, and if you
24
+ went to `/dashboard.json` you would see the JSON version of the exact same
25
+ content down to the footer.
26
+
27
+ The end result would be something like this:
28
+
29
+ ![No Apis](https://thoughtbot.github.io/superglue/images/no_apis.png)
30
+
31
+ ### Powered by Classic Rails
32
+ Superglue is mostly classic Rails. Features like the flash, cookie auth, and URL
33
+ helpers continue to be useful. Here's a look at the directory structure of a
34
+ typical Rails application with Superglue.
35
+
36
+ ```
37
+ MyRailsApp/
38
+ app/
39
+ views/
40
+ dashboard/
41
+ index.html.erb <- Mostly empty. Where `index.json.props` gets rendered as initial state
42
+ index.js <- Your page component, will receive `index.json.props`. Gets packaged with application.js
43
+ index.json.props <- will also respond to `.json` requests
44
+ ```
45
+
46
+ ### PropsTemplate
47
+ Powering these JSON responses is PropsTemplate, a traversable JSON templating DSL
48
+ inspired by JBuilder. With PropsTemplate you can specify a path of the node you
49
+ want, and PropsTemplate will walk the tree to it, skipping the execution of nodes
50
+ that don't match the keypath.
51
+
52
+ ![No Apis](https://thoughtbot.github.io/superglue/images/props_template.png)
53
+
54
+ ### All together now!
55
+ Superglue comes with batteries that bring all the above concepts together to make
56
+ building popular SPA features easy, painless, and productive.
57
+
58
+ #### SPA Navigation
59
+ A popular ask of SPAs is page-to-page navigation without reloading. This is
60
+ easily done with Superglue's own UJS attributes inspired by Turbolinks:
61
+
62
+ ```jsx
63
+ <a href='/posts' data-bz-visit={true} />
64
+ ```
65
+
66
+ The above will request for `/posts` with an `accept` of `application/json`, and
67
+ when the client receives the response, swap out the current component for the
68
+ component the response asks for, and `pushState` on history.
69
+
70
+
71
+ #### Partial updates
72
+ Some features rely on updating some parts of the existing page. In
73
+ addition to `data-bz-visit` and it's equivalent `this.props.visit`, Superglue
74
+ also provides `data-bz-remote` or `this.props.remote`, which you can use to
75
+ update parts of your page in async fashion without changing `window.history`.
76
+
77
+ Imagine having to implement search, where you enter some text, hit enter, and
78
+ results would show without reloading the screen. In traditional applications,
79
+ you may need a new controller, routes, a discussion over versioning, JSON
80
+ serializer, plenty of new JS code, etc.
81
+
82
+ ![haircuts](https://thoughtbot.github.io/superglue/images/haircuts.png)
83
+
84
+ With Superglue, this can be done in one line:
85
+
86
+ ```javascript
87
+ this.props.remote('/dashboard?qry=haircut&props_at=data.header.search')
88
+ ```
89
+
90
+ The above will make a request to `/dashboard?qry=haircut`, walk your props to
91
+ the `data.header.search` node, return it in the response, and immutably graft it
92
+ in the exact same path on the redux store before finally letting React
93
+ re-render.
94
+
95
+ For more on what you can do, check out our documentation.
96
+
97
+ #### Server-Side Rendering
98
+ Server-Side Rendering is supported via [Humid](https://github.com/thoughtbot/humid).
99
+ See the [documentation for server-side rendering][ssr docs].
100
+
101
+ [ssr docs]: ./recipes/server-side-rendering.md
102
+
103
+ ## Documentation
104
+
105
+ Documentation is hosted on [Github pages](https://thoughtbot.github.io/superglue).
106
+
107
+ ## Contributing
108
+
109
+ See the [CONTRIBUTING] document. Thank you, [contributors]!
110
+
111
+ [CONTRIBUTING]: CONTRIBUTING.md
112
+ [contributors]: https://github.com/thoughtbot/superglue/graphs/contributors
113
+
114
+ ## Special Thanks
115
+
116
+ Thanks to [jbuilder](https://github.com/rails/jbuilder),
117
+ [scour](https://github.com/rstacruz/scour),
118
+ [turbolinks3](https://github.com/turbolinks/turbolinks-classic),
119
+ [turbograft](https://github.com/Shopify/turbograft/),
120
+ [turbostreamer](https://github.com/malomalo/turbostreamer)
121
+
122
+
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ var _exportNames = {
5
+ copyPage: true,
6
+ saveResponse: true,
7
+ handleGraft: true,
8
+ saveAndProcessPage: true
9
+ };
10
+ exports.copyPage = copyPage;
11
+ exports.handleGraft = handleGraft;
12
+ exports.saveAndProcessPage = saveAndProcessPage;
13
+ exports.saveResponse = saveResponse;
14
+
15
+ var _utils = require("../utils");
16
+
17
+ var _urlParse = _interopRequireDefault(require("url-parse"));
18
+
19
+ var _actions = require("../actions");
20
+
21
+ var _requests = require("./requests");
22
+
23
+ Object.keys(_requests).forEach(function (key) {
24
+ if (key === "default" || key === "__esModule") return;
25
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
26
+ if (key in exports && exports[key] === _requests[key]) return;
27
+ exports[key] = _requests[key];
28
+ });
29
+
30
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
31
+
32
+ function copyPage(_ref) {
33
+ var from = _ref.from,
34
+ to = _ref.to;
35
+ return {
36
+ type: _actions.COPY_PAGE,
37
+ payload: {
38
+ from: from,
39
+ to: to
40
+ }
41
+ };
42
+ }
43
+
44
+ function saveResponse(_ref2) {
45
+ var pageKey = _ref2.pageKey,
46
+ page = _ref2.page;
47
+ pageKey = (0, _utils.urlToPageKey)(pageKey);
48
+ return {
49
+ type: _actions.SAVE_RESPONSE,
50
+ payload: {
51
+ pageKey: pageKey,
52
+ page: page
53
+ }
54
+ };
55
+ }
56
+
57
+ function handleGraft(_ref3) {
58
+ var pageKey = _ref3.pageKey,
59
+ page = _ref3.page;
60
+ pageKey = (0, _utils.urlToPageKey)(pageKey);
61
+ return {
62
+ type: _actions.HANDLE_GRAFT,
63
+ payload: {
64
+ pageKey: pageKey,
65
+ page: page
66
+ }
67
+ };
68
+ }
69
+
70
+ function fetchDeferments(pageKey, defers) {
71
+ if (defers === void 0) {
72
+ defers = [];
73
+ }
74
+
75
+ pageKey = (0, _utils.urlToPageKey)(pageKey);
76
+ return function (dispatch) {
77
+ var fetches = defers.filter(function (_ref4) {
78
+ var type = _ref4.type;
79
+ return type === 'auto';
80
+ }).map(function (_ref5) {
81
+ var url = _ref5.url,
82
+ _ref5$successAction = _ref5.successAction,
83
+ successAction = _ref5$successAction === void 0 ? _actions.GRAFTING_SUCCESS : _ref5$successAction,
84
+ _ref5$failAction = _ref5.failAction,
85
+ failAction = _ref5$failAction === void 0 ? _actions.GRAFTING_ERROR : _ref5$failAction;
86
+ var parsedUrl = new _urlParse["default"](url, true);
87
+ var keyPath = parsedUrl.query.props_at;
88
+ return dispatch((0, _requests.remote)(url, {
89
+ pageKey: pageKey
90
+ })).then(function () {
91
+ dispatch({
92
+ type: successAction,
93
+ payload: {
94
+ pageKey: pageKey,
95
+ keyPath: keyPath
96
+ }
97
+ });
98
+ })["catch"](function (err) {
99
+ dispatch({
100
+ type: failAction,
101
+ payload: {
102
+ url: url,
103
+ err: err,
104
+ pageKey: pageKey,
105
+ keyPath: keyPath
106
+ }
107
+ });
108
+ });
109
+ });
110
+ return Promise.all(fetches);
111
+ };
112
+ }
113
+
114
+ function updateFragmentsUsing(page) {
115
+ var changedFragments = {};
116
+ page.fragments.forEach(function (fragment) {
117
+ var type = fragment.type,
118
+ path = fragment.path;
119
+ changedFragments[type] = (0, _utils.getIn)(page, path);
120
+ });
121
+ return {
122
+ type: _actions.UPDATE_FRAGMENTS,
123
+ payload: {
124
+ changedFragments: changedFragments
125
+ }
126
+ };
127
+ }
128
+
129
+ function saveAndProcessPage(pageKey, page) {
130
+ return function (dispatch, getState) {
131
+ pageKey = (0, _utils.urlToPageKey)(pageKey);
132
+ var _page$defers = page.defers,
133
+ defers = _page$defers === void 0 ? [] : _page$defers;
134
+
135
+ if ((0, _utils.isGraft)(page)) {
136
+ dispatch(handleGraft({
137
+ pageKey: pageKey,
138
+ page: page
139
+ }));
140
+ } else {
141
+ dispatch(saveResponse({
142
+ pageKey: pageKey,
143
+ page: page
144
+ }));
145
+ }
146
+
147
+ var hasFetch = typeof fetch != 'undefined';
148
+
149
+ if (hasFetch) {
150
+ return dispatch(fetchDeferments(pageKey, defers)).then(function () {
151
+ if (page.fragments.length > 0) {
152
+ var finishedPage = getState().pages[pageKey];
153
+ return dispatch(updateFragmentsUsing(finishedPage));
154
+ }
155
+ });
156
+ } else {
157
+ return Promise.resolve();
158
+ }
159
+ };
160
+ }
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.clearFlash = clearFlash;
5
+ exports.remote = remote;
6
+ exports.visit = visit;
7
+
8
+ var _utils = require("../utils");
9
+
10
+ var _actions = require("../actions");
11
+
12
+ var _index = require("./index");
13
+
14
+ function beforeFetch(payload) {
15
+ return {
16
+ type: _actions.BEFORE_FETCH,
17
+ payload: payload
18
+ };
19
+ }
20
+
21
+ function handleError(err) {
22
+ return {
23
+ type: _actions.SUPERGLUE_ERROR,
24
+ payload: {
25
+ message: err.message
26
+ }
27
+ };
28
+ }
29
+
30
+ function handleFetchErr(err, fetchArgs, dispatch) {
31
+ err.fetchArgs = fetchArgs;
32
+ err.url = fetchArgs[0];
33
+ err.pageKey = (0, _utils.urlToPageKey)(fetchArgs[0]);
34
+ dispatch(handleError(err));
35
+ throw err;
36
+ }
37
+
38
+ function buildMeta(pageKey, page, state) {
39
+ var prevAssets = state.assets;
40
+ var nextAssets = page.assets;
41
+ return {
42
+ pageKey: pageKey,
43
+ page: page,
44
+ componentIdentifier: page.componentIdentifier,
45
+ needsRefresh: (0, _utils.needsRefresh)(prevAssets, nextAssets)
46
+ };
47
+ }
48
+
49
+ function clearFlash(_ref) {
50
+ var pageKey = _ref.pageKey;
51
+ return {
52
+ type: _actions.CLEAR_FLASH,
53
+ payload: {
54
+ pageKey: pageKey
55
+ }
56
+ };
57
+ }
58
+
59
+ function remote(path, _temp) {
60
+ var _ref2 = _temp === void 0 ? {} : _temp,
61
+ _ref2$method = _ref2.method,
62
+ method = _ref2$method === void 0 ? 'GET' : _ref2$method,
63
+ headers = _ref2.headers,
64
+ _ref2$body = _ref2.body,
65
+ body = _ref2$body === void 0 ? '' : _ref2$body,
66
+ pageKey = _ref2.pageKey,
67
+ _ref2$beforeSave = _ref2.beforeSave,
68
+ beforeSave = _ref2$beforeSave === void 0 ? function (prevPage, receivedPage) {
69
+ return receivedPage;
70
+ } : _ref2$beforeSave;
71
+
72
+ path = (0, _utils.withoutBusters)(path);
73
+ pageKey = pageKey && (0, _utils.urlToPageKey)(pageKey);
74
+ return function (dispatch, getState) {
75
+ var fetchArgs = (0, _utils.argsForFetch)(getState, path, {
76
+ method: method,
77
+ headers: headers,
78
+ body: body
79
+ });
80
+ pageKey = pageKey || getState().superglue.currentPageKey;
81
+ dispatch(beforeFetch({
82
+ fetchArgs: fetchArgs
83
+ }));
84
+ return fetch.apply(void 0, fetchArgs).then(_utils.parseResponse).then(function (_ref3) {
85
+ var rsp = _ref3.rsp,
86
+ json = _ref3.json;
87
+
88
+ var _getState = getState(),
89
+ superglue = _getState.superglue,
90
+ _getState$pages = _getState.pages,
91
+ pages = _getState$pages === void 0 ? {} : _getState$pages;
92
+
93
+ var meta = Object.assign({}, buildMeta(pageKey, json, superglue), {
94
+ redirected: rsp.redirected,
95
+ rsp: rsp,
96
+ fetchArgs: fetchArgs
97
+ });
98
+ var page = beforeSave(pages[pageKey], json);
99
+ return dispatch((0, _index.saveAndProcessPage)(pageKey, page)).then(function () {
100
+ meta.pageKey = pageKey;
101
+ return meta;
102
+ });
103
+ })["catch"](function (e) {
104
+ return handleFetchErr(e, fetchArgs, dispatch);
105
+ });
106
+ };
107
+ }
108
+
109
+ var lastVisitController = {
110
+ abort: function abort() {}
111
+ };
112
+
113
+ function visit(path, _temp2) {
114
+ var _ref4 = _temp2 === void 0 ? {} : _temp2,
115
+ _ref4$method = _ref4.method,
116
+ method = _ref4$method === void 0 ? 'GET' : _ref4$method,
117
+ headers = _ref4.headers,
118
+ _ref4$body = _ref4.body,
119
+ body = _ref4$body === void 0 ? '' : _ref4$body,
120
+ placeholderKey = _ref4.placeholderKey,
121
+ _ref4$beforeSave = _ref4.beforeSave,
122
+ beforeSave = _ref4$beforeSave === void 0 ? function (prevPage, receivedPage) {
123
+ return receivedPage;
124
+ } : _ref4$beforeSave;
125
+
126
+ path = (0, _utils.withoutBusters)(path);
127
+ var pageKey = (0, _utils.urlToPageKey)(path);
128
+ return function (dispatch, getState) {
129
+ var currentKey = getState().superglue.currentPageKey;
130
+ dispatch(clearFlash({
131
+ pageKey: currentKey
132
+ }));
133
+ placeholderKey = placeholderKey && (0, _utils.urlToPageKey)(placeholderKey);
134
+ var hasPlaceholder = !!getState().pages[placeholderKey];
135
+
136
+ if (placeholderKey && hasPlaceholder) {
137
+ dispatch((0, _index.copyPage)({
138
+ from: placeholderKey,
139
+ to: pageKey
140
+ }));
141
+ }
142
+
143
+ if (placeholderKey && !hasPlaceholder) {
144
+ console.warn("Could not find placeholder with key " + placeholderKey + " in state. The props_at param will be ignored");
145
+ path = (0, _utils.removePropsAt)(path);
146
+ }
147
+
148
+ if (!placeholderKey && (0, _utils.hasPropsAt)(path)) {
149
+ console.warn("visit was called with props_at param in the path " + path + ", this will be ignore unless you provide a placeholder.");
150
+ path = (0, _utils.removePropsAt)(path);
151
+ }
152
+
153
+ var controller = new AbortController();
154
+ var signal = controller.signal;
155
+ var fetchArgs = (0, _utils.argsForFetch)(getState, path, {
156
+ headers: headers,
157
+ body: body,
158
+ method: method,
159
+ signal: signal
160
+ });
161
+ dispatch(beforeFetch({
162
+ fetchArgs: fetchArgs
163
+ }));
164
+ lastVisitController.abort();
165
+ lastVisitController = controller;
166
+ return fetch.apply(void 0, fetchArgs).then(_utils.parseResponse).then(function (_ref5) {
167
+ var rsp = _ref5.rsp,
168
+ json = _ref5.json;
169
+
170
+ var _getState2 = getState(),
171
+ superglue = _getState2.superglue,
172
+ _getState2$pages = _getState2.pages,
173
+ pages = _getState2$pages === void 0 ? {} : _getState2$pages;
174
+
175
+ var meta = Object.assign({}, buildMeta(pageKey, json, superglue), {
176
+ redirected: rsp.redirected,
177
+ rsp: rsp,
178
+ fetchArgs: fetchArgs
179
+ });
180
+ meta.suggestedAction = 'push';
181
+
182
+ if (!rsp.redirected && fetchArgs[1].method != 'GET') {
183
+ meta.suggestedAction = 'replace';
184
+ }
185
+
186
+ if (method !== 'GET') {
187
+ var contentLocation = rsp.headers.get('content-location');
188
+
189
+ if (contentLocation) {
190
+ pageKey = (0, _utils.urlToPageKey)(contentLocation);
191
+ }
192
+ }
193
+
194
+ if (rsp.redirected) {
195
+ pageKey = (0, _utils.urlToPageKey)(rsp.url);
196
+ }
197
+
198
+ var page = beforeSave(pages[pageKey], json);
199
+ return dispatch((0, _index.saveAndProcessPage)(pageKey, page)).then(function () {
200
+ meta.pageKey = pageKey;
201
+ return meta;
202
+ });
203
+ })["catch"](function (e) {
204
+ return handleFetchErr(e, fetchArgs, dispatch);
205
+ });
206
+ };
207
+ }
package/actions.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.UPDATE_FRAGMENTS = exports.SUPERGLUE_ERROR = exports.SET_CSRF_TOKEN = exports.SAVE_RESPONSE = exports.REMOVE_PAGE = exports.HISTORY_CHANGE = exports.HANDLE_GRAFT = exports.GRAFTING_SUCCESS = exports.GRAFTING_ERROR = exports.COPY_PAGE = exports.CLEAR_FLASH = exports.BEFORE_FETCH = void 0;
5
+ var BEFORE_FETCH = '@@superglue/BEFORE_FETCH';
6
+ exports.BEFORE_FETCH = BEFORE_FETCH;
7
+ var SAVE_RESPONSE = '@@superglue/SAVE_RESPONSE';
8
+ exports.SAVE_RESPONSE = SAVE_RESPONSE;
9
+ var HANDLE_GRAFT = '@@superglue/HANDLE_GRAFT';
10
+ exports.HANDLE_GRAFT = HANDLE_GRAFT;
11
+ var CLEAR_FLASH = '@@superglue/CLEAR_FLASH';
12
+ exports.CLEAR_FLASH = CLEAR_FLASH;
13
+ var SUPERGLUE_ERROR = '@@superglue/ERROR';
14
+ exports.SUPERGLUE_ERROR = SUPERGLUE_ERROR;
15
+ var GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR';
16
+ exports.GRAFTING_ERROR = GRAFTING_ERROR;
17
+ var GRAFTING_SUCCESS = '@@superglue/GRAFTING_SUCCESS';
18
+ exports.GRAFTING_SUCCESS = GRAFTING_SUCCESS;
19
+ var HISTORY_CHANGE = '@@superglue/HISTORY_CHANGE';
20
+ exports.HISTORY_CHANGE = HISTORY_CHANGE;
21
+ var SET_CSRF_TOKEN = '@@superglue/SET_CSRF_TOKEN';
22
+ exports.SET_CSRF_TOKEN = SET_CSRF_TOKEN;
23
+ var REMOVE_PAGE = '@@superglue/REMOVE_PAGE';
24
+ exports.REMOVE_PAGE = REMOVE_PAGE;
25
+ var COPY_PAGE = '@@superglue/COPY_PAGE';
26
+ exports.COPY_PAGE = COPY_PAGE;
27
+ var UPDATE_FRAGMENTS = '@@superglue/UPDATE_FRAGMENTS';
28
+ exports.UPDATE_FRAGMENTS = UPDATE_FRAGMENTS;
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports["default"] = void 0;
5
+
6
+ var _react = _interopRequireDefault(require("react"));
7
+
8
+ var _utils = require("../utils");
9
+
10
+ var _actions = require("../actions");
11
+
12
+ var _propTypes = _interopRequireDefault(require("prop-types"));
13
+
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15
+
16
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
17
+
18
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
19
+
20
+ function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
21
+
22
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
23
+
24
+ var Nav = /*#__PURE__*/function (_React$Component) {
25
+ _inheritsLoose(Nav, _React$Component);
26
+
27
+ function Nav(props) {
28
+ var _this;
29
+
30
+ _this = _React$Component.call(this, props) || this;
31
+ var _this$props = _this.props,
32
+ history = _this$props.history,
33
+ initialPageKey = _this$props.initialPageKey;
34
+ _this.history = history;
35
+ _this.navigateTo = _this.navigateTo.bind(_assertThisInitialized(_this));
36
+ _this.onHistoryChange = _this.onHistoryChange.bind(_assertThisInitialized(_this));
37
+ _this.state = {
38
+ pageKey: initialPageKey,
39
+ ownProps: {}
40
+ };
41
+ return _this;
42
+ }
43
+
44
+ var _proto = Nav.prototype;
45
+
46
+ _proto.componentDidMount = function componentDidMount() {
47
+ this.unsubscribeHistory = this.history.listen(this.onHistoryChange);
48
+ };
49
+
50
+ _proto.componentWillUnmount = function componentWillUnmount() {
51
+ this.unsubscribeHistory();
52
+ };
53
+
54
+ _proto.navigateTo = function navigateTo(path, _temp) {
55
+ var _ref = _temp === void 0 ? {
56
+ action: 'push',
57
+ ownProps: {}
58
+ } : _temp,
59
+ action = _ref.action,
60
+ ownProps = _ref.ownProps;
61
+
62
+ path = (0, _utils.pathWithoutBZParams)(path);
63
+ var nextPageKey = (0, _utils.urlToPageKey)(path);
64
+ var store = this.props.store;
65
+ var hasPage = !!store.getState().pages[nextPageKey];
66
+
67
+ if (hasPage) {
68
+ var prevPageKey = this.history.location.state.pageKey;
69
+ var historyArgs = [path, {
70
+ pageKey: nextPageKey,
71
+ superglue: true
72
+ }];
73
+
74
+ if (action === 'push') {
75
+ var _this$history;
76
+
77
+ (_this$history = this.history).push.apply(_this$history, historyArgs);
78
+ }
79
+
80
+ if (action === 'replace') {
81
+ var _this$history2;
82
+
83
+ (_this$history2 = this.history).replace.apply(_this$history2, historyArgs);
84
+ }
85
+
86
+ this.setState({
87
+ pageKey: nextPageKey,
88
+ ownProps: ownProps
89
+ });
90
+
91
+ if (action === 'replace' && prevPageKey && prevPageKey !== nextPageKey) {
92
+ store.dispatch({
93
+ type: _actions.REMOVE_PAGE,
94
+ payload: {
95
+ pageKey: prevPageKey
96
+ }
97
+ });
98
+ }
99
+
100
+ return true;
101
+ } else {
102
+ console.warn("`navigateTo` was called , but could not find.\n the pageKey in the store. This may happen when the wrong\n content_location was set in your non-get controller action.\n No navigation will take place");
103
+ return false;
104
+ }
105
+ };
106
+
107
+ _proto.onHistoryChange = function onHistoryChange(location) {
108
+ var store = this.props.store;
109
+ var pathname = location.pathname,
110
+ search = location.search,
111
+ hash = location.hash,
112
+ state = location.state;
113
+
114
+ if (state && state.superglue) {
115
+ store.dispatch({
116
+ type: _actions.HISTORY_CHANGE,
117
+ payload: {
118
+ pathname: pathname,
119
+ search: search,
120
+ hash: hash
121
+ }
122
+ });
123
+ var pageKey = state.pageKey;
124
+ var containsKey = !!store.getState().pages[pageKey];
125
+
126
+ if (containsKey) {
127
+ this.setState({
128
+ pageKey: pageKey
129
+ });
130
+ } else {
131
+ this.reloadPage();
132
+ }
133
+ }
134
+ };
135
+
136
+ _proto.reloadPage = function reloadPage() {
137
+ window.location.reload();
138
+ };
139
+
140
+ _proto.notFound = function notFound(identifier) {
141
+ var reminder = '';
142
+
143
+ if (!identifier) {
144
+ reminder = 'Did you forget to add `json.component_identifier` in your application.json.props layout?';
145
+ }
146
+
147
+ var error = new Error("Superglue Nav component was looking for " + identifier + " but could not find it in your mapping. " + reminder);
148
+ throw error;
149
+ };
150
+
151
+ _proto.render = function render() {
152
+ var _this$props2 = this.props,
153
+ store = _this$props2.store,
154
+ visit = _this$props2.visit,
155
+ remote = _this$props2.remote;
156
+ var _this$state = this.state,
157
+ pageKey = _this$state.pageKey,
158
+ ownProps = _this$state.ownProps;
159
+ var componentIdentifier = store.getState().pages[pageKey].componentIdentifier;
160
+ var Component = this.props.mapping[componentIdentifier];
161
+
162
+ if (Component) {
163
+ return /*#__PURE__*/_react["default"].createElement(Component, _extends({
164
+ pageKey: pageKey,
165
+ navigateTo: this.navigateTo,
166
+ visit: visit,
167
+ remote: remote
168
+ }, ownProps));
169
+ } else {
170
+ this.notFound(componentIdentifier);
171
+ }
172
+ };
173
+
174
+ return Nav;
175
+ }(_react["default"].Component);
176
+
177
+ Nav.propTypes = {
178
+ store: _propTypes["default"].object,
179
+ history: _propTypes["default"].object,
180
+ mapping: _propTypes["default"].object,
181
+ visit: _propTypes["default"].func,
182
+ remote: _propTypes["default"].func,
183
+ initialPageKey: _propTypes["default"].string
184
+ };
185
+ var _default = Nav;
186
+ exports["default"] = _default;