lifeform 0.1.0 → 0.4.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/CHANGELOG.md +5 -0
- data/Gemfile.lock +4 -1
- data/README.md +54 -1
- data/lib/lifeform/form.rb +17 -4
- data/lib/lifeform/libraries/default/button.rb +52 -0
- data/lib/lifeform/libraries/default/input.rb +15 -7
- data/lib/lifeform/libraries/default/submit_button.rb +16 -0
- data/lib/lifeform/libraries/default.rb +3 -0
- data/lib/lifeform/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f1e91a0e3977e9c1ee9bf2fadc00d427efa8f7fcf720ba0670905832e89e41c
|
4
|
+
data.tar.gz: 458c2edd232353260115c6eb794ebfcc7298696723e3ec5f49518ed8ccb68e19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8c0c7b398b5375cc50f0fb9d59ad5f759dcd05cd355fba4ed8c24c6c1e3e11c2447d888592f0c2ccb799a596bdfc23902fd822bd397cbf731c2ef77f453effc
|
7
|
+
data.tar.gz: e96679b59c1abae814f740ba190659eb29a4bae5c1fcc8809bff3336b138b13aded6f87d5bf0a2522ec86de80f8c98c1586eb8fcb81986edd242093294c0d1b0
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
lifeform (0.
|
4
|
+
lifeform (0.4.0)
|
5
5
|
activesupport (>= 6.0)
|
6
6
|
papercraft (~> 0.24)
|
7
7
|
zeitwerk (~> 2.5)
|
@@ -31,6 +31,8 @@ GEM
|
|
31
31
|
minitest (5.15.0)
|
32
32
|
nokogiri (1.13.6-arm64-darwin)
|
33
33
|
racc (~> 1.4)
|
34
|
+
nokogiri (1.13.6-x86_64-linux)
|
35
|
+
racc (~> 1.4)
|
34
36
|
papercraft (0.24)
|
35
37
|
escape_utils (~> 1.2.1)
|
36
38
|
kramdown (~> 2.3.1)
|
@@ -93,6 +95,7 @@ GEM
|
|
93
95
|
|
94
96
|
PLATFORMS
|
95
97
|
arm64-darwin-21
|
98
|
+
x86_64-linux
|
96
99
|
|
97
100
|
DEPENDENCIES
|
98
101
|
lifeform!
|
data/README.md
CHANGED
@@ -12,7 +12,60 @@ $ bundle add lifeform
|
|
12
12
|
|
13
13
|
## Usage
|
14
14
|
|
15
|
-
|
15
|
+
Full documentation coming as the library begins to mature. TL;DR:
|
16
|
+
|
17
|
+
Given a form object of:
|
18
|
+
|
19
|
+
```rb
|
20
|
+
class TestForm < Lifeform::Form
|
21
|
+
field :occupation, label: "Your Job", id: "your-occupation", required: true
|
22
|
+
field :age, library: :shoelace, label: "Your Age"
|
23
|
+
|
24
|
+
field :submit, type: :submit_button, label: "Save", class: "font-bold"
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
And a template rendering of:
|
29
|
+
|
30
|
+
```erb
|
31
|
+
<%= render TestForm.new(url: "/path") do %>
|
32
|
+
<%= render f.field(:occupation) %>
|
33
|
+
<%= render f.field(:age, value: 47) %>
|
34
|
+
<%= render f.field(:submit) %>
|
35
|
+
<% end %>
|
36
|
+
```
|
37
|
+
|
38
|
+
You get the following HTML output:
|
39
|
+
|
40
|
+
```html
|
41
|
+
<form method="post" accept-charset="UTF-8" action="/path">
|
42
|
+
<input type="hidden" name="authenticity_token" value="[token]" />
|
43
|
+
<form-field name="occupation">
|
44
|
+
<label for="your-occupation">Your Job</label>
|
45
|
+
<input type="text" id="your-occupation" required name="occupation" />
|
46
|
+
</form-field>
|
47
|
+
<form-field name="age">
|
48
|
+
<sl-input type="text" label="Your Age" name="age" value="47" id="age"></sl-input>
|
49
|
+
</form-field>
|
50
|
+
<form-button name="commit">
|
51
|
+
<button class="font-bold" name="commit" type="submit">Save</button>
|
52
|
+
</form-button>
|
53
|
+
</form>
|
54
|
+
```
|
55
|
+
|
56
|
+
Nested names based on models (aka `profile[name]`) and inferred action paths are supported as well.
|
57
|
+
|
58
|
+
Multiple component libraries and input types—and easy customizability via [Papercraft](https://github.com/digital-fabric/papercraft) templates—are a fundamental aspect of the architecture of Lifeform.
|
59
|
+
|
60
|
+
### Automatic Field Rendering
|
61
|
+
|
62
|
+
For simple forms, you can avoid the need to render fields individually in your template. Given the form example above, you could write in your template:
|
63
|
+
|
64
|
+
```erb
|
65
|
+
<%= render TestForm.new(url: "/path") %>
|
66
|
+
```
|
67
|
+
|
68
|
+
And the fields defined in `TestForm` would render out automatically (since no block was provided to the `render` method).
|
16
69
|
|
17
70
|
## Development
|
18
71
|
|
data/lib/lifeform/form.rb
CHANGED
@@ -10,6 +10,11 @@ module Lifeform
|
|
10
10
|
MODEL_PATH_HELPER = :polymorphic_path
|
11
11
|
|
12
12
|
class << self
|
13
|
+
def inherited(subclass)
|
14
|
+
super
|
15
|
+
subclass.library library
|
16
|
+
end
|
17
|
+
|
13
18
|
# Helper to point to `I18n.t` method
|
14
19
|
def t(...)
|
15
20
|
I18n.t(...)
|
@@ -26,7 +31,8 @@ module Lifeform
|
|
26
31
|
end
|
27
32
|
|
28
33
|
def library(library_name = nil)
|
29
|
-
@library
|
34
|
+
@library = library_name if library_name
|
35
|
+
@library ||= :default
|
30
36
|
end
|
31
37
|
|
32
38
|
def escape_value(value)
|
@@ -112,17 +118,24 @@ module Lifeform
|
|
112
118
|
end
|
113
119
|
|
114
120
|
def field(name, **field_parameters)
|
121
|
+
# @type [FieldDefinition]
|
115
122
|
field_definition = self.class.fields[name]
|
116
|
-
|
123
|
+
# @type [Class<Libraries::Default>]
|
124
|
+
field_library = field_definition.library
|
125
|
+
field_library.object_for_field_definition(
|
117
126
|
self, field_definition, self.class.parameters_to_attributes(field_parameters)
|
118
127
|
)
|
119
128
|
end
|
120
129
|
|
121
|
-
def render_in(view_context, &block) # rubocop:disable Metrics
|
130
|
+
def render_in(view_context, &block) # rubocop:disable Metrics
|
122
131
|
form_tag = library::FORM_TAG
|
123
132
|
parameters[:action] ||= url || (model ? view_context.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
|
124
133
|
|
125
|
-
content =
|
134
|
+
content = if block
|
135
|
+
view_context.capture(self, &block)
|
136
|
+
else
|
137
|
+
self.class.fields.map { |k, _v| field(k).render_in(self) }.join
|
138
|
+
end
|
126
139
|
|
127
140
|
return content unless emit_form_tag
|
128
141
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lifeform
|
4
|
+
module Libraries
|
5
|
+
class Default
|
6
|
+
class Button
|
7
|
+
attr_reader :form, :field_definition, :attributes
|
8
|
+
|
9
|
+
WRAPPER_TAG = :form_button
|
10
|
+
BUTTON_TAG = :button
|
11
|
+
|
12
|
+
def initialize(form, field_definition, **attributes)
|
13
|
+
@form = form
|
14
|
+
@field_definition = field_definition
|
15
|
+
@attributes = Lifeform::Form.parameters_to_attributes(field_definition.parameters).merge(attributes)
|
16
|
+
@if = @attributes.delete(:if)
|
17
|
+
@label = @attributes.delete(:label) || "Unlabeled Button"
|
18
|
+
@attributes[:type] ||= :button
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_in(view_context, &block)
|
22
|
+
@view_context = view_context
|
23
|
+
@content = block
|
24
|
+
return "" if !@if.nil? && !@if
|
25
|
+
|
26
|
+
template
|
27
|
+
end
|
28
|
+
|
29
|
+
def template # rubocop:disable Metrics/AbcSize
|
30
|
+
Papercraft.html do |wrapper_tag:, button_tag:, attributes:, field_data:|
|
31
|
+
field_body = proc {
|
32
|
+
send(button_tag, **attributes) do
|
33
|
+
emit field_data[:content] || field_data[:label]
|
34
|
+
end
|
35
|
+
}
|
36
|
+
next field_body.call unless wrapper_tag
|
37
|
+
|
38
|
+
send wrapper_tag, name: attributes[:name], &field_body
|
39
|
+
end.render(
|
40
|
+
wrapper_tag: self.class.const_get(:WRAPPER_TAG),
|
41
|
+
button_tag: self.class.const_get(:BUTTON_TAG),
|
42
|
+
attributes: attributes,
|
43
|
+
field_data: {
|
44
|
+
label: @label,
|
45
|
+
content: @content && @view_context.capture(&@content)
|
46
|
+
}
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -22,6 +22,7 @@ module Lifeform
|
|
22
22
|
@model = attributes.delete(:model)
|
23
23
|
@model = form.model if form.model && @model.nil?
|
24
24
|
|
25
|
+
@if = attributes.delete(:if)
|
25
26
|
attributes[:value] ||= value_for_model if form.model
|
26
27
|
attributes[:name] = "#{model_name}[#{attributes[:name]}]" if @model
|
27
28
|
attributes[:id] ||= attributes[:name].parameterize(separator: "_")
|
@@ -50,16 +51,20 @@ module Lifeform
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
|
-
def render_in(view_context)
|
54
|
+
def render_in(view_context, &block)
|
54
55
|
@view_context = view_context
|
56
|
+
@content = block
|
57
|
+
return "" if !@if.nil? && !@if
|
58
|
+
|
55
59
|
template
|
56
60
|
end
|
57
61
|
|
58
|
-
def template
|
59
|
-
Papercraft.html do |wrapper_tag:, input_tag:, attributes:,
|
62
|
+
def template # rubocop:disable Metrics/AbcSize
|
63
|
+
Papercraft.html do |wrapper_tag:, input_tag:, attributes:, field_data:|
|
60
64
|
field_body = proc {
|
61
|
-
emit(
|
62
|
-
send input_tag, type:
|
65
|
+
emit(field_data[:label]) if field_data[:label]
|
66
|
+
send input_tag, type: field_data[:type], **attributes
|
67
|
+
emit(field_data[:content]) if field_data[:content]
|
63
68
|
}
|
64
69
|
next field_body.call unless wrapper_tag
|
65
70
|
|
@@ -68,8 +73,11 @@ module Lifeform
|
|
68
73
|
wrapper_tag: self.class.const_get(:WRAPPER_TAG),
|
69
74
|
input_tag: self.class.const_get(:INPUT_TAG),
|
70
75
|
attributes: attributes,
|
71
|
-
|
72
|
-
|
76
|
+
field_data: {
|
77
|
+
type: @field_type,
|
78
|
+
label: @label,
|
79
|
+
content: @content && @view_context.capture(&@content)
|
80
|
+
}
|
73
81
|
)
|
74
82
|
end
|
75
83
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lifeform
|
4
|
+
module Libraries
|
5
|
+
class Default
|
6
|
+
class SubmitButton < Button
|
7
|
+
def initialize(form, field_definition, **attributes)
|
8
|
+
attributes[:name] ||= "commit"
|
9
|
+
attributes[:type] = :submit
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -5,6 +5,9 @@ module Lifeform
|
|
5
5
|
class Default
|
6
6
|
FORM_TAG = :form
|
7
7
|
|
8
|
+
# @param form [LifeForm::Form]
|
9
|
+
# @param field_definition [LifeForm::FieldDefinition]
|
10
|
+
# @param attributes [Hash]
|
8
11
|
# @return [Input]
|
9
12
|
def self.object_for_field_definition(form, field_definition, attributes)
|
10
13
|
type_classname = field_definition[:type].to_s.classify
|
data/lib/lifeform/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lifeform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.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: 2022-
|
11
|
+
date: 2022-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -74,7 +74,9 @@ files:
|
|
74
74
|
- lib/lifeform.rb
|
75
75
|
- lib/lifeform/form.rb
|
76
76
|
- lib/lifeform/libraries/default.rb
|
77
|
+
- lib/lifeform/libraries/default/button.rb
|
77
78
|
- lib/lifeform/libraries/default/input.rb
|
79
|
+
- lib/lifeform/libraries/default/submit_button.rb
|
78
80
|
- lib/lifeform/libraries/shoelace.rb
|
79
81
|
- lib/lifeform/libraries/shoelace/input.rb
|
80
82
|
- lib/lifeform/version.rb
|