primer_view_components 0.0.48 → 0.0.49

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/app/components/primer/beta/avatar.rb +1 -1
  4. data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
  5. data/app/components/primer/beta/avatar_stack.rb +92 -0
  6. data/app/components/primer/image_crop.html.erb +4 -4
  7. data/app/components/primer/navigation/tab_component.rb +15 -1
  8. data/app/components/primer/tab_nav_component.rb +4 -3
  9. data/app/components/primer/truncate.rb +1 -1
  10. data/app/components/primer/underline_nav_component.rb +3 -2
  11. data/lib/primer/classify/utilities.rb +33 -12
  12. data/lib/primer/view_components.rb +34 -6
  13. data/lib/primer/view_components/constants.rb +55 -0
  14. data/lib/primer/view_components/linters/argument_mappers/base.rb +39 -0
  15. data/lib/primer/view_components/linters/argument_mappers/button.rb +35 -44
  16. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +25 -0
  17. data/lib/primer/view_components/linters/argument_mappers/label.rb +56 -0
  18. data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
  19. data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
  20. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
  21. data/lib/primer/view_components/linters/helpers.rb +42 -41
  22. data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
  23. data/lib/primer/view_components/version.rb +1 -1
  24. data/lib/tasks/constants.rake +12 -0
  25. data/lib/tasks/docs.rake +24 -23
  26. data/lib/tasks/utilities.rake +2 -10
  27. data/lib/yard/docs_helper.rb +12 -3
  28. data/static/arguments.yml +977 -0
  29. data/static/assets/view-components.svg +18 -0
  30. data/static/classes.yml +174 -0
  31. data/static/constants.json +628 -0
  32. data/static/statuses.json +1 -1
  33. metadata +16 -4
  34. data/app/components/primer/avatar_stack_component.rb +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c751bc60362c19e97ba5fbe22227e19186efa799862932a6f7b8541ad8e1eaa
4
- data.tar.gz: 4efd584159e4883f8bcc72954fff356c753b0b8980056ee0c58b7a3bd650cb90
3
+ metadata.gz: 43c27ddfb1f920ba9dfd9989d859cc61b3fd26bc3788a44873412c971ad58cc1
4
+ data.tar.gz: 640aed54b2b1e68bb24c06989320f445da9e2e3c2981e959e693345f61fc92cf
5
5
  SHA512:
6
- metadata.gz: c6169f90241d046f9cee4faf1fb971cac34360c8ebb116e2c2e39fdd0aeff5e8cca17e899bdd8a97f94ebefa4c3705d6929b0978a96f0264dcab3fa96342faaf
7
- data.tar.gz: 8576857a521647f43ccb3fe413b0e24b5d65a8c06e9036dd3035b37d8fb5989aa43a7ac2d33863f5faa022c099c6a8386d30de8b764e19cf93b9dcb207fd4eef
6
+ metadata.gz: 7c6b6ce07b479c462a01cfe65ccda3da920689c5e6642231f897bf5f92f559836d30d6f01bfec2c7ae99545c391abe25b85e7cd45da18de8249f63176b00bedb
7
+ data.tar.gz: ef88c518675d73c7c418fee48a11f173200f3a98ab4f10115fcfad5ccf5fa4ef0b3452da7bb9577a55a3d3286a3536f616f56aac4a07108421e8466abc76250b
data/CHANGELOG.md CHANGED
@@ -30,6 +30,49 @@ The category for changes related to documentation, testing and tooling. Also, fo
30
30
 
31
31
  ## main
32
32
 
33
+ ## 0.0.49
34
+
35
+ ### New
36
+
37
+ * Add linter suggestions for `Label` component.
38
+
39
+ *Manuel Puyol*
40
+
41
+ * Add linter suggestions for `ClipboardCopy` component.
42
+
43
+ *Manuel Puyol*
44
+
45
+ ### Updates
46
+
47
+ * Update the `Truncate` component to accept `:strong` as a tag.
48
+
49
+ *Amélia Chavot*
50
+
51
+ * Improve `Primer::Classify::Utilities.classes_to_hash` performance.
52
+
53
+ *Manuel Puyol*
54
+
55
+ ### Breaking changes
56
+
57
+ * Require tab with panels to have `panel_id` so `aria-controls` can be set.
58
+
59
+ *Kate Higa*
60
+
61
+ * Renames:
62
+ * `Primer::AvatarStackComponent` to `Primer::Beta::AvatarStack`.
63
+
64
+ *Manuel Puyol*
65
+
66
+ ### Misc
67
+
68
+ * Extract example tag parsing into helper.
69
+
70
+ *Kate Higa*
71
+
72
+ * Generate a static constant JSON and use it when defining linters.
73
+
74
+ *Manuel Puyol*
75
+
33
76
  ## 0.0.48
