opal-vite 0.3.12 → 0.3.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9090275c2e356c56f2251c8553177f531703d22f134ce8fa8b68e11893f2ee29
4
- data.tar.gz: 2d329e601b63709562865683389d41fe63250e1bc380f4c293a9342b900b84c6
3
+ metadata.gz: 67f79084fe35586cb8dc0f98103778f6fe8a87a14876dc94d974c5ab434be56d
4
+ data.tar.gz: 4f4f7c07407bd93599f9230168992cd16af6f61a708fab7db12a3229300a1f55
5
5
  SHA512:
6
- metadata.gz: ba6714e48e3df9aa55671f9bce896b786443c34a9de6efc82b00955edb7fb2f5247a35c3de98e8ad2cad37bf0bf2e2931221e2276dec8128629a1a147554de85
7
- data.tar.gz: 41cc25cdaa6b11f66a95082bc56828284a43b20fb2beac8c8ee043fb8b65e2637c1d68c07faa2ac1e5cb832b90216cf59ed0c67dde1e18b11425b5fadfebd8ea
6
+ metadata.gz: 2ef2c6d46990c04cc7b7d23267d255a384d4d6b263f7a1d83d47f2a7c82969796edd7d6e1ebcfa6cf209fd1eb53ff83cde108aced69e387b27e7ff9274a08a38
7
+ data.tar.gz: 11497fc562b1fc9a1ca9836cbe218988e771576a3bb2258915ceb7440c91aabfeecea843cea34a9f861f2c30498084574ccf94c10a311301c2bdb7130025761c
@@ -1,5 +1,5 @@
1
1
  module Opal
2
2
  module Vite
3
- VERSION = "0.3.12"
3
+ VERSION = "0.3.13"
4
4
  end
5
5
  end
@@ -0,0 +1,112 @@
1
+ # backtick_javascript: true
2
+
3
+ module OpalVite
4
+ module Concerns
5
+ module V1
6
+ # Component - a lightweight, framework-agnostic UI component base class.
7
+ #
8
+ # opal-rails users coming from hand-written opal-jquery DOM code (or
9
+ # Hyperstack) usually just want "a base class that holds state and
10
+ # re-renders". This provides exactly that, with no React/Vue dependency,
11
+ # using only the native DOM. Because it is Sprockets-independent it runs
12
+ # unchanged under Vite.
13
+ #
14
+ # @example
15
+ # class Counter < OpalComponent
16
+ # def initial_state
17
+ # { count: 0 }
18
+ # end
19
+ #
20
+ # def render
21
+ # "<button>count: #{state[:count]}</button>"
22
+ # end
23
+ #
24
+ # def after_render
25
+ # on('button', 'click') { set_state(count: state[:count] + 1) }
26
+ # end
27
+ # end
28
+ #
29
+ # Counter.new.mount('#app')
30
+ class Component
31
+ attr_reader :state, :props, :el
32
+
33
+ # @param props [Hash] immutable inputs passed from the parent/caller
34
+ def initialize(props = {})
35
+ @props = props
36
+ @state = initial_state
37
+ @el = nil
38
+ end
39
+
40
+ # Override to provide the initial state hash. Defaults to empty.
41
+ def initial_state
42
+ {}
43
+ end
44
+
45
+ # Override to return the component's HTML as a String.
46
+ def render
47
+ ''
48
+ end
49
+
50
+ # Optional hook run after every render. Attach event listeners here
51
+ # (the DOM produced by #render only exists after rendering).
52
+ def after_render; end
53
+
54
+ # Mount the component into a DOM element.
55
+ # @param target [String, Native] a CSS selector or a native element
56
+ # @return [self]
57
+ def mount(target)
58
+ @el = resolve_el(target)
59
+ raise "OpalComponent#mount: target not found: #{target}" if `#{@el} == null`
60
+
61
+ do_render
62
+ self
63
+ end
64
+
65
+ # Merge +partial+ into the current state and re-render (if mounted).
66
+ # @param partial [Hash]
67
+ # @return [Hash] the new state
68
+ def set_state(partial)
69
+ unless partial.is_a?(Hash)
70
+ raise ArgumentError, "OpalComponent#set_state expects a Hash, got #{partial.class}"
71
+ end
72
+
73
+ @state = @state.merge(partial)
74
+ do_render if @el
75
+ @state
76
+ end
77
+
78
+ # querySelector scoped to this component's element.
79
+ def query(selector)
80
+ `#{@el}.querySelector(#{selector})`
81
+ end
82
+
83
+ # Attach an event listener to a descendant matched by +selector+.
84
+ # The block receives the native DOM event.
85
+ def on(selector, event, &block)
86
+ node = query(selector)
87
+ return if `#{node} == null`
88
+
89
+ `#{node}.addEventListener(#{event}, #{block})`
90
+ end
91
+
92
+ private
93
+
94
+ def do_render
95
+ `#{@el}.innerHTML = #{render}`
96
+ after_render
97
+ end
98
+
99
+ def resolve_el(target)
100
+ if target.is_a?(String)
101
+ `document.querySelector(#{target})`
102
+ else
103
+ target
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # Friendly top-level alias (the base class users subclass).
112
+ OpalComponent = OpalVite::Concerns::V1::Component
@@ -12,3 +12,4 @@ require 'opal_vite/concerns/v1/base64_helpers'
12
12
  require 'opal_vite/concerns/v1/debug_helpers'
13
13
  require 'opal_vite/concerns/v1/action_cable_helpers'
14
14
  require 'opal_vite/concerns/v1/turbo_helpers'
15
+ require 'opal_vite/concerns/v1/component'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-vite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.12
4
+ version: 0.3.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - stofu1234
@@ -122,6 +122,7 @@ files:
122
122
  - opal/opal_vite/concerns/v1.rb
123
123
  - opal/opal_vite/concerns/v1/action_cable_helpers.rb
124
124
  - opal/opal_vite/concerns/v1/base64_helpers.rb
125
+ - opal/opal_vite/concerns/v1/component.rb
125
126
  - opal/opal_vite/concerns/v1/debug_helpers.rb
126
127
  - opal/opal_vite/concerns/v1/dom_helpers.rb
127
128
  - opal/opal_vite/concerns/v1/functional_component.rb