phlexi-display 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/phlexi/display/base.rb +35 -158
  3. data/lib/phlexi/display/components/base.rb +1 -14
  4. data/lib/phlexi/display/components/concerns/displays_value.rb +54 -0
  5. data/lib/phlexi/display/components/date_time.rb +49 -0
  6. data/lib/phlexi/display/components/{error.rb → description.rb} +5 -5
  7. data/lib/phlexi/display/components/hint.rb +1 -1
  8. data/lib/phlexi/display/components/label.rb +3 -15
  9. data/lib/phlexi/display/components/number.rb +37 -0
  10. data/lib/phlexi/display/components/placeholder.rb +15 -0
  11. data/lib/phlexi/display/components/string.rb +17 -0
  12. data/lib/phlexi/display/components/wrapper.rb +4 -18
  13. data/lib/phlexi/display/field_options/associations.rb +2 -2
  14. data/lib/phlexi/display/field_options/attachments.rb +21 -0
  15. data/lib/phlexi/display/field_options/description.rb +22 -0
  16. data/lib/phlexi/display/field_options/hints.rb +1 -1
  17. data/lib/phlexi/display/field_options/inferred_types.rb +26 -52
  18. data/lib/phlexi/display/field_options/{placeholder.rb → placeholders.rb} +2 -2
  19. data/lib/phlexi/display/field_options/themes.rb +45 -120
  20. data/lib/phlexi/display/structure/dom.rb +7 -27
  21. data/lib/phlexi/display/structure/field_builder.rb +75 -151
  22. data/lib/phlexi/display/structure/field_collection.rb +5 -20
  23. data/lib/phlexi/display/structure/namespace.rb +22 -34
  24. data/lib/phlexi/display/structure/namespace_collection.rb +1 -9
  25. data/lib/phlexi/display/structure/node.rb +9 -3
  26. data/lib/phlexi/display/version.rb +1 -1
  27. data/lib/phlexi/display.rb +0 -1
  28. metadata +11 -31
  29. data/lib/phlexi/display/components/checkbox.rb +0 -48
  30. data/lib/phlexi/display/components/collection_checkboxes.rb +0 -44
  31. data/lib/phlexi/display/components/collection_radio_buttons.rb +0 -35
  32. data/lib/phlexi/display/components/concerns/handles_array_input.rb +0 -21
  33. data/lib/phlexi/display/components/concerns/handles_input.rb +0 -53
  34. data/lib/phlexi/display/components/concerns/has_options.rb +0 -37
  35. data/lib/phlexi/display/components/concerns/submits_form.rb +0 -39
  36. data/lib/phlexi/display/components/file_input.rb +0 -32
  37. data/lib/phlexi/display/components/full_error.rb +0 -21
  38. data/lib/phlexi/display/components/input.rb +0 -84
  39. data/lib/phlexi/display/components/input_array.rb +0 -45
  40. data/lib/phlexi/display/components/radio_button.rb +0 -41
  41. data/lib/phlexi/display/components/select.rb +0 -69
  42. data/lib/phlexi/display/components/submit_button.rb +0 -41
  43. data/lib/phlexi/display/components/textarea.rb +0 -34
  44. data/lib/phlexi/display/field_options/autofocus.rb +0 -18
  45. data/lib/phlexi/display/field_options/collection.rb +0 -54
  46. data/lib/phlexi/display/field_options/disabled.rb +0 -18
  47. data/lib/phlexi/display/field_options/errors.rb +0 -92
  48. data/lib/phlexi/display/field_options/length.rb +0 -53
  49. data/lib/phlexi/display/field_options/limit.rb +0 -66
  50. data/lib/phlexi/display/field_options/min_max.rb +0 -92
  51. data/lib/phlexi/display/field_options/multiple.rb +0 -65
  52. data/lib/phlexi/display/field_options/pattern.rb +0 -38
  53. data/lib/phlexi/display/field_options/readonly.rb +0 -18
  54. data/lib/phlexi/display/field_options/required.rb +0 -37
  55. data/lib/phlexi/display/field_options/validators.rb +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b140e54c49ca3a4a8808a12bb7a91dd8d250c91e2d7d29a8d7f9be2c20a7dbf5
4
- data.tar.gz: 9c70cec19581873bb9b93fc887571d6c8d5d65c95a25576bdf26a67e2bb30046
3
+ metadata.gz: 6269ae20b09b902ba613e2f158eae3de8c5b6a900264225a0580b97fb77e6ebe
4
+ data.tar.gz: 776a1c152a6e8e877f27747db06575c327ab042923b5068749631351938bae8a
5
5
  SHA512:
