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
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class CollectionRadioButtons < Base
7
- include Concerns::HandlesInput
8
- include Concerns::HasOptions
9
-
10
- def view_template
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
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
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
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
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
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- module Concerns
7
- module HasOptions
8
- protected
9
-
10
- def build_attributes
11
- super
12
- @collection = attributes.delete(:collection) || field.collection
13
- @label_method = attributes.delete(:label_method)
14
- @value_method = attributes.delete(:value_method)
15
- end
16
-
17
- def option_mapper
18
- @option_mapper ||= OptionMapper.new(@collection, label_method: @label_method, value_method: @value_method)
19
- end
20
-
21
- def selected?(option)
22
- if attributes[:multiple]
23
- @options_list ||= Array(field.value)
24
- @options_list.any? { |item| item.to_s == option.to_s }
25
- else
26
- field.value.to_s == option.to_s
27
- end
28
- end
29
-
30
- def normalize_simple_input(input_value)
31
- ([super] & option_mapper.values)[0]
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- module Concerns
7
- module SubmitsDisplay
8
- def submit_type_value
9
- if field.object.respond_to?(:persisted?)
10
- field.object.persisted? ? :update : :create
11
- else
12
- :submit
13
- end
14
- end
15
-
16
- def submit_type_label
17
- @submit_type_label ||= begin
18
- key = submit_type_value
19
-
20
- model_object = field.dom.lineage.first.key.to_s
21
- model_name_human = if field.object.respond_to?(:model_name)
22
- field.object.model_name.human
23
- else
24
- model_object.humanize
25
- end
26
-
27
- defaults = []
28
- defaults << :"helpers.submit.#{model_object}.#{key}"
29
- defaults << :"helpers.submit.#{key}"
30
- defaults << "#{key.to_s.humanize} #{model_name_human}"
31
-
32
- I18n.t(defaults.shift, model: model_name_human, default: defaults)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class FileInput < Input
7
- def view_template
8
- input(type: :hidden, name: attributes[:name], value: "", autocomplete: "off", hidden: true) if include_hidden?
9
- input(**attributes)
10
- end
11
-
12
- protected
13
-
14
- def build_input_attributes
15
- attributes[:type] = :file
16
- super
17
- attributes[:value] = false
18
- end
19
-
20
- def include_hidden?
21
- return false if @include_hidden == false
22
-
23
- attributes[:multiple]
24
- end
25
-
26
- def normalize_input(input_value)
27
- input_value
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class FullError < Base
7
- def view_template
8
- p(**attributes) do
9
- field.full_error
10
- end
11
- end
12
-
13
- private
14
-
15
- def render?
16
- field.show_errors? && field.has_errors?
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class Input < Base
7
- include Concerns::HandlesInput
8
-
9
- def view_template
10
- input(**attributes)
11
- end
12
-
13
- protected
14
-
15
- def build_attributes
16
- super
17
-
18
- # only overwrite id if it was set in Base
19
- attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
20
-
21
- attributes[:name] = field.dom.name
22
- attributes[:value] = field.dom.value
23
-
24
- build_input_attributes
25
- end
26
-
27
- def build_input_attributes
28
- attributes.fetch(:type) { attributes[:type] = field.inferred_input_type }
29
- attributes.fetch(:disabled) { attributes[:disabled] = field.disabled? }
30
-
31
- case attributes[:type]
32
- when :text, :password, :email, :tel, :url, :search
33
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
34
- attributes.fetch(:placeholder) { attributes[:placeholder] = field.placeholder }
35
- attributes.fetch(:minlength) { attributes[:minlength] = field.minlength }
36
- attributes.fetch(:maxlength) { attributes[:maxlength] = field.maxlength }
37
- attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
38
- attributes.fetch(:required) { attributes[:required] = field.required? }
39
- attributes.fetch(:pattern) { attributes[:pattern] = field.pattern }
40
- when :number
41
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
42
- attributes.fetch(:placeholder) { attributes[:placeholder] = field.placeholder }
43
- attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
44
- attributes.fetch(:required) { attributes[:required] = field.required? }
45
- attributes.fetch(:min) { attributes[:min] = field.min }
46
- attributes.fetch(:max) { attributes[:max] = field.max }
47
- attributes.fetch(:step) { attributes[:step] = field.step }
48
- when :checkbox, :radio
49
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
50
- attributes.fetch(:required) { attributes[:required] = field.required? }
51
- when :file
52
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
53
- attributes.fetch(:required) { attributes[:required] = field.required? }
54
- attributes.fetch(:multiple) { attributes[:multiple] = field.multiple? }
55
- when :date, :time, :datetime_local
56
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
57
- attributes.fetch(:readonly) { attributes[:readonly] = field.readonly? }
58
- attributes.fetch(:required) { attributes[:required] = field.required? }
59
- attributes.fetch(:min) { attributes[:min] = field.min }
60
- attributes.fetch(:max) { attributes[:max] = field.max }
61
- when :color
62
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
63
- when :range
64
- attributes.fetch(:autofocus) { attributes[:autofocus] = field.focused? }
65
- attributes.fetch(:min) { attributes[:min] = field.min }
66
- attributes.fetch(:max) { attributes[:max] = field.max }
67
- attributes.fetch(:step) { attributes[:step] = field.step }
68
- when :hidden
69
- attributes[:class] = false
70
- attributes[:hidden] = true
71
- attributes[:autocomplete] = "off"
72
- else
73
- # Handle any unrecognized input types
74
- # Rails.logger.warn("Unhandled input type: #{attributes[:type]}")
75
- end
76
-
77
- if (attributes[:type] == :file) ? attributes[:multiple] : attributes.delete(:multiple)
78
- attributes[:name] = "#{attributes[:name].sub(/\[\]$/, "")}[]"
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class InputArray < Base
7
- include Concerns::HandlesInput
8
- include Concerns::HandlesArrayInput
9
-
10
- def view_template
11
- div(**attributes.slice(:id, :class)) do
12
- field.multi(values.length) do |builder|
13
- render builder.hidden_field_tag if builder.index == 0
14
-
15
- field = builder.field(
16
- label: builder.key,
17
- # we expect key to be an integer string starting from "1"
18
- value: values[builder.index]
19
- )
20
- if block_given?
21
- yield field
22
- else
23
- render field.input_tag
24
- end
25
- end
26
- end
27
- end
28
-
29
- protected
30
-
31
- def build_attributes
32
- super
33
-
34
- attributes[:multiple] = true
35
- end
36
-
37
- private
38
-
39
- def values
40
- @values ||= Array(field.value)
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class RadioButton < Input
7
- def view_template
8
- input(**attributes, value: @checked_value)
9
- end
10
-
11
- def extract_input(...)
12
- # when a radio is not submitted, nothing is returned
13
- super.compact
14
- end
15
-
16
- protected
17
-
18
- def build_input_attributes
19
- attributes[:type] = :radio
20
- super
21
-
22
- @checked_value = (attributes.key?(:checked_value) ? attributes.delete(:checked_value) : "1").to_s
23
-
24
- # this is a hack to workaround the fact that radio cannot be indexed/multiple
25
- attributes[:name] = attributes[:name].sub(/\[\]$/, "")
26
- attributes[:value] = @checked_value
27
- attributes[:checked] = attributes.fetch(:checked) { checked? }
28
- end
29
-
30
- def checked?
31
- field.dom.value == @checked_value
32
- end
33
-
34
- def normalize_input(...)
35
- input_value = super
36
- (input_value == @checked_value) ? input_value : nil
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class Select < Base
7
- include Concerns::HandlesInput
8
- include Concerns::HandlesArrayInput
9
- include Concerns::HasOptions
10
-
11
- def view_template
12
- PUI::Select.new
13
- end
14
-
15
- protected
16
-
17
- def options
18
- option_mapper.each do |value, label|
19
- option(selected: selected?(value), value: value) { label }
20
- end
21
- end
22
-
23
- def blank_option(&)
24
- option(selected: field.value.nil?, &)
25
- end
26
-
27
- def build_attributes
28
- super
29
-
30
- attributes[:id] = field.dom.id
31
- attributes[:name] = field.dom.name
32
-
33
- build_select_attributes
34
- end
35
-
36
- def build_select_attributes
37
- @include_blank = attributes.delete(:include_blank)
38
- @include_hidden = attributes.delete(:include_hidden)
39
-
40
- attributes[:autofocus] = attributes.fetch(:autofocus, field.focused?)
41
- attributes[:required] = attributes.fetch(:required, field.required?)
42
- attributes[:disabled] = attributes.fetch(:disabled, field.disabled?)
43
- attributes[:multiple] = attributes.fetch(:multiple, field.multiple?)
44
- attributes[:size] = attributes.fetch(:size, field.limit)
45
- end
46
-
47
- def blank_option_text
48
- field.placeholder
49
- end
50
-
51
- def include_blank?
52
- return true if @include_blank == true
53
-
54
- @include_blank != false && !attributes[:multiple]
55
- end
56
-
57
- def include_hidden?
58
- return false if @include_hidden == false
59
-
60
- attributes[:multiple]
61
- end
62
-
63
- def normalize_input(input_value)
64
- attributes[:multiple] ? normalize_array_input(input_value) : normalize_simple_input(input_value)
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class SubmitButton < Base
7
- include Concerns::SubmitsDisplay
8
-
9
- def view_template(&content)
10
- content ||= proc { submit_type_label }
11
- button(**attributes, &content)
12
- end
13
-
14
- protected
15
-
16
- def build_attributes
17
- root_key = field.dom.lineage.first.respond_to?(:dom_id) ? field.dom.lineage.first.dom_id : field.dom.lineage.first.key
18
- attributes.fetch(:id) { attributes[:id] = "#{root_key}_submit_button" }
19
- attributes[:class] = tokens(
20
- component_name,
21
- submit_type_value,
22
- attributes[:class]
23
- )
24
-
25
- build_button_attributes
26
- end
27
-
28
- def build_button_attributes
29
- formmethod = attributes[:formmethod]
30
- if formmethod.present? && !/post|get/i.match?(formmethod) && !attributes.key?(:name) && !attributes.key?(:value)
31
- attributes.merge! formmethod: :post, name: "_method", value: formmethod
32
- end
33
-
34
- attributes.fetch(:name) { attributes[:name] = "commit" }
35
- attributes.fetch(:value) { attributes[:value] = submit_type_label }
36
- attributes.fetch(:type) { attributes[:type] = :submit }
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module Components
6
- class Textarea < Base
7
- def view_template
8
- textarea(**attributes) { field.dom.value }
9
- end
10
-
11
- protected
12
-
13
- def build_attributes
14
- super
15
-
16
- attributes[:id] = field.dom.id
17
- attributes[:name] = field.dom.name
18
-
19
- build_textarea_attributes
20
- end
21
-
22
- def build_textarea_attributes
23
- attributes[:placeholder] = attributes.fetch(:placeholder, field.placeholder)
24
- attributes[:autofocus] = attributes.fetch(:autofocus, field.focused?)
25
- attributes[:minlength] = attributes.fetch(:minlength, field.minlength)
26
- attributes[:maxlength] = attributes.fetch(:maxlength, field.maxlength)
27
- attributes[:readonly] = attributes.fetch(:readonly, field.readonly?)
28
- attributes[:required] = attributes.fetch(:required, field.required?)
29
- attributes[:disabled] = attributes.fetch(:disabled, field.disabled?)
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module FieldOptions
6
- module Autofocus
7
- def focused?
8
- options[:autofocus] == true
9
- end
10
-
11
- def focused!(autofocus = true)
12
- options[:autofocus] = autofocus
13
- self
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module FieldOptions
6
- module Collection
7
- def collection(collection = nil)
8
- if collection.nil?
9
- options[:collection] = options.fetch(:collection) { infer_collection }
10
- else
11
- options[:collection] = collection
12
- self
13
- end
14
- end
15
-
16
- private
17
-
18
- def infer_collection
19
- collection_value_from_association || collection_value_from_validator
20
- end
21
-
22
- def collection_value_from_association
23
- return unless reflection
24
-
25
- relation = reflection.klass.all
26
-
27
- if reflection.respond_to?(:scope) && reflection.scope
28
- relation = if reflection.scope.parameters.any?
29
- reflection.klass.instance_exec(object, &reflection.scope)
30
- else
31
- reflection.klass.instance_exec(&reflection.scope)
32
- end
33
- else
34
- order = reflection.options[:order]
35
- conditions = reflection.options[:conditions]
36
- conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call)
37
-
38
- relation = relation.where(conditions) if relation.respond_to?(:where) && conditions.present?
39
- relation = relation.order(order) if relation.respond_to?(:order)
40
- end
41
-
42
- relation
43
- end
44
-
45
- def collection_value_from_validator
46
- return unless has_validators?
47
-
48
- inclusion_validator = find_validator(:inclusion)
49
- inclusion_validator.options[:in] || inclusion_validator.options[:within] if inclusion_validator
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexi
4
- module Display
5
- module FieldOptions
6
- module Disabled
7
- def disabled?
8
- options[:disabled] == true
9
- end
10
-
11
- def disabled!(disabled = true)
12
- options[:disabled] = disabled
13
- self
14
- end
15
- end
16
- end
17
- end
18
- end