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.
- checksums.yaml +4 -4
- data/Gemfile +0 -3
- data/Gemfile.lock +55 -52
- data/README.md +261 -93
- data/README.md.orig +292 -0
- data/Rakefile +13 -1
- data/app/assets/builds/turbo_ready.js +1 -1
- data/app/assets/builds/turbo_ready.js.map +3 -3
- data/app/assets/images/turbo-ready-logo-dark.webp +0 -0
- data/app/assets/images/turbo-ready-logo-light.webp +0 -0
- data/app/javascript/turbo_ready.js +1 -1
- data/app/jobs/turbo_ready/broadcast_invoke_job.rb +9 -0
- data/bin/loc +1 -1
- data/lib/turbo_ready/engine.rb +13 -0
- data/lib/turbo_ready/patches/broadcastable.rb +21 -0
- data/lib/turbo_ready/patches/broadcasts.rb +18 -0
- data/lib/turbo_ready/patches/tag_builder.rb +15 -0
- data/lib/turbo_ready/patches.rb +8 -0
- data/lib/turbo_ready/string_wrapper.rb +32 -0
- data/lib/turbo_ready/tag_helper.rb +42 -0
- data/lib/turbo_ready/version.rb +1 -1
- data/lib/turbo_ready.rb +1 -10
- data/package.json +2 -2
- data/turbo_ready.gemspec +28 -19
- data/yarn.lock +155 -150
- metadata +141 -7
- data/lib/turbo_ready/railtie.rb +0 -12
- data/lib/turbo_ready/string.rb +0 -37
- data/lib/turbo_ready/tag_builder.rb +0 -33
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
<p align="center">
|
2
|
-
<
|
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>
|
3
6
|
<h3 align="center">
|
4
7
|
Turbo Stream's Swiss Army Knife
|
5
8
|
</h3>
|
@@ -7,47 +10,76 @@
|
|
7
10
|
Welcome to TurboReady 👋
|
8
11
|
</h1>
|
9
12
|
<p align="center">
|
10
|
-
<a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/"
|
11
|
-
<img alt="Lines of Code" src="https://img.shields.io/badge/
|
13
|
+
<a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/">
|
14
|
+
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-143-47d299.svg" />
|
12
15
|
</a>
|
13
|
-
<a href="https://
|
14
|
-
<img
|
16
|
+
<a href="https://codeclimate.com/github/hopsoft/turbo_ready/maintainability">
|
17
|
+
<img src="https://api.codeclimate.com/v1/badges/a69b6f73abc3ccd49261/maintainability" />
|
15
18
|
</a>
|
16
|
-
<a href="https://
|
17
|
-
<img alt="
|
19
|
+
<a href="https://rubygems.org/gems/turbo_ready">
|
20
|
+
<img alt="GEM" src="https://img.shields.io/gem/v/turbo_ready?color=168AFE&include_prereleases&logo=ruby&logoColor=FE1616">
|
18
21
|
</a>
|
19
|
-
<a href="https://
|
20
|
-
<img alt="
|
22
|
+
<a href="https://rubygems.org/gems/turbo_ready">
|
23
|
+
<img alt="Gem" src="https://img.shields.io/gem/dt/turbo_ready?color=168AFE&logo=ruby&logoColor=FE1616">
|
24
|
+
</a>
|
25
|
+
<a href="https://github.com/testdouble/standard">
|
26
|
+
<img alt="Ruby Style" src="https://img.shields.io/badge/style-standard-168AFE?logo=ruby&logoColor=FE1616" />
|
27
|
+
</a>
|
28
|
+
<a href="https://www.npmjs.com/package/turbo_ready">
|
29
|
+
<img alt="NPM" src="https://img.shields.io/npm/v/turbo_ready?color=168AFE&logo=npm">
|
30
|
+
</a>
|
31
|
+
<a href="https://www.npmjs.com/package/turbo_ready">
|
32
|
+
<img alt="npm" src="https://img.shields.io/npm/dm/turbo_ready?color=168AFE&logo=npm">
|
33
|
+
</a>
|
34
|
+
<a href="https://bundlephobia.com/package/turbo_ready@">
|
35
|
+
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/turbo_ready?label=bundle%20size&logo=npm&color=47d299">
|
36
|
+
</a>
|
37
|
+
<a href="https://github.com/sheerun/prettier-standard">
|
38
|
+
<img alt="JavaScript Style" src="https://img.shields.io/badge/style-prettier--standard-168AFE?logo=javascript&logoColor=f4e137" />
|
39
|
+
</a>
|
40
|
+
<a href="https://github.com/hopsoft/turbo_ready/actions/workflows/tests.yml">
|
41
|
+
<img alt="Tests" src="https://github.com/hopsoft/turbo_ready/actions/workflows/tests.yml/badge.svg" />
|
42
|
+
</a>
|
43
|
+
<a href="https://twitter.com/hopsoft">
|
44
|
+
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/hopsoft?logo=twitter&style=social">
|
21
45
|
</a>
|
22
46
|
</p>
|
23
47
|
</p>
|
24
48
|
|
25
|
-
TurboReady extends [Turbo Streams](https://turbo.hotwired.dev/reference/streams) to give you full control of the
|
26
|
-
browser's [Document Object Model (DOM).](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)
|
27
|
-
|
28
|
-
**Thats right!**
|
29
|
-
You can `invoke` any DOM method on any DOM object *(including 3rd party libs)* using Turbo Streams.
|
49
|
+
**TurboReady extends [Turbo Streams](https://turbo.hotwired.dev/reference/streams) to give you full control of the
|
50
|
+
browser's [Document Object Model (DOM).](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)**
|
30
51
|
|
31
52
|
```ruby
|
32
|
-
turbo_stream.invoke "console.log", "Hello World!"
|
53
|
+
turbo_stream.invoke "console.log", args: ["Hello World!"]
|
33
54
|
```
|
34
55
|
|
56
|
+
**Thats right!**
|
57
|
+
You can `invoke` any DOM method on the client with Turbo Streams.
|
58
|
+
|
35
59
|
<!-- Tocer[start]: Auto-generated, don't remove. -->
|
36
60
|
|
37
61
|
## Table of Contents
|
38
62
|
|
39
63
|
- [Why TurboReady?](#why-turboready)
|
40
|
-
- [Discord Community](#discord-community)
|
41
64
|
- [Sponsors](#sponsors)
|
42
65
|
- [Dependencies](#dependencies)
|
43
66
|
- [Installation](#installation)
|
44
67
|
- [Setup](#setup)
|
45
68
|
- [Usage](#usage)
|
46
|
-
|
47
|
-
|
69
|
+
- [Method Chaining](#method-chaining)
|
70
|
+
- [Dispatching Events](#dispatching-events)
|
71
|
+
- [Syntax Styles](#syntax-styles)
|
48
72
|
- [Extending Behavior](#extending-behavior)
|
49
|
-
|
73
|
+
- [Implementation Details](#implementation-details)
|
74
|
+
- [Broadcasting](#broadcasting)
|
75
|
+
- [Background Job Queues](#background-job-queues)
|
76
|
+
- [FAQ](#faq)
|
50
77
|
- [A Word of Caution](#a-word-of-caution)
|
78
|
+
- [Community](#community)
|
79
|
+
- [Discord](#discord)
|
80
|
+
- [Discussions](#discussions)
|
81
|
+
- [Twitter](#twitter)
|
82
|
+
- [TODOs](#todos)
|
51
83
|
- [Releasing](#releasing)
|
52
84
|
- [License](#license)
|
53
85
|
|
@@ -55,21 +87,17 @@ turbo_stream.invoke "console.log", "Hello World!"
|
|
55
87
|
|
56
88
|
## Why TurboReady?
|
57
89
|
|
58
|
-
Turbo Streams [intentionally restricts](https://turbo.hotwired.dev/handbook/streams#but-what-about-running-javascript)
|
90
|
+
Turbo Streams [intentionally restricts](https://turbo.hotwired.dev/handbook/streams#but-what-about-running-javascript%3F)
|
59
91
|
official actions to CRUD related activity.
|
60
|
-
|
61
|
-
|
92
|
+
These [official actions](https://turbo.hotwired.dev/reference/streams#the-seven-actions) work well for a considerable number of use cases.
|
93
|
+
*Try pushing Turbo Streams as far as possible before reaching for TurboReady.*
|
62
94
|
|
63
|
-
If you
|
95
|
+
If you find that CRUD isn't enough, TurboReady is there to handle pretty much everything else.
|
64
96
|
|
65
|
-
|
66
|
-
|
67
|
-
Please join nearly 2000 of us on [Discord](https://discord.gg/stimulus-reflex) for support getting started,
|
68
|
-
as well as active discussions around Rails, Hotwire, Stimulus, Turbo (Drive, Frames, Streams), TurboReady, CableReady, StimulusReflex, ViewComponent, Phlex, and more.
|
69
|
-
|
70
|
-

|
97
|
+
> ⚠️ TurboReady is intended for Rails apps that use Hotwire but not [CableReady](https://github.com/stimulusreflex/cable_ready).
|
98
|
+
This is because CableReady already provides a rich set of powerful [DOM operations](https://cableready.stimulusreflex.com/reference/operations).
|
71
99
|
|
72
|
-
|
100
|
+
> 📘 **NOTE:** Efforts are underway to bring [CableReady's DOM operations to Turbo Streams](https://github.com/marcoroth/turbo_power).
|
73
101
|
|
74
102
|
## Sponsors
|
75
103
|
|
@@ -90,73 +118,84 @@ Stop by #newcomers and introduce yourselves!
|
|
90
118
|
|
91
119
|
## Installation
|
92
120
|
|
121
|
+
Be sure to install the same version for each libary.
|
122
|
+
|
93
123
|
```sh
|
94
124
|
bundle add "turbo_ready --version VERSION"
|
95
125
|
yarn add "turbo_ready@VERSION --exact"
|
96
126
|
```
|
97
127
|
|
98
|
-
**IMPORTANT:** Be sure to use the same version for each libary.
|
99
|
-
|
100
128
|
## Setup
|
101
129
|
|
102
|
-
|
130
|
+
Import and intialize TurboReady in your application.
|
103
131
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
132
|
+
```diff
|
133
|
+
# Gemfile
|
134
|
+
+gem "turbo_ready", "~> 0.0.6"
|
135
|
+
```
|
108
136
|
|
109
|
-
|
110
|
-
|
137
|
+
```diff
|
138
|
+
# package.json
|
139
|
+
"dependencies": {
|
140
|
+
+ "@hotwired/turbo-rails": ">=7.2.0-beta.2",
|
141
|
+
+ "turbo_ready": "^0.0.6"
|
142
|
+
```
|
143
|
+
|
144
|
+
```diff
|
145
|
+
# app/javascript/application.js
|
146
|
+
import '@hotwired/turbo-rails'
|
147
|
+
+import TurboReady from 'turbo_ready'
|
148
|
+
|
149
|
+
+TurboReady.initialize(Turbo.StreamActions) // Adds TurboReady stream actions to Turbo
|
150
|
+
```
|
111
151
|
|
112
152
|
## Usage
|
113
153
|
|
114
|
-
Manipulate the DOM from anywhere you use
|
115
|
-
|
116
|
-
[
|
117
|
-
|
154
|
+
Manipulate the DOM from anywhere you use official [Turbo Streams](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks).
|
155
|
+
The possibilities are endless.
|
156
|
+
[Learn more about the DOM at MDN.](https://developer.mozilla.org/en-US/docs/Web/API.)
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
turbo_stream.invoke "console.log", args: ["Hello World!"]
|
160
|
+
```
|
161
|
+
|
162
|
+
### Method Chaining
|
118
163
|
|
119
|
-
You can
|
164
|
+
You can use [dot notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#dot_notation)
|
165
|
+
or [selectors](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) and even combine them!
|
120
166
|
|
121
167
|
```ruby
|
122
168
|
turbo_stream
|
123
|
-
.invoke("document.body.insertAdjacentHTML", "afterbegin", "<h1>Hello World!</h1>") # dot notation
|
124
|
-
.invoke("setAttribute", "data-turbo-ready", true, selector: ".button") # selector
|
125
|
-
.invoke("classList.add", "turbo-ready", selector: "a") # dot notation + selector
|
126
|
-
.flush # flush
|
169
|
+
.invoke("document.body.insertAdjacentHTML", args: ["afterbegin", "<h1>Hello World!</h1>"]) # dot notation
|
170
|
+
.invoke("setAttribute", args: ["data-turbo-ready", true], selector: ".button") # selector
|
171
|
+
.invoke("classList.add", args: ["turbo-ready"], selector: "a") # dot notation + selector
|
172
|
+
.flush # call flush when chaining invocations
|
127
173
|
```
|
128
174
|
|
129
|
-
|
130
|
-
or [selectors](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)... and can even combine them!** 🤯
|
175
|
+
### Dispatching Events
|
131
176
|
|
132
|
-
|
177
|
+
It's possible to fire events on `window`, `document`, and element(s).
|
133
178
|
|
134
179
|
```ruby
|
135
180
|
turbo_stream
|
136
|
-
.invoke("dispatchEvent", "turbo-ready:demo")
|
137
|
-
.invoke("dispatchEvent", "turbo-ready:demo"
|
138
|
-
.invoke("dispatchEvent",
|
181
|
+
.invoke("dispatchEvent", args: ["turbo-ready:demo"]) # fires on window
|
182
|
+
.invoke("document.dispatchEvent", args: ["turbo-ready:demo"]) # fires on document
|
183
|
+
.invoke("dispatchEvent", args: ["turbo-ready:demo"], selector: "#my-element") # fires on matching element(s)
|
184
|
+
.invoke("dispatchEvent", args: ["turbo-ready:demo", {bubbles: true, detail: {...}}]) # set event options
|
139
185
|
.flush
|
140
186
|
```
|
141
187
|
|
142
|
-
|
143
|
-
|
144
|
-
**What else can I do?**
|
145
|
-
MDN has your back... [learn about the DOM and web APIs here.](https://developer.mozilla.org/en-US/docs/Web/API.)
|
188
|
+
### Syntax Styles
|
146
189
|
|
147
|
-
|
148
|
-
|
149
|
-
You can use symbols and [snake case](https://en.wikipedia.org/wiki/Snake_case) when invoking DOM functionality.
|
150
|
-
It'll implicitly convert to [camel case](https://en.wikipedia.org/wiki/Camel_case). 💎
|
190
|
+
You can use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) when invoking DOM functionality.
|
191
|
+
It will implicitly convert to [`camelCase`](https://en.wikipedia.org/wiki/Camel_case).
|
151
192
|
|
152
193
|
```ruby
|
153
|
-
turbo_stream
|
154
|
-
|
155
|
-
.invoke(:dispatch_event, {detail: {converts_to_camel_case: true}})
|
156
|
-
.flush
|
194
|
+
turbo_stream.invoke :dispatch_event,
|
195
|
+
args: ["turbo-ready:demo", {detail: {converts_to_camel_case: true}}]
|
157
196
|
```
|
158
197
|
|
159
|
-
Need to opt
|
198
|
+
Need to opt-out? No problem... just disable it.
|
160
199
|
|
161
200
|
```ruby
|
162
201
|
turbo_stream.invoke :contrived_demo, camelize: false
|
@@ -164,10 +203,10 @@ turbo_stream.invoke :contrived_demo, camelize: false
|
|
164
203
|
|
165
204
|
### Extending Behavior
|
166
205
|
|
167
|
-
|
206
|
+
If you add new capabilities to the browser, you can control them from the server.
|
168
207
|
|
169
208
|
```js
|
170
|
-
// JavaScript
|
209
|
+
// JavaScript on the client
|
171
210
|
import morphdom from 'morphdom'
|
172
211
|
|
173
212
|
window.MyNamespace = {
|
@@ -178,51 +217,180 @@ window.MyNamespace = {
|
|
178
217
|
```
|
179
218
|
|
180
219
|
```ruby
|
181
|
-
# Ruby
|
182
|
-
turbo_stream
|
183
|
-
|
220
|
+
# Ruby on the server
|
221
|
+
turbo_stream.invoke "MyNamespace.morph",
|
222
|
+
args: [
|
223
|
+
"#demo",
|
224
|
+
"<div id='demo'><p>You've changed...</p></div>",
|
225
|
+
{children_only: true}
|
226
|
+
]
|
184
227
|
```
|
185
228
|
|
186
|
-
|
229
|
+
### Implementation Details
|
187
230
|
|
188
|
-
There's
|
189
|
-
[tag builder](https://github.com/hopsoft/turbo_ready/blob/main/lib/turbo_ready/tag_builder.rb).
|
231
|
+
There's basically one method to learn... `invoke`
|
190
232
|
|
191
233
|
```ruby
|
192
234
|
# Ruby
|
193
235
|
turbo_stream
|
194
|
-
.invoke(method,
|
195
|
-
# |
|
196
|
-
# |
|
197
|
-
# |
|
198
|
-
# |
|
199
|
-
# |
|
200
|
-
# |
|
201
|
-
# |
|
202
|
-
# |
|
203
|
-
# |
|
236
|
+
.invoke(method, args: [], selector: nil, camelize: true, id: nil)
|
237
|
+
# | | | | |
|
238
|
+
# | | | | |- Identifies this invocation (optional)
|
239
|
+
# | | | |
|
240
|
+
# | | | |- Should we camelize the JavaScript stuff? (optional)
|
241
|
+
# | | | (allows us to write snake_case in Ruby)
|
242
|
+
# | | |
|
243
|
+
# | | |- A CSS selector for the element(s) to target (optional)
|
244
|
+
# | |
|
245
|
+
# | |- The arguments to pass to the JavaScript method (optional)
|
204
246
|
# |
|
205
247
|
# |- The JavaScript method to invoke (can use dot notation)
|
206
248
|
```
|
207
249
|
|
208
|
-
**NOTE:** The
|
250
|
+
> 📘 **NOTE:** The method will be invoked on all matching elements if a `selector` is present.
|
251
|
+
|
252
|
+
The following Ruby code,
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
turbo_stream.invoke "console.log", args: ["Hello World!"], id: "1"
|
256
|
+
```
|
257
|
+
|
258
|
+
emits this HTML markup.
|
259
|
+
|
260
|
+
```html
|
261
|
+
<turbo-stream action="invoke" target="DOM">
|
262
|
+
<template>{"id":"1","receiver":"console","method":"log","args":["Hello World!"]}</template>
|
263
|
+
</turbo-stream>
|
264
|
+
```
|
265
|
+
|
266
|
+
When this element enters the DOM,
|
267
|
+
Turbo Streams automatically executes `invoke` on the client with the template's JSON payload and then removes the element from the DOM.
|
268
|
+
|
269
|
+
### Broadcasting
|
270
|
+
|
271
|
+
You can also broadcast DOM invocations to subscribed users.
|
272
|
+
|
273
|
+
1. First, setup the stream subscription.
|
274
|
+
|
275
|
+
```erb
|
276
|
+
<!-- app/views/posts/show.html.erb -->
|
277
|
+
<%= turbo_stream_from @post %>
|
278
|
+
<!-- |
|
279
|
+
|- *streamables - model(s), string(s), etc...
|
280
|
+
-->
|
281
|
+
```
|
282
|
+
|
283
|
+
2. Then, broadcast to the subscription.
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
# app/models/post.rb
|
287
|
+
class Post < ApplicationRecord
|
288
|
+
after_save do
|
289
|
+
# emit a message in the browser conosle for anyone subscribed to this post
|
290
|
+
broadcast_invoke "console.log", args: ["Post was saved! #{to_gid.to_s}"]
|
291
|
+
|
292
|
+
# broadcast with a background job
|
293
|
+
broadcast_invoke_later "console.log", args: ["Post was saved! #{to_gid.to_s}"]
|
294
|
+
end
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
# app/controllers/posts_controller.rb
|
300
|
+
class PostsController < ApplicationController
|
301
|
+
def create
|
302
|
+
@post = Post.find params[:id]
|
303
|
+
|
304
|
+
if @post.update post_params
|
305
|
+
# emit a message in the browser conosle for anyone subscribed to this post
|
306
|
+
@post.broadcast_invoke "console.log", args: ["Post was saved! #{to_gid.to_s}"]
|
307
|
+
|
308
|
+
# broadcast with a background job
|
309
|
+
@post.broadcast_invoke_later "console.log", args: ["Post was saved! #{to_gid.to_s}"]
|
310
|
+
|
311
|
+
# you can also broadcast directly from the channel
|
312
|
+
Turbo::StreamsChannel.broadcast_invoke_to @post, "console.log",
|
313
|
+
args: ["Post was saved! #{@post.to_gid.to_s}"]
|
314
|
+
|
315
|
+
# broadcast with a background job
|
316
|
+
Turbo::StreamsChannel.broadcast_invoke_later_to @post, "console.log",
|
317
|
+
args: ["Post was saved! #{@post.to_gid.to_s}"]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
```
|
322
|
+
|
323
|
+
> 📘 **NOTE:** [Method Chaining](#method-chaining) is not currently supported when broadcasting.
|
324
|
+
|
325
|
+
#### Background Job Queues
|
326
|
+
|
327
|
+
You may want to change the queue name for Turbo Stream background jobs in order to isolate, prioritize, and scale the workers independently.
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
# config/initializers/turbo_streams.rb
|
331
|
+
Turbo::Streams::BroadcastJob.queue_name = :turbo_streams
|
332
|
+
TurboReady::BroadcastInvokeJob.queue_name = :turbo_streams
|
333
|
+
```
|
334
|
+
|
335
|
+
## FAQ
|
336
|
+
|
337
|
+
- Isn't this just RJS?
|
338
|
+
|
339
|
+
> No. But, perhaps it could be considered RJS's "modern" spirtual successor. 🤷♂️
|
340
|
+
> Though it embraces JavaScript instead of trying to avoid it.
|
341
|
+
|
342
|
+
- Does it use `eval`?
|
343
|
+
|
344
|
+
> **No.** TurboReady can only invoke existing functions on the client.
|
345
|
+
> It's not a carte blanche invitation to emit free-form JavaScript to be evaluated on the client.
|
209
346
|
|
210
347
|
## A Word of Caution
|
211
348
|
|
212
|
-
|
213
|
-
**⚠️ Don't abuse this superpower!**
|
349
|
+
**Don't abuse this superpower!**
|
214
350
|
|
215
351
|
> With great power comes great responsibility. *-Uncle Ben*
|
216
352
|
|
353
|
+
Manually orchestrating DOM activity is tedious.
|
354
|
+
*Don't overdo it... or you may find that you've created spaghetti reminiscent of the jQuery days.*
|
355
|
+
|
217
356
|
This library is an extremely sharp tool. 🔪
|
218
|
-
Consider it a low-level building block that can be used to craft additional libraries
|
219
|
-
great [DX](https://en.wikipedia.org/wiki/User_experience#Developer_experience)
|
357
|
+
Consider it a low-level building block that can be used to craft additional libraries
|
220
358
|
like [CableReady](https://github.com/stimulusreflex/cable_ready)
|
221
359
|
and [StimulusReflex](https://github.com/stimulusreflex/stimulus_reflex).
|
222
360
|
|
223
|
-
|
224
|
-
|
225
|
-
|
361
|
+
## Community
|
362
|
+
|
363
|
+
### Discord
|
364
|
+
|
365
|
+
Please join nearly 2000 of us on [Discord](https://discord.gg/stimulus-reflex) for support getting started,
|
366
|
+
as well as active discussions around Rails, Hotwire, Stimulus, Turbo (Drive, Frames, Streams), TurboReady, CableReady, StimulusReflex, ViewComponent, Phlex, and more.
|
367
|
+
|
368
|
+
<a href="https://discord.gg/stimulus-reflex" target="_blank">
|
369
|
+
<img alt="Discord" src="https://img.shields.io/discord/629472241427415060?color=168AFE&logo=discord&logoColor=FFF">
|
370
|
+
</a>
|
371
|
+
|
372
|
+
Be sure to introduce yourselves in the #newcomers channel!
|
373
|
+
|
374
|
+
### Discussions
|
375
|
+
|
376
|
+
Feel free to add to the conversation here on [GitHub Discussions](https://github.com/hopsoft/turbo_ready/discussions).
|
377
|
+
|
378
|
+
<a href="https://github.com/hopsoft/turbo_ready/discussions" target="_blank">
|
379
|
+
<img alt="GitHub Discussions" src="https://img.shields.io/github/discussions/hopsoft/turbo_ready?color=168AFE&logo=github">
|
380
|
+
</a>
|
381
|
+
|
382
|
+
### Twitter
|
383
|
+
|
384
|
+
Connect with the core team on Twitter.
|
385
|
+
|
386
|
+
<a href="https://twitter.com/hopsoft" target="_blank">
|
387
|
+
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/hopsoft?logo=twitter&style=social">
|
388
|
+
</a>
|
389
|
+
|
390
|
+
## TODOs
|
391
|
+
|
392
|
+
- [ ] Add system tests [(review turbo-rails for guidance)](https://github.com/hotwired/turbo-rails/blob/main/test/system/broadcasts_test.rb)
|
393
|
+
- [ ] Look into adding method chaining for broadcasts
|
226
394
|
|
227
395
|
## Releasing
|
228
396
|
|