phlexi-display 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/phlexi/display/base.rb +37 -30
  3. data/lib/phlexi/display/builder.rb +174 -0
  4. data/lib/phlexi/display/components/association.rb +41 -0
  5. data/lib/phlexi/display/components/base.rb +2 -29
  6. data/lib/phlexi/display/components/color.rb +20 -0
  7. data/lib/phlexi/display/components/concerns/displays_value.rb +5 -19
  8. data/lib/phlexi/display/components/date_time.rb +14 -14
  9. data/lib/phlexi/display/components/email.rb +43 -0
  10. data/lib/phlexi/display/components/enum.rb +17 -0
  11. data/lib/phlexi/display/components/integer.rb +17 -0
  12. data/lib/phlexi/display/components/json.rb +25 -0
  13. data/lib/phlexi/display/components/password.rb +23 -0
  14. data/lib/phlexi/display/components/placeholder.rb +1 -1
  15. data/lib/phlexi/display/components/time.rb +15 -0
  16. data/lib/phlexi/display/components/url.rb +44 -0
  17. data/lib/phlexi/display/html.rb +15 -0
  18. data/lib/phlexi/display/options/inferred_types.rb +29 -0
  19. data/lib/phlexi/display/theme.rb +35 -0
  20. data/lib/phlexi/display/version.rb +1 -1
  21. data/lib/phlexi/display.rb +4 -6
  22. metadata +29 -17
  23. data/lib/phlexi/display/field_options/associations.rb +0 -21
  24. data/lib/phlexi/display/field_options/attachments.rb +0 -21
  25. data/lib/phlexi/display/field_options/description.rb +0 -22
  26. data/lib/phlexi/display/field_options/hints.rb +0 -22
  27. data/lib/phlexi/display/field_options/inferred_types.rb +0 -129
  28. data/lib/phlexi/display/field_options/labels.rb +0 -28
  29. data/lib/phlexi/display/field_options/placeholders.rb +0 -18
  30. data/lib/phlexi/display/field_options/themes.rb +0 -132
  31. data/lib/phlexi/display/option_mapper.rb +0 -154
  32. data/lib/phlexi/display/structure/dom.rb +0 -42
  33. data/lib/phlexi/display/structure/field_builder.rb +0 -160
  34. data/lib/phlexi/display/structure/field_collection.rb +0 -39
  35. data/lib/phlexi/display/structure/namespace.rb +0 -123
  36. data/lib/phlexi/display/structure/namespace_collection.rb +0 -40
  37. data/lib/phlexi/display/structure/node.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6269ae20b09b902ba613e2f158eae3de8c5b6a900264225a0580b97fb77e6ebe
4
- data.tar.gz: 776a1c152a6e8e877f27747db06575c327ab042923b5068749631351938bae8a
3
+ metadata.gz: b0c24a5fa14dc380439a665f86ab750dce0dfc4533960518e2ebd62c4a4a3a38
4
+ data.tar.gz: c3a8f5f8c11819831b77a43b30b6ddebce4cdc349b0a1087407b1cb3ca9e8860
5
5
  SHA512:
6
- metadata.gz: 6e0b53271d6d515923b6c05f0fd5d83a8f54e413058b0cd023a662e3a1e1d02c62f0205ccf411cd64daf22b1ae2457676aa9d52399444421a2cabe211509a352
7
- data.tar.gz: 11bb8cd334e94ed31bcd096684cb1e7c844a13704df363dab0a540b0268440f0dcbf5a87973b7cd7ed7016e3bb45c8fe0ddbf0450a61332fd534bd0ae1f04e8d
6
+ metadata.gz: 35e8e3cb43b9949317ed4ea0df9ff5fa98e408a3fd78f8ce16315343a91aed8748f6a987f068927f73c1c682e4f3c560d28f9876176de841987ef932f5afe0ec
7
+ data.tar.gz: 6a0016904df13b9c35e5463a0f5f5e72963c2766be0513e76b21d4bfd1c94258ced23e1a0d23487d6feb6ec1ed555556df8f01de5d73692d84d3e5a30e7f3181
@@ -15,10 +15,18 @@ module Phlexi
15
15
  #
16
16
  # @attr_reader [Symbol] key The display's key, derived from the record or explicitly set
