phlexi-form 0.2.0 → 0.3.0.rc1
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/Appraisals +4 -9
- data/README.md +115 -316
- data/TODO +4 -0
- data/config.ru +0 -3
- data/gemfiles/default.gemfile.lock +22 -2
- data/gemfiles/rails_7.gemfile +8 -0
- data/gemfiles/rails_7.gemfile.lock +282 -0
- data/lib/phlexi/form/base.rb +52 -35
- data/lib/phlexi/form/components/base.rb +12 -6
- data/lib/phlexi/form/components/checkbox.rb +5 -0
- data/lib/phlexi/form/components/collection_checkboxes.rb +28 -14
- data/lib/phlexi/form/components/collection_radio_buttons.rb +19 -13
- data/lib/phlexi/form/components/concerns/handles_array_input.rb +21 -0
- data/lib/phlexi/form/components/concerns/handles_input.rb +53 -0
- data/lib/phlexi/form/components/concerns/has_options.rb +6 -2
- data/lib/phlexi/form/components/concerns/submits_form.rb +39 -0
- data/lib/phlexi/form/components/file_input.rb +32 -0
- data/lib/phlexi/form/components/input.rb +39 -33
- data/lib/phlexi/form/components/input_array.rb +45 -0
- data/lib/phlexi/form/components/label.rb +2 -1
- data/lib/phlexi/form/components/radio_button.rb +11 -1
- data/lib/phlexi/form/components/select.rb +21 -5
- data/lib/phlexi/form/components/submit_button.rb +41 -0
- data/lib/phlexi/form/field_options/associations.rb +21 -0
- data/lib/phlexi/form/field_options/autofocus.rb +1 -1
- data/lib/phlexi/form/field_options/collection.rb +26 -9
- data/lib/phlexi/form/field_options/errors.rb +10 -0
- data/lib/phlexi/form/field_options/{type.rb → inferred_types.rb} +12 -12
- data/lib/phlexi/form/field_options/multiple.rb +2 -0
- data/lib/phlexi/form/field_options/themes.rb +207 -0
- data/lib/phlexi/form/option_mapper.rb +2 -2
- data/lib/phlexi/form/structure/dom.rb +19 -14
- data/lib/phlexi/form/structure/field_builder.rb +145 -108
- data/lib/phlexi/form/structure/field_collection.rb +14 -5
- data/lib/phlexi/form/structure/namespace.rb +31 -19
- data/lib/phlexi/form/structure/namespace_collection.rb +20 -20
- data/lib/phlexi/form/structure/node.rb +1 -1
- data/lib/phlexi/form/version.rb +1 -1
- data/lib/phlexi/form.rb +4 -1
- metadata +30 -6
- data/CODE_OF_CONDUCT.md +0 -84
@@ -0,0 +1,282 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
phlexi-form (0.2.0)
|
5
|
+
activesupport
|
6
|
+
phlex (~> 1.11)
|
7
|
+
zeitwerk
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actioncable (7.1.3.4)
|
13
|
+
actionpack (= 7.1.3.4)
|
14
|
+
activesupport (= 7.1.3.4)
|
15
|
+
nio4r (~> 2.0)
|
16
|
+
websocket-driver (>= 0.6.1)
|
17
|
+
zeitwerk (~> 2.6)
|
18
|
+
actionmailbox (7.1.3.4)
|
19
|
+
actionpack (= 7.1.3.4)
|
20
|
+
activejob (= 7.1.3.4)
|
21
|
+
activerecord (= 7.1.3.4)
|
22
|
+
activestorage (= 7.1.3.4)
|
23
|
+
activesupport (= 7.1.3.4)
|
24
|
+
mail (>= 2.7.1)
|
25
|
+
net-imap
|
26
|
+
net-pop
|
27
|
+
net-smtp
|
28
|
+
actionmailer (7.1.3.4)
|
29
|
+
actionpack (= 7.1.3.4)
|
30
|
+
actionview (= 7.1.3.4)
|
31
|
+
activejob (= 7.1.3.4)
|
32
|
+
activesupport (= 7.1.3.4)
|
33
|
+
mail (~> 2.5, >= 2.5.4)
|
34
|
+
net-imap
|
35
|
+
net-pop
|
36
|
+
net-smtp
|
37
|
+
rails-dom-testing (~> 2.2)
|
38
|
+
actionpack (7.1.3.4)
|
39
|
+
actionview (= 7.1.3.4)
|
40
|
+
activesupport (= 7.1.3.4)
|
41
|
+
nokogiri (>= 1.8.5)
|
42
|
+
racc
|
43
|
+
rack (>= 2.2.4)
|
44
|
+
rack-session (>= 1.0.1)
|
45
|
+
rack-test (>= 0.6.3)
|
46
|
+
rails-dom-testing (~> 2.2)
|
47
|
+
rails-html-sanitizer (~> 1.6)
|
48
|
+
actiontext (7.1.3.4)
|
49
|
+
actionpack (= 7.1.3.4)
|
50
|
+
activerecord (= 7.1.3.4)
|
51
|
+
activestorage (= 7.1.3.4)
|
52
|
+
activesupport (= 7.1.3.4)
|
53
|
+
globalid (>= 0.6.0)
|
54
|
+
nokogiri (>= 1.8.5)
|
55
|
+
actionview (7.1.3.4)
|
56
|
+
activesupport (= 7.1.3.4)
|
57
|
+
builder (~> 3.1)
|
58
|
+
erubi (~> 1.11)
|
59
|
+
rails-dom-testing (~> 2.2)
|
60
|
+
rails-html-sanitizer (~> 1.6)
|
61
|
+
activejob (7.1.3.4)
|
62
|
+
activesupport (= 7.1.3.4)
|
63
|
+
globalid (>= 0.3.6)
|
64
|
+
activemodel (7.1.3.4)
|
65
|
+
activesupport (= 7.1.3.4)
|
66
|
+
activerecord (7.1.3.4)
|
67
|
+
activemodel (= 7.1.3.4)
|
68
|
+
activesupport (= 7.1.3.4)
|
69
|
+
timeout (>= 0.4.0)
|
70
|
+
activestorage (7.1.3.4)
|
71
|
+
actionpack (= 7.1.3.4)
|
72
|
+
activejob (= 7.1.3.4)
|
73
|
+
activerecord (= 7.1.3.4)
|
74
|
+
activesupport (= 7.1.3.4)
|
75
|
+
marcel (~> 1.0)
|
76
|
+
activesupport (7.1.3.4)
|
77
|
+
base64
|
78
|
+
bigdecimal
|
79
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
80
|
+
connection_pool (>= 2.2.5)
|
81
|
+
drb
|
82
|
+
i18n (>= 1.6, < 2)
|
83
|
+
minitest (>= 5.1)
|
84
|
+
mutex_m
|
85
|
+
tzinfo (~> 2.0)
|
86
|
+
addressable (2.8.7)
|
87
|
+
public_suffix (>= 2.0.2, < 7.0)
|
88
|
+
ansi (1.5.0)
|
89
|
+
appraisal (2.5.0)
|
90
|
+
bundler
|
91
|
+
rake
|
92
|
+
thor (>= 0.14.0)
|
93
|
+
ast (2.4.2)
|
94
|
+
base64 (0.2.0)
|
95
|
+
bigdecimal (3.1.8)
|
96
|
+
builder (3.3.0)
|
97
|
+
bundle-audit (0.1.0)
|
98
|
+
bundler-audit
|
99
|
+
bundler-audit (0.9.1)
|
100
|
+
bundler (>= 1.2.0, < 3)
|
101
|
+
thor (~> 1.0)
|
102
|
+
capybara (3.40.0)
|
103
|
+
addressable
|
104
|
+
matrix
|
105
|
+
mini_mime (>= 0.1.3)
|
106
|
+
nokogiri (~> 1.11)
|
107
|
+
rack (>= 1.6.0)
|
108
|
+
rack-test (>= 0.6.3)
|
109
|
+
regexp_parser (>= 1.5, < 3.0)
|
110
|
+
xpath (~> 3.2)
|
111
|
+
combustion (1.5.0)
|
112
|
+
activesupport (>= 3.0.0)
|
113
|
+
railties (>= 3.0.0)
|
114
|
+
thor (>= 0.14.6)
|
115
|
+
concurrent-ruby (1.3.3)
|
116
|
+
connection_pool (2.4.1)
|
117
|
+
crass (1.0.6)
|
118
|
+
date (3.3.4)
|
119
|
+
drb (2.2.1)
|
120
|
+
erubi (1.13.0)
|
121
|
+
globalid (1.2.1)
|
122
|
+
activesupport (>= 6.1)
|
123
|
+
i18n (1.14.5)
|
124
|
+
concurrent-ruby (~> 1.0)
|
125
|
+
io-console (0.7.2)
|
126
|
+
irb (1.14.0)
|
127
|
+
rdoc (>= 4.0.0)
|
128
|
+
reline (>= 0.4.2)
|
129
|
+
json (2.7.2)
|
130
|
+
language_server-protocol (3.17.0.3)
|
131
|
+
lint_roller (1.1.0)
|
132
|
+
loofah (2.22.0)
|
133
|
+
crass (~> 1.0.2)
|
134
|
+
nokogiri (>= 1.12.0)
|
135
|
+
mail (2.8.1)
|
136
|
+
mini_mime (>= 0.1.1)
|
137
|
+
net-imap
|
138
|
+
net-pop
|
139
|
+
net-smtp
|
140
|
+
marcel (1.0.4)
|
141
|
+
matrix (0.4.2)
|
142
|
+
mini_mime (1.1.5)
|
143
|
+
minitest (5.24.1)
|
144
|
+
minitest-reporters (1.7.1)
|
145
|
+
ansi
|
146
|
+
builder
|
147
|
+
minitest (>= 5.0)
|
148
|
+
ruby-progressbar
|
149
|
+
mutex_m (0.2.0)
|
150
|
+
net-imap (0.4.14)
|
151
|
+
date
|
152
|
+
net-protocol
|
153
|
+
net-pop (0.1.2)
|
154
|
+
net-protocol
|
155
|
+
net-protocol (0.2.2)
|
156
|
+
timeout
|
157
|
+
net-smtp (0.5.0)
|
158
|
+
net-protocol
|
159
|
+
nio4r (2.7.3)
|
160
|
+
nokogiri (1.16.7-x86_64-darwin)
|
161
|
+
racc (~> 1.4)
|
162
|
+
parallel (1.25.1)
|
163
|
+
parser (3.3.4.0)
|
164
|
+
ast (~> 2.4.1)
|
165
|
+
racc
|
166
|
+
phlex (1.11.0)
|
167
|
+
phlex-testing-capybara (0.1.0)
|
168
|
+
capybara (~> 3.38)
|
169
|
+
phlex (>= 0.5)
|
170
|
+
psych (5.1.2)
|
171
|
+
stringio
|
172
|
+
public_suffix (6.0.1)
|
173
|
+
racc (1.8.1)
|
174
|
+
rack (3.1.7)
|
175
|
+
rack-session (2.0.0)
|
176
|
+
rack (>= 3.0.0)
|
177
|
+
rack-test (2.1.0)
|
178
|
+
rack (>= 1.3)
|
179
|
+
rackup (2.1.0)
|
180
|
+
rack (>= 3)
|
181
|
+
webrick (~> 1.8)
|
182
|
+
rails (7.1.3.4)
|
183
|
+
actioncable (= 7.1.3.4)
|
184
|
+
actionmailbox (= 7.1.3.4)
|
185
|
+
actionmailer (= 7.1.3.4)
|
186
|
+
actionpack (= 7.1.3.4)
|
187
|
+
actiontext (= 7.1.3.4)
|
188
|
+
actionview (= 7.1.3.4)
|
189
|
+
activejob (= 7.1.3.4)
|
190
|
+
activemodel (= 7.1.3.4)
|
191
|
+
activerecord (= 7.1.3.4)
|
192
|
+
activestorage (= 7.1.3.4)
|
193
|
+
activesupport (= 7.1.3.4)
|
194
|
+
bundler (>= 1.15.0)
|
195
|
+
railties (= 7.1.3.4)
|
196
|
+
rails-dom-testing (2.2.0)
|
197
|
+
activesupport (>= 5.0.0)
|
198
|
+
minitest
|
199
|
+
nokogiri (>= 1.6)
|
200
|
+
rails-html-sanitizer (1.6.0)
|
201
|
+
loofah (~> 2.21)
|
202
|
+
nokogiri (~> 1.14)
|
203
|
+
railties (7.1.3.4)
|
204
|
+
actionpack (= 7.1.3.4)
|
205
|
+
activesupport (= 7.1.3.4)
|
206
|
+
irb
|
207
|
+
rackup (>= 1.0.0)
|
208
|
+
rake (>= 12.2)
|
209
|
+
thor (~> 1.0, >= 1.2.2)
|
210
|
+
zeitwerk (~> 2.6)
|
211
|
+
rainbow (3.1.1)
|
212
|
+
rake (13.2.1)
|
213
|
+
rdoc (6.7.0)
|
214
|
+
psych (>= 4.0.0)
|
215
|
+
regexp_parser (2.9.2)
|
216
|
+
reline (0.5.9)
|
217
|
+
io-console (~> 0.5)
|
218
|
+
rexml (3.3.2)
|
219
|
+
strscan
|
220
|
+
rubocop (1.64.1)
|
221
|
+
json (~> 2.3)
|
222
|
+
language_server-protocol (>= 3.17.0)
|
223
|
+
parallel (~> 1.10)
|
224
|
+
parser (>= 3.3.0.2)
|
225
|
+
rainbow (>= 2.2.2, < 4.0)
|
226
|
+
regexp_parser (>= 1.8, < 3.0)
|
227
|
+
rexml (>= 3.2.5, < 4.0)
|
228
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
229
|
+
ruby-progressbar (~> 1.7)
|
230
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
231
|
+
rubocop-ast (1.31.3)
|
232
|
+
parser (>= 3.3.1.0)
|
233
|
+
rubocop-performance (1.21.1)
|
234
|
+
rubocop (>= 1.48.1, < 2.0)
|
235
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
236
|
+
ruby-progressbar (1.13.0)
|
237
|
+
sqlite3 (1.7.3-x86_64-darwin)
|
238
|
+
standard (1.39.2)
|
239
|
+
language_server-protocol (~> 3.17.0.2)
|
240
|
+
lint_roller (~> 1.0)
|
241
|
+
rubocop (~> 1.64.0)
|
242
|
+
standard-custom (~> 1.0.0)
|
243
|
+
standard-performance (~> 1.4)
|
244
|
+
standard-custom (1.0.2)
|
245
|
+
lint_roller (~> 1.0)
|
246
|
+
rubocop (~> 1.50)
|
247
|
+
standard-performance (1.4.0)
|
248
|
+
lint_roller (~> 1.1)
|
249
|
+
rubocop-performance (~> 1.21.0)
|
250
|
+
stringio (3.1.1)
|
251
|
+
strscan (3.1.0)
|
252
|
+
thor (1.3.1)
|
253
|
+
timeout (0.4.1)
|
254
|
+
tzinfo (2.0.6)
|
255
|
+
concurrent-ruby (~> 1.0)
|
256
|
+
unicode-display_width (2.5.0)
|
257
|
+
webrick (1.8.1)
|
258
|
+
websocket-driver (0.7.6)
|
259
|
+
websocket-extensions (>= 0.1.0)
|
260
|
+
websocket-extensions (0.1.5)
|
261
|
+
xpath (3.2.0)
|
262
|
+
nokogiri (~> 1.8)
|
263
|
+
zeitwerk (2.6.17)
|
264
|
+
|
265
|
+
PLATFORMS
|
266
|
+
x86_64-darwin
|
267
|
+
|
268
|
+
DEPENDENCIES
|
269
|
+
appraisal
|
270
|
+
bundle-audit
|
271
|
+
combustion
|
272
|
+
minitest
|
273
|
+
minitest-reporters
|
274
|
+
phlex-testing-capybara
|
275
|
+
phlexi-form!
|
276
|
+
rails (~> 7.1.3, >= 7.1.3.4)
|
277
|
+
rake
|
278
|
+
sqlite3 (~> 1.4)
|
279
|
+
standard
|
280
|
+
|
281
|
+
BUNDLED WITH
|
282
|
+
2.5.16
|
data/lib/phlexi/form/base.rb
CHANGED
@@ -1,28 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "action_view/model_naming"
|
4
3
|
require "active_support/core_ext/module/delegation"
|
5
4
|
require "active_support/string_inquirer"
|
6
|
-
require "active_support/core_ext/
|
5
|
+
require "active_support/core_ext/hash/deep_merge"
|
6
|
+
require "active_support/core_ext/string/inflections"
|
7
7
|
|
8
8
|
module Phlexi
|
9
9
|
module Form
|
10
10
|
# A form component for building flexible and customizable forms.
|
11
11
|
#
|
12
12
|
# @example Basic usage
|
13
|
-
# Form.new(user, action: '/users', method: 'post') do |f|
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# Phlexi::Form.new(user, action: '/users', method: 'post') do |f|
|
14
|
+
# render field(:name).placeholder("Name").input_tag
|
15
|
+
# render field(:email).placeholder("Email").input_tag
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# @attr_reader [Symbol] key The form's key, derived from the record or explicitly set
|
19
19
|
# @attr_reader [ActiveModel::Model, nil] object The form's associated object
|
20
|
-
class Base <
|
21
|
-
|
20
|
+
class Base < COMPONENT_BASE
|
21
|
+
class Namespace < Structure::Namespace; end
|
22
|
+
|
23
|
+
class FieldBuilder < Structure::FieldBuilder; end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def inherited(subclass)
|
27
|
+
subclass.const_set(:Namespace, Class.new(self::Namespace)) unless subclass.const_defined?(:Namespace)
|
28
|
+
subclass.const_set(:FieldBuilder, Class.new(self::FieldBuilder)) unless subclass.const_defined?(:FieldBuilder)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
22
32
|
|
23
33
|
attr_reader :key, :object
|
24
34
|
|
25
|
-
delegate :field, :nest_one, :nest_many, to: :@namespace
|
35
|
+
delegate :field, :submit_button, :nest_one, :nest_many, to: :@namespace
|
26
36
|
|
27
37
|
# Initializes a new Form instance.
|
28
38
|
#
|
@@ -39,6 +49,8 @@ module Phlexi
|
|
39
49
|
@form_method = method
|
40
50
|
@form_class = options.delete(:class)
|
41
51
|
@attributes = attributes
|
52
|
+
@namespace_klass = options.delete(:namespace_klass) || default_namespace_klass
|
53
|
+
@builder_klass = options.delete(:builder_klass) || default_builder_klass
|
42
54
|
@options = options
|
43
55
|
|
44
56
|
initialize_object_and_key(record)
|
@@ -65,7 +77,7 @@ module Phlexi
|
|
65
77
|
#
|
66
78
|
# @yield The form's content
|
67
79
|
# @return [void]
|
68
|
-
def form_tag(&
|
80
|
+
def form_tag(&)
|
69
81
|
form(**form_attributes) do
|
70
82
|
render_hidden_method_field
|
71
83
|
render_authenticity_token if authenticity_token?
|
@@ -73,26 +85,33 @@ module Phlexi
|
|
73
85
|
end
|
74
86
|
end
|
75
87
|
|
88
|
+
def extract_input(params)
|
89
|
+
call unless @_rendered
|
90
|
+
@namespace.extract_input(params)
|
91
|
+
end
|
92
|
+
|
76
93
|
protected
|
77
94
|
|
78
|
-
attr_reader :options, :attributes
|
95
|
+
attr_reader :options, :attributes, :namespace_klass, :builder_klass
|
79
96
|
|
80
97
|
# Initializes the object and key based on the given record.
|
81
98
|
#
|
82
99
|
# @param record [ActiveModel::Model, Symbol, String] The form's associated record or key
|
83
100
|
# @return [void]
|
84
101
|
def initialize_object_and_key(record)
|
102
|
+
# always pop these keys
|
103
|
+
# add support for `as` to make it more rails friendly
|
104
|
+
@key = options.delete(:key) || options.delete(:as)
|
105
|
+
|
85
106
|
case record
|
86
107
|
when String, Symbol
|
87
108
|
@object = nil
|
88
109
|
@key = record
|
89
110
|
else
|
90
|
-
@object =
|
91
|
-
@key = options.delete(:as)
|
92
|
-
|
111
|
+
@object = record
|
93
112
|
if @key.nil?
|
94
|
-
unless object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key
|
95
|
-
raise ArgumentError, "record must respond to #model_name.param_key with a non nil value"
|
113
|
+
unless object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key.present?
|
114
|
+
raise ArgumentError, "record must respond to #model_name.param_key with a non nil value or set `key` option e.g. Phlexi::Form(record, key: :record)"
|
96
115
|
end
|
97
116
|
@key = object.model_name.param_key
|
98
117
|
end
|
@@ -111,7 +130,7 @@ module Phlexi
|
|
111
130
|
#
|
112
131
|
# @return [void]
|
113
132
|
def initialize_attributes
|
114
|
-
attributes[:accept_charset]
|
133
|
+
attributes.fetch(:accept_charset) { attributes[:accept_charset] = "UTF-8" }
|
115
134
|
end
|
116
135
|
|
117
136
|
# Determines the form's action URL.
|
@@ -140,9 +159,7 @@ module Phlexi
|
|
140
159
|
# Retrieves the form's CSS classes.
|
141
160
|
#
|
142
161
|
# @return [String] The form's CSS classes
|
143
|
-
|
144
|
-
@form_class || "flex flex-col space-y-6 px-4 py-2"
|
145
|
-
end
|
162
|
+
attr_reader :form_class
|
146
163
|
|
147
164
|
# Checks if the authenticity token should be included.
|
148
165
|
#
|
@@ -171,22 +188,11 @@ module Phlexi
|
|
171
188
|
#
|
172
189
|
# @return [String, nil] The appropriate form method
|
173
190
|
def object_form_method
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
#
|
180
|
-
# @return [Class] The namespace class
|
181
|
-
def namespace_klass
|
182
|
-
@namespace_klass ||= options.delete(:namespace_klass) || Structure::Namespace
|
183
|
-
end
|
184
|
-
|
185
|
-
# Retrieves the builder class.
|
186
|
-
#
|
187
|
-
# @return [Class] The builder class
|
188
|
-
def builder_klass
|
189
|
-
@builder_klass ||= options.delete(:builder_klass) || Structure::FieldBuilder
|
191
|
+
if object.respond_to?(:persisted?)
|
192
|
+
object.persisted? ? "patch" : "post"
|
193
|
+
elsif object.present?
|
194
|
+
"post"
|
195
|
+
end
|
190
196
|
end
|
191
197
|
|
192
198
|
# Renders the hidden method field for non-standard HTTP methods.
|
@@ -216,6 +222,7 @@ module Phlexi
|
|
216
222
|
# @return [Hash] The form attributes
|
217
223
|
def form_attributes
|
218
224
|
{
|
225
|
+
id: @namespace.dom_id,
|
219
226
|
action: form_action,
|
220
227
|
method: standardized_form_method,
|
221
228
|
class: form_class,
|
@@ -229,6 +236,16 @@ module Phlexi
|
|
229
236
|
def render_authenticity_token
|
230
237
|
authenticity_token_field
|
231
238
|
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def default_namespace_klass
|
243
|
+
self.class::Namespace
|
244
|
+
end
|
245
|
+
|
246
|
+
def default_builder_klass
|
247
|
+
self.class::FieldBuilder
|
248
|
+
end
|
232
249
|
end
|
233
250
|
end
|
234
251
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
5
|
module Components
|
6
|
-
class Base <
|
6
|
+
class Base < COMPONENT_BASE
|
7
7
|
attr_reader :field, :attributes
|
8
8
|
|
9
9
|
def initialize(field, **attributes)
|
@@ -11,20 +11,26 @@ module Phlexi
|
|
11
11
|
@attributes = attributes
|
12
12
|
|
13
13
|
build_attributes
|
14
|
+
append_attribute_classes
|
14
15
|
end
|
15
16
|
|
16
17
|
protected
|
17
18
|
|
18
19
|
def build_attributes
|
19
|
-
attributes[:id]
|
20
|
+
attributes.fetch(:id) { attributes[:id] = "#{field.dom.id}_#{component_name}" }
|
21
|
+
end
|
22
|
+
|
23
|
+
def append_attribute_classes
|
24
|
+
return if attributes[:class] == false
|
25
|
+
|
20
26
|
attributes[:class] = tokens(
|
21
27
|
component_name,
|
22
28
|
attributes[:class],
|
23
|
-
-> {
|
24
|
-
-> { !
|
29
|
+
-> { attributes[:required] } => "required",
|
30
|
+
-> { !attributes[:required] } => "optional",
|
25
31
|
-> { field.has_errors? } => "invalid",
|
26
|
-
-> {
|
27
|
-
-> {
|
32
|
+
-> { attributes[:readonly] } => "readonly",
|
33
|
+
-> { attributes[:disabled] } => "disabled"
|
28
34
|
)
|
29
35
|
end
|
30
36
|
|
@@ -4,26 +4,40 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
class CollectionCheckboxes < Base
|
7
|
+
include Concerns::HandlesInput
|
8
|
+
include Concerns::HandlesArrayInput
|
7
9
|
include Concerns::HasOptions
|
8
10
|
|
9
11
|
def view_template
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
div(**attributes.slice(:id, :class)) do
|
13
|
+
field.multi(option_mapper.values) do |builder|
|
14
|
+
render builder.hidden_field_tag if builder.index == 0
|
15
|
+
|
16
|
+
field = builder.field(
|
17
|
+
label: option_mapper[builder.key],
|
18
|
+
# We set the attributes here so they are applied to all input components even if the user decides to use a block
|
19
|
+
input_attributes: {
|
20
|
+
checked_value: builder.key,
|
21
|
+
include_hidden: false,
|
22
|
+
checked: selected?(builder.key)
|
23
|
+
}
|
24
|
+
)
|
25
|
+
if block_given?
|
26
|
+
yield field
|
27
|
+
else
|
28
|
+
render field.checkbox_tag
|
29
|
+
render field.label_tag
|
30
|
+
end
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def build_attributes
|
38
|
+
super
|
39
|
+
attributes[:multiple] = true
|
40
|
+
end
|
27
41
|
end
|
28
42
|
end
|
29
43
|
end
|
@@ -4,22 +4,28 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
class CollectionRadioButtons < Base
|
7
|
+
include Concerns::HandlesInput
|
7
8
|
include Concerns::HasOptions
|
8
9
|
|
9
10
|
def view_template
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
div(**attributes.slice(:id, :class)) do
|
12
|
+
field.multi(option_mapper.values) do |builder|
|
13
|
+
render builder.hidden_field_tag if builder.index == 0
|
14
|
+
|
15
|
+
field = builder.field(
|
16
|
+
label: option_mapper[builder.key],
|
17
|
+
# We set the attributes here so they are applied to all input components even if the user decides to use a block
|
18
|
+
input_attributes: {
|
19
|
+
checked_value: builder.key,
|
20
|
+
checked: selected?(builder.key)
|
21
|
+
}
|
22
|
+
)
|
23
|
+
if block_given?
|
24
|
+
yield field
|
25
|
+
else
|
26
|
+
render field.radio_button_tag
|
27
|
+
render field.label_tag
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
25
31
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
module Concerns
|
7
|
+
module HandlesArrayInput
|
8
|
+
protected
|
9
|
+
|
10
|
+
def normalize_input(input_value)
|
11
|
+
normalize_array_input(input_value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def normalize_array_input(input_value)
|
15
|
+
Array(input_value).map { |nested_input_value| normalize_simple_input(nested_input_value) }.compact
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Components
|
6
|
+
module Concerns
|
7
|
+
module HandlesInput
|
8
|
+
# Collects parameters matching the input field's param key.
|
9
|
+
#
|
10
|
+
# @param params [Hash] the parameters to collect from.
|
11
|
+
# @return [Hash] the collected parameters.
|
12
|
+
def extract_input(params)
|
13
|
+
# # Handles multi parameter attributes
|
14
|
+
# # https://www.cookieshq.co.uk/posts/rails-spelunking-date-select
|
15
|
+
# # https://www.cookieshq.co.uk/posts/multiparameter-attributes
|
16
|
+
|
17
|
+
# # Matches
|
18
|
+
# # - parameter
|
19
|
+
# # - parameter(1)
|
20
|
+
# # - parameter(2)
|
21
|
+
# # - parameter(1i)
|
22
|
+
# # - parameter(2f)
|
23
|
+
# regex = /^#{param}(\(\d+[if]?\))?$/
|
24
|
+
# keys = params.select { |key, _| regex.match?(key) }.keys
|
25
|
+
# params.slice(*keys)
|
26
|
+
|
27
|
+
params ||= {}
|
28
|
+
{input_param => normalize_input(params[field.key])}
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def build_attributes
|
34
|
+
super
|
35
|
+
@input_param = attributes.delete(:input_param) || field.key
|
36
|
+
end
|
37
|
+
|
38
|
+
def input_param
|
39
|
+
@input_param
|
40
|
+
end
|
41
|
+
|
42
|
+
def normalize_input(input_value)
|
43
|
+
normalize_simple_input(input_value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def normalize_simple_input(input_value)
|
47
|
+
input_value.to_s.presence
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|