6
- metadata.gz: 466d34728adaedd7c4669a7419ec53929e49e1b4466135e5a7cc1eb42c88aa196b344ca4e29d8f27fb56a1e83437500678a2b003ca95fc82bbf70ab1ad017afc
7
- data.tar.gz: 047a28cd2c6afba47d9b6c8a833437ac2c009e626f747663dc9f506ef8d805b7979b8f59e4b0fe6e59a8180538d7e66cf323aba83e26e671e567ff12a3236a2c
6
+ metadata.gz: 6e0b53271d6d515923b6c05f0fd5d83a8f54e413058b0cd023a662e3a1e1d02c62f0205ccf411cd64daf22b1ae2457676aa9d52399444421a2cabe211509a352
7
+ data.tar.gz: 11bb8cd334e94ed31bcd096684cb1e7c844a13704df363dab0a540b0268440f0dcbf5a87973b7cd7ed7016e3bb45c8fe0ddbf0450a61332fd534bd0ae1f04e8d
@@ -1,22 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
- require "active_support/string_inquirer"
5
- require "active_support/core_ext/hash/deep_merge"
6
4
  require "active_support/core_ext/string/inflections"
7
5
 
8
6
  module Phlexi
9
7
  module Display
10
- # A form component for building flexible and customizable forms.
8
+ # A display component for rendering flexible and customizable data views.
11
9
  #
12
10
  # @example Basic usage
13
- # Phlexi::Display.new(user, action: '/users', method: 'post') do |f|
14
- # render field(:name).placeholder("Name").input_tag
15
- # render field(:email).placeholder("Email").input_tag
11
+ # Phlexi::Display.new(user) do |d|
12
+ # render d.field(:name).text
13
+ # render d.field(:email).text
16
14
  # end
17
15
  #
18
- # @attr_reader [Symbol] key The form's key, derived from the record or explicitly set
19
- # @attr_reader [ActiveModel::Model, nil] object The form's associated object
16
+ # @attr_reader [Symbol] key The display's key, derived from the record or explicitly set
17
+ # @attr_reader [ActiveModel::Model, nil] object The display's associated object
20
18
  class Base < COMPONENT_BASE
21
19
  class Namespace < Structure::Namespace; end
22
20
 
@@ -24,22 +22,18 @@ module Phlexi
24
22
 
25
23
  attr_reader :key, :object
26
24
 
27
- delegate :field, :submit_button, :nest_one, :nest_many, to: :@namespace
25
+ delegate :field, :nest_one, :nest_many, to: :@namespace
28
26
 
29
27
  # Initializes a new Display instance.
30
28
  #
31
- # @param record [ActiveModel::Model, Symbol, String] The form's associated record or key
32
- # @param action [String, nil] The form's action URL
33
- # @param method [String, nil] The form's HTTP method
34
- # @param attributes [Hash] Additional HTML attributes for the form tag
35
- # @param options [Hash] Additional options for form configuration
36
- # @option options [String] :class CSS classes for the form
29
+ # @param record [ActiveModel::Model, Symbol, String] The display's associated record or key
30
+ # @param attributes [Hash] Additional HTML attributes for the display container
31
+ # @param options [Hash] Additional options for display configuration
32
+ # @option options [String] :class CSS classes for the display
37
33
  # @option options [Class] :namespace_klass Custom namespace class
38
34
  # @option options [Class] :builder_klass Custom field builder class
39
- def initialize(record, action: nil, method: nil, attributes: {}, **options)
40
- @form_action = action
41
- @form_method = method
42
- @form_class = options.delete(:class)
35
+ def initialize(record, attributes: {}, **options)
36
+ @display_class = options.delete(:class)
43
37
  @attributes = attributes
44
38
  @namespace_klass = options.delete(:namespace_klass) || default_namespace_klass
45
39
  @builder_klass = options.delete(:builder_klass) || default_builder_klass
@@ -47,52 +41,32 @@ module Phlexi
47
41
 
48
42
  initialize_object_and_key(record)
49
43
  initialize_namespace
50
- initialize_attributes
51
44
  end
52
45
 
53
- # Renders the form template.
46
+ # Renders the display template.
54
47
  #
55
48
  # @return [void]
56
49
  def view_template
57
- form_tag { form_template }
50
+ display_template
58
51
  end
59
52
 
