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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/app/components/primer/beta/avatar.rb +1 -1
- data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
- data/app/components/primer/beta/avatar_stack.rb +92 -0
- data/app/components/primer/image_crop.html.erb +4 -4
- data/app/components/primer/navigation/tab_component.rb +15 -1
- data/app/components/primer/tab_nav_component.rb +4 -3
- data/app/components/primer/truncate.rb +1 -1
- data/app/components/primer/underline_nav_component.rb +3 -2
- data/lib/primer/classify/utilities.rb +33 -12
- data/lib/primer/view_components.rb +34 -6
- data/lib/primer/view_components/constants.rb +55 -0
- data/lib/primer/view_components/linters/argument_mappers/base.rb +39 -0
- data/lib/primer/view_components/linters/argument_mappers/button.rb +35 -44
- data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +25 -0
- data/lib/primer/view_components/linters/argument_mappers/label.rb +56 -0
- data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
- data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
- data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
- data/lib/primer/view_components/linters/helpers.rb +42 -41
- data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/constants.rake +12 -0
- data/lib/tasks/docs.rake +24 -23
- data/lib/tasks/utilities.rake +2 -10
- data/lib/yard/docs_helper.rb +12 -3
- data/static/arguments.yml +977 -0
- data/static/assets/view-components.svg +18 -0
- data/static/classes.yml +174 -0
- data/static/constants.json +628 -0
- data/static/statuses.json +1 -1
- metadata +16 -4
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43c27ddfb1f920ba9dfd9989d859cc61b3fd26bc3788a44873412c971ad58cc1
|
4
|
+
data.tar.gz: 640aed54b2b1e68bb24c06989320f445da9e2e3c2981e959e693345f61fc92cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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::
|
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.
|
File without changes
|
@@ -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
|
@@ -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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
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
|
-
|
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:
|
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:
|
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
|