turbo_ready 0.0.5 → 0.0.6

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.
data/README.md.orig ADDED
@@ -0,0 +1,292 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://ik.imagekit.io/hopsoft/turbo-ready-logo-light_df4jcvbDL.webp?ik-sdk-version=javascript-1.4.3&updatedAt=1661615678275">
4
+ <img height="200" src="https://ik.imagekit.io/hopsoft/turbo-ready-logo-dark_VN4hA2ctc.webp?ik-sdk-version=javascript-1.4.3&updatedAt=1661615678278" />
5
+ </picture>
6
+ <h3 align="center">
7
+ Turbo Stream's Swiss Army Knife
8
+ </h3>
9
+ <h1 align="center">
10
+ Welcome to TurboReady 👋
11
+ </h1>
12
+ <p align="center">
13
+ <a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/" target="_blank">
14
+ <img alt="Lines of Code" src="https://img.shields.io/badge/loc-278-47d299.svg" />
15
+ <<<<<<< HEAD
16
+ </a>
17
+ <a href="https://codeclimate.com/github/hopsoft/turbo_ready/maintainability" target="_blank">
18
+ <img src="https://api.codeclimate.com/v1/badges/a69b6f73abc3ccd49261/maintainability" />
19
+ </a>
20
+ <a href="https://rubygems.org/gems/turbo_ready" target="_blank">
21
+ <img alt="GEM" src="https://img.shields.io/gem/v/turbo_ready?color=168AFE&include_prereleases&logo=ruby&logoColor=FE1616">
22
+ </a>
23
+ <a href="https://www.npmjs.com/package/turbo_ready" target="_blank">
24
+ <img alt="NPM" src="https://img.shields.io/npm/v/turbo_ready?color=168AFE&logo=npm">
25
+ =======
26
+ </a>
27
+ <a href="https://codeclimate.com/github/hopsoft/turbo_ready/maintainability">
28
+ <img src="https://api.codeclimate.com/v1/badges/a69b6f73abc3ccd49261/maintainability" />
29
+ </a>
30
+
31
+ <a href="https://rubygems.org/gems/turbo_ready" target="_blank">
32
+ <img alt="Gem (including prereleases)" src="https://img.shields.io/gem/v/turbo_ready?color=168AFE&include_prereleases&logo=ruby&logoColor=FE1616">
33
+ </a>
34
+ <a href="https://github.com/testdouble/standard" target="_blank">
35
+ <img alt="Ruby Style" src="https://img.shields.io/badge/style-standard-999?logo=ruby&logoColor=FE1616" />
36
+ </a>
37
+
38
+ <br>
39
+
40
+ <a href="https://www.npmjs.com/package/turbo_ready" target="_blank">
41
+ <img alt="npm" src="https://img.shields.io/npm/v/turbo_ready?color=168AFE&logo=npm">
42
+ >>>>>>> 2ca627a (Badge updates)
43
+ </a>
44
+ <a href="https://bundlephobia.com/package/turbo_ready@" target="_blank">
45
+ <img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/turbo_ready?label=bundle%20size&logo=javascript&color=47d299">
46
+ </a>
47
+ <<<<<<< HEAD
48
+ <a href="https://github.com/testdouble/standard" target="_blank">
49
+ <img alt="Ruby Style" src="https://img.shields.io/badge/style-standard-168AFE?logo=ruby&logoColor=FE1616" />
50
+ </a>
51
+ <a href="https://github.com/sheerun/prettier-standard" target="_blank">
52
+ <img alt="JavaScript Style" src="https://img.shields.io/badge/style-prettier--standard-168AFE?logo=javascript&logoColor=f4e137" />
53
+ =======
54
+ <a href="https://github.com/sheerun/prettier-standard" target="_blank">
55
+ <img alt="JavaScript Style" src="https://img.shields.io/badge/style-prettier--standard-999?logo=javascript&logoColor=f4e137" />
56
+ >>>>>>> 2ca627a (Badge updates)
57
+ </a>
58
+ </p>
59
+ </p>
60
+
61
+ TurboReady extends [Turbo Streams](https://turbo.hotwired.dev/reference/streams) to give you full control of the
62
+ browser's [Document Object Model (DOM).](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)
63
+
64
+ **Thats right!**
65
+ You can `invoke` any DOM method on any DOM object *(including 3rd party libs)* using Turbo Streams.
66
+
67
+ ```ruby
68
+ turbo_stream.invoke "console.log", "Hello World!"
69
+ ```
70
+
71
+ <!-- Tocer[start]: Auto-generated, don't remove. -->
72
+
73
+ ## Table of Contents
74
+
75
+ - [Why TurboReady?](#why-turboready)
76
+ - [Community](#community)
77
+ - [Sponsors](#sponsors)
78
+ - [Dependencies](#dependencies)
79
+ - [Installation](#installation)
80
+ - [Setup](#setup)
81
+ - [Usage](#usage)
82
+ - [Advanced Usage](#advanced-usage)
83
+ - [What Else Can I Do?](#what-else-can-i-do)
84
+ - [Extending Behavior](#extending-behavior)
85
+ - [Public API](#public-api)
86
+ - [A Word of Caution](#a-word-of-caution)
87
+ - [Releasing](#releasing)
88
+ - [License](#license)
89
+
90
+ <!-- Tocer[finish]: Auto-generated, don't remove. -->
91
+
92
+ ## Why TurboReady?
93
+
94
+ Turbo Streams [intentionally restricts](https://turbo.hotwired.dev/handbook/streams#but-what-about-running-javascript%3F)
95
+ official actions to CRUD related activity.
96
+ The [official actions](https://turbo.hotwired.dev/reference/streams#the-seven-actions) work well for a
97
+ considerable number of use cases and you should push Streams as far as possible before reaching for TurboReady.
98
+
99
+ If you discover that CRUD isn't enough, TurboReady covers pretty much everything else.
100
+
101
+ ## Community
102
+
103
+ Please join nearly 2000 of us on [Discord](https://discord.gg/stimulus-reflex) for support getting started,
104
+ as well as active discussions around Rails, Hotwire, Stimulus, Turbo (Drive, Frames, Streams), TurboReady, CableReady, StimulusReflex, ViewComponent, Phlex, and more.
105
+
106
+ ![](https://img.shields.io/discord/629472241427415060)
107
+
108
+ Stop by #newcomers and introduce yourselves!
109
+
110
+ ## Sponsors
111
+
112
+ <p align="center">
113
+ <em>Proudly sponsored by</em>
114
+ </p>
115
+ <p align="center">
116
+ <a href="https://www.clickfunnels.com?utm_source=hopsoft&utm_medium=open-source&utm_campaign=turbo_ready">
117
+ <img src="https://images.clickfunnel.com/uploads/digital_asset/file/176632/clickfunnels-dark-logo.svg" width="575" />
118
+ </a>
119
+ </p>
120
+
121
+ ## Dependencies
122
+
123
+ - [rails](https://rubygems.org/gems/rails) `>=6.1`
124
+ - [turbo-rails](https://rubygems.org/gems/turbo-rails) `>=1.1`
125
+ - [@hotwired/turbo-rails](https://yarnpkg.com/package/@hotwired/turbo-rails) `>=7.2.0-beta.2`
126
+
127
+ ## Installation
128
+
129
+ ```sh
130
+ bundle add "turbo_ready --version VERSION"
131
+ yarn add "turbo_ready@VERSION --exact"
132
+ ```
133
+
134
+ **IMPORTANT:** Be sure to use the same version for each libary.
135
+
136
+ ## Setup
137
+
138
+ 1. Import and intialize TurboReady in your application.
139
+
140
+ ```diff
141
+ # Gemfile
142
+ +gem "turbo_ready", "~> 0.0.5"
143
+ ```
144
+
145
+ ```diff
146
+ # package.json
147
+ "dependencies": {
148
+ + "@hotwired/turbo-rails": ">=7.2.0-beta.2",
149
+ + "turbo_ready": "^0.0.5"
150
+ ```
151
+
152
+ ```diff
153
+ # app/javascript/application.js
154
+ import '@hotwired/turbo-rails'
155
+ +import TurboReady from 'turbo_ready'
156
+
157
+ +TurboReady.initialize(Turbo.StreamActions) // Adds TurboReady stream actions to Turbo
158
+ ```
159
+
160
+ ## Usage
161
+
162
+ Manipulate the DOM from anywhere you use [official Turbo Streams](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks).
163
+ Namely, [**M**odels](https://guides.rubyonrails.org/active_model_basics.html),
164
+ [**V**iews](https://guides.rubyonrails.org/action_view_overview.html),
165
+ [**C**ontrollers](https://guides.rubyonrails.org/action_controller_overview.html)
166
+ and [Jobs](https://guides.rubyonrails.org/active_job_basics.html).
167
+
168
+ You can **chain invocations.** ❤️
169
+
170
+ ```ruby
171
+ turbo_stream
172
+ .invoke("document.body.insertAdjacentHTML", "afterbegin", "<h1>Hello World!</h1>") # dot notation
173
+ .invoke("setAttribute", "data-turbo-ready", true, selector: ".button") # selector
174
+ .invoke("classList.add", "turbo-ready", selector: "a") # dot notation + selector
175
+ .flush # flush must be called when chaining invocations
176
+ ```
177
+
178
+ You can use [dot notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#dot_notation)
179
+ or [selectors](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)... **and can even combine them!** 🤯
180
+
181
+ Can I dispatch events? **You bet!** ⚡️
182
+
183
+ ```ruby
184
+ turbo_stream
185
+ .invoke("dispatchEvent", "turbo-ready:demo") # fires on window
186
+ .invoke("document.dispatchEvent", "turbo-ready:demo") # fires on document
187
+ .invoke("dispatchEvent", "turbo-ready:demo", selector: "#my-element") # fires on matching element(s)
188
+ .invoke("dispatchEvent", {bubbles: true, detail: {...}}) # set event options
189
+ .flush
190
+ ```
191
+
192
+ ## Advanced Usage
193
+
194
+ You can use symbols and [snake case](https://en.wikipedia.org/wiki/Snake_case) when invoking DOM functionality.
195
+ It'll implicitly convert to [camel case](https://en.wikipedia.org/wiki/Camel_case). 💎
196
+
197
+ ```ruby
198
+ turbo_stream
199
+ .invoke(:animate, [{opacity: 0}, {opacity: 1}], 2000, selector: "#example")
200
+ .invoke(:dispatch_event, {detail: {converts_to_camel_case: true}}, selector: "#example")
201
+ .flush
202
+ ```
203
+
204
+ Need to opt out of camelize? No problem... just disable it.
205
+
206
+ ```ruby
207
+ turbo_stream.invoke :contrived_demo, camelize: false
208
+ ```
209
+
210
+ ## What Else Can I Do?
211
+
212
+ **The possibilities are endless**
213
+ and MDN has your back... [learn about the DOM and web APIs here.](https://developer.mozilla.org/en-US/docs/Web/API.)
214
+
215
+ ### Extending Behavior
216
+
217
+ Want to extend things with custom functionality? **Let's do it.** 🔌
218
+
219
+ ```js
220
+ // JavaScript
221
+ import morphdom from 'morphdom'
222
+
223
+ window.MyNamespace = {
224
+ morph: (from, to, options = {}) => {
225
+ morphdom(document.querySelector(from), to, options)
226
+ }
227
+ }
228
+ ```
229
+
230
+ ```ruby
231
+ # Ruby
232
+ turbo_stream
233
+ .invoke "MyNamespace.morph", "#demo", "<div id='demo'><p>You've changed...</p></div>", {childrenOnly: true}
234
+ ```
235
+
236
+ ## Public API
237
+
238
+ There's only one method to consider, `invoke` defined in the
239
+ [tag builder](https://github.com/hopsoft/turbo_ready/blob/main/lib/turbo_ready/tag_builder.rb).
240
+
241
+ ```ruby
242
+ # Ruby
243
+ turbo_stream
244
+ .invoke(method, *args, selector: nil, camelize: true, id: nil)
245
+ # | | | | |
246
+ # | | | | |- Identifies this invocation (optional)
247
+ # | | | |
248
+ # | | | |- Should we camelize the JavaScript stuff? (optional)
249
+ # | | | (allows us to write snake_case Ruby)
250
+ # | | |
251
+ # | | |- An CSS selector for the element(s) to target (optional)
252
+ # | |
253
+ # | |- The arguments to pass to the JavaScript method being invoked (optional)
254
+ # |
255
+ # |- The JavaScript method to invoke (can use dot notation)
256
+ ```
257
+
258
+ **NOTE:** The JavaScript method will be invoked on all matching elements when a `selector` is passed.
259
+
260
+ ## A Word of Caution
261
+
262
+ Manually orchestrating DOM activity gets tedious fast.
263
+ **⚠️ Don't abuse this superpower!**
264
+
265
+ > With great power comes great responsibility. *-Uncle Ben*
266
+
267
+ This library is an extremely sharp tool. 🔪
268
+ Consider it a low-level building block that can be used to craft additional libraries with
269
+ great [DX](https://en.wikipedia.org/wiki/User_experience#Developer_experience)
270
+ like [CableReady](https://github.com/stimulusreflex/cable_ready)
271
+ and [StimulusReflex](https://github.com/stimulusreflex/stimulus_reflex).
272
+
273
+ Restrict your direct application usage to DOM manipulation that falls outside the purview of
274
+ [Turbo's official actions](https://turbo.hotwired.dev/reference/streams#the-seven-actions)...
275
+ *don't overdo it and find yourself maintaining spaghetti code reminiscent of the jQuery days.*
276
+
277
+ ## Releasing
278
+
279
+ 1. Run `yarn` and `bundle` to pick up the latest
280
+ 1. Bump version number at `lib/turbo_ready/version.rb`. Pre-release versions use `.preN`
281
+ 1. Run `rake build` and `yarn build`
282
+ 1. Run `bin/standardize`
283
+ 1. Commit and push changes to GitHub
284
+ 1. Run `rake release`
285
+ 1. Run `yarn publish --no-git-tag-version`
286
+ 1. Yarn will prompt you for the new version. Pre-release versions use `-preN`
287
+ 1. Commit and push changes to GitHub
288
+ 1. Create a new release on GitHub ([here](https://github.com/hopsoft/turbo_ready/releases)) and generate the changelog for the stable release for it
289
+
290
+ ## License
291
+
292
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,5 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/setup"
4
-
5
4
  require "bundler/gem_tasks"
5
+ require "rake/testtask"
6
+
7
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
8
+ load "rails/tasks/engine.rake"
9
+ load "rails/tasks/statistics.rake"
10
+
11
+ Rake::TestTask.new do |test|
12
+ test.libs << "test"
13
+ test.test_files = FileList["test/**/*_test.rb"]
14
+ test.warning = false
15
+ end
16
+
17
+ task default: :test
@@ -1,2 +1,2 @@
1
- function l(){let n=JSON.parse(this.templateContent.textContent),{id:h,method:c,args:i,receiver:a,selector:r}=n,t=[self];switch(r&&(t=Array.from(document.querySelectorAll(r))),a&&(t=t.map(o=>{let e=o,s=a.split(".");for(;s.length>0;)e=e[s.shift()];return e})),c){case"dispatchEvent":let o=new CustomEvent(i[0],i[1]||{});t.forEach(e=>e.dispatchEvent(o));break;default:t.forEach(e=>e[c].apply(e,i))}}function f(n){n.invoke=l}var p={initialize:f};export{p as default};
1
+ function l(){let n=JSON.parse(this.templateContent.textContent),{id:h,selector:c,receiver:a,method:r,args:i}=n,t=[self];switch(c&&(t=Array.from(document.querySelectorAll(c))),a&&(t=t.map(o=>{let e=o,s=a.split(".");for(;s.length>0;)e=e[s.shift()];return e})),r){case"dispatchEvent":let o=new CustomEvent(i[0],i[1]||{});t.forEach(e=>e.dispatchEvent(o));break;default:t.forEach(e=>e[r].apply(e,i))}}function f(n){n.invoke=l}var p={initialize:f};export{p as default};
2
2
  //# sourceMappingURL=turbo_ready.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../javascript/turbo_ready.js"],
4
- "sourcesContent": ["function invoke () {\n const payload = JSON.parse(this.templateContent.textContent)\n const { id, method, args, receiver, selector } = payload\n let receivers = [self]\n if (selector) receivers = Array.from(document.querySelectorAll(selector))\n\n if (receiver) {\n receivers = receivers.map(r => {\n let context = r\n const chain = receiver.split('.')\n while (chain.length > 0) context = context[chain.shift()]\n return context\n })\n }\n\n switch (method) {\n case 'dispatchEvent':\n const evt = new CustomEvent(args[0], args[1] || {})\n receivers.forEach(r => r.dispatchEvent(evt))\n break\n default:\n receivers.forEach(r => r[method].apply(r, args))\n }\n}\n\nfunction initialize (streamActions) {\n streamActions.invoke = invoke\n}\n\nexport default { initialize }\n"],
5
- "mappings": "AAAA,SAASA,GAAU,CACjB,IAAMC,EAAU,KAAK,MAAM,KAAK,gBAAgB,WAAW,EACrD,CAAE,GAAAC,EAAI,OAAAC,EAAQ,KAAAC,EAAM,SAAAC,EAAU,SAAAC,CAAS,EAAIL,EAC7CM,EAAY,CAAC,IAAI,EAYrB,OAXID,IAAUC,EAAY,MAAM,KAAK,SAAS,iBAAiBD,CAAQ,CAAC,GAEpED,IACFE,EAAYA,EAAU,IAAIC,GAAK,CAC7B,IAAIC,EAAUD,EACRE,EAAQL,EAAS,MAAM,GAAG,EAChC,KAAOK,EAAM,OAAS,GAAGD,EAAUA,EAAQC,EAAM,MAAM,GACvD,OAAOD,CACT,CAAC,GAGKN,OACD,gBACH,IAAMQ,EAAM,IAAI,YAAYP,EAAK,GAAIA,EAAK,IAAM,CAAC,CAAC,EAClDG,EAAU,QAAQC,GAAKA,EAAE,cAAcG,CAAG,CAAC,EAC3C,cAEAJ,EAAU,QAAQC,GAAKA,EAAEL,GAAQ,MAAMK,EAAGJ,CAAI,CAAC,EAErD,CAEA,SAASQ,EAAYC,EAAe,CAClCA,EAAc,OAASb,CACzB,CAEA,IAAOc,EAAQ,CAAE,WAAAF,CAAW",
6
- "names": ["invoke", "payload", "id", "method", "args", "receiver", "selector", "receivers", "r", "context", "chain", "evt", "initialize", "streamActions", "turbo_ready_default"]
4
+ "sourcesContent": ["function invoke () {\n const payload = JSON.parse(this.templateContent.textContent)\n const { id, selector, receiver, method, args } = payload\n let receivers = [self]\n if (selector) receivers = Array.from(document.querySelectorAll(selector))\n\n if (receiver) {\n receivers = receivers.map(r => {\n let context = r\n const chain = receiver.split('.')\n while (chain.length > 0) context = context[chain.shift()]\n return context\n })\n }\n\n switch (method) {\n case 'dispatchEvent':\n const evt = new CustomEvent(args[0], args[1] || {})\n receivers.forEach(r => r.dispatchEvent(evt))\n break\n default:\n receivers.forEach(r => r[method].apply(r, args))\n }\n}\n\nfunction initialize (streamActions) {\n streamActions.invoke = invoke\n}\n\nexport default { initialize }\n"],
5
+ "mappings": "AAAA,SAASA,GAAU,CACjB,IAAMC,EAAU,KAAK,MAAM,KAAK,gBAAgB,WAAW,EACrD,CAAE,GAAAC,EAAI,SAAAC,EAAU,SAAAC,EAAU,OAAAC,EAAQ,KAAAC,CAAK,EAAIL,EAC7CM,EAAY,CAAC,IAAI,EAYrB,OAXIJ,IAAUI,EAAY,MAAM,KAAK,SAAS,iBAAiBJ,CAAQ,CAAC,GAEpEC,IACFG,EAAYA,EAAU,IAAIC,GAAK,CAC7B,IAAIC,EAAUD,EACRE,EAAQN,EAAS,MAAM,GAAG,EAChC,KAAOM,EAAM,OAAS,GAAGD,EAAUA,EAAQC,EAAM,MAAM,GACvD,OAAOD,CACT,CAAC,GAGKJ,OACD,gBACH,IAAMM,EAAM,IAAI,YAAYL,EAAK,GAAIA,EAAK,IAAM,CAAC,CAAC,EAClDC,EAAU,QAAQC,GAAKA,EAAE,cAAcG,CAAG,CAAC,EAC3C,cAEAJ,EAAU,QAAQC,GAAKA,EAAEH,GAAQ,MAAMG,EAAGF,CAAI,CAAC,EAErD,CAEA,SAASM,EAAYC,EAAe,CAClCA,EAAc,OAASb,CACzB,CAEA,IAAOc,EAAQ,CAAE,WAAAF,CAAW",
6
+ "names": ["invoke", "payload", "id", "selector", "receiver", "method", "args", "receivers", "r", "context", "chain", "evt", "initialize", "streamActions", "turbo_ready_default"]
7
7
  }
@@ -1,6 +1,6 @@
1
1
  function invoke () {
2
2
  const payload = JSON.parse(this.templateContent.textContent)
3
- const { id, method, args, receiver, selector } = payload
3
+ const { id, selector, receiver, method, args } = payload
4
4
  let receivers = [self]
5
5
  if (selector) receivers = Array.from(document.querySelectorAll(selector))
6
6
 
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TurboReady::BroadcastInvokeJob < ActiveJob::Base
4
+ include TurboReady::TagHelper
5
+
6
+ def perform(*streamables, method, **kwargs)
7
+ Turbo::StreamsChannel.broadcast_stream_to(*streamables, content: turbo_stream_invoke_tag(method, **kwargs))
8
+ end
9
+ end
data/bin/loc CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/bin/bash
2
2
 
3
- cloc --exclude-dir=Gemfile,Dockerfile,bin,builds,db,docs,log,node_modules,Procfile,public,storage,tmp --exclude-ext=example,json,lock,md,ru,toml,sql,svg,txt,yml "${1:-.}"
3
+ cloc --exclude-ext=svg app lib
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "turbo-rails"
4
+ require_relative "version"
5
+ require_relative "patches"
6
+
7
+ class TurboReady::Engine < ::Rails::Engine
8
+ config.after_initialize do
9
+ ::Turbo::Streams::TagBuilder.send :include, TurboReady::Patches::TagBuilder
10
+ ::Turbo::Streams::Broadcasts.send :include, TurboReady::Patches::Broadcasts
11
+ ::Turbo::Broadcastable.send :include, TurboReady::Patches::Broadcastable
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Patch for Turbo::Broadcastable which is mixed into ActiveRecord
4
+ # SEE: https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb
5
+ module TurboReady::Patches::Broadcastable
6
+ def broadcast_invoke_to(*streamables, method, **kwargs)
7
+ Turbo::StreamsChannel.broadcast_invoke_to(*streamables, method, **kwargs)
8
+ end
9
+
10
+ def broadcast_invoke_later_to(*streamables, method, **kwargs)
11
+ Turbo::StreamsChannel.broadcast_invoke_later_to(*streamables, method, **kwargs)
12
+ end
13
+
14
+ def broadcast_invoke(method, **kwargs)
15
+ broadcast_invoke_to(self, method, **kwargs)
16
+ end
17
+
18
+ def broadcast_invoke_later(method, **kwargs)
19
+ broadcast_invoke_later_to(self, method, **kwargs)
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../tag_helper"
4
+ require_relative "../../../app/jobs/turbo_ready/broadcast_invoke_job"
5
+
6
+ # Patch for Turbo::Streams::Broadcasts which is mixed into Turbo::StreamsChannel
7
+ # SEE: https://github.com/hotwired/turbo-rails/blob/main/app/channels/turbo/streams/broadcasts.rb
8
+ module TurboReady::Patches::Broadcasts
9
+ include TurboReady::TagHelper
10
+
11
+ def broadcast_invoke_to(*streamables, method, **kwargs)
12
+ broadcast_stream_to(*streamables, content: turbo_stream_invoke_tag(method, **kwargs))
13
+ end
14
+
15
+ def broadcast_invoke_later_to(*streamables, method, **kwargs)
16
+ TurboReady::BroadcastInvokeJob.perform_later(*streamables, method, **kwargs)
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../string_wrapper"
4
+ require_relative "../tag_helper"
5
+
6
+ # Patch for Turbo::Streams::TagBuilder typically exposed as `turbo_stream`
7
+ # SEE: https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb
8
+ module TurboReady::Patches::TagBuilder
9
+ include TurboReady::TagHelper
10
+
11
+ def invoke(method, args: [], selector: nil, camelize: true, id: nil)
12
+ tag = turbo_stream_invoke_tag(method, args: args, selector: selector, camelize: camelize, id: id)
13
+ TurboReady::StringWrapper.new tag
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TurboReady::Patches
4
+ end
5
+
6
+ require_relative "patches/broadcastable"
7
+ require_relative "patches/broadcasts"
8
+ require_relative "patches/tag_builder"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TurboReady::StringWrapper
4
+ include TurboReady::TagHelper
5
+ attr_reader :turbo_stream_string
6
+
7
+ delegate_missing_to :turbo_stream_string
8
+
9
+ def initialize(turbo_stream_string, turbo_stream_strings: Set.new)
10
+ @turbo_stream_string = turbo_stream_string
11
+ @turbo_stream_strings = turbo_stream_strings
12
+ @turbo_stream_strings << turbo_stream_string
13
+ end
14
+
15
+ def invoke(...)
16
+ TurboReady::StringWrapper.new turbo_stream_invoke_tag(...), turbo_stream_strings: turbo_stream_strings
17
+ end
18
+
19
+ def flush
20
+ turbo_stream_strings.to_a.join("\n").html_safe
21
+ ensure
22
+ turbo_stream_strings.clear
23
+ end
24
+
25
+ alias_method :to_s, :flush
26
+
27
+ private
28
+
29
+ def turbo_stream_strings
30
+ @turbo_stream_strings ||= Set.new
31
+ end
32
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TurboReady::TagHelper
4
+ def turbo_stream_invoke_tag(method, args: [], selector: nil, camelize: true, id: nil)
5
+ id = SecureRandom.uuid if id.blank?
6
+ payload = HashWithIndifferentAccess.new(id: id.to_s, selector: selector)
7
+ payload.merge! method_details(method, args: args, camelize: camelize)
8
+ payload.select! { |_, v| v.present? }
9
+ %(<turbo-stream action="invoke" target="DOM"><template>#{payload.to_json}</template></turbo-stream>).html_safe
10
+ end
11
+
12
+ private
13
+
14
+ def method_details(method, args: [], camelize: true)
15
+ if camelize
16
+ method = camelize_method(method)
17
+ args = camelize_args(args)
18
+ end
19
+
20
+ method_parts = method.to_s.split(".")
21
+
22
+ HashWithIndifferentAccess.new(
23
+ receiver: method_parts[0..-2].join("."),
24
+ method: method_parts.last,
25
+ args: args
26
+ )
27
+ end
28
+
29
+ def camelize_method(method)
30
+ method.to_s.split(".").map { |s| s.camelize(:lower) }.join(".")
31
+ end
32
+
33
+ def camelize_args(args = [])
34
+ args.map do |param|
35
+ if param.is_a? Hash
36
+ param.deep_transform_keys { |key| key.to_s.camelize(:lower) }
37
+ else
38
+ param
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TurboReady
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.6"
5
5
  end
data/lib/turbo_ready.rb CHANGED
@@ -1,12 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "turbo_ready/version"
4
- require "turbo_ready/railtie"
5
- require "turbo_ready/string"
6
- require "turbo_ready/tag_builder"
7
-
8
- module TurboReady
9
- def self.patch!
10
- Turbo::Streams::TagBuilder.send :include, TurboReady::TagBuilder
11
- end
12
- end
3
+ require "turbo_ready/engine"
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo_ready",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Take full control of the DOM with Turbo Streams",
5
5
  "main": "app/assets/builds/turbo_ready.js",
6
6
  "repository": "https://github.com/hopsoft/turbo_ready",
@@ -10,7 +10,7 @@
10
10
  "@hotwired/turbo-rails": ">= 7.1"
11
11
  },
12
12
  "devDependencies": {
13
- "esbuild": "^0.14.48",
13
+ "esbuild": "^0.15.5",
14
14
  "eslint": "^8.19.0",
15
15
  "prettier-standard": "^16.4.1"
16
16
  },
data/turbo_ready.gemspec CHANGED
@@ -2,27 +2,36 @@
2
2
 
3
3
  require_relative "lib/turbo_ready/version"
4
4
 
5
- Gem::Specification.new do |spec|
6
- spec.name = "turbo_ready"
7
- spec.version = TurboReady::VERSION
8
- spec.authors = ["Nate Hopkins (hopsoft)"]
9
- spec.email = ["natehop@gmail.com"]
10
- spec.homepage = "https://github.com/hopsoft/turbo_ready"
11
- spec.summary = "Take full control of the DOM with Turbo Streams"
12
- spec.description = spec.summary
13
- spec.license = "MIT"
5
+ Gem::Specification.new do |s|
6
+ s.name = "turbo_ready"
7
+ s.version = TurboReady::VERSION
8
+ s.authors = ["Nate Hopkins (hopsoft)"]
9
+ s.email = ["natehop@gmail.com"]
10
+ s.homepage = "https://github.com/hopsoft/turbo_ready"
11
+ s.summary = "Take full control of the DOM with Turbo Streams"
12
+ s.description = s.summary
13
+ s.license = "MIT"
14
14
 
15
- spec.metadata["homepage_uri"] = spec.homepage
16
- spec.metadata["source_code_uri"] = spec.homepage
17
- spec.metadata["changelog_uri"] = spec.homepage + "/blob/master/CHANGELOG.md"
15
+ s.metadata["homepage_uri"] = s.homepage
16
+ s.metadata["source_code_uri"] = s.homepage
17
+ s.metadata["changelog_uri"] = s.homepage + "/blob/master/CHANGELOG.md"
18
18
 
19
- spec.files = Dir["lib/**/*.rb", "app/**/*", "bin/*", "[A-Z]*"]
19
+ s.files = Dir["lib/**/*.rb", "app/**/*", "bin/*", "[A-Z]*"]
20
20
 
21
- spec.add_dependency "rails", ">= 6.1"
22
- spec.add_dependency "turbo-rails", ">= 1.1"
21
+ s.add_dependency "rails", ">= 6.1"
22
+ s.add_dependency "turbo-rails", ">= 1.1"
23
23
 
24
- spec.add_development_dependency "magic_frozen_string_literal"
25
- spec.add_development_dependency "pry-byebug"
26
- spec.add_development_dependency "standardrb"
27
- spec.add_development_dependency "tocer"
24
+ s.add_development_dependency "capybara"
25
+ s.add_development_dependency "importmap-rails"
26
+ s.add_development_dependency "magic_frozen_string_literal"
27
+ s.add_development_dependency "net-smtp"
28
+ s.add_development_dependency "pry-byebug"
29
+ s.add_development_dependency "puma"
30
+ s.add_development_dependency "rake"
31
+ s.add_development_dependency "rexml"
32
+ s.add_development_dependency "selenium-webdriver"
33
+ s.add_development_dependency "sprockets-rails"
34
+ s.add_development_dependency "sqlite3"
35
+ s.add_development_dependency "standardrb"
36
+ s.add_development_dependency "webdrivers"
28
37
  end