stimulus_reflex 3.5.0.pre10 → 3.5.0.rc1

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.
@@ -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