60
- # Executes the form's content block.
61
- # Override this in subclasses to defie a static form.
62
- #
63
- # @return [void]
64
- def form_template
65
- instance_exec(&@_content_block) if @_content_block
66
- end
53
+ protected
54
+
55
+ attr_reader :options, :attributes, :namespace_klass, :builder_klass
67
56
 
68
- # Renders the form tag with its contents.
57
+ # Executes the display's content block.
58
+ # Override this in subclasses to define a static display.
69
59
  #
70
- # @yield The form's content
71
60
  # @return [void]
72
- def form_tag(&)
73
- form(**form_attributes) do
74
- render_hidden_method_field
75
- render_authenticity_token if authenticity_token?
76
- yield
77
- end
78
- end
79
-
80
- def extract_input(params)
81
- call unless @_rendered
82
- @namespace.extract_input(params)
61
+ def display_template
62
+ instance_exec(&@_content_block) if @_content_block
83
63
  end
84
64
 
85
- protected
86
-
87
- attr_reader :options, :attributes, :namespace_klass, :builder_klass
88
-
89
65
  # Initializes the object and key based on the given record.
90
66
  #
91
- # @param record [ActiveModel::Model, Symbol, String] The form's associated record or key
67
+ # @param record [ActiveModel::Model, Symbol, String] The display's associated record or key
92
68
  # @return [void]
93
69
  def initialize_object_and_key(record)
94
- # always pop these keys
95
- # add support for `as` to make it more rails friendly
96
70
  @key = options.delete(:key) || options.delete(:as)
97
71
 
98
72
  case record
@@ -101,134 +75,37 @@ module Phlexi
101
75
  @key = record
102
76
  else
103
77
  @object = record
104
- if @key.nil?
105
- unless object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key.present?
106
- raise ArgumentError, "record must respond to #model_name.param_key with a non nil value or set `key` option e.g. Phlexi::Display(record, key: :record)"
107
- end
108
- @key = object.model_name.param_key
78
+ @key = if @key.nil? && object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key.present?
79
+ object.model_name.param_key
80
+ else
81
+ :object
109
82
  end
110
83
  end
111
84
  @key = @key.to_sym
112
85
  end
113
86
 
114
- # Initializes the namespace for the form.
87
+ # Initializes the namespace for the display.
115
88
  #
116
89
  # @return [void]
117
90
  def initialize_namespace
118
91
  @namespace = namespace_klass.root(key, object: object, builder_klass: builder_klass)
119
92
  end
120
-
121
- # Initializes form attributes.
122
- #
123
- # @return [void]
124
- def initialize_attributes
125
- attributes.fetch(:accept_charset) { attributes[:accept_charset] = "UTF-8" }
126
- end
127
-
128
- # Determines the form's action URL.
129
- #
130
- # @return [String, nil] The form's action URL
131
- def form_action
132
- puts ""
133
- # if @form_action != false
134
- # @form_action ||= if options[:format].nil?
135
- # polymorphic_path(object, {})
136
- # else
137
- # polymorphic_path(object, format: options[:format])
138
- # end
139
- # end
140
- @form_action
141
- end
142
-
143
- # Determines the form's HTTP method.
144
- #
145
- # @return [ActiveSupport::StringInquirer] The form's HTTP method
146
- def form_method
147
- @form_method ||= (object_form_method || "get").to_s.downcase
148
- ActiveSupport::StringInquirer.new(@form_method)
149
- end
150
-
151
- # Retrieves the form's CSS classes.
152
- #
153
- # @return [String] The form's CSS classes
154
- attr_reader :form_class
155
-
156
- # Checks if the authenticity token should be included.
157
- #
158
- # @return [Boolean] True if the authenticity token should be included, false otherwise
159
- def authenticity_token?
160
- defined?(helpers) && options.fetch(:authenticity_token) { !form_method.get? }
161
- end
162
-
163
- # Retrieves the authenticity token.
164
- #
165
- # @return [String] The authenticity token
166
- def authenticity_token
167
- options.fetch(:authenticity_token) { helpers.form_authenticity_token }
168
- end
169
-
170
- # Renders the authenticity token field.
171
- #
172
- # @param name [String] The name attribute for the authenticity token field
173
- # @param value [String] The value for the authenticity token field
174
- # @return [void]
175
- def authenticity_token_field(name = "authenticity_token", value = authenticity_token)
176
- input(name: name, value: value, type: "hidden", hidden: true)
177
- end
178
-
179
- # Determines the appropriate form method based on the object's state.
93
+ # Retrieves the display's CSS classes.
180
94
  #
