@thoughtbot/superglue 0.30.0 → 0.41.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 CHANGED
@@ -60,7 +60,7 @@ A popular ask of SPAs is page-to-page navigation without reloading. This is
60
60
  easily done with Superglue's own UJS attributes inspired by Turbolinks:
61
61
 
62
62
  ```jsx
63
- <a href='/posts' data-bz-visit={true} />
63
+ <a href='/posts' data-sg-visit={true} />
64
64
  ```
65
65
 
66
66
  The above will request for `/posts` with an `accept` of `application/json`, and
@@ -70,8 +70,8 @@ component the response asks for, and `pushState` on history.
70
70
 
71
71
  #### Partial updates
72
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
73
+ addition to `data-sg-visit` and it's equivalent `this.props.visit`, Superglue
74
+ also provides `data-sg-remote` or `this.props.remote`, which you can use to
75
75
  update parts of your page in async fashion without changing `window.history`.
76
76
 
77
77
  Imagine having to implement search, where you enter some text, hit enter, and
@@ -121,7 +121,9 @@ function visit(path, _temp2) {
121
121
  _ref4$beforeSave = _ref4.beforeSave,
122
122
  beforeSave = _ref4$beforeSave === void 0 ? function (prevPage, receivedPage) {
123
123
  return receivedPage;
124
- } : _ref4$beforeSave;
124
+ } : _ref4$beforeSave,
125
+ _ref4$revisit = _ref4.revisit,
126
+ revisit = _ref4$revisit === void 0 ? false : _ref4$revisit;
125
127
 
126
128
  path = (0, _utils.withoutBusters)(path);
127
129
  var pageKey = (0, _utils.urlToPageKey)(path);
@@ -183,6 +185,14 @@ function visit(path, _temp2) {
183
185
  meta.suggestedAction = 'replace';
184
186
  }
185
187
 
188
+ if (revisit && fetchArgs[1].method == 'GET') {
189
+ if (rsp.redirected) {
190
+ meta.suggestedAction = 'replace';
191
+ } else {
192
+ meta.suggestedAction = 'none';
193
+ }
194
+ }
195
+
186
196
  if (method !== 'GET') {
187
197
  var contentLocation = rsp.headers.get('content-location');
188
198
 
package/components/Nav.js CHANGED
@@ -9,8 +9,6 @@ var _utils = require("../utils");
9
9
 
10
10
  var _actions = require("../actions");
11
11
 
12
- var _propTypes = _interopRequireDefault(require("prop-types"));
13
-
14
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15
13
 
16
14
  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); }
@@ -33,11 +31,13 @@ var Nav = /*#__PURE__*/function (_React$Component) {
33
31
  initialPageKey = _this$props.initialPageKey;
34
32
  _this.history = history;
35
33
  _this.navigateTo = _this.navigateTo.bind(_assertThisInitialized(_this));
34
+ _this.scrollTo = _this.scrollTo.bind(_assertThisInitialized(_this));
36
35
  _this.onHistoryChange = _this.onHistoryChange.bind(_assertThisInitialized(_this));
37
36
  _this.state = {
38
37
  pageKey: initialPageKey,
39
38
  ownProps: {}
40
39
  };
40
+ _this.hasWindow = typeof window !== 'undefined';
41
41
  return _this;
42
42
  }
43
43
 
