stimulus_reflex 3.5.0.pre10 → 3.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stimulus_reflex might be problematic. Click here for more details.

@@ -1,8 +1,284 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@hotwired/stimulus"), require("@rails/actioncable"), require("cable_ready")) : typeof define === "function" && define.amd ? define([ "exports", "@hotwired/stimulus", "@rails/actioncable", "cable_ready" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
3
- factory(global.StimulusReflex = {}, global.Stimulus, global.ActionCable, global.CableReady));
4
- })(this, (function(exports, stimulus, actioncable, CableReady) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@hotwired/stimulus"), require("cable_ready"), require("@rails/actioncable")) : typeof define === "function" && define.amd ? define([ "exports", "@hotwired/stimulus", "cable_ready", "@rails/actioncable" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
3
+ factory(global.StimulusReflex = {}, global.Stimulus, global.CableReady, global.ActionCable));
4
+ })(this, (function(exports, stimulus, CableReady, actioncable) {
5
5
  "use strict";
6
+ /*!
7
+ * Toastify js 1.12.0
8
+ * https://github.com/apvarun/toastify-js
9
+ * @license MIT licensed
10
+ *
11
+ * Copyright (C) 2018 Varun A P
12
+ */ class Toastify {
13
+ defaults={
14
+ oldestFirst: true,
15
+ text: "Toastify is awesome!",
16
+ node: undefined,
17
+ duration: 3e3,
18
+ selector: undefined,
19
+ callback: function() {},
20
+ destination: undefined,
21
+ newWindow: false,
22
+ close: false,
23
+ gravity: "toastify-top",
24
+ positionLeft: false,
25
+ position: "",
26
+ backgroundColor: "",
27
+ avatar: "",
28
+ className: "",
29
+ stopOnFocus: true,
30
+ onClick: function() {},
31
+ offset: {
32
+ x: 0,
33
+ y: 0
34
+ },
35
+ escapeMarkup: true,
36
+ ariaLive: "polite",
37
+ style: {
38
+ background: ""
39
+ }
40
+ };
41
+ constructor(options) {
42
+ this.version = "1.12.0";
43
+ this.options = {};
44
+ this.toastElement = null;
45
+ this._rootElement = document.body;
46
+ this._init(options);
47
+ }
48
+ showToast() {
49
+ this.toastElement = this._buildToast();
50
+ if (typeof this.options.selector === "string") {
51
+ this._rootElement = document.getElementById(this.options.selector);
52
+ } else if (this.options.selector instanceof HTMLElement || this.options.selector instanceof ShadowRoot) {
53
+ this._rootElement = this.options.selector;
54
+ } else {
55
+ this._rootElement = document.body;
56
+ }
57
+ if (!this._rootElement) {
58
+ throw "Root element is not defined";
59
+ }
60
+ this._rootElement.insertBefore(this.toastElement, this._rootElement.firstChild);
61
+ this._reposition();
62
+ if (this.options.duration > 0) {
63
+ this.toastElement.timeOutValue = window.setTimeout((() => {
64
+ this._removeElement(this.toastElement);
65
+ }), this.options.duration);
66
+ }
67
+ return this;
68
+ }
69
+ hideToast() {
70
+ if (this.toastElement.timeOutValue) {
71
+ clearTimeout(this.toastElement.timeOutValue);
72
+ }
73
+ this._removeElement(this.toastElement);
74
+ }
75
+ _init(options) {
76
+ this.options = Object.assign(this.defaults, options);
77
+ if (this.options.backgroundColor) {
78
+ console.warn('DEPRECATION NOTICE: "backgroundColor" is being deprecated. Please use the "style.background" property.');
79
+ }
80
+ this.toastElement = null;
81
+ this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : "toastify-top";
82
+ this.options.stopOnFocus = options.stopOnFocus === undefined ? true : options.stopOnFocus;
83
+ if (options.backgroundColor) {
84
+ this.options.style.background = options.backgroundColor;
85
+ }
86
+ }
87
+ _buildToast() {
88
+ if (!this.options) {
89
+ throw "Toastify is not initialized";
90
+ }
91
+ let divElement = document.createElement("div");
92
+ divElement.className = `toastify on ${this.options.className}`;
93
+ divElement.className += ` toastify-${this.options.position}`;
94
+ divElement.className += ` ${this.options.gravity}`;
95
+ for (const property in this.options.style) {
96
+ divElement.style[property] = this.options.style[property];
97
+ }
98
+ if (this.options.ariaLive) {
99
+ divElement.setAttribute("aria-live", this.options.ariaLive);
100
+ }
101
+ if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) {
102
+ divElement.appendChild(this.options.node);
103
+ } else {
104
+ if (this.options.escapeMarkup) {
105
+ divElement.innerText = this.options.text;
106
+ } else {
107
+ divElement.innerHTML = this.options.text;
108
+ }
109
+ if (this.options.avatar !== "") {
110
+ let avatarElement = document.createElement("img");
111
+ avatarElement.src = this.options.avatar;
112
+ avatarElement.className = "toastify-avatar";
113
+ if (this.options.position == "left") {
114
+ divElement.appendChild(avatarElement);
115
+ } else {
116
+ divElement.insertAdjacentElement("afterbegin", avatarElement);
117
+ }
118
+ }
119
+ }
120
+ if (this.options.close === true) {
121
+ let closeElement = document.createElement("button");
122
+ closeElement.type = "button";
123
+ closeElement.setAttribute("aria-label", "Close");
124
+ closeElement.className = "toast-close";
125
+ closeElement.innerHTML = "✖";
126
+ closeElement.addEventListener("click", (event => {
127
+ event.stopPropagation();
128
+ this._removeElement(this.toastElement);
129
+ window.clearTimeout(this.toastElement.timeOutValue);
130
+ }));
131
+ const width = window.innerWidth > 0 ? window.innerWidth : screen.width;
132
+ if (this.options.position == "left" && width > 360) {
133
+ divElement.insertAdjacentElement("afterbegin", closeElement);
134
+ } else {
135
+ divElement.appendChild(closeElement);
136
+ }
137
+ }
138
+ if (this.options.stopOnFocus && this.options.duration > 0) {
139
+ divElement.addEventListener("mouseover", (event => {
140
+ window.clearTimeout(divElement.timeOutValue);
141
+ }));
142
+ divElement.addEventListener("mouseleave", (() => {
143
+ divElement.timeOutValue = window.setTimeout((() => {
144
+ this._removeElement(divElement);
145
+ }), this.options.duration);
146
+ }));
147
+ }
148
+ if (typeof this.options.destination !== "undefined") {
149
+ divElement.addEventListener("click", (event => {
150
+ event.stopPropagation();
151
+ if (this.options.newWindow === true) {
152
+ window.open(this.options.destination, "_blank");
153
+ } else {
154
+ window.location = this.options.destination;
155
+ }
156
+ }));
157
+ }
158
+ if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") {
159
+ divElement.addEventListener("click", (event => {
160
+ event.stopPropagation();
161
+ this.options.onClick();
162
+ }));
163
+ }
164
+ if (typeof this.options.offset === "object") {
165
+ const x = this._getAxisOffsetAValue("x", this.options);
166
+ const y = this._getAxisOffsetAValue("y", this.options);
167
+ const xOffset = this.options.position == "left" ? x : `-${x}`;
168
+ const yOffset = this.options.gravity == "toastify-top" ? y : `-${y}`;
169
+ divElement.style.transform = `translate(${xOffset},${yOffset})`;
170
+ }
171
+ return divElement;
172
+ }
173
+ _removeElement(toastElement) {
174
+ toastElement.className = toastElement.className.replace(" on", "");
175
+ window.setTimeout((() => {
176
+ if (this.options.node && this.options.node.parentNode) {
177
+ this.options.node.parentNode.removeChild(this.options.node);
178
+ }
179
+ if (toastElement.parentNode) {
180
+ toastElement.parentNode.removeChild(toastElement);
181
+ }
182
+ this.options.callback.call(toastElement);
183
+ this._reposition();
184
+ }), 400);
185
+ }
186
+ _reposition() {
187
+ let topLeftOffsetSize = {
188
+ top: 15,
189
+ bottom: 15
190
+ };
191
+ let topRightOffsetSize = {
192
+ top: 15,
193
+ bottom: 15
194
+ };
195
+ let offsetSize = {
196
+ top: 15,
197
+ bottom: 15
198
+ };
199
+ let allToasts = this._rootElement.querySelectorAll(".toastify");
200
+ let classUsed;
201
+ for (let i = 0; i < allToasts.length; i++) {
202
+ if (allToasts[i].classList.contains("toastify-top") === true) {
203
+ classUsed = "toastify-top";
204
+ } else {
205
+ classUsed = "toastify-bottom";
206
+ }
207
+ let height = allToasts[i].offsetHeight;
208
+ classUsed = classUsed.substr(9, classUsed.length - 1);
209
+ let offset = 15;
210
+ let width = window.innerWidth > 0 ? window.innerWidth : screen.width;
211
+ if (width <= 360) {
212
+ allToasts[i].style[classUsed] = `${offsetSize[classUsed]}px`;
213
+ offsetSize[classUsed] += height + offset;
214
+ } else {
215
+ if (allToasts[i].classList.contains("toastify-left") === true) {
216
+ allToasts[i].style[classUsed] = `${topLeftOffsetSize[classUsed]}px`;
217
+ topLeftOffsetSize[classUsed] += height + offset;
218
+ } else {
219
+ allToasts[i].style[classUsed] = `${topRightOffsetSize[classUsed]}px`;
220
+ topRightOffsetSize[classUsed] += height + offset;
221
+ }
222
+ }
223
+ }
224
+ }
225
+ _getAxisOffsetAValue(axis, options) {
226
+ if (options.offset[axis]) {
227
+ if (isNaN(options.offset[axis])) {
228
+ return options.offset[axis];
229
+ } else {
230
+ return `${options.offset[axis]}px`;
231
+ }
232
+ }
233
+ return "0px";
234
+ }
235
+ }
236
+ function StartToastifyInstance(options) {
237
+ return new Toastify(options);
238
+ }
239
+ CableReady.operations.stimulusReflexVersionMismatch = operation => {
240
+ const levels = {
241
+ info: {},
242
+ success: {
243
+ background: "#198754",
244
+ color: "white"
245
+ },
246
+ warn: {
247
+ background: "#ffc107",
248
+ color: "black"
249
+ },
250
+ error: {
251
+ background: "#dc3545",
252
+ color: "white"
253
+ }
254
+ };
255
+ const defaults = {
256
+ selector: setupToastify(),
257
+ close: true,
258
+ duration: 30 * 1e3,
259
+ gravity: "bottom",
260
+ position: "right",
261
+ newWindow: true,
262
+ style: levels[operation.level || "info"]
263
+ };
264
+ StartToastifyInstance({
265
+ ...defaults,
266
+ ...operation
267
+ }).showToast();
268
+ };
269
+ function setupToastify() {
270
+ const id = "stimulus-reflex-toast-element";
271
+ let element = document.querySelector(`#${id}`);
272
+ if (!element) {
273
+ element = document.createElement("div");
274
+ element.id = id;
275
+ document.documentElement.appendChild(element);
276
+ const styles = document.createElement("style");
277
+ styles.innerHTML = `\n #${id} .toastify {\n padding: 12px 20px;\n color: #ffffff;\n display: inline-block;\n background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);\n background: linear-gradient(135deg, #73a5ff, #5477f5);\n position: fixed;\n opacity: 0;\n transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);\n border-radius: 2px;\n cursor: pointer;\n text-decoration: none;\n max-width: calc(50% - 20px);\n z-index: 2147483647;\n bottom: -150px;\n right: 15px;\n }\n\n #${id} .toastify.on {\n opacity: 1;\n }\n\n #${id} .toast-close {\n background: transparent;\n border: 0;\n color: white;\n cursor: pointer;\n font-family: inherit;\n font-size: 1em;\n opacity: 0.4;\n padding: 0 5px;\n }\n `;
278
+ document.head.appendChild(styles);
279
+ }
280
+ return element;
281
+ }
6
282
  let deprecationWarnings = true;
7
283
  var Deprecate = {
8
284
  get enabled() {
@@ -149,6 +425,7 @@
149
425
  }
150
426
  return list;
151
427
  };
428
+ const reflexNameToControllerIdentifier = reflexName => reflexName.replace(/([a-z0–9])([A-Z])/g, "$1-$2").replace(/(::)/g, "--").replace(/-reflex$/gi, "").toLowerCase();
152
429
  const stages = [ "created", "before", "delivered", "queued", "after", "finalized", "success", "error", "halted", "forbidden" ];
153
430
  let lastReflex;
154
431
  const reflexes = new Proxy({}, {
@@ -585,7 +862,7 @@
585
862
  return attrs;
586
863
  };
587
864
  var name = "stimulus_reflex";
588
- var version = "3.5.0-pre10";
865
+ var version = "3.5.0-rc1";
589
866
  var description = "Build reactive applications with the Rails tooling you already know and love.";
590
867
  var keywords = [ "ruby", "rails", "websockets", "actioncable", "turbolinks", "reactive", "cable", "ujs", "ssr", "stimulus", "reflex", "stimulus_reflex", "dom", "morphdom" ];
591
868
  var homepage = "https://docs.stimulusreflex.com";
@@ -607,17 +884,18 @@
607
884
  "build:watch": "yarn rollup -wc",
608
885
  watch: "yarn build:watch",
609
886
  test: "web-test-runner javascript/test/**/*.test.js",
887
+ "test:watch": "yarn test --watch",
610
888
  "docs:dev": "vitepress dev docs",
611
- "docs:build": "vitepress build docs",
889
+ "docs:build": "vitepress build docs && cp docs/_redirects docs/.vitepress/dist",
612
890
  "docs:preview": "vitepress preview docs"
613
891
  };
614
892
  var peerDependencies = {
615
893
  "@hotwired/stimulus": ">= 3.0"
616
894
  };
617
895
  var dependencies = {
618
- "@hotwired/stimulus": ">= 3.0, < 4",
619
- "@rails/actioncable": ">= 6.0, < 8",
620
- cable_ready: "5.0.0-pre10"
896
+ "@hotwired/stimulus": "^3",
897
+ "@rails/actioncable": "^6 || ^7",
898
+ cable_ready: "5.0.0-rc1"
621
899
  };
622
900
  var devDependencies = {
623
901
  "@open-wc/testing": "^3.1.7",
@@ -626,10 +904,11 @@
626
904
  "@rollup/plugin-terser": "^0.4.0",
627
905
  "@web/dev-server-esbuild": "^0.3.3",
628
906
  "@web/dev-server-rollup": "^0.3.21",
629
- "@web/test-runner": "^0.15.0",
907
+ "@web/test-runner": "^0.15.1",
630
908
  "prettier-standard": "^16.4.1",
631
- rollup: "^3.17.1",
632
- vitepress: "^1.0.0-alpha.47"
909
+ rollup: "^3.19.1",
910
+ "toastify-js": "^1.12.0",
911
+ vitepress: "^1.0.0-alpha.56"
633
912
  };
634
913
  var packageInfo = {
635
914
  name: name,
@@ -847,11 +1126,11 @@
847
1126
  toString: () => reflex.error
848
1127
  })));