181
- # @return [String, nil] The appropriate form method
182
- def object_form_method
183
- if object.respond_to?(:persisted?)
184
- object.persisted? ? "patch" : "post"
185
- elsif object.present?
186
- "post"
187
- end
188
- end
95
+ # @return [String] The display's CSS classes
96
+ attr_reader :display_class
189
97
 
190
- # Renders the hidden method field for non-standard HTTP methods.
98
+ # Generates the display attributes hash.
191
99
  #
192
- # @return [void]
193
- def render_hidden_method_field
194
- return if standard_form_method?
195
- input(name: "_method", value: form_method, type: "hidden", hidden: true)
196
- end
197
-
198
- # Checks if the form method is standard (GET or POST).
199
- #
200
- # @return [Boolean] True if the form method is standard, false otherwise
201
- def standard_form_method?
202
- form_method.get? || form_method.post?
203
- end
204
-
205
- # Returns the standardized form method for the HTML form tag.
206
- #
207
- # @return [String] The standardized form method
208
- def standardized_form_method
209
- standard_form_method? ? form_method : "post"
210
- end
211
-
212
- # Generates the form attributes hash.
213
- #
214
- # @return [Hash] The form attributes
215
- def form_attributes
100
+ # @return [Hash] The display attributes
101
+ def display_attributes
216
102
  {
217
103
  id: @namespace.dom_id,
218
- action: form_action,
219
- method: standardized_form_method,
220
- class: form_class,
104
+ class: display_class,
221
105
  **attributes
222
106
  }
223
107
  end
224
108
 
225
- # Renders the authenticity token if required.
226
- #
227
- # @return [void]
228
- def render_authenticity_token
229
- authenticity_token_field
230
- end
231
-
232
109
  private
233
110
 
234
111
  def default_namespace_klass
@@ -25,12 +25,7 @@ module Phlexi
25
25
 
26
26
  attributes[:class] = tokens(
27
27
  component_name,
28
- attributes[:class],
29
- -> { attributes[:required] } => "required",
30
- -> { !attributes[:required] } => "optional",
31
- -> { field.has_errors? } => "invalid",
32
- -> { attributes[:readonly] } => "readonly",
33
- -> { attributes[:disabled] } => "disabled"
28
+ attributes[:class]
34
29
  )
35
30
  end
36
31
 
@@ -41,11 +36,3 @@ module Phlexi
41
36
  end
42
37
  end
43
38
  end
44
-
45
-
46
-
47
- User
48
- name: :string
49
- validate :name, presence: true
50
-
51
- f.input :name
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ module Concerns
7
+ module DisplaysValue
8
+ def view_template
9
+ value = normalize_value(field.value)
10
+ if value.blank?
11
+ render field.placeholder_tag(**@placeholder_attributes)
12
+ else
13
+ render_value(value)
14
+ end
15
+ end
16
+
17
+ # Renders the field value for display.
18
+ #
19
+ # @return [String] the formatted field value for display.
20
+ def render_value(value)
21
+ raise NotImplementedError, "#{self.class}#render_value"
22
+ # format_value()
23
+ end
24
+
25
+ protected
26
+
27
+ def build_attributes
28
+ super
29
+
30
+ @placeholder_attributes = attributes.delete(:placeholder_attributes) || {}
31
+ attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
32
+ end
33
+
34
+ # def format_value(value)
35
+ # case value
36
+ # when Array
37
+ # format_array_value(value)
38
+ # else
39
+ # format_single_value(value)
40
+ # end
41
+ # end
42
+
43
+ # def format_array_value(array)
44
+ # array.map { |item| format_single_value(item) }.join(", ")
45
+ # end
46
+
47
+ def normalize_value(value)
48
+ value.to_s
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class DateTime < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ # Renders the date time value
10
+ #
11
+ # @param value [String, Date, Time, DateTime] The value to be rendered
12
+ # @return [void]
13
+ def render_value(value)
14
+ formatted_value = format_date_time(value)
15
+ p(**attributes) { formatted_value }
16
+ end
17
+
18
+ protected
19
+
20
+ def build_attributes
21
+ super
22
+
23
+ @options = {
24
+ format: default_format
25
+ }.merge(attributes.delete(:options) || {}).compact
26
+ end
27
+
28
+ private
29
+
30
+ def format_date_time(value)
31
+ I18n.l(value, **@options)
32
+ end
33
+
34
+ def default_format
35
+ :long
36
+ end
37
+
38
+ def normalize_value(value)
39
+ case value
40
+ when Date, DateTime, Time, nil
41
+ value
42
+ else
43
+ raise ArgumentError, "Value must be a Date, DateTime or Time object. #{value.inspect} given."
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -3,17 +3,17 @@
3
3
  module Phlexi
