phlexi-display 0.0.2 → 0.0.4

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.
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