17
17
  # @attr_reader [ActiveModel::Model, nil] object The display's associated object
18
- class Base < COMPONENT_BASE
19
- class Namespace < Structure::Namespace; end
18
+ class Base < Phlexi::Display::HTML
19
+ class Namespace < Phlexi::Field::Structure::Namespace; end
20
20
 
21
- class FieldBuilder < Structure::FieldBuilder; end
21
+ class Builder < Phlexi::Display::Builder; end
22
+
23
+ def self.inline(*, **, &block)
24
+ raise ArgumentError, "block is required" unless block
25
+
26
+ new(*, **) do |f|
27
+ f.instance_exec(&block)
28
+ end
29
+ end
22
30
 
23
31
  attr_reader :key, :object
24
32
 
@@ -33,10 +41,9 @@ module Phlexi
33
41
  # @option options [Class] :namespace_klass Custom namespace class
34
42
  # @option options [Class] :builder_klass Custom field builder class
35
43
  def initialize(record, attributes: {}, **options)
36
- @display_class = options.delete(:class)
37
44
  @attributes = attributes
38
- @namespace_klass = options.delete(:namespace_klass) || default_namespace_klass
39
- @builder_klass = options.delete(:builder_klass) || default_builder_klass
45
+ @namespace_klass = options.delete(:namespace_klass) || self.class::Namespace
46
+ @builder_klass = options.delete(:builder_klass) || self.class::Builder
40
47
  @options = options
41
48
 
42
49
  initialize_object_and_key(record)
@@ -46,22 +53,22 @@ module Phlexi
46
53
  # Renders the display template.
47
54
  #
48
55
  # @return [void]
49
- def view_template
50
- display_template
56
+ def view_template(&)
57
+ display_wrapper { display_template(&) }
51
58
  end
52
59
 
53
- protected
54
-
55
- attr_reader :options, :attributes, :namespace_klass, :builder_klass
56
-
57
60
  # Executes the display's content block.
58
61
  # Override this in subclasses to define a static display.
59
62
  #
60
63
  # @return [void]
61
64
  def display_template
62
- instance_exec(&@_content_block) if @_content_block
65
+ yield if block_given?
63
66
  end
64
67
 
68
+ protected
69
+
70
+ attr_reader :options, :attributes, :namespace_klass, :builder_klass
71
+
65
72
  # Initializes the object and key based on the given record.
66
73
  #
67
74
  # @param record [ActiveModel::Model, Symbol, String] The display's associated record or key
@@ -75,10 +82,12 @@ module Phlexi
75
82
  @key = record
76
83
  else
77
84
  @object = record
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
85
+ if @key.nil?
86
+ @key = if object.respond_to?(:model_name) && object.model_name.respond_to?(:param_key) && object.model_name.param_key.present?
87
+ object.model_name.param_key
88
+ else
89
+ object.class.name.demodulize.underscore
90
+ end
82
91
  end
83
92
  end
84
93
  @key = @key.to_sym
@@ -90,30 +99,28 @@ module Phlexi
90
99
  def initialize_namespace
91
100
  @namespace = namespace_klass.root(key, object: object, builder_klass: builder_klass)
92
101
  end
102
+
93
103
  # Retrieves the display's CSS classes.
94
104
  #
95
105
  # @return [String] The display's CSS classes
96
- attr_reader :display_class
106
+ def display_class
107
+ themed(:base)
108
+ end
97
109
 
98
110
  # Generates the display attributes hash.
99
111
  #
100
112
  # @return [Hash] The display attributes
101
113
  def display_attributes
102
- {
114
+ mix({
103
115
  id: @namespace.dom_id,
104
- class: display_class,
105
- **attributes
106
- }
116
+ class: display_class
117
+ }, attributes)
107
118
  end
108
119
 
109
- private
110
-
111
- def default_namespace_klass
112
- self.class::Namespace
113
- end
114
-
115
- def default_builder_klass
116
- self.class::FieldBuilder
120
+ def display_wrapper(&)
121
+ div(**display_attributes) do
122
+ yield
123
+ end
117
124
  end
118
125
  end
119
126
  end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "phlex"