4
4
  module Display
5
5
  module Components
6
- class Error < Base
6
+ class Description < Base
7
7
  def view_template
8
- p(**attributes) do
9
- field.error
10
- end
8
+ p(**attributes) {
9
+ field.description
10
+ }
11
11
  end
12
12
 
13
13
  private
14
14
 
15
15
  def render?
16
- field.show_errors? && field.has_errors?
16
+ field.has_description?
17
17
  end
18
18
  end
19
19
  end
@@ -13,7 +13,7 @@ module Phlexi
13
13
  private
14
14
 
15
15
  def render?
16
- field.hint.present? && (!field.show_errors? || !field.has_errors?)
16
+ field.has_hint?
17
17
  end
18
18
  end
19
19
  end
@@ -5,21 +5,9 @@ module Phlexi
5
5
  module Components
6
6
  class Label < Base
7
7
  def view_template
8
- label(**attributes) do
9
- if field.required?
10
- abbr(title: "required") { "*" }
11
- whitespace
12
- end
13
- plain field.label
14
- end
15
- end
16
-
17
- protected
18
-
19
- def build_attributes
20
- super
21
-
22
- attributes.fetch(:for) { attributes[:for] = field.dom.id }
8
+ h5(**attributes) {
9
+ field.label
10
+ }
23
11
  end
24
12
  end
25
13
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper"
4
+
5
+ module Phlexi
6
+ module Display
7
+ module Components
8
+ class Number < Base
9
+ include Concerns::DisplaysValue
10
+
11
+ def render_value(value)
12
+ p(**attributes) {
13
+ format_number(value)
14
+ }
15
+ end
16
+
17
+ protected
18
+
19
+ def build_attributes
20
+ super
21
+
22
+ @options = attributes.delete(:options) || {}
23
+ end
24
+
25
+ private
26
+
27
+ def format_number(value)
28
+ ActiveSupport::NumberHelper.number_to_delimited(value, **@options)
29
+ end
30
+
31
+ def normalize_value(value)
32
+ Float(value.to_s)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Placeholder < Base
7
+ def view_template
8
+ p(**attributes) {
9
+ field.placeholder
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class String < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ def render_value(value)
10
+ p(**attributes) {
11
+ value
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -4,26 +4,12 @@ module Phlexi
4
4
  module Display
5
5
  module Components
6
6
  class Wrapper < Base
7
- attr_reader :inner_attributes
8
-
9
7
  def view_template
10
- div(**attributes) do
8
+ div(**attributes) {
11
9
  render field.label_tag
12
- div(**inner_attributes) do
13
- yield field if block_given?
14
- render field.full_error_tag
15
- render field.hint_tag
16
- end
17
- end
18
- end
19
-
20
- protected
21
-
22
- def build_attributes
23
- super
24
-
25
- @inner_attributes = attributes.delete(:inner) || {}
26
- inner_attributes[:class] = tokens("inner-wrapper", inner_attributes[:class])
10
+ yield field if block_given?
11
+ render field.description_tag
12
+ }
27
13
  end
28
14
  end
29
15
  end
@@ -6,8 +6,8 @@ module Phlexi
6
6
  module Associations
7
7
  protected
8
8
 
9
- def reflection
10
- @reflection ||= find_association_reflection
9
+ def association_reflection
10
+ @association_reflection ||= find_association_reflection
11
11
  end
12
12
 
13
13
  def find_association_reflection
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module FieldOptions
6
+ module Attachments
7
+ protected
8
+
9
+ def attachment_reflection
10
+ @attachment_reflection ||= find_attachment_reflection
11
+ end
12
+
13
+ def find_attachment_reflection
14
+ if object.class.respond_to?(:reflect_on_attachment)
15
+ object.class.reflect_on_attachment(key)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module FieldOptions
6
+ module Description
7
+ def description(description = nil)
8
+ if description.nil?
9
+ options[:description]
10
+ else
11
+ options[:description] = description
12
+ self
13
+ end
14
+ end
15
+
16
+ def has_description?
17
+ description.present?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -14,7 +14,7 @@ module Phlexi
14
14
  end
15
15
 
16
16
  def has_hint?
17
- options[:hint] != false && hint.present?
17
+ hint.present?
18
18
  end
19
19
  end
20
20
  end