849
1128
  };
850
- const localReflexControllers = element => attributeValues(element.getAttribute(Schema.controller)).reduce(((memo, name) => {
851
- const controller = App.app.getControllerForElementAndIdentifier(element, name);
852
- if (controller && controller.StimulusReflex) memo.push(controller);
853
- return memo;
854
- }), []);
1129
+ const localReflexControllers = element => {
1130
+ const potentialIdentifiers = attributeValues(element.getAttribute(Schema.controller));
1131
+ const potentialControllers = potentialIdentifiers.map((identifier => App.app.getControllerForElementAndIdentifier(element, identifier)));
1132
+ return potentialControllers.filter((controller => controller && controller.StimulusReflex));
1133
+ };
855
1134
  const allReflexControllers = element => {
856
1135
  let controllers = [];
857
1136
  while (element) {
@@ -862,8 +1141,9 @@
862
1141
  };
863
1142
  const findControllerByReflexName = (reflexName, controllers) => {
864
1143
  const controller = controllers.find((controller => {
865
- if (!controller.identifier) return;
866
- return extractReflexName(reflexName).replace(/([a-z0–9])([A-Z])/g, "$1-$2").replace(/(::)/g, "--").toLowerCase() === controller.identifier;
1144
+ if (!controller || !controller.identifier) return;
1145
+ const identifier = reflexNameToControllerIdentifier(extractReflexName(reflexName));
1146
+ return identifier === controller.identifier;
867
1147
  }));
868
1148
  return controller || controllers[0];
869
1149
  };
@@ -871,18 +1151,22 @@
871
1151
  const reflexElements = document.querySelectorAll(`[${Schema.reflex}]`);
872
1152
  reflexElements.forEach((element => scanForReflexesOnElement(element)));
873
1153
  }), 20);