4
+
5
+ module Phlexi
6
+ module Display
7
+ # Builder class is responsible for building display fields with various options and components.
8
+ class Builder < Phlexi::Field::Builder
9
+ include Phlexi::Display::Options::InferredTypes
10
+
11
+ # Creates a label tag for the field.
12
+ #
13
+ # @param attributes [Hash] Additional attributes for the label.
14
+ # @return [Components::Label] The label component.
15
+ def label_tag(**, &)
16
+ create_component(Components::Label, :label, **, &)
17
+ end
18
+
19
+ # Creates a Placeholder tag for the field.
20
+ #
21
+ # @param attributes [Hash] Additional attributes for the placeholder.
22
+ # @return [Components::Placeholder] The placeholder component.
23
+ def placeholder_tag(**, &)
24
+ create_component(Components::Placeholder, :placeholder, **, &)
25
+ end
26
+
27
+ # Creates a Description tag for the field.
28
+ #
29
+ # @param attributes [Hash] Additional attributes for the description.
30
+ # @return [Components::Description] The description component.
31
+ def description_tag(**, &)
32
+ create_component(Components::Description, :description, **, &)
33
+ end
34
+
35
+ # Creates a string display tag for the field.
36
+ #
37
+ # @param attributes [Hash] Additional attributes for the string display.
38
+ # @return [Components::String] The string component.
39
+ def string_tag(**, &)
40
+ create_component(Components::String, :string, **, &)
41
+ end
42
+ alias_method :search_tag, :string_tag
43
+
44
+ def text_tag(**, &)
45
+ create_component(Components::String, :text, **, &)
46
+ end
47
+
48
+ def phone_tag(**, &)
49
+ create_component(Components::String, :phone, **, &)
50
+ end
51
+
52
+ # Creates a number display tag for the field.
53
+ #
54
+ # @param attributes [Hash] Additional attributes for the number display.
55
+ # @return [Components::Number] The number component.
56
+ def number_tag(**, &)
57
+ create_component(Components::Number, :number, **, &)
58
+ end
59
+
60
+ def integer_tag(**, &)
61
+ create_component(Components::Integer, :integer, **, &)
62
+ end
63
+
64
+ def json_tag(**, &)
65
+ create_component(Components::JSON, :json, **, &)
66
+ end
67
+
68
+ def hstore_tag(**, &)
69
+ create_component(Components::JSON, :hstore, **, &)
70
+ end
71
+
72
+ # Creates a datetime display for the field.
73
+ #
74
+ # @param attributes [Hash] Additional attributes for the datetime display.
75
+ # @return [Components::DateTime] The datetime component.
76
+ def datetime_tag(**, &)
77
+ create_component(Components::DateTime, :datetime, **, &)
78
+ end
79
+
80
+ def date_tag(**, &)
81
+ create_component(Components::DateTime, :date, **, &)
82
+ end
83
+
84
+ def time_tag(**, &)
85
+ create_component(Components::Time, :time, **, &)
86
+ end
87
+
88
+ # # Creates a boolean display tag for the field.
89
+ # #
90
+ # # @param attributes [Hash] Additional attributes for the boolean display.
91
+ # # @return [Components::Boolean] The boolean component.
92
+ # def boolean_tag(**, &)
93
+ # create_component(Components::Boolean, :boolean, **, &)
94
+ # end
95
+
96
+ # Creates a color display tag for the field.
97
+ #
98
+ # @param attributes [Hash] Additional attributes for the color display.
99
+ # @return [Components::Color] The color component.
100
+ def color_tag(**, &)
101
+ create_component(Components::Color, :color, **, &)
102
+ end
103
+
104
+ # Creates a password display tag for the field.
105
+ #
106
+ # @param attributes [Hash] Additional attributes for the password display.
107
+ # @return [Components::Password] The password component.
108
+ def password_tag(**, &)
109
+ create_component(Components::Password, :password, **, &)
110
+ end
111
+
112
+ # Creates a enum display tag for the field.
113
+ #
114
+ # @param attributes [Hash] Additional attributes for the enum display.
115
+ # @return [Components::Enum] The enum component.
116
+ def enum_tag(**, &)
117
+ create_component(Components::Enum, :enum, **, &)
118
+ end
119
+
120
+ # Creates a email display tag for the field.
121
+ #
122
+ # @param attributes [Hash] Additional attributes for the email display.
123
+ # @return [Components::Email] The email component.
124
+ def email_tag(**, &)
125
+ create_component(Components::Email, :email, **, &)
126
+ end
127
+
128
+ # Creates a url display tag for the field.
129
+ #
130
+ # @param attributes [Hash] Additional attributes for the url display.
131
+ # @return [Components::Url] The url component.
132
+ def url_tag(**, &)
133
+ create_component(Components::Url, :url, **, &)
134
+ end
135
+
136
+ # Creates an association display tag for the field.
137
+ #
138
+ # @param attributes [Hash] Additional attributes for the association display.
139
+ # @return [Components::Association] The association component.
140
+ def association_tag(**, &)
141
+ create_component(Components::Association, :association, **, &)
142
+ end
143
+
144
+ # # Creates an attachment display tag for the field.
145
+ # #
146
+ # # @param attributes [Hash] Additional attributes for the attachment display.
147
+ # # @return [Components::Attachment] The attachment component.
148
+ # def attachment_tag(**, &)
149
+ # create_component(Components::Attachment, :attachment, **, &)
150
+ # end
151
+
152
+ # Wraps the field with additional markup.
153
+ #
154
+ # @param attributes [Hash] Additional attributes for the wrapper.
155
+ # @yield [block] The block to be executed within the wrapper.
156
+ # @return [Components::Wrapper] The wrapper component.
157
+ def wrapped(**, &)
158
+ create_component(Components::Wrapper, :wrapper, **, &)
159
+ end
160
+
161
+ protected
162
+
163
+ def create_component(component_class, theme_key, **attributes, &)
164
+ theme_key = attributes.delete(:theme) || theme_key
165
+ attributes = mix({class: themed(theme_key)}, attributes) unless attributes.key?(:class!)
166
+ component_class.new(self, **attributes, &)
167
+ end
168
+
169
+ def themed(component)
170
+ Phlexi::Display::Theme.instance.resolve_theme(component)
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Association < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ def render_value(value)
10
+ p(**attributes) {
11
+ display_name_of(value)
12
+ }
13
+ end
14
+
15
+ protected
16
+
17
+ def display_name_of(obj, separator: ", ")
18
+ return unless obj.present?
19
+
20
+ # Retrieve the value from a predefined list
21
+ %i[to_label name title].each do |method|
22
+ name = obj.public_send(method) if obj.respond_to?(method)
23
+ return name if name.present?
24
+ end
25
+
26
+ # Maybe this is a record?
27
+ if (primary_key = Phlexi::Field.object_primary_key(obj))
28
+ return "#{obj.class.model_name.human} ##{primary_key}"
29
+ end
30
+
31
+ # Oh well. Just convert it to a string.
32
+ obj.to_s
33
+ end
34
+
35
+ def normalize_value(value)
36
+ value
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,35 +3,8 @@
3
3
  module Phlexi
