lifeform 0.3.0 → 0.5

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: 43833cf5f9112ae7e24d2f14e24f41629e7a728740ee768383c7072e9484eb69
4
- data.tar.gz: db8424032dc11a96dc91ac8bb653e317bca8215de44c15664fed68c8b91f97de
3
+ metadata.gz: b554a393fe6d14365108e97b9da374e73da67f0d6728b8605f6d2ddea2f3e3f5
4
+ data.tar.gz: 5749f82de0a38dd41d7fd75245ed1cab66b0b2550bdabc722620e70c2345bf37
5
5
  SHA512:
6
- metadata.gz: edd2ea3eabdad15d8dc27d2da4cf07b04bc0d00302761ecef5562a0dd999ffa5badf9f7c9eb53a322a309dee7d75cf1475aa952f1f1944cb5ff065517f0f0120
7
- data.tar.gz: 33fb2e8b4276da626de9736cd568a6c34be23cade8eed0a0672cb1e909b5b911aca8136334d61e07d5b04937b450b7126066dfa1ebfb7c46d8af719d518147ec
6
+ metadata.gz: 86f68d5c0673570a0e549c2f68afb731b749ab305fb9a3a2f2013820389985cd3468b56263ec738ee113a90c49889cc755efd93427c985788af84e37b83b2d56
7
+ data.tar.gz: d6f72691ee444c44f78a8b8c1bfb7f93c10105398d77f4be6c593e96d85bf58ee031c7fe30f572a133ebeffdd3791aaed2b99438848e27e51431e4da048690a5
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.5.0] - 2022-06-10
6
+
7
+ ## [0.4.0] - 2022-06-08
8
+
9
+ - Add support for submit buttons
10
+
11
+ ## [0.3.0] - 2022-06-08
12
+
13
+ - Add automatic field rendering
14
+
5
15
  ## [0.2.0] - 2022-05-31
6
16
 
7
17
  - Fields now support content blocks, conditional rendering
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifeform (0.3.0)
4
+ lifeform (0.5)
5
5
  activesupport (>= 6.0)
6
6
  papercraft (~> 0.24)
7
7
  zeitwerk (~> 2.5)
data/README.md CHANGED
@@ -20,6 +20,8 @@ Given a form object of:
20
20
  class TestForm < Lifeform::Form
21
21
  field :occupation, label: "Your Job", id: "your-occupation", required: true
22
22
  field :age, library: :shoelace, label: "Your Age"
23
+
24
+ field :submit, type: :submit_button, label: "Save", class: "font-bold"
23
25
  end
24
26
  ```
25
27
 
@@ -29,6 +31,7 @@ And a template rendering of:
29
31
  <%= render TestForm.new(url: "/path") do %>
30
32
  <%= render f.field(:occupation) %>
31
33
  <%= render f.field(:age, value: 47) %>
34
+ <%= render f.field(:submit) %>
32
35
  <% end %>
33
36
  ```
34
37
 
@@ -44,6 +47,9 @@ You get the following HTML output:
44
47
  <form-field name="age">
45
48
  <sl-input type="text" label="Your Age" name="age" value="47" id="age"></sl-input>
46
49
  </form-field>
50
+ <form-button name="commit">
51
+ <button class="font-bold" name="commit" type="submit">Save</button>
52
+ </form-button>
47
53
  </form>