874
- const scanForReflexesOnElement = element => {
1154
+ const scanForReflexesOnElement = (element, controller = null) => {
875
1155
  const controllerAttribute = element.getAttribute(Schema.controller);
876
- const controllers = attributeValues(controllerAttribute);
1156
+ const controllers = attributeValues(controllerAttribute).filter((controller => controller !== "stimulus-reflex"));
877
1157
  const reflexAttribute = element.getAttribute(Schema.reflex);
878
1158
  const reflexAttributeNames = attributeValues(reflexAttribute);
879
1159
  const actionAttribute = element.getAttribute(Schema.action);
880
1160
  const actions = attributeValues(actionAttribute).filter((action => !action.includes("#__perform")));
881
1161
  reflexAttributeNames.forEach((reflexName => {
882
- const controller = findControllerByReflexName(reflexName, allReflexControllers(element));
1162
+ const potentialControllers = [ controller ].concat(allReflexControllers(element));
1163
+ controller = findControllerByReflexName(reflexName, potentialControllers);
883
1164
  const controllerName = controller ? controller.identifier : "stimulus-reflex";
884
1165
  actions.push(`${reflexName.split("->")[0]}->${controllerName}#__perform`);
885
- controllers.push(controllerName);
1166
+ const parentControllerElement = element.closest(`[data-controller~=${controllerName}]`);
1167
+ if (!parentControllerElement) {
1168
+ controllers.push(controllerName);
1169
+ }
886
1170
  }));
887
1171
  const controllerValue = attributeValue(controllers);
888
1172
  const actionValue = attributeValue(actions);
@@ -1005,7 +1289,7 @@
1005
1289
  });