34
77
 
35
78
  ### Breaking changes
@@ -8,7 +8,7 @@ module Primer
8
8
  # for organizations or any other non-human avatars.
9
9
  # - By default, `Avatar` will render a static `<img>`. To have `Avatar` function as a link, set the `href` which will wrap the `<img>` in a `<a>`.
10
10
  # - Set `size` to update the height and width of the `Avatar` in pixels.
11
- # - To stack multiple avatars together, use <%= link_to_component(Primer::AvatarStackComponent) %>.
11
+ # - To stack multiple avatars together, use <%= link_to_component(Primer::Beta::AvatarStack) %>.
12
12
  #
13
13
  # @accessibility
14
14
  # Images should have text alternatives that describe the information or function represented.
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # Use `AvatarStack` to stack multiple avatars together.
6
+ class AvatarStack < Primer::Component
7
+ status :beta
8
+
9
+ ALIGN_DEFAULT = :left
10
+ ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
11
+
12
+ DEFAULT_TAG = :div
13
+ TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
14
+
15
+ DEFAULT_BODY_TAG = :div
16
+ BODY_TAG_OPTIONS = [DEFAULT_BODY_TAG, :span].freeze
17
+ # Required list of stacked avatars.
18
+ #
19
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Avatar) %>.
20
+ renders_many :avatars, "Primer::Beta::Avatar"
21
+
22
+ # @example Default
23
+ # <%= render(Primer::Beta::AvatarStack.new) do |c| %>
24
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
25
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
26
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
27
+ # <% end %>
28
+ #
29
+ # @example Align right
30
+ # <%= render(Primer::Beta::AvatarStack.new(align: :right)) do |c| %>
31
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
32
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
33
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
34
+ # <% end %>
35
+ #
36
+ # @example With tooltip
37
+ # <%= render(Primer::Beta::AvatarStack.new(tooltipped: true, body_arguments: { label: 'This is a tooltip!' })) do |c| %>
38
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
39
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
40
+ # <%= c.avatar(src: "http://placekitten.com/200/200", alt: "@kittenuser") %>
41
+ # <% end %>
42
+ #
43
+ # @param tag [Symbol] <%= one_of(Primer::Beta::AvatarStack::TAG_OPTIONS) %>
44
+ # @param align [Symbol] <%= one_of(Primer::Beta::AvatarStack::ALIGN_OPTIONS) %>
45
+ # @param tooltipped [Boolean] Whether to add a tooltip to the stack or not.
46
+ # @param body_arguments [Hash] Parameters to add to the Body. If `tooltipped` is set, has the same arguments as <%= link_to_component(Primer::Tooltip) %>.
47
+ # The default tag is <%= pretty_value(Primer::Beta::AvatarStack::DEFAULT_BODY_TAG) %> but can be changed using `tag:`
48
+ # to <%= one_of(Primer::Beta::AvatarStack::BODY_TAG_OPTIONS, lower: true) %>
49
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
50
+ def initialize(tag: DEFAULT_TAG, align: ALIGN_DEFAULT, tooltipped: false, body_arguments: {}, **system_arguments)
51
+ @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
52
+ @system_arguments = system_arguments
53
+ @tooltipped = tooltipped
54
+ @body_arguments = body_arguments
55
+
56
+ body_tag = @body_arguments[:tag] || DEFAULT_BODY_TAG
57
+ @body_arguments[:tag] = fetch_or_fallback(BODY_TAG_OPTIONS, body_tag, DEFAULT_BODY_TAG)
58
+ @body_arguments[:classes] = class_names(
59
+ "AvatarStack-body",
60
+ @body_arguments[:classes]
61
+ )
62
+
63
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
64
+ @system_arguments[:classes] = class_names(
65
+ "AvatarStack",
66
+ system_arguments[:classes],
67
+ "AvatarStack--right" => @align == :right
68
+ )
69
+ end
70
+
71
+ def body_component
72
+ if @tooltipped
73
+ Primer::Tooltip.new(**@body_arguments)
74
+ else
75
+ Primer::BaseComponent.new(**@body_arguments)
76
+ end
77
+ end
78
+
79
+ def before_render
80
+ @system_arguments[:classes] = class_names(
81
+ @system_arguments[:classes],
82
+ "AvatarStack--two" => avatars.size == 2,
83
+ "AvatarStack--three-plus" => avatars.size > 2
84
+ )
85
+ end
86
+
87
+ def render?
88
+ avatars.any?
89
+ end
90
+ end
91
+ end
92
+ end
@@ -5,8 +5,8 @@
5
5
  <%= render(Primer::SpinnerComponent.new(size: :large, flex: 1, "data-loading-slot": true)) %>