@@ -59,21 +59,39 @@ var Nav = /*#__PURE__*/function (_React$Component) {
59
59
  action = _ref.action,
60
60
  ownProps = _ref.ownProps;
61
61
 
62
+ if (action === 'none') {
63
+ return false;
64
+ }
65
+
62
66
  path = (0, _utils.pathWithoutBZParams)(path);
63
67
  var nextPageKey = (0, _utils.urlToPageKey)(path);
64
68
  var store = this.props.store;
65
69
  var hasPage = !!store.getState().pages[nextPageKey];
66
70
 
67
71
  if (hasPage) {
68
- var prevPageKey = this.history.location.state.pageKey;
72
+ var location = this.history.location;
73
+ var prevPageKey = location.state.pageKey;
69
74
  var historyArgs = [path, {
70
75
  pageKey: nextPageKey,
71
- superglue: true
76
+ superglue: true,
77
+ posY: 0,
78
+ posX: 0
72
79
  }];
73
80
 
74
81
  if (action === 'push') {
75
82
  var _this$history;
76
83
 
84
+ if (this.hasWindow) {
85
+ this.history.replace({
86
+ pathname: location.pathname,
87
+ search: location.search,
88
+ hash: location.hash
89
+ }, Object.assign({}, location.state, {
90
+ posY: window.pageYOffset,
91
+ posX: window.pageXOffset
92
+ }));
93
+ }
94
+
77
95
  (_this$history = this.history).push.apply(_this$history, historyArgs);
78
96
  }
79
97
 
@@ -87,6 +105,7 @@ var Nav = /*#__PURE__*/function (_React$Component) {
87
105
  pageKey: nextPageKey,
88
106
  ownProps: ownProps
89
107
  });
108
+ this.scrollTo(0, 0);
90
109
 
91
110
  if (action === 'replace' && prevPageKey && prevPageKey !== nextPageKey) {
92
111
  store.dispatch({
@@ -104,8 +123,18 @@ var Nav = /*#__PURE__*/function (_React$Component) {
104
123
  }
105
124
  };
106
125
 
107
- _proto.onHistoryChange = function onHistoryChange(location) {
108
- var store = this.props.store;
126
+ _proto.scrollTo = function scrollTo(posX, posY) {
127
+ this.hasWindow && window.scrollTo(posX, posY);
128
+ };
129
+
130
+ _proto.onHistoryChange = function onHistoryChange(_ref2) {
131
+ var _this2 = this;
132
+
133
+ var location = _ref2.location,
134
+ action = _ref2.action;
135
+ var _this$props2 = this.props,
136
+ store = _this$props2.store,
137
+ visit = _this$props2.visit;
109
138
  var pathname = location.pathname,
110
139
  search = location.search,
111
140
  hash = location.hash,
@@ -120,23 +149,75 @@ var Nav = /*#__PURE__*/function (_React$Component) {
120
149
  hash: hash
121
150
  }
122
151
  });
123
- var pageKey = state.pageKey;
152
+
153
+ if (action !== 'POP') {
154
+ return;
155
+ }
156
+
157
+ var pageKey = state.pageKey,
158
+ posX = state.posX,
159
+ posY = state.posY;
124
160
  var containsKey = !!store.getState().pages[pageKey];
125
161
 
126
162
  if (containsKey) {
127
- this.setState({
128
- pageKey: pageKey
129
- });
163
+ var restoreStrategy = store.getState().pages[pageKey].restoreStrategy;
164
+
165
+ switch (restoreStrategy) {
166
+ case 'fromCacheOnly':
167
+ this.setState({
168
+ pageKey: pageKey
169
+ });
170
+ this.scrollTo(posX, posY);
171
+ break;
172
+
173
+ case 'fromCacheAndRevisitInBackground':
174
+ this.setState({
175
+ pageKey: pageKey
176
+ });
177
+ this.scrollTo(posX, posY);
178
+ visit(pageKey, {
179
+ revisit: true
180
+ });
181
+ break;
182
+
183
+ case 'revisitOnly':
184
+ default:
185
+ visit(pageKey, {
186
+ revisit: true
187
+ }).then(function (meta) {
188
+ if (meta === undefined) {
189
+ console.warn("scoll restoration was skipped. Your visit's then funtion\n should return the meta object it recieved if you want your\n application to restore the page's previous scroll.");
190
+ }
191
+
192
+ if (!!meta && meta.suggestedAction === 'none') {
193
+ _this2.setState({
194
+ pageKey: pageKey
195
+ });
196
+
197
+ _this2.scrollTo(posX, posY);
198
+ }
199
+ });
200
+ }
130
201
  } else {
131
- this.reloadPage();
202
+ visit(pageKey, {
203
+ revisit: true
204
+ }).then(function (meta) {
205
+ if (meta === undefined) {
206
+ console.warn("scoll restoration was skipped. Your visit's then funtion\n should return the meta object it recieved if you want your\n application to restore the page's previous scroll.");
207
+ }
208
+
209
+ if (!!meta && meta.suggestedAction === 'none') {
210
+ _this2.setState({
211
+ pageKey: pageKey
212
+ });
213
+
214
+ _this2.scrollTo(posX, posY);
215
+ }
216
+ });
132
217
  }
133
218
  }
134
219
  };
135
220
 
136
- _proto.reloadPage = function reloadPage() {
137
- window.location.reload();
138
- };
139
-
140
221
  _proto.notFound = function notFound(identifier) {
141
222
  var reminder = '';
142
223
 
@@ -149,10 +230,10 @@ var Nav = /*#__PURE__*/function (_React$Component) {
149
230
  };
150
231
 
151
232
  _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;
233
+ var _this$props3 = this.props,
234
+ store = _this$props3.store,
235
+ visit = _this$props3.visit,
236
+ remote = _this$props3.remote;
156
237
  var _this$state = this.state,
157
238
  pageKey = _this$state.pageKey,
158
239
  ownProps = _this$state.ownProps;
@@ -174,13 +255,5 @@ var Nav = /*#__PURE__*/function (_React$Component) {
174
255
  return Nav;
175
256
  }(_react["default"].Component);
176
257
 
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
258
  var _default = Nav;
186
259
  exports["default"] = _default;
@@ -7,10 +7,6 @@ var _react = _interopRequireDefault(require("react"));
7
7
 
8
8
  var _htmlReactParser = _interopRequireWildcard(require("html-react-parser"));
9
9
 
10
- var _attributesToProps = _interopRequireDefault(require("html-react-parser/lib/attributes-to-props"));
11
-
12
- var _propTypes = _interopRequireDefault(require("prop-types"));
13
-
14
10
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
11
 
16
12
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -48,7 +44,7 @@ var RailsTag = /*#__PURE__*/function (_React$Component) {
48
44
  children = domNode.children;
49
45
 
50
46
  if (!parent && type === 'tag') {
51
- var nextProps = Object.assign({}, this.props, (0, _attributesToProps["default"])(attribs), {
47
+ var nextProps = Object.assign({}, this.props, (0, _htmlReactParser.attributesToProps)(attribs), {
52
48
  children: (0, _htmlReactParser.domToReact)(children)
53
49
  });
54
50
  delete nextProps.html;
@@ -65,7 +61,4 @@ var RailsTag = /*#__PURE__*/function (_React$Component) {
65
61
  return RailsTag;
66
62
  }(_react["default"].Component);
67
63
 
68
- exports["default"] = RailsTag;
69
- RailsTag.propTypes = {
70
- html: _propTypes["default"].string
71
- };
64
+ exports["default"] = RailsTag;
package/index.js CHANGED
@@ -34,8 +34,6 @@ var _history = require("history");
34
34
 
35
35
  var _Nav = _interopRequireDefault(require("./components/Nav"));
36
36
 
37
- var _propTypes = _interopRequireDefault(require("prop-types"));
38
-
39
37
  var _react2 = require("./utils/react");
40
38
 
41
39
  exports.mapStateToProps = _react2.mapStateToProps;
@@ -198,7 +196,7 @@ var ApplicationBase = /*#__PURE__*/function (_React$Component) {
198
196
  visit: this.visit,
199
197
  remote: this.remote,
200
198
  store: this.store,
201
- ujsAttributePrefix: 'data-bz'
199
+ ujsAttributePrefix: 'data-sg'
202
200
  });
203
201
  var _this$ujsHandlers = this.ujsHandlers,
204
202
  onClick = _this$ujsHandlers.onClick,
@@ -254,10 +252,4 @@ var ApplicationBase = /*#__PURE__*/function (_React$Component) {
254
252
  return ApplicationBase;
255
253
  }(_react["default"].Component);
256
254
 
257
- exports.ApplicationBase = ApplicationBase;
258
- ApplicationBase.propTypes = {
259
- initialPage: _propTypes["default"].object,
260
- baseUrl: _propTypes["default"].string,
261
- path: _propTypes["default"].string,
262
- appEl: _propTypes["default"].object
263
- };
255
+ exports.ApplicationBase = ApplicationBase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtbot/superglue",
3
- "version": "0.30.0",
3
+ "version": "0.41.0",
4
4
  "description": "Use a vanilla Rails with React and Redux",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "eslint-plugin-react": "^7.24.0",
27
27
  "fetch-headers": "^2.0.0",
28
28
  "fetch-mock": "^9.11.0",
29
- "history": "^4.7.1",
29
+ "history": "^5.3.0",
30
30
  "html-react-parser": "^1.2.6",
31
31
  "jest": "^27.0.4",
32
32
  "node-fetch": "^2.6.1",
@@ -40,15 +40,16 @@
40
40
  "redux-thunk": "^2.3.0"
41
41
  },
42
42
  "peerDependencies": {
43
+ "history": "^5.3.0",
43
44
  "html-react-parser": ">=1.2.6",
44
45
  "react": ">=16",
45
- "redux": ">=4.1",
46
- "history": "^4.7.1",
47
46
  "react-redux": ">=7.2",
47
+ "redux": ">=4.1",
48
48
  "redux-thunk": ">=2.3"
49
49
  },
50
50
  "dependencies": {
51
51
  "abortcontroller-polyfill": "^1.7.3",
52
+ "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
52
53
  "url-parse": "^1.5.1"
53
54
  }
54
55
  }
package/utils/helpers.js CHANGED
@@ -31,6 +31,8 @@ function argsForHistory(path) {
31
31
  var pageKey = (0, _url.urlToPageKey)(path);
32
32
  return [path, {
33
33
  superglue: true,
34
- pageKey: pageKey
34
+ pageKey: pageKey,
35
+ posX: 0,
36
+ posY: 0
35
37
  }];
36
38
  }