snabberb 0.1.0
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +37 -0
- data/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +167 -0
- data/Rakefile +10 -0
- data/examples/rack/Gemfile +8 -0
- data/examples/rack/Gemfile.lock +31 -0
- data/examples/rack/README.md +13 -0
- data/examples/rack/app/application.rb +68 -0
- data/examples/rack/config.ru +18 -0
- data/examples/rack/index.html.erb +11 -0
- data/lib/snabberb.rb +6 -0
- data/lib/snabberb/version.rb +5 -0
- data/opal/snabberb.rb +17 -0
- data/opal/snabberb/component.rb +148 -0
- data/opal/vendor/snabbdom-attributes.js +71 -0
- data/opal/vendor/snabbdom-class.js +29 -0
- data/opal/vendor/snabbdom-eventlisteners.js +99 -0
- data/opal/vendor/snabbdom-props.js +30 -0
- data/opal/vendor/snabbdom-style.js +90 -0
- data/opal/vendor/snabbdom-to-html.js +4960 -0
- data/opal/vendor/snabbdom.js +506 -0
- data/opal/vendor/tovnode.js +126 -0
- data/snabberb.gemspec +37 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: adebae58664968503236700933371f7d76003468056be676156f39c268edb88c
|
4
|
+
data.tar.gz: 41124f485907d7a84e537191ac8fad844f21beb009ddf7a1979a3d44e1b33522
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5038c8f60b03ea4bf7e2d3f636007ae4f393ced975fef43aa75bcc0abd6e97e530320dea6787e952a97d7bea238057b55927fd191044461f20533b23c06a93cc
|
7
|
+
data.tar.gz: 0c4f20f341244f14e64c88828d194f4ae582394910e65a10f63da781d229e721f7fbbf49e8d3f23d0d5ec4df52fae474c27f35d1d9f994b2cb874007afff700f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Layout/IndentFirstArrayElement:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Metrics/AbcSize:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Metrics/BlockLength:
|
8
|
+
Enabled: False
|
9
|
+
Metrics/LineLength:
|
10
|
+
Max: 120
|
11
|
+
|
12
|
+
Metrics/MethodLength:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Style/ClassVars:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Style/CommandLiteral:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/Documentation:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/EmptyCaseCondition:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/TrailingCommaInArguments:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/TrailingCommaInArrayLiteral:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/TrailingCommaInHashLiteral:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
AllCops:
|
37
|
+
TargetRubyVersion: 2.6
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Tobias Mao
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# Snabberb
|
2
|
+
|
3
|
+
Snabberb is a simple Ruby view framework built on [Opal](https://github.com/opal/opal) and [Snabbdom](https://github.com/snabbdom/snabbdom).
|
4
|
+
|
5
|
+
You can write reactive views in plain Ruby that compile to efficient Javascript.
|
6
|
+
|
7
|
+
## Inline Example
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require 'opal'
|
11
|
+
require 'snabberb'
|
12
|
+
|
13
|
+
class TextBox < Snabberb::Component
|
14
|
+
needs :text
|
15
|
+
needs :selected, default: false, store: true
|
16
|
+
|
17
|
+
def render
|
18
|
+
onclick = lambda do
|
19
|
+
store(:selected, !@selected)
|
20
|
+
end
|
21
|
+
|
22
|
+
style = {
|
23
|
+
cursor: 'pointer',
|
24
|
+
border: 'solid 1px rgba(0,0,0,0.2)',
|
25
|
+
}
|
26
|
+
|
27
|
+
style['background-color'] = 'lightblue' if @selected
|
28
|
+
|
29
|
+
h(:div, { style: style, on: { click: onclick } }, [
|
30
|
+
h(:div, @text)
|
31
|
+
])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Assuming you have a DOM element with ID=app
|
37
|
+
TextBox.attach('app', text: 'hello world')
|
38
|
+
|
39
|
+
# Or you can get the HTML string for isomorphic applications
|
40
|
+
TextBox.html(text: 'hello world')
|
41
|
+
```
|
42
|
+
|
43
|
+
## Examples
|
44
|
+
[Rack App](examples/rack)
|
45
|
+
|
46
|
+
## Usage
|
47
|
+
|
48
|
+
### Creating DOM Elements With h
|
49
|
+
|
50
|
+
Subclass Snabberb::Component and override #render to build divs using \#h.
|
51
|
+
|
52
|
+
Render should only return one root element.
|
53
|
+
|
54
|
+
\#h takes either a DOM symbol (:div, :span, :a, ...) or another Snabberb::Component class.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
...
|
58
|
+
class DomExample < Snabberb::Component
|
59
|
+
def render
|
60
|
+
h(:div)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ComponentExample < Snabberb::Component
|
65
|
+
def render
|
66
|
+
h(OtherComponent)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Like Snabbdom, \#h with DOM elements can take props which take the form of a dict.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
...
|
75
|
+
class PropsExample < Snabberb::Component
|
76
|
+
def render
|
77
|
+
h(:div, { style: { display: 'inline-block' }, class: { selected: true } })
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Components do not take props, instead they take [needs](#Needs) which are dependent arguments.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
...
|
86
|
+
class PassingNeedsExample < Snabberb::Component
|
87
|
+
def render
|
88
|
+
h(ChildComponent, need1: 1, need2: 2)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
\#h can also be nested with a child or multiple children.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
...
|
97
|
+
class NestedExample < Snabberb::Component
|
98
|
+
def render
|
99
|
+
h(:div, [
|
100
|
+
h(ChildComponent, need1: 1, need2: 2),
|
101
|
+
h(:div, { style: { width: '100px' } }, [
|
102
|
+
h(:div, 'hello'),
|
103
|
+
])
|
104
|
+
](
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
### Needs
|
110
|
+
|
111
|
+
Components can define needs which allow parent components to pass down arguments. They can also be stateful which allows changes to propogate easily throughout the application.
|
112
|
+
|
113
|
+
Needs are by default required. They can be set with default values. Needs are accesible with instance variables that are automatically set.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
...
|
117
|
+
class NeedsExample < Snabberb::Component
|
118
|
+
needs :name
|
119
|
+
needs :value, default: 0, store: true
|
120
|
+
|
121
|
+
def render
|
122
|
+
onclick = lambda do
|
123
|
+
store(:value, @value + 1)
|
124
|
+
end
|
125
|
+
|
126
|
+
h(:div, [
|
127
|
+
h(:div, @name),
|
128
|
+
h(:div, { on: { click: onclick} }, @value),
|
129
|
+
])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
When simple state changes must be tracked, a need can define store: true. This will use the stored value of this key which is set on the root node.
|
135
|
+
The precedence of need values is stored > passed needs > default value.
|
136
|
+
|
137
|
+
Needs can be set with #store which will trigger a view update. Snabberb uses Snabbdom to update the DOM, so only the differences in the DOM are changed.
|
138
|
+
|
139
|
+
## Installation
|
140
|
+
|
141
|
+
Add this line to your application's Gemfile:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
gem 'snabberb'
|
145
|
+
```
|
146
|
+
|
147
|
+
And then execute:
|
148
|
+
|
149
|
+
$ bundle
|
150
|
+
|
151
|
+
Or install it yourself as:
|
152
|
+
|
153
|
+
$ gem install snabberb
|
154
|
+
|
155
|
+
## Development
|
156
|
+
|
157
|
+
```
|
158
|
+
bundle install
|
159
|
+
bundle exec rake
|
160
|
+
```
|
161
|
+
## Contributing
|
162
|
+
|
163
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/tobymao/snabberb.
|
164
|
+
|
165
|
+
## License
|
166
|
+
|
167
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
snabberb (0.1.0)
|
5
|
+
opal (~> 1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.0)
|
11
|
+
c_lexer (2.5.3.0.0)
|
12
|
+
ast (~> 2.4.0)
|
13
|
+
parser (= 2.5.3.0)
|
14
|
+
opal (1.0.0)
|
15
|
+
ast (>= 2.3.0)
|
16
|
+
parser (= 2.5.3.0)
|
17
|
+
parser (2.5.3.0)
|
18
|
+
ast (~> 2.4.0)
|
19
|
+
rack (2.0.7)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
c_lexer
|
26
|
+
opal
|
27
|
+
rack
|
28
|
+
snabberb!
|
29
|
+
|
30
|
+
BUNDLED WITH
|
31
|
+
2.0.2
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'opal'
|
4
|
+
require 'snabberb'
|
5
|
+
|
6
|
+
class Row < Snabberb::Component
|
7
|
+
needs :index
|
8
|
+
needs :value
|
9
|
+
needs :selected_id, default: nil, store: true
|
10
|
+
|
11
|
+
def selected?
|
12
|
+
@index == @selected_id
|
13
|
+
end
|
14
|
+
|
15
|
+
def render
|
16
|
+
onclick = lambda do
|
17
|
+
store(:selected_id, selected? ? nil : @index)
|
18
|
+
end
|
19
|
+
|
20
|
+
style = {
|
21
|
+
cursor: 'pointer',
|
22
|
+
border: 'solid 1px rgba(0,0,0,0.2)',
|
23
|
+
}
|
24
|
+
|
25
|
+
style['background-color'] = 'lightblue' if selected?
|
26
|
+
|
27
|
+
h(:div, { style: style, on: { click: onclick } }, [
|
28
|
+
h(:div, @value)
|
29
|
+
])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Form < Snabberb::Component
|
34
|
+
needs :values, store: true
|
35
|
+
|
36
|
+
def render
|
37
|
+
input = h(:input, props: { type: 'text', value: @values.last })
|
38
|
+
|
39
|
+
onclick = lambda do |event|
|
40
|
+
value = input.JS['elm'].JS['value']
|
41
|
+
event.JS.preventDefault
|
42
|
+
store(:values, @values + [value])
|
43
|
+
end
|
44
|
+
|
45
|
+
h(:form, { style: { width: '300px' } }, [
|
46
|
+
input,
|
47
|
+
h(:button, { on: { click: onclick } }, 'Add row'),
|
48
|
+
])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Application < Snabberb::Component
|
53
|
+
needs :values, store: true
|
54
|
+
|
55
|
+
def render
|
56
|
+
rows = @values.map.with_index do |value, index|
|
57
|
+
h(Row, index: index, value: value)
|
58
|
+
end
|
59
|
+
|
60
|
+
h(:div, { style: { width: '100px' } }, [
|
61
|
+
h(:div, 'List of Fruits'),
|
62
|
+
*rows,
|
63
|
+
h(Form),
|
64
|
+
])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Application.attach('app', values: %w[apple banana cantaloupe])
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.require
|
5
|
+
|
6
|
+
# Instructions: bundle in this directory
|
7
|
+
# then run `bundle exec rackup` to start the server
|
8
|
+
# and browse to http://localhost:9292
|
9
|
+
|
10
|
+
# the directory where the code is (add to opal load path )
|
11
|
+
Opal.append_path('app')
|
12
|
+
|
13
|
+
run(Opal::SimpleServer.new do |s|
|
14
|
+
# the name of the ruby file to load. To use more files they must be required from here (see app)
|
15
|
+
s.main = 'application'
|
16
|
+
# need to set the index explicitly for opal server to pick it up
|
17
|
+
s.index_path = 'index.html.erb'
|
18
|
+
end)
|