6
6
  <% end %>
7
7
 
8
- <input type="hidden" data-image-crop-input="x" name="cropped_x">
9
- <input type="hidden" data-image-crop-input="y" name="cropped_y">
10
- <input type="hidden" data-image-crop-input="width" name="cropped_width">
11
- <input type="hidden" data-image-crop-input="height" name="cropped_height">
8
+ <input autocomplete="off" type="hidden" data-image-crop-input="x" name="cropped_x">
9
+ <input autocomplete="off" type="hidden" data-image-crop-input="y" name="cropped_y">
10
+ <input autocomplete="off" type="hidden" data-image-crop-input="width" name="cropped_width">
11
+ <input autocomplete="off" type="hidden" data-image-crop-input="height" name="cropped_height">
12
12
  <% end %>
@@ -20,6 +20,7 @@ module Primer
20
20
  renders_one :panel, lambda { |**system_arguments|
21
21
  return unless @with_panel
22
22
 
23
+ system_arguments[:id] = @panel_id
23
24
  system_arguments[:tag] = :div
24
25
  system_arguments[:role] ||= :tabpanel
25
26
  system_arguments[:tabindex] = 0
@@ -98,10 +99,11 @@ module Primer
98
99
  # @param list [Boolean] Whether the Tab is an item in a `<ul>` list.
99
100
  # @param selected [Boolean] Whether the Tab is selected or not.
100
101
  # @param with_panel [Boolean] Whether the Tab has an associated panel.
102
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
101
103
  # @param icon_classes [Boolean] Classes that must always be applied to icons.
102
104
  # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> to be used in the `<li>` wrapper when the tab is an item in a list.
103
105
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
104
- def initialize(list: false, selected: false, with_panel: false, icon_classes: "", wrapper_arguments: {}, **system_arguments)
106
+ def initialize(list: false, selected: false, with_panel: false, panel_id: "", icon_classes: "", wrapper_arguments: {}, **system_arguments)
105
107
  @selected = selected
106
108
  @icon_classes = icon_classes
107
109
  @list = list
@@ -114,6 +116,7 @@ module Primer
114
116
  @system_arguments[:tag] = :button
115
117
  @system_arguments[:type] = :button
116
118
  @system_arguments[:role] = :tab
119
+ panel_id(panel_id)
117
120
  else
118
121
  @system_arguments[:tag] = :a
119
122
  end
@@ -142,6 +145,17 @@ module Primer
142
145
  yield
143
146
  end
144
147
  end
148
+
149
+ private
150
+
151
+ def panel_id(panel_id)
152
+ if panel_id.blank?
153
+ raise ArgumentError, "`panel_id` is required" unless Rails.env.production?
154
+ else
155
+ @panel_id = panel_id
156
+ @system_arguments[:"aria-controls"] = @panel_id
157
+ end
158
+ end
145
159
  end
146
160
  end
147
161
  end
@@ -13,6 +13,7 @@ module Primer
13
13
  # Tabs to be rendered. When `with_panel` is set on the parent, a button is rendered for panel navigation. Otherwise,
14
14
  # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
15
15
  #
16
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique ID of panel.
16
17
  # @param selected [Boolean] Whether the tab is selected.
17
18
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
18
19
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -63,19 +64,19 @@ module Primer
63
64
  #
64
65
  # @example With panels
65
66
  # <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
66
- # <% c.tab(selected: true, id: "tab-1") do |t| %>
67
+ # <% c.tab(selected: true, panel_id: "panel-1", id: "tab-1") do |t| %>
67
68
  # <% t.text { "Tab 1" } %>
68
69
  # <% t.panel do %>
69
70
  # Panel 1
70
71
  # <% end %>
71
72
  # <% end %>
72
- # <% c.tab(id: "tab-2") do |t| %>
73
+ # <% c.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
73
74
  # <% t.text { "Tab 2" } %>
74
75
  # <% t.panel do %>
75
76
  # Panel 2
76
77
  # <% end %>
77
78
  # <% end %>
78
- # <% c.tab(id: "tab-3") do |t| %>
79
+ # <% c.tab(id: "tab-3", panel_id: "panel-3") do |t| %>
79
80
  # <% t.text { "Tab 3" } %>
80
81
  # <% t.panel do %>
81
82
  # Panel 3
@@ -6,7 +6,7 @@ module Primer
6
6
  status :beta
7
7
 
8
8
  DEFAULT_TAG = :div
9
- TAG_OPTIONS = [DEFAULT_TAG, :span, :p].freeze
9
+ TAG_OPTIONS = [DEFAULT_TAG, :span, :p, :strong].freeze
10
10
 
11
11
  # @example Default
12
12
  # <div class="col-2">
@@ -19,6 +19,7 @@ module Primer
19
19
  # Use the tabs to list navigation items. When `with_panel` is set on the parent, a button is rendered for panel navigation. Otherwise,
20
20
  # an anchor tag is rendered for page navigation. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
21
21
  #
22
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
22
23
  # @param selected [Boolean] Whether the tab is selected.
23
24
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
25
  renders_many :tabs, lambda { |selected: false, **system_arguments|
@@ -104,13 +105,13 @@ module Primer
104
105
  #
105
106
  # @example With panels
106
107
  # <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
107
- # <% component.tab(selected: true, id: "tab-1") do |t| %>
108
+ # <% component.tab(selected: true, id: "tab-1", panel_id: "panel-1") do |t| %>
108
109
  # <% t.text { "Item 1" } %>
109
110
  # <% t.panel do %>
110
111
  # Panel 1
111
112
  # <% end %>
112
113
  # <% end %>
113
- # <% component.tab(id: "tab-2") do |t| %>
114
+ # <% component.tab(id: "tab-2", panel_id: "panel-2") do |t| %>
114
115
  # <% t.text { "Item 2" } %>
115
116
  # <% t.panel do %>
116
117
  # Panel 2
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  # :nodoc:
4
6
  module Primer
5
7
  class Classify
@@ -16,6 +18,15 @@ module Primer
16
18
  # rubocop:enable Security/YAMLLoad
17
19
  BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
18
20
 
21
+ # Replacements for some classnames that end up being a different argument key
22
+ REPLACEMENT_KEYS = {
23
+ "^anim" => "animation",
24
+ "^v-align" => "vertical_align",
25
+ "^d" => "display",
26
+ "^wb" => "word_break",
27
+ "^v" => "visibility"
28
+ }.freeze
29
+
19
30
  class << self
20
31
  def classname(key, val, breakpoint = "")
21
32
  if (valid = validate(key, val, breakpoint))
@@ -104,23 +115,33 @@ module Primer
104
115
  private
105
116
 
106
117
  def find_selector(selector)
107
- # Search each key/value_hash pair, eg. key `:mr` and value_hash `{ 0 => [ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ] }`
108
- UTILITIES.each do |key, value_hash|
109
- # Each value hash will also contain an array of classnames for breakpoints
110
- # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
111
- value_hash.each do |key_argument, classnames|
112
- # Skip each value hash until we get one with the selector
113
- next unless classnames.include?(selector)
114
-
115
- # Return [:mr, 0, 1]
116
- # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
117
- return [key, key_argument, classnames.index(selector)]
118
- end
118
+ key = infer_selector_key(selector)
119
+ value_hash = UTILITIES[key]
120
+
121
+ return nil if value_hash.blank?
122
+
123
+ # Each value hash will also contain an array of classnames for breakpoints
124
+ # Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
125
+ value_hash.each do |key_argument, classnames|
126
+ # Skip each value hash until we get one with the selector
127
+ next unless classnames.include?(selector)
128
+
129
+ # Return [:mr, 0, 1]
130
+ # has index of classname, so we can match it up with responsvie array `mr: [nil, 0]`
131
+ return [key, key_argument, classnames.index(selector)]
119
132
  end
120
133
 
121
134
  nil
122
135
  end
123
136
 
137
+ def infer_selector_key(selector)
138
+ REPLACEMENT_KEYS.each do |k, v|
139
+ return v.to_sym if selector.match?(Regexp.new(k))
140
+ end
141
+
142
+ selector.split("-").first.to_sym
143
+ end
144
+
124
145
  def validate(key, val, breakpoint)
125
146
  unless supported_key?(key)
126
147
  raise ArgumentError, "#{key} is not a valid Primer utility key" unless ENV["RAILS_ENV"] == "production"
@@ -7,22 +7,21 @@ require "primer/view_components/engine"
7
7
  module Primer
8
8
  # :nodoc:
9
9
  module ViewComponents
10
- DEFAULT_STATUSES_PATH = File.expand_path("static")
10
+ DEFAULT_STATIC_PATH = File.expand_path("static")
11
11
  DEFAULT_STATUS_FILE_NAME = "statuses.json"
12
+ DEFAULT_CONSTANTS_FILE_NAME = "constants.json"
12
13
 
13
14
  # generate_statuses returns a hash mapping component name to
14
15
  # the component's status sorted alphabetically by the component name.
15
16
  def self.generate_statuses
16
- statuses = Primer::Component.descendants.each_with_object({}) do |component, mem|
17
+ Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
17
18
  mem[component.to_s] = component.status.to_s
18
19
  end
19
-
20
- statuses.sort_by { |k, _v| k }.to_h
21
20
  end
22
21
 
23
22
  # dump_statuses generates the status hash and then serializes
24
23
  # it as json at the given path
25
- def self.dump_statuses(path: DEFAULT_STATUSES_PATH)
24
+ def self.dump_statuses(path: DEFAULT_STATIC_PATH)
26
25
  require "json"
27
26
 
28
27
  statuses = generate_statuses
@@ -35,8 +34,37 @@ module Primer
35
34
 
36
35
  # read_statuses returns a JSON string matching the output of
37
36
  # generate_statuses
38
- def self.read_statuses(path: DEFAULT_STATUSES_PATH)
37
+ def self.read_statuses(path: DEFAULT_STATIC_PATH)
39
38
  File.read(File.join(path, DEFAULT_STATUS_FILE_NAME))
40
39
  end
40
+
41
+ # generate_constants returns a hash mapping component name to
42
+ # all of its constants.
43
+ def self.generate_constants
44
+ Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
45
+ mem[component.to_s] = component.constants(false).sort.each_with_object({}) do |constant, h|
46
+ h[constant] = component.const_get(constant)
47
+ end
48
+ end
49
+ end
50
+
51
+ # dump_constants generates the constants hash and then serializes
52
+ # it as json at the given path
53
+ def self.dump_constants(path: DEFAULT_STATIC_PATH)
54
+ require "json"
55
+
56
+ constants = generate_constants
57
+
58
+ File.open(File.join(path, DEFAULT_CONSTANTS_FILE_NAME), "w") do |f|
59
+ f.write(JSON.pretty_generate(constants))
60
+ f.write($INPUT_RECORD_SEPARATOR)
61
+ end
62
+ end
63
+
64
+ # read_constants returns a JSON string matching the output of
65
+ # generate_constants
66
+ def self.read_constants(path: DEFAULT_STATIC_PATH)
67
+ File.read(File.join(path, DEFAULT_CONSTANTS_FILE_NAME))
68
+ end
41
69
  end
42
70
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Primer
6
+ module ViewComponents
7
+ # A module for constants that are used in the view components.
8
+ class Constants
9
+ CONSTANTS = JSON.parse(
10
+ File.read(
11
+ File.join(File.dirname(__FILE__), "../../../static/constants.json")
12
+ )
13
+ ).freeze
14
+
15
+ class << self
16
+ def get(component:, constant:, invert: true, symbolize: false)
17
+ values = CONSTANTS.dig(component, constant)
18
+
19
+ case values
20
+ when Hash
21
+ format_hash(values, invert, symbolize)
22
+ when Array
23
+ format_array(values, symbolize)
24
+ else
25
+ values
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def format_hash(values, invert, symbolize)
32
+ val = values.invert if invert
33
+ # remove defaults
34
+ val = val.except("", nil)
35
+
36
+ return val.transform_values { |v| symbolize_value(v) } if symbolize
37
+
38
+ val
39
+ end
40
+
41
+ def format_array(values, symbolize)
42
+ val = values.select(&:present?)
43
+
44
+ return val.map { |v| symbolize_value(v) } if symbolize
45
+
46
+ val
47
+ end
48
+
49
+ def symbolize_value(value)
50
+ ":#{value}"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end