lifeform 0.3.0 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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