lifeform 0.11.0 → 0.12.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 +4 -4
- data/.rubocop.yml +19 -26
- data/Gemfile +1 -0
- data/Gemfile.lock +57 -30
- data/README.md +2 -15
- data/lib/lifeform/form.rb +35 -27
- data/lib/lifeform/libraries/default/button.rb +16 -15
- data/lib/lifeform/libraries/default/input.rb +26 -19
- data/lib/lifeform/libraries/default.rb +1 -1
- data/lib/lifeform/libraries/shoelace/button.rb +0 -2
- data/lib/lifeform/libraries/shoelace/input.rb +0 -2
- data/lib/lifeform/version.rb +1 -1
- data/lib/lifeform.rb +1 -12
- data/lifeform.gemspec +3 -3
- metadata +22 -10
- data/lib/lifeform/capturing_renderable.rb +0 -17
- data/lib/lifeform/phlex_renderable.rb +0 -73
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b73201515b3b27e577ed299923e2e2b0dbe4e8597761947c47d4c67eb3d2a8c0
|
|
4
|
+
data.tar.gz: 47f7c3d4bb4eb9f82c1f02ebd70066f2509cc1b0b685cd11f88377fb4ef2b7d4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ce0937077dbae812e9c88707f40c22815e3f72c95afa3d85717cc8957fb024f311f123cc487d2107fba117129f756198e2aea346b1d6ff46e03afede3f4d574
|
|
7
|
+
data.tar.gz: 53b27483e4125eec6c6e9f5ca44f56702c9f2b2913523981f8ec94eae01726441288716e91381a545bd392fbe49d1bb85697955e7b59a02dd43a861be3076d63
|
data/.rubocop.yml
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
require:
|
|
2
|
+
- rubocop-bridgetown
|
|
2
3
|
- rubocop-minitest
|
|
3
4
|
- rubocop-rake
|
|
4
5
|
|
|
6
|
+
inherit_gem:
|
|
7
|
+
rubocop-bridgetown: .rubocop.yml
|
|
8
|
+
|
|
5
9
|
AllCops:
|
|
6
10
|
TargetRubyVersion: 3.0
|
|
7
11
|
NewCops: enable
|
|
12
|
+
|
|
8
13
|
Exclude:
|
|
9
|
-
-
|
|
14
|
+
- .gitignore
|
|
15
|
+
- .rubocop.yml
|
|
16
|
+
- "*.gemspec"
|
|
17
|
+
|
|
18
|
+
- Gemfile.lock
|
|
19
|
+
- CHANGELOG.md
|
|
20
|
+
- LICENSE.txt
|
|
21
|
+
- README.md
|
|
22
|
+
- Rakefile
|
|
23
|
+
|
|
24
|
+
- bin/**/*
|
|
25
|
+
- test/fixtures/**/*
|
|
26
|
+
- vendor/**/*
|
|
10
27
|
|
|
11
|
-
|
|
28
|
+
Layout/MultilineBlockLayout:
|
|
12
29
|
Enabled: false
|
|
13
30
|
|
|
14
31
|
Metrics/AbcSize:
|
|
@@ -20,32 +37,8 @@ Metrics/ClassLength:
|
|
|
20
37
|
- test/**/*.rb
|
|
21
38
|
|
|
22
39
|
Metrics/MethodLength:
|
|
23
|
-
Max: 20
|
|
24
40
|
Exclude:
|
|
25
41
|
- test/**/*.rb
|
|
26
42
|
|
|
27
|
-
Style/Documentation:
|
|
28
|
-
Enabled: false
|
|
29
|
-
|
|
30
|
-
Style/Lambda:
|
|
31
|
-
Enabled: false
|
|
32
|
-
|
|
33
|
-
Style/LambdaCall:
|
|
34
|
-
Enabled: false
|
|
35
|
-
|
|
36
|
-
Style/MultilineBlockChain:
|
|
37
|
-
Enabled: false
|
|
38
|
-
|
|
39
|
-
Style/StringLiterals:
|
|
40
|
-
Enabled: true
|
|
41
|
-
EnforcedStyle: double_quotes
|
|
42
|
-
|
|
43
|
-
Style/StringLiteralsInInterpolation:
|
|
44
|
-
Enabled: true
|
|
45
|
-
EnforcedStyle: double_quotes
|
|
46
|
-
|
|
47
|
-
Style/ParallelAssignment:
|
|
48
|
-
Enabled: false
|
|
49
|
-
|
|
50
43
|
Layout/LineLength:
|
|
51
44
|
Max: 120
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
lifeform (0.
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
lifeform (0.12.0)
|
|
5
|
+
hash_with_dot_access (>= 1.2)
|
|
6
|
+
sequel (>= 5.72)
|
|
7
|
+
streamlined (>= 0.2.0)
|
|
7
8
|
zeitwerk (~> 2.5)
|
|
8
9
|
|
|
9
10
|
GEM
|
|
10
11
|
remote: https://rubygems.org/
|
|
11
12
|
specs:
|
|
12
|
-
activesupport (7.
|
|
13
|
+
activesupport (7.1.1)
|
|
14
|
+
base64
|
|
15
|
+
bigdecimal
|
|
13
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
17
|
+
connection_pool (>= 2.2.5)
|
|
18
|
+
drb
|
|
14
19
|
i18n (>= 1.6, < 2)
|
|
15
20
|
minitest (>= 5.1)
|
|
21
|
+
mutex_m
|
|
16
22
|
tzinfo (~> 2.0)
|
|
17
23
|
ansi (1.5.0)
|
|
18
24
|
ast (2.4.2)
|
|
19
25
|
backport (1.2.0)
|
|
26
|
+
base64 (0.1.1)
|
|
20
27
|
benchmark (0.2.1)
|
|
28
|
+
bigdecimal (3.1.4)
|
|
21
29
|
builder (3.2.4)
|
|
22
|
-
cgi (0.3.6)
|
|
23
30
|
concurrent-ruby (1.2.2)
|
|
31
|
+
connection_pool (2.4.1)
|
|
24
32
|
diff-lcs (1.5.0)
|
|
33
|
+
drb (2.1.1)
|
|
34
|
+
ruby2_keywords
|
|
25
35
|
e2mmap (0.1.0)
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
erubi (1.12.0)
|
|
37
|
+
hash_with_dot_access (1.2.0)
|
|
38
|
+
activesupport (>= 5.0.0, < 8.0)
|
|
28
39
|
i18n (1.14.1)
|
|
29
40
|
concurrent-ruby (~> 1.0)
|
|
30
41
|
jaro_winkler (1.5.6)
|
|
@@ -33,51 +44,63 @@ GEM
|
|
|
33
44
|
rexml
|
|
34
45
|
kramdown-parser-gfm (1.1.0)
|
|
35
46
|
kramdown (~> 2.0)
|
|
36
|
-
|
|
37
|
-
minitest
|
|
47
|
+
language_server-protocol (3.17.0.3)
|
|
48
|
+
minitest (5.20.0)
|
|
49
|
+
minitest-reporters (1.6.1)
|
|
38
50
|
ansi
|
|
39
51
|
builder
|
|
40
52
|
minitest (>= 5.0)
|
|
41
53
|
ruby-progressbar
|
|
42
|
-
|
|
54
|
+
mutex_m (0.1.2)
|
|
55
|
+
nokogiri (1.15.4-arm64-darwin)
|
|
43
56
|
racc (~> 1.4)
|
|
44
|
-
nokogiri (1.15.
|
|
57
|
+
nokogiri (1.15.4-x86_64-linux)
|
|
45
58
|
racc (~> 1.4)
|
|
46
59
|
parallel (1.23.0)
|
|
47
|
-
parser (3.2.2.
|
|
60
|
+
parser (3.2.2.4)
|
|
48
61
|
ast (~> 2.4.1)
|
|
49
62
|
racc
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
racc (1.7.1)
|
|
55
|
-
rails-dom-testing (2.0.3)
|
|
56
|
-
activesupport (>= 4.2.0)
|
|
63
|
+
racc (1.7.3)
|
|
64
|
+
rails-dom-testing (2.2.0)
|
|
65
|
+
activesupport (>= 5.0.0)
|
|
66
|
+
minitest
|
|
57
67
|
nokogiri (>= 1.6)
|
|
58
68
|
rainbow (3.1.1)
|
|
59
|
-
rake (13.0
|
|
60
|
-
regexp_parser (2.8.
|
|
69
|
+
rake (13.1.0)
|
|
70
|
+
regexp_parser (2.8.2)
|
|
61
71
|
reverse_markdown (2.1.1)
|
|
62
72
|
nokogiri
|
|
63
|
-
rexml (3.2.
|
|
64
|
-
rubocop (1.
|
|
73
|
+
rexml (3.2.6)
|
|
74
|
+
rubocop (1.57.2)
|
|
65
75
|
json (~> 2.3)
|
|
76
|
+
language_server-protocol (>= 3.17.0)
|
|
66
77
|
parallel (~> 1.10)
|
|
67
|
-
parser (>= 3.2.2.
|
|
78
|
+
parser (>= 3.2.2.4)
|
|
68
79
|
rainbow (>= 2.2.2, < 4.0)
|
|
69
80
|
regexp_parser (>= 1.8, < 3.0)
|
|
70
81
|
rexml (>= 3.2.5, < 4.0)
|
|
71
|
-
rubocop-ast (>= 1.28.
|
|
82
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
|
72
83
|
ruby-progressbar (~> 1.7)
|
|
73
84
|
unicode-display_width (>= 2.4.0, < 3.0)
|
|
74
|
-
rubocop-ast (1.
|
|
85
|
+
rubocop-ast (1.30.0)
|
|
75
86
|
parser (>= 3.2.1.0)
|
|
87
|
+
rubocop-bridgetown (0.4.0)
|
|
88
|
+
rubocop (~> 1.23)
|
|
89
|
+
rubocop-performance (~> 1.12)
|
|
76
90
|
rubocop-minitest (0.20.1)
|
|
77
91
|
rubocop (>= 0.90, < 2.0)
|
|
92
|
+
rubocop-performance (1.19.1)
|
|
93
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
94
|
+
rubocop-ast (>= 0.4.0)
|
|
78
95
|
rubocop-rake (0.6.0)
|
|
79
96
|
rubocop (~> 1.0)
|
|
80
97
|
ruby-progressbar (1.13.0)
|
|
98
|
+
ruby2_keywords (0.0.5)
|
|
99
|
+
sequel (5.74.0)
|
|
100
|
+
bigdecimal
|
|
101
|
+
serbea (2.1.0)
|
|
102
|
+
erubi (>= 1.10)
|
|
103
|
+
tilt (~> 2.0)
|
|
81
104
|
solargraph (0.45.0)
|
|
82
105
|
backport (~> 1.2)
|
|
83
106
|
benchmark
|
|
@@ -93,13 +116,16 @@ GEM
|
|
|
93
116
|
thor (~> 1.0)
|
|
94
117
|
tilt (~> 2.0)
|
|
95
118
|
yard (~> 0.9, >= 0.9.24)
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
streamlined (0.2.0)
|
|
120
|
+
serbea (>= 2.1)
|
|
121
|
+
zeitwerk (~> 2.5)
|
|
122
|
+
thor (1.3.0)
|
|
123
|
+
tilt (2.3.0)
|
|
98
124
|
tzinfo (2.0.6)
|
|
99
125
|
concurrent-ruby (~> 1.0)
|
|
100
|
-
unicode-display_width (2.
|
|
126
|
+
unicode-display_width (2.5.0)
|
|
101
127
|
yard (0.9.34)
|
|
102
|
-
zeitwerk (2.6.
|
|
128
|
+
zeitwerk (2.6.12)
|
|
103
129
|
|
|
104
130
|
PLATFORMS
|
|
105
131
|
arm64-darwin-21
|
|
@@ -112,6 +138,7 @@ DEPENDENCIES
|
|
|
112
138
|
rails-dom-testing (~> 2.0)
|
|
113
139
|
rake (~> 13.0)
|
|
114
140
|
rubocop (~> 1.21)
|
|
141
|
+
rubocop-bridgetown (~> 0.4)
|
|
115
142
|
rubocop-minitest (~> 0.20.0)
|
|
116
143
|
rubocop-rake (~> 0.6.0)
|
|
117
144
|
solargraph (~> 0.45.0)
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Lifeform
|
|
2
2
|
|
|
3
|
-
Component-centric form object rendering for Ruby.
|
|
3
|
+
Component-centric form object rendering for Ruby. Rails and Bridgetown both supported.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,8 +10,6 @@ Add Lifeform to your application's Gemfile by running:
|
|
|
10
10
|
bundle add lifeform
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
If you're in a Rails app, you'll want to `bundle add phlex-rails` as well for Action View rendering support.
|
|
14
|
-
|
|
15
13
|
## Usage
|
|
16
14
|
|
|
17
15
|
Full documentation coming as the library begins to mature. TL;DR:
|
|
@@ -38,17 +36,6 @@ And a template rendering of:
|
|
|
38
36
|
<% end %>
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
```rb
|
|
42
|
-
# Or Phlex:
|
|
43
|
-
def template
|
|
44
|
-
render TestForm.new(url: "/path") do |f|
|
|
45
|
-
render f.field(:occupation)
|
|
46
|
-
render f.field(:age, value: 47)
|
|
47
|
-
render f.field(:submit)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
```
|
|
51
|
-
|
|
52
39
|
You get the following HTML output:
|
|
53
40
|
|
|
54
41
|
```html
|
|
@@ -69,7 +56,7 @@ You get the following HTML output:
|
|
|
69
56
|
|
|
70
57
|
Nested names based on models (aka `profile[name]`) and inferred action paths are supported as well.
|
|
71
58
|
|
|
72
|
-
Multiple component libraries and input types—and easy customizability
|
|
59
|
+
Multiple component libraries and input types—and easy customizability using string interpolation templates and helpers—are a fundamental aspect of the architecture of Lifeform. Until further docs have been written, you can look in `lib/lifeform/libraries` to see how some initial field types were constructed.
|
|
73
60
|
|
|
74
61
|
### Automatic Field Rendering
|
|
75
62
|
|
data/lib/lifeform/form.rb
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
require "
|
|
3
|
+
require "hash_with_dot_access"
|
|
4
|
+
require "sequel/model/default_inflections"
|
|
5
|
+
require "sequel/model/inflections"
|
|
5
6
|
|
|
6
7
|
module Lifeform
|
|
7
8
|
FieldDefinition = Struct.new(:type, :library, :parameters)
|
|
8
9
|
|
|
9
10
|
# A form object which stores field definitions and can be rendered as a component
|
|
10
|
-
class Form
|
|
11
|
-
include
|
|
11
|
+
class Form
|
|
12
|
+
include Streamlined::Renderable
|
|
13
|
+
extend Sequel::Inflections
|
|
14
|
+
|
|
12
15
|
MODEL_PATH_HELPER = :polymorphic_path
|
|
13
16
|
|
|
14
17
|
class << self
|
|
@@ -20,13 +23,13 @@ module Lifeform
|
|
|
20
23
|
# Helper to point to `I18n.t` method
|
|
21
24
|
def t(...) = I18n.t(...)
|
|
22
25
|
|
|
23
|
-
def configuration = @configuration ||=
|
|
26
|
+
def configuration = @configuration ||= HashWithDotAccess::Hash.new
|
|
24
27
|
|
|
25
28
|
# @param block [Proc, nil]
|
|
26
29
|
# @return [Hash<Symbol, FieldDefinition>]
|
|
27
30
|
def fields(&block)
|
|
28
31
|
@fields ||= {}
|
|
29
|
-
@fields_setup_block = block if
|
|
32
|
+
@fields_setup_block = block if block
|
|
30
33
|
|
|
31
34
|
@fields
|
|
32
35
|
end
|
|
@@ -41,7 +44,7 @@ module Lifeform
|
|
|
41
44
|
|
|
42
45
|
def field(name, type: :text, library: self.library, **parameters)
|
|
43
46
|
parameters[:name] = name.to_sym
|
|
44
|
-
fields[name] = FieldDefinition.new(type, Libraries.const_get(library
|
|
47
|
+
fields[name] = FieldDefinition.new(type, Libraries.const_get(camelize(library)), parameters)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
def subform(name, klass, parent_name: nil)
|
|
@@ -92,7 +95,7 @@ module Lifeform
|
|
|
92
95
|
model.to_model.model_name.param_key
|
|
93
96
|
else
|
|
94
97
|
# Or just use basic underscore
|
|
95
|
-
model.class.name.
|
|
98
|
+
underscore(model.class.name).tr("/", "_")
|
|
96
99
|
end
|
|
97
100
|
end
|
|
98
101
|
|
|
@@ -126,7 +129,7 @@ module Lifeform
|
|
|
126
129
|
)
|
|
127
130
|
@model, @url, @library_name, @parameters, @emit_form_tag, @parent_name =
|
|
128
131
|
model, url, library, parameters, emit_form_tag, parent_name
|
|
129
|
-
@library = Libraries.const_get(@library_name
|
|
132
|
+
@library = Libraries.const_get(self.class.send(:camelize, @library_name))
|
|
130
133
|
@subform_instances = {}
|
|
131
134
|
|
|
132
135
|
self.class.initialize_field_definitions!
|
|
@@ -139,25 +142,23 @@ module Lifeform
|
|
|
139
142
|
def verify_method
|
|
140
143
|
return if %w[get post].include?(parameters[:method].to_s.downcase)
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
def initialize(method:)
|
|
144
|
-
@method = method
|
|
145
|
-
end
|
|
145
|
+
method_value = @parameters[:method].to_s.downcase
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
@method_tag = -> {
|
|
148
|
+
<<~HTML
|
|
149
|
+
<input type="hidden" name="_method" value="#{text -> { method_value }}" autocomplete="off">
|
|
150
|
+
HTML
|
|
151
|
+
}
|
|
151
152
|
|
|
152
153
|
parameters[:method] = :post
|
|
153
154
|
end
|
|
154
155
|
|
|
155
|
-
def add_authenticity_token
|
|
156
|
+
def add_authenticity_token
|
|
156
157
|
if helpers.respond_to?(:token_tag, true) # Rails
|
|
157
158
|
helpers.send(:token_tag, nil, form_options: {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
action: parameters[:action].to_s,
|
|
160
|
+
method: parameters[:method].to_s.downcase,
|
|
161
|
+
})
|
|
161
162
|
elsif helpers.respond_to?(:csrf_tag, true) # Roda
|
|
162
163
|
helpers.send(:csrf_tag, parameters[:action].to_s, @method.to_s)
|
|
163
164
|
else
|
|
@@ -191,13 +192,20 @@ module Lifeform
|
|
|
191
192
|
form_tag = library::FORM_TAG
|
|
192
193
|
parameters[:action] ||= url || (model ? helpers.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
|
|
193
194
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
|
|
196
|
+
<#{form_tag} #{html_attributes attributes}>
|
|
197
|
+
#{add_authenticity_token unless parameters[:method].to_s.casecmp("get").zero?}
|
|
198
|
+
#{@method_tag&.() || ""}
|
|
199
|
+
#{block ? capture(self, &block) : auto_render_fields}
|
|
200
|
+
</#{form_tag}>
|
|
201
|
+
HTML
|
|
202
|
+
}
|
|
199
203
|
end
|
|
200
204
|
|
|
201
|
-
def auto_render_fields = self.class.fields
|
|
205
|
+
def auto_render_fields = html_map(self.class.fields) { |k, _v| render(field(k)) }
|
|
206
|
+
|
|
207
|
+
def render(field_object)
|
|
208
|
+
field_object.render_in(helpers || self)
|
|
209
|
+
end
|
|
202
210
|
end
|
|
203
211
|
end
|
|
@@ -3,17 +3,14 @@
|
|
|
3
3
|
module Lifeform
|
|
4
4
|
module Libraries
|
|
5
5
|
class Default
|
|
6
|
-
class Button
|
|
7
|
-
|
|
8
|
-
include CapturingRenderable
|
|
6
|
+
class Button
|
|
7
|
+
include Streamlined::Renderable
|
|
9
8
|
|
|
10
9
|
attr_reader :form, :field_definition, :attributes
|
|
11
10
|
|
|
12
11
|
WRAPPER_TAG = :form_button
|
|
13
12
|
BUTTON_TAG = :button
|
|
14
13
|
|
|
15
|
-
register_element WRAPPER_TAG
|
|
16
|
-
|
|
17
14
|
def initialize(form, field_definition, **attributes)
|
|
18
15
|
@form = form
|
|
19
16
|
@field_definition = field_definition
|
|
@@ -24,20 +21,24 @@ module Lifeform
|
|
|
24
21
|
end
|
|
25
22
|
|
|
26
23
|
def template(&block)
|
|
27
|
-
return if !@if.nil? && !@if
|
|
24
|
+
return "" if !@if.nil? && !@if
|
|
25
|
+
|
|
26
|
+
wrapper_tag = dashed self.class.const_get(:WRAPPER_TAG)
|
|
27
|
+
button_tag = dashed self.class.const_get(:BUTTON_TAG)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
button_tag = self.class.const_get(:BUTTON_TAG)
|
|
29
|
+
label_text = block ? capture(self, &block) : @label.is_a?(Proc) ? @label.pipe : @label # rubocop:disable Style/NestedTernaryOperator
|
|
31
30
|
|
|
32
|
-
field_body =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
yield_content(&block)
|
|
36
|
-
end
|
|
31
|
+
field_body = html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
|
|
32
|
+
<#{button_tag}#{html_attributes @attributes, prefix_space: true}>#{text -> { label_text }}</#{button_tag}>
|
|
33
|
+
HTML
|
|
37
34
|
}
|
|
38
|
-
return field_body.() unless wrapper_tag
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
return field_body unless wrapper_tag
|
|
37
|
+
|
|
38
|
+
html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
|
|
39
|
+
<#{wrapper_tag} #{html_attributes name: @attributes[:name]}>#{field_body}</#{wrapper_tag}>
|
|
40
|
+
HTML
|
|
41
|
+
}
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
end
|
|
@@ -3,17 +3,14 @@
|
|
|
3
3
|
module Lifeform
|
|
4
4
|
module Libraries
|
|
5
5
|
class Default
|
|
6
|
-
class Input
|
|
7
|
-
|
|
8
|
-
include CapturingRenderable
|
|
6
|
+
class Input
|
|
7
|
+
include Streamlined::Renderable
|
|
9
8
|
|
|
10
9
|
attr_reader :form, :field_definition, :attributes
|
|
11
10
|
|
|
12
11
|
WRAPPER_TAG = :form_field
|
|
13
12
|
INPUT_TAG = :input
|
|
14
13
|
|
|
15
|
-
register_element WRAPPER_TAG
|
|
16
|
-
|
|
17
14
|
def initialize(form, field_definition, **attributes)
|
|
18
15
|
@form = form
|
|
19
16
|
@field_definition = field_definition
|
|
@@ -30,7 +27,8 @@ module Lifeform
|
|
|
30
27
|
@if = attributes.delete(:if)
|
|
31
28
|
attributes[:value] ||= value_for_model if form.model
|
|
32
29
|
attributes[:name] = "#{model_name}[#{attributes[:name]}]" if @model
|
|
33
|
-
|
|
30
|
+
# TODO: validate if this is enough
|
|
31
|
+
attributes[:id] ||= attributes[:name].tr("[]", "_").gsub("__", "_").chomp("_") if attributes[:name]
|
|
34
32
|
@label = handle_labels if attributes[:label]
|
|
35
33
|
end
|
|
36
34
|
|
|
@@ -43,30 +41,39 @@ module Lifeform
|
|
|
43
41
|
def value_for_model = @model.send(attributes[:name])
|
|
44
42
|
|
|
45
43
|
def handle_labels
|
|
46
|
-
label_text = attributes[:label].
|
|
44
|
+
label_text = attributes[:label].is_a?(Proc) ? attributes[:label].pipe : attributes[:label]
|
|
47
45
|
label_name = (attributes[:id] || attributes[:name]).to_s
|
|
48
46
|
|
|
49
47
|
@attributes = attributes.filter_map { |k, v| [k, v] unless k == :label }.to_h
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
label
|
|
49
|
+
-> { <<~HTML
|
|
50
|
+
<label for="#{text -> { label_name }}">#{text -> { label_text }}</label>
|
|
51
|
+
HTML
|
|
53
52
|
}
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
def template(&block)
|
|
57
|
-
return if !@if.nil? && !@if
|
|
55
|
+
def template(&block) # rubocop:disable Metrics/AbcSize
|
|
56
|
+
return "" if !@if.nil? && !@if
|
|
58
57
|
|
|
59
|
-
wrapper_tag = self.class.const_get(:WRAPPER_TAG)
|
|
60
|
-
input_tag = self.class.const_get(:INPUT_TAG)
|
|
58
|
+
wrapper_tag = dashed self.class.const_get(:WRAPPER_TAG)
|
|
59
|
+
input_tag = dashed self.class.const_get(:INPUT_TAG)
|
|
60
|
+
closing_tag = input_tag != "input"
|
|
61
61
|
|
|
62
|
-
field_body =
|
|
63
|
-
@label
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
field_body = html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
|
|
63
|
+
#{html(@label || -> {}).to_s.strip}
|
|
64
|
+
<#{input_tag} #{html_attributes type: @field_type.to_s, **@attributes}>#{
|
|
65
|
+
"</#{input_tag}>" if closing_tag
|
|
66
|
+
}
|
|
67
|
+
#{html -> { capture(self, &block) } if block}
|
|
68
|
+
HTML
|
|
66
69
|
}
|
|
67
|
-
return field_body.() unless wrapper_tag
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
return field_body unless wrapper_tag
|
|
72
|
+
|
|
73
|
+
html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
|
|
74
|
+
<#{wrapper_tag} #{html_attributes name: @attributes[:name]}>#{field_body.to_s.strip}</#{wrapper_tag}>
|
|
75
|
+
HTML
|
|
76
|
+
}
|
|
70
77
|
end
|
|
71
78
|
end
|
|
72
79
|
end
|
|
@@ -10,7 +10,7 @@ module Lifeform
|
|
|
10
10
|
# @param attributes [Hash]
|
|
11
11
|
# @return [Input]
|
|
12
12
|
def self.object_for_field_definition(form, field_definition, attributes)
|
|
13
|
-
type_classname = field_definition[:type]
|
|
13
|
+
type_classname = Lifeform::Form.send(:camelize, field_definition[:type])
|
|
14
14
|
if const_defined?(type_classname)
|
|
15
15
|
const_get(type_classname)
|
|
16
16
|
else
|
data/lib/lifeform/version.rb
CHANGED
data/lib/lifeform.rb
CHANGED
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
require "active_support/core_ext/string/output_safety"
|
|
5
|
-
|
|
3
|
+
require "streamlined"
|
|
6
4
|
require "zeitwerk"
|
|
7
5
|
loader = Zeitwerk::Loader.for_gem
|
|
8
6
|
loader.setup
|
|
9
7
|
|
|
10
8
|
module Lifeform
|
|
11
9
|
class Error < StandardError; end
|
|
12
|
-
|
|
13
|
-
module RefineProcToString
|
|
14
|
-
refine Proc do
|
|
15
|
-
def to_s
|
|
16
|
-
call.to_s
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
10
|
end
|
|
21
11
|
|
|
22
12
|
if defined?(Bridgetown)
|
|
@@ -24,6 +14,5 @@ if defined?(Bridgetown)
|
|
|
24
14
|
raise "The Lifeform support for Bridgetown requires v1.2 or newer" if Bridgetown::VERSION.to_f < 1.2
|
|
25
15
|
|
|
26
16
|
Bridgetown.initializer :lifeform do # |config|
|
|
27
|
-
require "lifeform/phlex_renderable" unless Phlex::HTML.instance_methods.include?(:render_in)
|
|
28
17
|
end
|
|
29
18
|
end
|
data/lifeform.gemspec
CHANGED
|
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
end
|
|
24
24
|
spec.require_paths = ["lib"]
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
spec.add_dependency "
|
|
28
|
-
spec.add_dependency "
|
|
26
|
+
spec.add_dependency "hash_with_dot_access", ">= 1.2"
|
|
27
|
+
spec.add_dependency "sequel", ">= 5.72"
|
|
28
|
+
spec.add_dependency "streamlined", ">= 0.2.0"
|
|
29
29
|
spec.add_dependency "zeitwerk", "~> 2.5"
|
|
30
30
|
end
|
metadata
CHANGED
|
@@ -1,43 +1,57 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lifeform
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bridgetown Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-11-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: hash_with_dot_access
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '1.2'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '1.2'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: sequel
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '5.72'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '5.72'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: streamlined
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.2.0
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.2.0
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: zeitwerk
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,7 +86,6 @@ files:
|
|
|
72
86
|
- bin/rubocop
|
|
73
87
|
- bin/setup
|
|
74
88
|
- lib/lifeform.rb
|
|
75
|
-
- lib/lifeform/capturing_renderable.rb
|
|
76
89
|
- lib/lifeform/form.rb
|
|
77
90
|
- lib/lifeform/libraries/default.rb
|
|
78
91
|
- lib/lifeform/libraries/default/button.rb
|
|
@@ -82,7 +95,6 @@ files:
|
|
|
82
95
|
- lib/lifeform/libraries/shoelace/button.rb
|
|
83
96
|
- lib/lifeform/libraries/shoelace/input.rb
|
|
84
97
|
- lib/lifeform/libraries/shoelace/submit_button.rb
|
|
85
|
-
- lib/lifeform/phlex_renderable.rb
|
|
86
98
|
- lib/lifeform/version.rb
|
|
87
99
|
- lifeform.gemspec
|
|
88
100
|
homepage: https://github.com/bridgetownrb/lifeform
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Lifeform
|
|
4
|
-
module CapturingRenderable
|
|
5
|
-
# NOTE: the previous `with_output_buffer` stuff is for some reason incompatible with Serbea.
|
|
6
|
-
# So we'll use a simpler capture.
|
|
7
|
-
def render_in(view_context, &block)
|
|
8
|
-
if block
|
|
9
|
-
call(view_context: view_context) do |*args, **kwargs|
|
|
10
|
-
unsafe_raw(view_context.capture(*args, **kwargs, &block))
|
|
11
|
-
end.html_safe
|
|
12
|
-
else
|
|
13
|
-
call(view_context: view_context).html_safe
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Bridgetown-specific workaround that got copied over from the phlex-rails gem (for now)
|
|
4
|
-
module Lifeform
|
|
5
|
-
module PhlexRenderable
|
|
6
|
-
def helpers
|
|
7
|
-
@_view_context
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def render(renderable, *args, **kwargs, &block)
|
|
11
|
-
return super if renderable.is_a?(Phlex::HTML)
|
|
12
|
-
return super if renderable.is_a?(Class) && renderable < Phlex::HTML
|
|
13
|
-
|
|
14
|
-
@_target << @_view_context.render(renderable, *args, **kwargs, &block)
|
|
15
|
-
|
|
16
|
-
nil
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def render_in(view_context, &block)
|
|
20
|
-
if block_given?
|
|
21
|
-
call(view_context: view_context) do |*args|
|
|
22
|
-
view_context.with_output_buffer(self) do
|
|
23
|
-
original_length = @_target.length
|
|
24
|
-
output = yield(*args)
|
|
25
|
-
unchanged = (original_length == @_target.length)
|
|
26
|
-
|
|
27
|
-
if unchanged
|
|
28
|
-
if output.is_a?(ActiveSupport::SafeBuffer)
|
|
29
|
-
unsafe_raw(output)
|
|
30
|
-
else
|
|
31
|
-
text(output)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end.html_safe
|
|
36
|
-
else
|
|
37
|
-
call(view_context: view_context).html_safe
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def safe_append=(value)
|
|
42
|
-
return unless value
|
|
43
|
-
|
|
44
|
-
@_target << case value
|
|
45
|
-
when String then value
|
|
46
|
-
when Symbol then value.name
|
|
47
|
-
else value.to_s
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def append=(value)
|
|
52
|
-
return unless value
|
|
53
|
-
|
|
54
|
-
if value.html_safe?
|
|
55
|
-
self.safe_append = value
|
|
56
|
-
else
|
|
57
|
-
@_target << case value
|
|
58
|
-
when String then ERB::Util.html_escape(value)
|
|
59
|
-
when Symbol then ERB::Util.html_escape(value.name)
|
|
60
|
-
else ERB::Util.html_escape(value.to_s)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def capture = super.html_safe
|
|
66
|
-
|
|
67
|
-
# Trick ViewComponent into thinking we're a ViewComponent to fix rendering output
|
|
68
|
-
def set_original_view_context(view_context)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
Phlex::HTML.prepend(Lifeform::PhlexRenderable)
|