4
4
  module Display
5
5
  module Components
6
- class Base < COMPONENT_BASE
7
- attr_reader :field, :attributes
8
-
9
- def initialize(field, **attributes)
10
- @field = field
11
- @attributes = attributes
12
-
13
- build_attributes
14
- append_attribute_classes
15
- end
16
-
17
- protected
18
-
19
- def build_attributes
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
-
26
- attributes[:class] = tokens(
27
- component_name,
28
- attributes[:class]
29
- )
30
- end
31
-
32
- def component_name
33
- @component_name ||= self.class.name.demodulize.underscore
34
- end
6
+ class Base < Phlexi::Field::Components::Base
7
+ include Phlexi::Display::HTML::Behaviour
35
8
  end
36
9
  end
37
10
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Color < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ def render_value(value)
10
+ div(**attributes) {
11
+ div(class: themed(:color_indicator), style: "background-color: #{value};") {
12
+ whitespace
13
+ }
14
+ p { value }
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -6,11 +6,11 @@ module Phlexi
6
6
  module Concerns
7
7
  module DisplaysValue
8
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)
9
+ return render(field.placeholder_tag(**@placeholder_attributes)) unless field.has_value?
10
+
11
+ values = (field.multiple? && field.value.respond_to?(:each)) ? field.value : [field.value]
12
+ values.each do |value|
13
+ render_value(normalize_value(value))
14
14
  end
15
15
  end
16
16
 
@@ -19,7 +19,6 @@ module Phlexi
19
19
  # @return [String] the formatted field value for display.
20
20
  def render_value(value)
