action_form 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.
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionForm
4
+ # Provides DSL methods for defining form schemas and converting them to EasyParams
5
+ module SchemaDSL
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods # rubocop:disable Style/Documentation
11
+ def params_class
12
+ EasyParams::Base
13
+ end
14
+
15
+ def params_definition(*) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
16
+ schema = Class.new(params_class)
17
+ elements.each do |name, element_definition|
18
+ if element_definition < ActionForm::SubformsCollection
19
+ # nested forms are passed as a hash that looks like this:
20
+ # { "0" => { "id" => "1" }, "1" => { "id" => "2" } }
21
+ # it is coercing to an array of hashes:
22
+ # [['0', { "id" => "1" }], ['1', { "id" => "2" }]]
23
+ # we need to normalize it to an array of hashes:
24
+ # [ { "id" => "1" }, { "
25
+ # id" => "2" } ]
26
+ schema.each(:"#{name}_attributes", element_definition.subform_definition.params_definition,
27
+ normalize: ->(value) { value.flatten.select { |v| v.is_a?(Hash) } },
28
+ default: element_definition.default)
29
+ elsif element_definition < ActionForm::Subform
30
+ schema.has(:"#{name}_attributes", element_definition.params_definition, default: element_definition.default)
31
+ elsif element_definition < ActionForm::Element
32
+ options = element_definition.output_options.dup
33
+ method_name = options.delete(:type)
34
+ schema.public_send(method_name, name, **options)
35
+ end
36
+ end
37
+ schema
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionForm
4
+ # Subform class for ActionForm that handles nested form structures.
5
+ # It allows building forms within forms, supporting has_one and has_many relationships.
6
+ # Includes schema and element DSL functionality for defining form elements.
7
+ class Subform < ::Phlex::HTML
8
+ include ActionForm::Rendering
9
+ include ActionForm::SchemaDSL
10
+ include ActionForm::ElementsDSL
11
+
12
+ class << self
13
+ attr_accessor :default
14
+ end
15
+
16
+ attr_reader :elements_instances, :tags, :name, :object
17
+ attr_accessor :helpers
18
+
19
+ def initialize(name:, scope: nil, model: nil, params: nil, **tags)
20
+ super()
21
+ @name = name
22
+ @scope = scope
23
+ @object = model
24
+ @params = params
25
+ @elements_instances = []
26
+ @tags = tags
27
+ build_from_object
28
+ end
29
+
30
+ def build_from_object
31
+ self.class.elements.each do |element_name, element_definition|
32
+ @elements_instances << element_definition.new(element_name, @params || @object, parent_name: @scope)
33
+ @elements_instances.last.tags.merge!(subform: @name)
34
+ end
35
+ end
36
+
37
+ def render?
38
+ true
39
+ end
40
+
41
+ def template_html_id
42
+ "#{name}_template"
43
+ end
44
+
45
+ def html_id
46
+ "#{name}_#{tags[:index]}"
47
+ end
48
+
49
+ def html_class
50
+ "#{name}_subform"
51
+ end
52
+
53
+ def view_template
54
+ render_elements
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionForm
4
+ # Collection of subforms that can be iterated and rendered
5
+ class SubformsCollection < ::Phlex::HTML
6
+ extend Forwardable
7
+ include ActionForm::Rendering
8
+
9
+ def_delegators :@subforms, :last, :first, :length, :size, :[], :<<
10
+
11
+ attr_reader :subforms, :tags, :name
12
+ attr_accessor :helpers
13
+
14
+ class << self
15
+ attr_reader :subform_definition
16
+ attr_accessor :default, :host_class
17
+
18
+ def subform(subform_class = nil, &block)
19
+ @subform_definition = subform_class || Class.new(host_class.subform_class)
20
+ @subform_definition.class_eval(&block) if block
21
+ end
22
+ end
23
+
24
+ def initialize(name)
25
+ super()
26
+ @name = name
27
+ @subforms = []
28
+ @tags = {}
29
+ end
30
+
31
+ def each(&block)
32
+ return to_enum(:each) unless block
33
+
34
+ @subforms.each(&block)
35
+ end
36
+
37
+ def render?
38
+ true
39
+ end
40
+
41
+ def template_html_id
42
+ "#{name}_template"
43
+ end
44
+
45
+ def add_subform_js
46
+ <<~JS
47
+ function easyFormAddSubform(event) {
48
+ event.preventDefault()
49
+ var template = document.querySelector("##{template_html_id}")
50
+ const content = template.innerHTML.replace(/NEW_RECORD/g, new Date().getTime().toString())
51
+ var beforeElement = event.target.closest(event.target.dataset.insertBeforeSelector)
52
+ if (beforeElement) {
53
+ beforeElement.insertAdjacentHTML("beforebegin", content)
54
+ } else {
55
+ event.target.parentElement.insertAdjacentHTML("beforebegin", content)
56
+ }
57
+ }
58
+ JS
59
+ end
60
+
61
+ def remove_subform_js
62
+ <<~JS
63
+ function easyFormRemoveSubform(event) {
64
+ event.preventDefault()
65
+ var subform = event.target.closest(".new_#{name}")
66
+ if (subform) { subform.remove() }
67
+ var subform = event.target.closest(".#{name}_subform")
68
+ if (subform) {
69
+ subform.style.display = "none"
70
+ var input = subform.querySelector("input[name*='_destroy']")
71
+ if (input) { input.value = "1" }
72
+ }
73
+ }
74
+ JS
75
+ end
76
+
77
+ def view_template # rubocop:disable Metrics/AbcSize
78
+ script(type: "text/javascript") { raw safe(remove_subform_js) }
79
+ script(type: "text/javascript") { raw safe(add_subform_js) }
80
+ subforms.each do |subform|
81
+ subform.helpers = helpers
82
+ if subform.tags[:template]
83
+ render_subform_template(subform)
84
+ else
85
+ div(id: subform.html_id, class: subform.html_class) { render_subform(subform) }
86
+ end
87
+ end
88
+ end
89
+
90
+ def render_subform_template(subform)
91
+ template(id: template_html_id) do
92
+ div(class: "new_#{name}") { render_subform(subform) }
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionForm
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "phlex"
4
+ require "easy_params"
5
+ require "forwardable"
6
+ require_relative "action_form/version"
7
+ require_relative "action_form/schema_dsl"
8
+ require_relative "action_form/elements_dsl"
9
+ require_relative "action_form/input"
10
+ require_relative "action_form/rendering"
11
+ require_relative "action_form/subform"
12
+ require_relative "action_form/subforms_collection"
13
+ require_relative "action_form/element"
14
+ require_relative "action_form/base"
15
+ require_relative "action_form/rails/rendering"
16
+ require_relative "action_form/rails/subform"
17
+ require_relative "action_form/rails/base"
18
+
19
+ module ActionForm
20
+ class Error < StandardError; end
21
+ end
@@ -0,0 +1,4 @@
1
+ module ActionForm
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
data/sig/easy_form.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module ActionForm
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_form
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrii Baran
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: easy_params
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.6.3
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.6.3
26
+ - !ruby/object:Gem::Dependency
27
+ name: phlex
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: railties
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 6.0.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 6.0.0
54
+ description: Action form builder for Rails
55
+ email:
56
+ - andriy.baran.v@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".qlty/.gitignore"
62
+ - ".qlty/qlty.toml"
63
+ - CHANGELOG.md
64
+ - CODE_OF_CONDUCT.md
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/action_form.rb
69
+ - lib/action_form/base.rb
70
+ - lib/action_form/element.rb
71
+ - lib/action_form/elements_dsl.rb
72
+ - lib/action_form/input.rb
73
+ - lib/action_form/rails/base.rb
74
+ - lib/action_form/rails/rendering.rb
75
+ - lib/action_form/rails/subform.rb
76
+ - lib/action_form/rendering.rb
77
+ - lib/action_form/schema_dsl.rb
78
+ - lib/action_form/subform.rb
79
+ - lib/action_form/subforms_collection.rb
80
+ - lib/action_form/version.rb
81
+ - sig/action_form.rbs
82
+ - sig/easy_form.rbs
83
+ homepage: https://github.com/andriy-baran/action_form
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ allowed_push_host: https://rubygems.org
88
+ homepage_uri: https://github.com/andriy-baran/action_form
89
+ source_code_uri: https://github.com/andriy-baran/action_form
90
+ changelog_uri: https://github.com/andriy-baran/action_form/blob/main/CHANGELOG.md
91
+ rubygems_mfa_required: 'true'
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 2.7.0
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubygems_version: 3.7.1
107
+ specification_version: 4
108
+ summary: Action form builder for Rails
109
+ test_files: []