phlexi-form 0.2.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 +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +395 -0
- data/Rakefile +14 -0
- data/config.ru +9 -0
- data/gemfiles/default.gemfile +5 -0
- data/gemfiles/default.gemfile.lock +174 -0
- data/lib/generators/superform/install/USAGE +8 -0
- data/lib/generators/superform/install/install_generator.rb +34 -0
- data/lib/generators/superform/install/templates/application_form.rb +31 -0
- data/lib/phlexi/form/base.rb +234 -0
- data/lib/phlexi/form/components/base.rb +37 -0
- data/lib/phlexi/form/components/checkbox.rb +43 -0
- data/lib/phlexi/form/components/collection_checkboxes.rb +30 -0
- data/lib/phlexi/form/components/collection_radio_buttons.rb +29 -0
- data/lib/phlexi/form/components/concerns/has_options.rb +33 -0
- data/lib/phlexi/form/components/error.rb +21 -0
- data/lib/phlexi/form/components/full_error.rb +21 -0
- data/lib/phlexi/form/components/hint.rb +21 -0
- data/lib/phlexi/form/components/input.rb +78 -0
- data/lib/phlexi/form/components/label.rb +26 -0
- data/lib/phlexi/form/components/radio_button.rb +31 -0
- data/lib/phlexi/form/components/select.rb +57 -0
- data/lib/phlexi/form/components/textarea.rb +34 -0
- data/lib/phlexi/form/components/wrapper.rb +31 -0
- data/lib/phlexi/form/field_options/autofocus.rb +18 -0
- data/lib/phlexi/form/field_options/collection.rb +37 -0
- data/lib/phlexi/form/field_options/disabled.rb +18 -0
- data/lib/phlexi/form/field_options/errors.rb +82 -0
- data/lib/phlexi/form/field_options/hints.rb +22 -0
- data/lib/phlexi/form/field_options/labels.rb +28 -0
- data/lib/phlexi/form/field_options/length.rb +53 -0
- data/lib/phlexi/form/field_options/limit.rb +66 -0
- data/lib/phlexi/form/field_options/min_max.rb +92 -0
- data/lib/phlexi/form/field_options/multiple.rb +63 -0
- data/lib/phlexi/form/field_options/pattern.rb +38 -0
- data/lib/phlexi/form/field_options/placeholder.rb +18 -0
- data/lib/phlexi/form/field_options/readonly.rb +18 -0
- data/lib/phlexi/form/field_options/required.rb +37 -0
- data/lib/phlexi/form/field_options/type.rb +155 -0
- data/lib/phlexi/form/field_options/validators.rb +48 -0
- data/lib/phlexi/form/option_mapper.rb +154 -0
- data/lib/phlexi/form/structure/dom.rb +57 -0
- data/lib/phlexi/form/structure/field_builder.rb +199 -0
- data/lib/phlexi/form/structure/field_collection.rb +45 -0
- data/lib/phlexi/form/structure/namespace.rb +123 -0
- data/lib/phlexi/form/structure/namespace_collection.rb +48 -0
- data/lib/phlexi/form/structure/node.rb +18 -0
- data/lib/phlexi/form/version.rb +7 -0
- data/lib/phlexi/form.rb +28 -0
- data/lib/phlexi-form.rb +3 -0
- data/sig/phlexi/form.rbs +6 -0
- metadata +243 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "phlex"
|
4
|
+
|
5
|
+
module Phlexi
|
6
|
+
module Form
|
7
|
+
module Structure
|
8
|
+
class FieldBuilder < Node
|
9
|
+
include Phlex::Helpers
|
10
|
+
include FieldOptions::Validators
|
11
|
+
include FieldOptions::Labels
|
12
|
+
include FieldOptions::Hints
|
13
|
+
include FieldOptions::Errors
|
14
|
+
include FieldOptions::Type
|
15
|
+
include FieldOptions::Collection
|
16
|
+
include FieldOptions::Placeholder
|
17
|
+
include FieldOptions::Required
|
18
|
+
include FieldOptions::Autofocus
|
19
|
+
include FieldOptions::Disabled
|
20
|
+
include FieldOptions::Readonly
|
21
|
+
include FieldOptions::Length
|
22
|
+
include FieldOptions::MinMax
|
23
|
+
include FieldOptions::Pattern
|
24
|
+
include FieldOptions::Multiple
|
25
|
+
include FieldOptions::Limit
|
26
|
+
|
27
|
+
attr_reader :dom, :options, :object, :attributes
|
28
|
+
attr_accessor :value
|
29
|
+
alias_method :serialize, :value
|
30
|
+
alias_method :assign, :value=
|
31
|
+
|
32
|
+
def initialize(key, parent:, object: nil, value: :__i_form_builder_nil_value_i__, attributes: {}, **options)
|
33
|
+
key = :"#{key}"
|
34
|
+
super(key, parent: parent)
|
35
|
+
|
36
|
+
@object = object
|
37
|
+
@value = if value != :__i_form_builder_nil_value_i__
|
38
|
+
value
|
39
|
+
else
|
40
|
+
object.respond_to?(key) ? object.send(key) : nil
|
41
|
+
end
|
42
|
+
@attributes = attributes
|
43
|
+
@options = options
|
44
|
+
@dom = Structure::DOM.new(field: self)
|
45
|
+
end
|
46
|
+
|
47
|
+
def label_tag(**attributes)
|
48
|
+
attributes = self.attributes.deep_merge(attributes)
|
49
|
+
label_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :label)
|
50
|
+
Components::Label.new(self, class: label_class, **attributes)
|
51
|
+
end
|
52
|
+
|
53
|
+
def input_tag(**attributes)
|
54
|
+
attributes = self.attributes.deep_merge(attributes)
|
55
|
+
input_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :input)
|
56
|
+
Components::Input.new(self, class: input_class, **attributes)
|
57
|
+
end
|
58
|
+
|
59
|
+
def checkbox_tag(**attributes)
|
60
|
+
attributes = self.attributes.deep_merge(attributes)
|
61
|
+
checkbox_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :checkbox)
|
62
|
+
Components::Checkbox.new(self, class: checkbox_class, **attributes)
|
63
|
+
end
|
64
|
+
|
65
|
+
def collection_checkboxes_tag(**attributes, &)
|
66
|
+
attributes = self.attributes.deep_merge(attributes)
|
67
|
+
collection_checkboxes_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :collection_checkboxes)
|
68
|
+
Components::CollectionCheckboxes.new(self, class: collection_checkboxes_class, **attributes, &)
|
69
|
+
end
|
70
|
+
|
71
|
+
def radio_button_tag(**attributes)
|
72
|
+
attributes = self.attributes.deep_merge(attributes)
|
73
|
+
radio_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :radio)
|
74
|
+
Components::RadioButton.new(self, class: radio_class, **attributes)
|
75
|
+
end
|
76
|
+
|
77
|
+
def collection_radio_buttons_tag(**attributes, &)
|
78
|
+
attributes = self.attributes.deep_merge(attributes)
|
79
|
+
collection_radio_buttons_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :collection_radio_buttons)
|
80
|
+
Components::CollectionRadioButtons.new(self, class: collection_radio_buttons_class, **attributes, &)
|
81
|
+
end
|
82
|
+
|
83
|
+
def textarea_tag(**attributes)
|
84
|
+
attributes = self.attributes.deep_merge(attributes)
|
85
|
+
textarea_class = attributes.delete(:class) || themed_input(attributes.delete(:theme) || :textarea)
|
86
|
+
Components::Textarea.new(self, class: textarea_class, **attributes)
|
87
|
+
end
|
88
|
+
|
89
|
+
def select_tag(**attributes)
|
90
|
+
attributes = self.attributes.deep_merge(attributes)
|
91
|
+
select_class = attributes.delete(:class) || themed_input(attributes.delete(:theme) || :select)
|
92
|
+
Components::Select.new(self, class: select_class, **attributes)
|
93
|
+
end
|
94
|
+
|
95
|
+
def hint_tag(**attributes)
|
96
|
+
attributes = self.attributes.deep_merge(attributes)
|
97
|
+
hint_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :hint)
|
98
|
+
Components::Hint.new(self, class: hint_class, **attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
def error_tag(**attributes)
|
102
|
+
attributes = self.attributes.deep_merge(attributes)
|
103
|
+
error_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :error)
|
104
|
+
Components::Error.new(self, class: error_class, **attributes)
|
105
|
+
end
|
106
|
+
|
107
|
+
def full_error_tag(**attributes)
|
108
|
+
attributes = self.attributes.deep_merge(attributes)
|
109
|
+
error_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :error)
|
110
|
+
Components::FullError.new(self, class: error_class, **attributes)
|
111
|
+
end
|
112
|
+
|
113
|
+
def wrapped(inner: {}, **attributes, &)
|
114
|
+
attributes = self.attributes.deep_merge(attributes)
|
115
|
+
wrapper_class = attributes.delete(:class) || themed(attributes.delete(:theme) || :wrapper)
|
116
|
+
inner[:class] = inner.delete(:class) || themed(inner.delete(:theme) || :inner_wrapper)
|
117
|
+
Components::Wrapper.new(self, class: wrapper_class, inner:, **attributes, &)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Wraps a field that's an array of values with a bunch of fields
|
121
|
+
#
|
122
|
+
# @example Usage
|
123
|
+
#
|
124
|
+
# ```ruby
|
125
|
+
# Phlexi::Form.new User.new do
|
126
|
+
# render field(:email).input_tag
|
127
|
+
# render field(:name).input_tag
|
128
|
+
# field(:roles).multi([["Admin", "admin"], ["Editor", "editor"]]) do |a|
|
129
|
+
# render a.label_tag
|
130
|
+
# render a.input_tag # => name="user[roles][]"
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
# ```
|
134
|
+
# The object within the block is a `FieldCollection` object
|
135
|
+
def multi(range = nil, &)
|
136
|
+
range ||= Array(collection)
|
137
|
+
FieldCollection.new(field: self, range:, &)
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def themed(component)
|
143
|
+
tokens(resolve_theme(component), resolve_validity_theme(component)).presence if component
|
144
|
+
end
|
145
|
+
|
146
|
+
def themed_input(input_component)
|
147
|
+
themed(input_component) || themed(:input) if input_component
|
148
|
+
end
|
149
|
+
|
150
|
+
def resolve_theme(property)
|
151
|
+
options[property] || theme[property]
|
152
|
+
end
|
153
|
+
|
154
|
+
def resolve_validity_theme(property)
|
155
|
+
validity_property = if has_errors?
|
156
|
+
# Apply invalid class if the object has errors
|
157
|
+
:"invalid_#{property}"
|
158
|
+
elsif (object.respond_to?(:persisted?) && object.persisted?) && (object.respond_to?(:errors) && !object.errors.empty?)
|
159
|
+
# The object is persisted, has been validated, and there are errors (not empty), but this field has no errors
|
160
|
+
# Apply valid class
|
161
|
+
:"valid_#{property}"
|
162
|
+
else
|
163
|
+
:"neutral_#{property}"
|
164
|
+
end
|
165
|
+
|
166
|
+
resolve_theme(validity_property)
|
167
|
+
end
|
168
|
+
|
169
|
+
def theme
|
170
|
+
@theme ||= {
|
171
|
+
# # label themes
|
172
|
+
# label: "md:w-1/6 mt-2 block mb-2 text-sm font-medium",
|
173
|
+
# invalid_label: "text-red-700 dark:text-red-500",
|
174
|
+
# valid_label: "text-green-700 dark:text-green-500",
|
175
|
+
# neutral_label: "text-gray-700 dark:text-white",
|
176
|
+
# # input themes
|
177
|
+
# input: "w-full p-2 border rounded-md shadow-sm font-medium text-sm dark:bg-gray-700",
|
178
|
+
# invalid_input: "bg-red-50 border-red-500 dark:border-red-500 text-red-900 dark:text-red-500 placeholder-red-700 dark:placeholder-red-500 focus:ring-red-500 focus:border-red-500",
|
179
|
+
# valid_input: "bg-green-50 border-green-500 dark:border-green-500 text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500 focus:ring-green-500 focus:border-green-500",
|
180
|
+
# neutral_input: "border-gray-300 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-primary-500 focus:border-primary-500",
|
181
|
+
# # hint themes
|
182
|
+
# hint: "mt-2 text-sm text-gray-500 dark:text-gray-200",
|
183
|
+
# # error themes
|
184
|
+
# error: "mt-2 text-sm text-red-600 dark:text-red-500",
|
185
|
+
# # wrapper themes
|
186
|
+
# wrapper: "flex flex-col md:flex-row items-start space-y-2 md:space-y-0 md:space-x-2 mb-4",
|
187
|
+
# inner_wrapper: "md:w-5/6 w-full",
|
188
|
+
}.freeze
|
189
|
+
end
|
190
|
+
|
191
|
+
def reflection = nil
|
192
|
+
|
193
|
+
def has_value?
|
194
|
+
value.present?
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Structure
|
6
|
+
class FieldCollection
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
class Builder
|
10
|
+
attr_reader :key
|
11
|
+
|
12
|
+
def initialize(key, field)
|
13
|
+
@key = key.to_s
|
14
|
+
@field = field
|
15
|
+
end
|
16
|
+
|
17
|
+
def field(**)
|
18
|
+
@field.class.new(key, attributes: @field.attributes, **, parent: @field).tap do |field|
|
19
|
+
yield field if block_given?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(field:, range:, &)
|
25
|
+
@field = field
|
26
|
+
@range = case range
|
27
|
+
when Range, Array
|
28
|
+
range
|
29
|
+
when Integer
|
30
|
+
1..range
|
31
|
+
else
|
32
|
+
range.to_a
|
33
|
+
end
|
34
|
+
each(&) if block_given?
|
35
|
+
end
|
36
|
+
|
37
|
+
def each(&)
|
38
|
+
@range.each do |key|
|
39
|
+
yield Builder.new(key, @field)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Structure
|
6
|
+
# A Namespace maps and object to values, but doesn't actually have a value itself. For
|
7
|
+
# example, a `User` object or ActiveRecord model could be passed into the `:user` namespace.
|
8
|
+
# To access the values on a Namespace, the `field` can be called for single values.
|
9
|
+
#
|
10
|
+
# Additionally, to access namespaces within a namespace, such as if a `User has_many :addresses` in
|
11
|
+
# ActiveRecord, the `namespace` method can be called which will return another Namespace object and
|
12
|
+
# set the current Namespace as the parent.
|
13
|
+
class Namespace < Structure::Node
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
attr_reader :builder_klass, :object
|
17
|
+
|
18
|
+
def initialize(key, parent:, object: nil, builder_klass: Field)
|
19
|
+
super(key, parent: parent)
|
20
|
+
@object = object
|
21
|
+
@builder_klass = builder_klass
|
22
|
+
@children = {}
|
23
|
+
yield self if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
def field(key, **attributes)
|
27
|
+
create_child(key, attributes.delete(:builder_klass) || builder_klass, object: object, **attributes).tap do |field|
|
28
|
+
yield field if block_given?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates a `Namespace` child instance with the parent set to the current instance, adds to
|
33
|
+
# the `@children` Hash to ensure duplicate child namespaces aren't created, then calls the
|
34
|
+
# method on the `@object` to get the child object to pass into that namespace.
|
35
|
+
#
|
36
|
+
# For example, if a `User#permission` returns a `Permission` object, we could map that to a
|
37
|
+
# form like this:
|
38
|
+
#
|
39
|
+
# ```ruby
|
40
|
+
# Superform :user, object: User.new do |form|
|
41
|
+
# form.nest_one :permission do |permission|
|
42
|
+
# form.field :role
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
# ```
|
46
|
+
def nest_one(key, object: nil, &)
|
47
|
+
object ||= object_for(key: key)
|
48
|
+
create_child(key, self.class, object:, builder_klass:, &)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Wraps an array of objects in Namespace classes. For example, if `User#addresses` returns
|
52
|
+
# an enumerable or array of `Address` classes:
|
53
|
+
#
|
54
|
+
# ```ruby
|
55
|
+
# Phlexi::Form.new User.new do |form|
|
56
|
+
# render form.field(:email).input_tag
|
57
|
+
# render form.field(:name).input_tag
|
58
|
+
# form.nest_many :addresses do |address|
|
59
|
+
# render address.field(:street).input_tag
|
60
|
+
# render address.field(:state).input_tag
|
61
|
+
# render address.field(:zip).input_tag
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# ```
|
65
|
+
# The object within the block is a `Namespace` object that maps each object within the enumerable
|
66
|
+
# to another `Namespace` or `Field`.
|
67
|
+
def nest_many(key, collection: nil, &)
|
68
|
+
collection ||= Array(object_for(key: key))
|
69
|
+
create_child(key, NamespaceCollection, collection:, &)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a Hash of Hashes and Arrays that represent the fields and collections of the Superform.
|
73
|
+
# This can be used to safely update ActiveRecord objects without the need for Strong Parameters.
|
74
|
+
# You will want to make sure that all the fields displayed in the form are ones that you're OK updating
|
75
|
+
# from the generated hash.
|
76
|
+
def serialize
|
77
|
+
each_with_object({}) do |child, hash|
|
78
|
+
hash[child.key] = child.serialize
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Iterates through the children of the current namespace, which could be `Namespace` or `Field`
|
83
|
+
# objects.
|
84
|
+
def each(&)
|
85
|
+
@children.values.each(&)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Assigns a hash to the current namespace and children namespace.
|
89
|
+
def assign(hash)
|
90
|
+
each do |child|
|
91
|
+
child.assign hash[child.key]
|
92
|
+
end
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a root Namespace, which is essentially a form.
|
97
|
+
def self.root(*, **, &)
|
98
|
+
new(*, parent: nil, **, &)
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
# Calls the corresponding method on the object for the `key` name, if it exists. For example
|
104
|
+
# if the `key` is `email` on `User`, this method would call `User#email` if the method is
|
105
|
+
# present.
|
106
|
+
#
|
107
|
+
# This method could be overwritten if the mapping between the `@object` and `key` name is not
|
108
|
+
# a method call. For example, a `Hash` would be accessed via `user[:email]` instead of `user.send(:email)`
|
109
|
+
def object_for(key:)
|
110
|
+
@object.send(key) if @object.respond_to? key
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
# Checks if the child exists. If it does then it returns that. If it doesn't, it will
|
116
|
+
# build the child.
|
117
|
+
def create_child(key, child_class, **kwargs, &block)
|
118
|
+
@children.fetch(key) { @children[key] = child_class.new(key, parent: self, **kwargs, &block) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Structure
|
6
|
+
class NamespaceCollection < Node
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(key, parent:, collection: nil, &)
|
10
|
+
super(key, parent: parent)
|
11
|
+
|
12
|
+
@namespaces = enumerate(collection)
|
13
|
+
each(&) if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def serialize
|
17
|
+
map(&:serialize)
|
18
|
+
end
|
19
|
+
|
20
|
+
def assign(array)
|
21
|
+
# The problem with zip-ing the array is if I need to add new
|
22
|
+
# elements to it and wrap it in the namespace.
|
23
|
+
zip(array) do |namespace, hash|
|
24
|
+
namespace.assign hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&)
|
29
|
+
@namespaces.each(&)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def enumerate(enumerator)
|
35
|
+
Enumerator.new do |y|
|
36
|
+
enumerator.each.with_index do |object, key|
|
37
|
+
y << build_namespace(key, object: object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_namespace(index, **)
|
43
|
+
parent.class.new(index, parent: self, builder_klass: parent.builder_klass, **)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Structure
|
6
|
+
# Superclass for Namespace and Field classes. Not much to it other than it has a `name`
|
7
|
+
# and `parent` node attribute. Think of it as a tree.
|
8
|
+
class Node
|
9
|
+
attr_reader :key, :parent
|
10
|
+
|
11
|
+
def initialize(key, parent:)
|
12
|
+
@key = key
|
13
|
+
@parent = parent
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/phlexi/form.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zeitwerk"
|
4
|
+
require "phlex"
|
5
|
+
|
6
|
+
module Phlexi
|
7
|
+
module Form
|
8
|
+
Loader = Zeitwerk::Loader.new.tap do |loader|
|
9
|
+
loader.tag = File.basename(__FILE__, ".rb")
|
10
|
+
loader.inflector.inflect(
|
11
|
+
"phlexi-form" => "Phlexi",
|
12
|
+
"phlexi" => "Phlexi",
|
13
|
+
"dom" => "DOM"
|
14
|
+
)
|
15
|
+
loader.push_dir(File.expand_path("..", __dir__))
|
16
|
+
loader.ignore(File.expand_path("../generators", __dir__))
|
17
|
+
loader.setup
|
18
|
+
end
|
19
|
+
|
20
|
+
BaseComponent = (defined?(::ApplicationComponent) ? ::ApplicationComponent : Phlex::HTML)
|
21
|
+
|
22
|
+
class Error < StandardError; end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def Phlexi.Form(...)
|
27
|
+
Phlexi::Form::Base.new(...)
|
28
|
+
end
|
data/lib/phlexi-form.rb
ADDED