48
54
  ```
49
55
 
data/lib/lifeform/form.rb CHANGED
@@ -6,7 +6,7 @@ module Lifeform
6
6
  FieldDefinition = Struct.new(:type, :library, :parameters)
7
7
 
8
8
  # A form object which stores field definitions and can be rendered as a component
9
- class Form
9
+ class Form # rubocop:todo Metrics/ClassLength
10
10
  MODEL_PATH_HELPER = :polymorphic_path
11
11
 
12
12
  class << self
@@ -25,13 +25,21 @@ module Lifeform
25
25
  @fields ||= {}
26
26
  end
27
27
 
28
+ def subforms
29
+ @subforms ||= {}
30
+ end
31
+
28
32
  def field(name, type: :text, library: self.library, **parameters)
29
- parameters[:name] = name
33
+ parameters[:name] = name.to_sym
30
34
  fields[name] = FieldDefinition.new(type, Libraries.const_get(library.to_s.classify), parameters)
31
35
  end
32
36
 
37
+ def subform(name, klass, parent_name: nil)
38
+ subforms[name.to_sym] = { class: klass, parent_name: parent_name }
39
+ end
40
+
33
41
  def library(library_name = nil)
34
- @library = library_name if library_name
42
+ @library = library_name.to_sym if library_name
35
43
  @library ||= :default
36
44
  end
37
45
 
@@ -65,6 +73,17 @@ module Lifeform
65
73
 
66
74
  attributes
67
75
  end
76
+
77
+ def name_of_model(model)
78
+ return "" if model.nil?
79
+
80
+ if model.respond_to?(:to_model)
81
+ model.to_model.model_name.param_key
82
+ else
83
+ # Or just use basic underscore
84
+ model.class.name.underscore.tr("/", "_")
85
+ end
86
+ end
68
87
  end
69
88
 
70
89
  # @return [Object]
@@ -82,9 +101,16 @@ module Lifeform
82
101
  # @return [Boolean]
83
102
  attr_reader :emit_form_tag
84
103
 
85
- def initialize(model = nil, url: nil, library: self.class.library, emit_form_tag: true, **parameters)
86
- @model, @url, @library_name, @parameters, @emit_form_tag = model, url, library, parameters, emit_form_tag
104
+ # @return [Boolean]
105
+ attr_reader :parent_name
106
+
107
+ def initialize( # rubocop:disable Metrics/ParameterLists
108
+ model = nil, url: nil, library: self.class.library, emit_form_tag: true, parent_name: nil, **parameters
109
+ )
110
+ @model, @url, @library_name, @parameters, @emit_form_tag, @parent_name =
111
+ model, url, library, parameters, emit_form_tag, parent_name
87
112
  @library = Libraries.const_get(@library_name.to_s.classify)
113
+ @subform_instances = {}
88
114
 
89
115
  parameters[:method] ||= model.respond_to?(:persisted?) && model.persisted? ? :patch : :post
90
116
  parameters[:accept_charset] ||= "UTF-8"
@@ -119,7 +145,7 @@ module Lifeform
119
145
 
120
146
  def field(name, **field_parameters)
121
147
  # @type [FieldDefinition]
122
- field_definition = self.class.fields[name]
148
+ field_definition = self.class.fields[name.to_sym]
123
149
  # @type [Class<Libraries::Default>]
124
150
  field_library = field_definition.library
125
151
  field_library.object_for_field_definition(
@@ -127,6 +153,14 @@ module Lifeform
127
153
  )
128
154
  end
129
155
 
156
+ def subform(name, model = nil)
157
+ @subform_instances[name.to_sym] ||= self.class.subforms[name.to_sym][:class].new(
158
+ model,
159
+ emit_form_tag: false,
160
+ parent_name: self.class.subforms[name.to_sym][:parent_name] || self.class.name_of_model(self.model)
161
+ )
162
+ end
163
+
130
164
  def render_in(view_context, &block) # rubocop:disable Metrics
131
165
  form_tag = library::FORM_TAG
132
166
  parameters[:action] ||= url || (model ? view_context.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
@@ -134,7 +168,9 @@ module Lifeform
134
168
  content = if block
135
169
  view_context.capture(self, &block)
136
170
  else
137
- self.class.fields.map { |k, _v| field(k).render_in(self) }.join
171
+ self.class.fields.map { |k, _v| field(k).render_in(self) }.join.then do |renderings|
172
+ renderings.respond_to?(:html_safe) ? renderings.html_safe : renderings
173
+ end
138
174
  end
139
175
 
140
176
  return content unless emit_form_tag
@@ -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
@@ -30,10 +30,9 @@ module Lifeform
30
30
  end
31
31
 
32
32
  def model_name
33
- return @model.to_model.model_name.param_key if @model.respond_to?(:to_model)
33
+ name_of_model = @form.class.name_of_model(@model)
34
34
 
35
- # Or just use basic underscore
36
- @model.class.name.underscore.tr("/", "_")
35
+ form.parent_name ? "#{form.parent_name}[#{name_of_model}]" : name_of_model
37
36
  end
38
37
 
39
38
  def value_for_model
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lifeform
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5"
5
5
  end
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.3.0
4
+ version: '0.5'
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-06-08 00:00:00.000000000 Z
11
+ date: 2022-06-11 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