21
21
  raise NotImplementedError, "#{self.class}#render_value"
22
- # format_value()
23
22
  end
24
23
 
25
24
  protected
@@ -31,19 +30,6 @@ module Phlexi
31
30
  attributes[:id] = field.dom.id if attributes[:id] == "#{field.dom.id}_#{component_name}"
32
31
  end
33
32
 
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
33
  def normalize_value(value)
48
34
  value.to_s
49
35
  end
@@ -11,8 +11,7 @@ module Phlexi
11
11
  # @param value [String, Date, Time, DateTime] The value to be rendered
12
12
  # @return [void]
13
13
  def render_value(value)
14
- formatted_value = format_date_time(value)
15
- p(**attributes) { formatted_value }
14
+ p(**attributes) { value }
16
15
  end
17
16
 
18
17
  protected
@@ -20,27 +19,28 @@ module Phlexi
20
19
  def build_attributes
21
20
  super
22
21
 
23
- @options = {
24
- format: default_format
25
- }.merge(attributes.delete(:options) || {}).compact
22
+ @options = attributes.delete(:options) || {}
23
+ @formats = Array(@options.delete(:format)).compact + default_formats
26
24
  end
27
25
 
28
- private
29
-
30
- def format_date_time(value)
31
- I18n.l(value, **@options)
26
+ def format_value(value)
27
+ @formats.each do |fmt|
28
+ return I18n.l(value, **@options, format: fmt)
29
+ rescue
30
+ nil
31
+ end
32
32
  end
33
33
 
34
- def default_format
35
- :long
34
+ def default_formats
35
+ [:long]
36
36
  end
37
37
 
38
38
  def normalize_value(value)
39
39
  case value
40
- when Date, DateTime, Time, nil
41
- value
40
+ when ::DateTime, ::Date, ::Time
41
+ format_value(value)
42
42
  else
43
- raise ArgumentError, "Value must be a Date, DateTime or Time object. #{value.inspect} given."
43
+ value.to_s
44
44
  end
45
45
  end
46
46
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Email < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ def render_value(value)
10
+ a(**attributes, href: "mailto:#{value}", target: "_blank") {
11
+ icon
12
+ plain value
13
+ }
14
+ end
15
+
16
+ protected
17
+
18
+ def icon
19
+ icon_theme = themed(:prefixed_icon)
20
+ svg(
21
+ xmlns: "http://www.w3.org/2000/svg",
22
+ width: icon_theme || "24",
23
+ height: icon_theme || "24",
24
+ class: icon_theme,
25
+ viewbox: "0 0 24 24",
26
+ fill: "none",
27
+ stroke: "currentColor",
28
+ stroke_width: "2",
29
+ stroke_linecap: "round",
30
+ stroke_linejoin: "round"
31
+ ) do |s|
32
+ s.path(stroke: "none", d: "M0 0h24v24H0z", fill: "none")
33
+ s.path(
34
+ d:
35
+ "M3 7a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10z"
36
+ )
37
+ s.path(d: "M3 7l9 6l9 -6")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Enum < 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
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper"
4
+
5
+ module Phlexi
6
+ module Display
7
+ module Components
8
+ class Integer < Number
9
+ private
10
+
11
+ def normalize_value(value)
12
+ value.to_i
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Phlexi
6
+ module Display
7
+ module Components
8
+ class JSON < Base
9
+ include Concerns::DisplaysValue
10
+
11
+ def render_value(value)
12
+ pre(**attributes) {
13
+ value
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def normalize_value(value)
20
+ ::JSON.pretty_generate(value)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Password < Base
7
+ include Concerns::DisplaysValue
8
+
9
+ def render_value(value)
10
+ p(**attributes) {
11
+ value
12
+ }
13
+ end
14
+
15
+ protected
16
+
17
+ def normalize_value(value)
18
+ "••••••••"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -6,7 +6,7 @@ module Phlexi
6
6
  class Placeholder < Base
7
7
  def view_template
8
8
  p(**attributes) {
9
- field.placeholder
9
+ field.placeholder || "-"
10
10
  }
11
11
  end
12
12
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexi
4
+ module Display
5
+ module Components
6
+ class Time < DateTime
7
+ protected
8
+
9
+ def default_formats
10
+ [:time, "%H:%M"]
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end