1006
1290
  }
1007
1291
  });
1008
- scanForReflexesOnElement(controller.element);
1292
+ scanForReflexesOnElement(controller.element, controller);
1009
1293
  emitEvent("stimulus-reflex:controller-registered", {
1010
1294
  detail: {
1011
1295
  controller: controller
@@ -27,24 +27,7 @@ class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.cons
27
27
  reflex.logger&.error error_message
28
28
  reflex.broadcast_error data: data, error: "#{exception} #{exception.backtrace.first.split(":in ")[0] if Rails.env.development?}"
29
29
  else
30
- if exception.is_a? StimulusReflex::Reflex::VersionMismatchError
31
- mismatch = "Reflex failed due to stimulus_reflex gem/NPM package version mismatch. Package versions must match exactly.\nNote that if you are using pre-release builds, gems use the \"x.y.z.preN\" version format, while NPM packages use \"x.y.z-preN\".\n\nstimulus_reflex gem: #{StimulusReflex::VERSION}\nstimulus_reflex NPM: #{data["version"]}"
32
-
33
- StimulusReflex.config.logger.error("\n\e[31m#{mismatch}\e[0m") unless StimulusReflex.config.on_failed_sanity_checks == :ignore
34
-
35
- if Rails.env.development?
36
- CableReady::Channels.instance[stream_name].console_log(
37
- message: mismatch,
38
- level: "error",
39
- id: data["id"]
40
- ).broadcast
41
- end
42
-
43
- if StimulusReflex.config.on_failed_sanity_checks == :exit
44
- sleep 0.1
45
- exit!
46
- end
47
- else
30
+ unless exception.is_a?(StimulusReflex::Reflex::VersionMismatchError)
48
31
  StimulusReflex.config.logger.error error_message
49
32
  end
50
33
 
@@ -34,20 +34,20 @@ class StimulusReflexGenerator < Rails::Generators::NamedBase
34
34
  end
35
35
 
36
36
  reflex_entrypoint = Rails.env.test? ? "tmp/app/reflexes" : "app/reflexes"
37
- reflex_src = fetch("/app/reflexes/%file_name%_reflex.rb.tt")
37
+ reflex_src = "app/reflexes/%file_name%_reflex.rb.tt"
38
38
  reflex_path = Rails.root.join(reflex_entrypoint, "#{file_name}_reflex.rb")
39
- stimulus_controller_src = fetch("/app/javascript/controllers/%file_name%_controller.js.tt")
39
+ stimulus_controller_src = "app/javascript/controllers/%file_name%_controller.js.tt"
40
40
  stimulus_controller_path = Rails.root.join(entrypoint, "controllers/#{file_name}_controller.js")
41
41
 
42
42
  template(reflex_src, reflex_path) unless options[:skip_reflex]
43
43
  template(stimulus_controller_src, stimulus_controller_path) unless options[:skip_stimulus]
44
44
 
45
45
  if file_name == "example"
46
- controller_src = fetch("/app/controllers/examples_controller.rb.tt")
46
+ controller_src = "app/controllers/examples_controller.rb.tt"
47
47
  controller_path = Rails.root.join("app/controllers/examples_controller.rb")
48
48
  template(controller_src, controller_path)
49
49
 
50
- view_src = fetch("/app/views/examples/show.html.erb.tt")
50
+ view_src = "app/views/examples/show.html.erb.tt"
51
51
  view_path = Rails.root.join("app/views/examples/show.html.erb")
52
52
  template(view_src, view_path)
53
53
 
@@ -83,10 +83,4 @@ class StimulusReflexGenerator < Rails::Generators::NamedBase
83
83
  end
84
84
  end
85
85
  end
86
-
87
- private
88
-
89
- def fetch(file)
90
- source_paths.first + file
91
- end
92
86
  end
@@ -66,7 +66,7 @@ class <%= class_name %>Reflex < ApplicationReflex
66
66
  <%- actions.each do |action| -%>
67
67
  def <%= action %>
68
68
  end
69
- <%= "\n" unless action == actions.last -%>
69
+ <%= "\n" unless action == actions.last -%>
70
70
  <%- end -%>
71
71
  <%- end -%>
72
72
  end
@@ -8,7 +8,7 @@ class ApplicationReflex < StimulusReflex::Reflex
8
8
  # If your ActionCable connection is: `identified_by :current_user`
9
9
  # delegate :current_user, to: :connection
10
10
  #
11
- # current_user delegation alloqs you to use the Current pattern, too:
11
+ # current_user delegation allows you to use the Current pattern, too:
12
12
  # before_reflex do
13
13
  # Current.user = current_user
14
14
  # end
@@ -19,4 +19,9 @@ CableReady.configure do |config|
19
19
  # Change the default Active Job queue used for broadcast_later and broadcast_later_to
20
20
  #
21
21
  # config.broadcast_job_queue = :default
22
+
23
+ # Specify a default debounce time for CableReady::Updatable callbacks
24
+ # Doing so is a best practice to avoid heavy ActionCable traffic
25
+ #
26
+ # config.updatable_debounce_time = 0.1.seconds
22
27
  end
@@ -36,13 +36,13 @@ lines = development_working_path.readlines
36
36
 
37
37
  if (index = lines.index { |line| line =~ /^[^#]*config.session_store/ })
38
38
  if /^[^#]*cookie_store/.match?(lines[index])
39
- write_redis_recommendation(development_working_path, lines, index, gemfile_path)
39
+ write_redis_recommendation(development_working_path, lines, index, gemfile)
40
40
  halt "StimulusReflex does not support session cookies. See https://docs.stimulusreflex.com/hello-world/setup#session-storage"
41
41
  return
42
42
  elsif /^[^#]*redis_session_store/.match?(lines[index])
43
43
  say "⏩ Already using redis-session-store for session storage. Skipping."
44
44
  else
45
- write_redis_recommendation(development_working_path, lines, index, gemfile_path)
45
+ write_redis_recommendation(development_working_path, lines, index, gemfile)
46
46
  say "🤷 We recommend using redis-session-store for session storage. See https://docs.stimulusreflex.com/hello-world/setup#session-storage"
47
47
  end
48
48
  # no session store defined, so let's opt-in to redis-session-store
@@ -50,7 +50,7 @@ backup(importmap_path) do
50
50
 
51
51
  if !importmap.include?("pin \"@hotwired/stimulus\"")
52
52
  append_file(importmap_path, <<~RUBY, verbose: false)
53
- pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
53
+ pin "@hotwired/stimulus", to: "stimulus.js", preload: true
54
54
  RUBY
55
55
  say "✅ pin @hotwired/stimulus"
56
56
  else
@@ -68,7 +68,7 @@ backup(importmap_path) do
68
68
 
69
69
  if !importmap.include?("pin \"cable_ready\"")
70
70
  append_file(importmap_path, <<~RUBY, verbose: false)
71
- pin "cable_ready", to: "cable_ready.min.js", preload: true
71
+ pin "cable_ready", to: "cable_ready.js", preload: true
72
72
  RUBY
73
73
  say "✅ pin cable_ready"
74
74
  else
@@ -77,7 +77,7 @@ backup(importmap_path) do
77
77
 
78
78
  if !importmap.include?("pin \"stimulus_reflex\"")
79
79
  append_file(importmap_path, <<~RUBY, verbose: false)
80
- pin "stimulus_reflex", to: "stimulus_reflex.min.js", preload: true
80
+ pin "stimulus_reflex", to: "stimulus_reflex.js", preload: true
81
81
  RUBY
82
82
  say "✅ pin stimulus_reflex"
83
83
  else
@@ -7,6 +7,7 @@ module StimulusReflex
7
7
  def initialize(reflex)
8
8
  @stream_name = reflex.stream_name
9
9
  @id = reflex.id
10
+ CableReady.config.add_operation_name(:stimulus_reflex_version_mismatch)
10
11
  end
11
12
 
12
13
  def cable_ready_channels
@@ -17,11 +17,7 @@ module StimulusReflex
17
17
  #
18
18
  PRECOMPILE_ASSETS = %w[
19
19
  stimulus_reflex.js
20
- stimulus_reflex.min.js
21
- stimulus_reflex.min.js.map
22
20
  stimulus_reflex.umd.js
23
- stimulus_reflex.umd.min.js
24
- stimulus_reflex.umd.min.js.map
25
21
  ]
26
22
 
27
23
  initializer "stimulus_reflex.assets" do |app|
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  pin "@rails/actioncable", to: "actioncable.esm.js", preload: true
4
- pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
4
+ pin "@hotwired/stimulus", to: "stimulus.js", preload: true
5
5
  pin "morphdom", to: "https://ga.jspm.io/npm:morphdom@2.6.1/dist/morphdom.js", preload: true
6
- pin "cable_ready", to: "cable_ready.min.js", preload: true
7
- pin "stimulus_reflex", to: "stimulus_reflex.min.js", preload: true
6
+ pin "cable_ready", to: "cable_ready.js", preload: true
7
+ pin "stimulus_reflex", to: "stimulus_reflex.js", preload: true
@@ -1,16 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "stimulus_reflex/cable_readiness"
4
+ require "stimulus_reflex/version_checker"
4
5
 
5
6
  # TODO remove xpath_controller and xpath_element for v4
6
- ClientAttributes = Struct.new(:id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, :version, :suppress_logging, keyword_init: true)
7
+ ClientAttributes = Struct.new(
8
+ :id,
9
+ :tab_id,
10
+ :reflex_controller,
11
+ :xpath_controller,
12
+ :xpath_element,
13
+ :permanent_attribute_name,
14
+ :version,
15
+ :npm_version,
16
+ :suppress_logging,
17
+ keyword_init: true
18
+ )
7
19
 
8
20
  class StimulusReflex::Reflex
9
- class VersionMismatchError < StandardError; end
10
-
11
21
  prepend StimulusReflex::CableReadiness
12
- include ActiveSupport::Rescuable
22
+ include StimulusReflex::VersionChecker
13
23
  include StimulusReflex::Callbacks
24
+ include ActiveSupport::Rescuable
14
25
  include ActionView::Helpers::TagHelper
15
26
  include CableReady::Identifiable
16
27
 
@@ -23,7 +34,7 @@ class StimulusReflex::Reflex
23
34
  delegate :controller_class, :flash, :session, to: :request
24
35
  delegate :broadcast, :broadcast_halt, :broadcast_forbid, :broadcast_error, to: :broadcaster
25
36
  # TODO remove xpath_controller and xpath_element for v4
26
- delegate :id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, :version, :suppress_logging, to: :client_attributes
37
+ delegate :id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, :version, :npm_version, :suppress_logging, to: :client_attributes
27
38
 
28
39
  def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, params: {}, client_attributes: {})
29
40
  @channel = channel
@@ -38,9 +49,7 @@ class StimulusReflex::Reflex
38
49
  @payload = {}
39
50
  @headers = {}
40
51
 
41
- if version != StimulusReflex::VERSION && StimulusReflex.config.on_failed_sanity_checks != :ignore
42
- raise VersionMismatchError.new("stimulus_reflex gem / NPM package version mismatch")
43
- end
52
+ check_version!
44
53
 
45
54
  self.params
46
55
  end
@@ -52,7 +52,7 @@ class StimulusReflex::ReflexData
52
52
  end
53
53
 
54
54
  def params
55
- form_params.merge(url_params)
55
+ form_params.deep_merge(url_params)
56
56
  end
57
57
 
58
58
  def form_params
@@ -85,6 +85,10 @@ class StimulusReflex::ReflexData
85
85
  data["reflexController"]
86
86
  end
87
87
 
88
+ def npm_version
89
+ data["version"].to_s
90
+ end
91
+
88
92
  def version
89
93
  data["version"].to_s.gsub("-pre", ".pre")
90
94
  end
@@ -20,7 +20,8 @@ class StimulusReflex::ReflexFactory
20
20
  reflex_controller: reflex_data.reflex_controller,
21
21
  permanent_attribute_name: reflex_data.permanent_attribute_name,
22
22
  suppress_logging: reflex_data.suppress_logging,
23
- version: reflex_data.version
23
+ version: reflex_data.version,
24
+ npm_version: reflex_data.npm_version
24
25
  })
25
26
  end
26
27
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "3.5.0.pre10"
4
+ VERSION = "3.5.0.rc1"
5
5
  end