turbo_boost-streams 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.
@@ -1,4 +1,4 @@
1
- import invoke from './invoke'
1
+ import { invoke, invokeEvents } from './invoke'
2
2
 
3
3
  if (!self['Turbo'])
4
4
  throw new Error(
@@ -12,8 +12,10 @@ if (!Turbo['StreamActions'])
12
12
 
13
13
  Turbo.StreamActions.invoke = invoke
14
14
  self.TurboBoost = self.TurboBoost || {}
15
- self.TurboBoost.Streams = { invoke }
15
+ self.TurboBoost.Streams = { invoke, invokeEvents }
16
16
 
17
17
  console.info(
18
18
  '@turbo-boost/streams has initialized and registered new stream actions with Turbo.'
19
19
  )
20
+
21
+ export default self.TurboBoost.Streams
@@ -1,38 +1,118 @@
1
- import dispatch from './methods/dispatch'
2
- import mutate from './methods/mutate'
1
+ import morph from './morph'
3
2
 
4
- function perform (method, args, receivers) {
5
- // dispatch / dispatchEvent
3
+ export const invokeEvents = {
4
+ before: 'turbo-boost:stream:before-invoke',
5
+ after: 'turbo-boost:stream:after-invoke',
6
+ finish: 'turbo-boost:stream:finish-invoke'
7
+ }
8
+
9
+ // Invokes the callback on a single receiver with before/after events
10
+ function withInvokeEvents (receiver, detail, callback) {
11
+ const { object, target } = receiver
12
+ detail = detail || {}
13
+ detail = { ...detail, object: receiver.object }
14
+ const options = { detail, bubbles: true }
15
+
16
+ target.dispatchEvent(new CustomEvent(invokeEvents.before, options))
17
+
18
+ const result = callback(object)
19
+ options.detail.result = result
20
+ target.dispatchEvent(new CustomEvent(invokeEvents.after, options))
21
+
22
+ let promise
23
+ if (result instanceof Animation) promise = result.finished
24
+ if (result instanceof Promise) promise = result
25
+
26
+ if (promise)
27
+ promise.then(
28
+ () => {
29
+ options.detail.promise = 'fulfilled'
30
+ target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
31
+ },
32
+ () => {
33
+ options.detail.promise = 'rejected'
34
+ target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
35
+ }
36
+ )
37
+ else target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
38
+ }
39
+
40
+ function invokeDispatchEvent (method, args, receivers) {
41
+ const eventName = args[0]
42
+ const eventOptions = args[1]
43
+ const detail = { method, eventName, eventOptions }
44
+ receivers.forEach(receiver =>
45
+ withInvokeEvents(receiver, detail, object =>
46
+ object.dispatchEvent(new CustomEvent(eventName, eventOptions))
47
+ )
48
+ )
49
+ }
50
+
51
+ function invokeMorph (method, args, receivers) {
52
+ const html = args[0]
53
+ const detail = { method, html }
54
+ receivers.forEach(receiver =>
55
+ withInvokeEvents(receiver, detail, object => morph(object, html))
56
+ )
57
+ }
58
+
59
+ function invokeAssignment (method, args, receivers) {
60
+ const property = method.slice(0, -1).trim()
61
+ const value = args[0]
62
+ const detail = { method, property, value }
63
+ receivers.forEach(receiver =>
64
+ withInvokeEvents(receiver, detail, object => (object[property] = value))
65
+ )
66
+ }
67
+
68
+ function invokeMethod (method, args, receivers) {
69
+ const detail = { method, args }
70
+ receivers.forEach(receiver =>
71
+ withInvokeEvents(receiver, detail, object =>
72
+ object[method].apply(object, args)
73
+ )
74
+ )
75
+ }
76
+
77
+ // Performs an invocation on all receivers for the given method and args
78
+ function performInvoke (method, args, receivers) {
79
+ // dispatch ................................................................................................
6
80
  if (method.match(/^dispatch(Event)?$/))
7
- return dispatch(receivers, args[0], args[1] || {})
81
+ return invokeDispatchEvent(method, args, receivers)
8
82
 
9
- // morph / mutate
10
- if (method.match(/^morph|mutate$/)) return mutate(receivers, args[0])
83
+ // morph ...................................................................................................
84
+ if (method.match(/^morph|mutate$/))
85
+ return invokeMorph(method, args, receivers)
11
86
 
12
- // property assignment
13
- if (method.endsWith('='))
14
- return receivers.forEach(r => (r[method.slice(0, -1).trim()] = args[0]))
87
+ // assignment ..............................................................................................
88
+ if (method.endsWith('=')) return invokeAssignment(method, args, receivers)
15
89
 
16
- // method invocation
17
- receivers.forEach(r => r[method].apply(r, args))
90
+ // method ..................................................................................................
91
+ return invokeMethod(method, args, receivers)
18
92
  }
19
93
 
20
- function invoke () {
94
+ export function invoke () {
21
95
  const payload = JSON.parse(this.templateContent.textContent)
22
- const { id, selector, receiver, method, args } = payload
23
- let receivers = [self]
24
- if (selector) receivers = Array.from(document.querySelectorAll(selector))
96
+ const { id, selector, receiver, method, args, delay } = payload
97
+ let receivers = [{ object: self, target: self }]
98
+ if (selector)
99
+ receivers = Array.from(document.querySelectorAll(selector)).map(el => ({
100
+ object: el,
101
+ target: el
102
+ }))
25
103
 
26
104
  if (receiver) {
27
105
  receivers = receivers.map(r => {
28
- let context = r
106
+ let { object, target } = r
29
107
  const chain = receiver.split('.')
30
- while (chain.length > 0) context = context[chain.shift()]
31
- return context
108
+ while (chain.length > 0) {
109
+ object = object[chain.shift()]
110
+ if (object.dispatchEvent) target = object
111
+ }
112
+ return { object, target }
32
113
  })
33
114
  }
34
115
 
35
- perform(method, args, receivers)
116
+ if (delay > 0) setTimeout(() => performInvoke(method, args, receivers), delay)
117
+ else performInvoke(method, args, receivers)
36
118
  }
37
-
38
- export default invoke
@@ -1,7 +1,7 @@
1
1
  import alpine from 'alpinejs'
2
- import morph from '@alpinejs/morph'
2
+ import alpineMorph from '@alpinejs/morph'
3
3
 
4
- alpine.plugin(morph)
4
+ alpine.plugin(alpineMorph)
5
5
 
6
6
  const input = /INPUT/i
7
7
  const inputTypes = /date|datetime-local|email|month|number|password|range|search|tel|text|time|url|week/i
@@ -18,8 +18,6 @@ function updating (el, toEl, childrenOnly, skip) {
18
18
  if (protect) return skip()
19
19
  }
20
20
 
21
- function mutate (elements, html) {
22
- elements.forEach(element => alpine.morph(element, html, { updating }))
21
+ export default function morph (element, html) {
22
+ alpine.morph(element, html, { updating })
23
23
  }
24
-
25
- export default mutate
@@ -8,8 +8,7 @@ require_relative "../tag_helper"
8
8
  module TurboBoost::Streams::Patches::TagBuilder
9
9
  include TurboBoost::Streams::TagHelper
10
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
- TurboBoost::Streams::StringWrapper.new tag
11
+ def invoke(...)
12
+ TurboBoost::Streams::StringWrapper.new turbo_stream_invoke_tag(...)
14
13
  end
15
14
  end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TurboBoost::Streams::TagHelper
4
- def turbo_stream_invoke_tag(method, args: [], selector: nil, camelize: true, id: nil)
4
+ def turbo_stream_invoke_tag(method, args: [], delay: 0, selector: nil, camelize: true, id: nil)
5
5
  id = SecureRandom.uuid if id.blank?
6
6
  payload = HashWithIndifferentAccess.new(id: id.to_s, selector: selector)
7
- payload.merge! method_details(method, args: args, camelize: camelize)
7
+ payload.merge! method_details(method, args: args, delay: delay, camelize: camelize)
8
8
  payload.select! { |_, v| v.present? }
9
9
  %(<turbo-stream action="invoke" target="DOM"><template>#{payload.to_json}</template></turbo-stream>).html_safe
10
10
  end
11
11
 
12
12
  private
13
13
 
14
- def method_details(method, args: [], camelize: true)
14
+ def method_details(method, args: [], delay: 0, camelize: true)
15
15
  if camelize
16
16
  method = camelize_method(method)
17
17
  args = camelize_args(args)
@@ -22,7 +22,8 @@ module TurboBoost::Streams::TagHelper
22
22
  HashWithIndifferentAccess.new(
23
23
  receiver: method_parts[0..-2].join("."),
24
24
  method: method_parts.last,
25
- args: args
25
+ args: args,
26
+ delay: delay.to_i
26
27
  )
27
28
  end
28
29
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TurboBoost
4
4
  module Streams
5
- VERSION = "0.0.5"
5
+ VERSION = "0.0.6"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_boost-streams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Hopkins (hopsoft)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-05 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -311,8 +311,7 @@ files:
311
311
  - app/assets/images/turbo-boost-mark.afdesign
312
312
  - app/javascript/index.js
313
313
  - app/javascript/invoke.js
314
- - app/javascript/methods/dispatch.js
315
- - app/javascript/methods/mutate.js
314
+ - app/javascript/morph.js
316
315
  - app/jobs/turbo_boost/streams/broadcast_invoke_job.rb
317
316
  - lib/turbo_boost/streams.rb
318
317
  - lib/turbo_boost/streams/engine.rb
@@ -338,14 +337,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
338
337
  requirements:
339
338
  - - ">="
340
339
  - !ruby/object:Gem::Version
341
- version: '0'
340
+ version: '2.7'
342
341
  required_rubygems_version: !ruby/object:Gem::Requirement
343
342
  requirements:
344
343
  - - ">="
345
344
  - !ruby/object:Gem::Version
346
345
  version: '0'
347
346
  requirements: []
348
- rubygems_version: 3.3.21
347
+ rubygems_version: 3.4.1
349
348
  signing_key:
350
349
  specification_version: 4
351
350
  summary: Take full control of the DOM with Turbo Streams
@@ -1,6 +0,0 @@
1
- function dispatch (targets, name, options = {}) {
2
- const evt = new CustomEvent(name, options)
3
- targets.forEach(t => t.dispatchEvent(evt))
4
- }
5
-
6
- export default dispatch