primer_view_components 0.0.36 → 0.0.41
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 +220 -24
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/components/primer/auto_complete.rb +3 -1
- data/app/components/primer/auto_complete/item.rb +1 -1
- data/app/components/primer/avatar_component.rb +22 -3
- data/app/components/primer/avatar_stack_component.rb +8 -5
- data/app/components/primer/base_button.rb +47 -0
- data/app/components/primer/base_component.rb +14 -10
- data/app/components/primer/blankslate_component.rb +10 -7
- data/app/components/primer/border_box_component.rb +1 -1
- data/app/components/primer/box_component.rb +1 -1
- data/app/components/primer/breadcrumb_component.rb +1 -1
- data/app/components/primer/button_component.html.erb +9 -0
- data/app/components/primer/button_component.rb +39 -21
- data/app/components/primer/{button_group_component.html.erb → button_group.html.erb} +0 -0
- data/app/components/primer/button_group.rb +61 -0
- data/app/components/primer/button_marketing_component.rb +4 -9
- data/app/components/primer/clipboard_copy.html.erb +8 -0
- data/app/components/primer/clipboard_copy.rb +26 -0
- data/app/components/primer/clipboard_copy_component.d.ts +1 -0
- data/app/components/primer/clipboard_copy_component.js +34 -0
- data/app/components/primer/clipboard_copy_component.ts +39 -0
- data/app/components/primer/close_button.rb +11 -2
- data/app/components/primer/component.rb +21 -2
- data/app/components/primer/counter_component.rb +6 -1
- data/app/components/primer/details_component.rb +1 -1
- data/app/components/primer/dropdown/menu_component.rb +1 -1
- data/app/components/primer/dropdown_component.rb +1 -1
- data/app/components/primer/flash_component.rb +3 -3
- data/app/components/primer/flex_component.rb +28 -1
- data/app/components/primer/flex_item_component.rb +20 -1
- data/app/components/primer/heading_component.rb +25 -4
- data/app/components/primer/hidden_text_expander.rb +2 -4
- data/app/components/primer/icon_button.rb +65 -0
- data/app/components/primer/image.rb +46 -0
- data/app/components/primer/image_crop.d.ts +1 -0
- data/app/components/primer/image_crop.html.erb +12 -0
- data/app/components/primer/image_crop.js +1 -0
- data/app/components/primer/image_crop.rb +36 -0
- data/app/components/primer/image_crop.ts +1 -0
- data/app/components/primer/label_component.rb +7 -3
- data/app/components/primer/layout_component.rb +1 -1
- data/app/components/primer/link_component.rb +1 -1
- data/app/components/primer/local_time.d.ts +1 -0
- data/app/components/primer/local_time.js +1 -0
- data/app/components/primer/local_time.rb +59 -0
- data/app/components/primer/local_time.ts +1 -0
- data/app/components/primer/{markdown_component.rb → markdown.rb} +6 -5
- data/app/components/primer/menu_component.rb +1 -1
- data/app/components/primer/navigation/tab_component.rb +8 -1
- data/app/components/primer/octicon_component.html.erb +7 -0
- data/app/components/primer/octicon_component.rb +53 -19
- data/app/components/primer/octicon_symbols_component.html.erb +3 -0
- data/app/components/primer/octicon_symbols_component.rb +61 -0
- data/app/components/primer/popover_component.rb +1 -1
- data/app/components/primer/primer.d.ts +3 -0
- data/app/components/primer/primer.js +3 -0
- data/app/components/primer/primer.ts +3 -0
- data/app/components/primer/progress_bar_component.rb +1 -1
- data/app/components/primer/spinner_component.rb +3 -3
- data/app/components/primer/state_component.rb +2 -2
- data/app/components/primer/subhead_component.rb +34 -4
- data/app/components/primer/tab_container_component.rb +1 -1
- data/app/components/primer/tab_nav_component.html.erb +2 -0
- data/app/components/primer/tab_nav_component.rb +23 -10
- data/app/components/primer/text_component.rb +6 -3
- data/app/components/primer/time_ago_component.rb +1 -1
- data/app/components/primer/timeline_item_component.rb +1 -1
- data/app/components/primer/{tooltip_component.rb → tooltip.rb} +11 -9
- data/app/components/primer/truncate.rb +1 -1
- data/app/components/primer/underline_nav_component.rb +1 -1
- data/app/lib/primer/classify.rb +11 -36
- data/app/lib/primer/classify/cache.rb +20 -15
- data/app/lib/primer/classify/flex.rb +111 -0
- data/app/lib/primer/classify/functional_border_colors.rb +1 -2
- data/app/lib/primer/fetch_or_fallback_helper.rb +2 -2
- data/app/lib/primer/octicon/cache.rb +42 -0
- data/app/lib/primer/view_helper.rb +2 -1
- data/lib/primer/view_components.rb +1 -1
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/coverage.rake +14 -0
- data/lib/tasks/docs.rake +315 -0
- data/lib/tasks/statuses.rake +12 -0
- data/lib/yard/docs_helper.rb +57 -0
- data/static/statuses.json +54 -1
- metadata +50 -11
- data/app/components/primer/button_group_component.rb +0 -35
- data/app/components/primer/foo_bar.d.ts +0 -1
- data/app/components/primer/foo_bar.js +0 -1
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
# Use `Image` to render images.
|
5
|
+
#
|
6
|
+
# @accessibility
|
7
|
+
# Always provide a meaningful `alt`.
|
8
|
+
class Image < Primer::Component
|
9
|
+
# @example Default
|
10
|
+
#
|
11
|
+
# <%= render(Primer::Image.new(src: "https://github.com/github.png", alt: "GitHub")) %>
|
12
|
+
#
|
13
|
+
# @example Helper
|
14
|
+
#
|
15
|
+
# <%= primer_image(src: "https://github.com/github.png", alt: "GitHub") %>
|
16
|
+
#
|
17
|
+
# @example Lazy loading
|
18
|
+
#
|
19
|
+
# <%= render(Primer::Image.new(src: "https://github.com/github.png", alt: "GitHub", lazy: true)) %>
|
20
|
+
#
|
21
|
+
# @example Custom size
|
22
|
+
#
|
23
|
+
# <%= render(Primer::Image.new(src: "https://github.com/github.png", alt: "GitHub", height: 100, width: 100)) %>
|
24
|
+
#
|
25
|
+
# @param src [String] The source url of the image.
|
26
|
+
# @param alt [String] Specifies an alternate text for the image.
|
27
|
+
# @param lazy [Boolean] Whether or not to lazily load the image.
|
28
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
29
|
+
def initialize(src:, alt:, lazy: false, **system_arguments)
|
30
|
+
@system_arguments = system_arguments
|
31
|
+
|
32
|
+
@system_arguments[:tag] = :img
|
33
|
+
@system_arguments[:src] = src
|
34
|
+
@system_arguments[:alt] = alt
|
35
|
+
|
36
|
+
return unless lazy
|
37
|
+
|
38
|
+
@system_arguments[:loading] = :lazy
|
39
|
+
@system_arguments[:decoding] = :async
|
40
|
+
end
|
41
|
+
|
42
|
+
def call
|
43
|
+
render(Primer::BaseComponent.new(**@system_arguments))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/image-crop-element';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
+
<% if loading.present? %>
|
3
|
+
<%= loading %>
|
4
|
+
<% else %>
|
5
|
+
<%= render(Primer::SpinnerComponent.new(size: :large, flex: 1, "data-loading-slot": true)) %>
|
6
|
+
<% end %>
|
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">
|
12
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/image-crop-element';
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
# A client-side mechanism to crop images.
|
5
|
+
class ImageCrop < Primer::Component
|
6
|
+
# A loading indicator that is shown while the image is loading.
|
7
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
8
|
+
renders_one :loading, lambda { |**system_arguments|
|
9
|
+
system_arguments[:tag] ||= :div
|
10
|
+
system_arguments[:"data-loading-slot"] = true
|
11
|
+
|
12
|
+
Primer::BaseComponent.new(**system_arguments)
|
13
|
+
}
|
14
|
+
|
15
|
+
# @example Simple cropper
|
16
|
+
# <%= render(Primer::ImageCrop.new(src: "https://github.com/koddsson.png")) %>
|
17
|
+
#
|
18
|
+
# @example Square cropper
|
19
|
+
# <%= render(Primer::ImageCrop.new(src: "https://github.com/koddsson.png", rounded: false)) %>
|
20
|
+
#
|
21
|
+
# @example Cropper with a custom loader
|
22
|
+
# <%= render(Primer::ImageCrop.new(src: "https://github.com/koddsson.png", rounded: false)) do |cropper| %>
|
23
|
+
# <% cropper.loading(style: "width: 120px", tag: :img, src: "spinner.gif") %>
|
24
|
+
# <% end %>
|
25
|
+
#
|
26
|
+
# @param src [String] The path of the image to crop.
|
27
|
+
# @param rounded [Boolean] If the crop mask should be a circle. Defaults to true.
|
28
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
29
|
+
def initialize(src:, rounded: true, **system_arguments)
|
30
|
+
@system_arguments = system_arguments
|
31
|
+
@system_arguments[:tag] = "image-crop"
|
32
|
+
@system_arguments[:src] = src
|
33
|
+
@system_arguments[:rounded] = true if rounded
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/image-crop-element'
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
-
# Use
|
4
|
+
# Use `Label` to add contextual metadata to a design.
|
5
5
|
class LabelComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
8
|
+
DEFAULT_TAG = :span
|
9
|
+
TAG_OPTIONS = [DEFAULT_TAG, :summary, :a, :div].freeze
|
10
|
+
|
8
11
|
SCHEME_MAPPINGS = {
|
9
12
|
primary: "Label--primary",
|
10
13
|
secondary: "Label--secondary",
|
@@ -38,13 +41,14 @@ module Primer
|
|
38
41
|
# <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "Default" } %>
|
39
42
|
# <%= render(Primer::LabelComponent.new(title: "Label: Label", variant: :large)) { "Large" } %>
|
40
43
|
#
|
44
|
+
# @param tag [Symbol] <%= one_of(Primer::LabelComponent::TAG_OPTIONS) %>
|
41
45
|
# @param title [String] `title` attribute for the component element.
|
42
46
|
# @param scheme [Symbol] <%= one_of(Primer::LabelComponent::SCHEME_MAPPINGS.keys) %>
|
43
47
|
# @param variant [Symbol] <%= one_of(Primer::LabelComponent::VARIANT_OPTIONS) %>
|
44
48
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
45
|
-
def initialize(title:, scheme: nil, variant: nil, **system_arguments)
|
49
|
+
def initialize(tag: DEFAULT_TAG, title:, scheme: nil, variant: nil, **system_arguments)
|
46
50
|
@system_arguments = system_arguments
|
47
|
-
@system_arguments[:tag]
|
51
|
+
@system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
|
48
52
|
@system_arguments[:title] = title
|
49
53
|
@system_arguments[:classes] = class_names(
|
50
54
|
"Label",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
-
# Use
|
4
|
+
# Use `Link` for navigating from one page to another. `Link` styles anchor tags with default blue styling and hover text-decoration.
|
5
5
|
class LinkComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements';
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements';
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
# Use `LocalTime` to format a date and time in the user's preferred locale format. This component requires JavaScript.
|
5
|
+
class LocalTime < Primer::Component
|
6
|
+
DEFAULT_DIGIT_TYPE = :numeric
|
7
|
+
DIGIT_TYPE_OPTIONS = [DEFAULT_DIGIT_TYPE, :"2-digit"].freeze
|
8
|
+
|
9
|
+
DEFAULT_TEXT_TYPE = :short
|
10
|
+
TEXT_TYPE_OPTIONS = [DEFAULT_TEXT_TYPE, :long].freeze
|
11
|
+
|
12
|
+
# @example Default
|
13
|
+
# <%= render(Primer::LocalTime.new(datetime: DateTime.parse("2014-06-01T13:05:07Z"))) %>
|
14
|
+
#
|
15
|
+
# @example All the options
|
16
|
+
# <%= render(Primer::LocalTime.new(datetime: DateTime.parse("2014-06-01T13:05:07Z"), weekday: :long, year: :"2-digit", month: :long, day: :"2-digit", hour: :"2-digit", minute: :"2-digit", second: :"2-digit", time_zone_name: :long)) %>
|
17
|
+
#
|
18
|
+
# @example With initial content
|
19
|
+
# <%= render(Primer::LocalTime.new(datetime: DateTime.parse("2014-06-01T13:05:07Z"))) do %>
|
20
|
+
# <!-- This content will be replaced once the component connects -->
|
21
|
+
# 2014/06/01 13:05
|
22
|
+
# <% end %>
|
23
|
+
#
|
24
|
+
# @param datetime [DateTime] The date to parse
|
25
|
+
# @param initial_text [String] Text to render before component is initialized
|
26
|
+
# @param weekday [Symbol] <%= one_of(Primer::LocalTime::TEXT_TYPE_OPTIONS) %>
|
27
|
+
# @param year [Symbol] <%= one_of(Primer::LocalTime::DIGIT_TYPE_OPTIONS) %>
|
28
|
+
# @param month [Symbol] <%= one_of(Primer::LocalTime::TEXT_TYPE_OPTIONS) %>
|
29
|
+
# @param day [Symbol] <%= one_of(Primer::LocalTime::DIGIT_TYPE_OPTIONS) %>
|
30
|
+
# @param hour [Symbol] <%= one_of(Primer::LocalTime::DIGIT_TYPE_OPTIONS) %>
|
31
|
+
# @param minute [Symbol] <%= one_of(Primer::LocalTime::DIGIT_TYPE_OPTIONS) %>
|
32
|
+
# @param second [Symbol] <%= one_of(Primer::LocalTime::DIGIT_TYPE_OPTIONS) %>
|
33
|
+
# @param time_zone_name [Symbol] <%= one_of(Primer::LocalTime::TEXT_TYPE_OPTIONS) %>
|
34
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
35
|
+
def initialize(datetime:, initial_text: nil, weekday: DEFAULT_TEXT_TYPE, year: DEFAULT_DIGIT_TYPE, month: DEFAULT_TEXT_TYPE, day: DEFAULT_DIGIT_TYPE, hour: DEFAULT_DIGIT_TYPE, minute: DEFAULT_DIGIT_TYPE, second: DEFAULT_DIGIT_TYPE, time_zone_name: DEFAULT_TEXT_TYPE, **system_arguments)
|
36
|
+
@system_arguments = system_arguments
|
37
|
+
|
38
|
+
@datetime = datetime
|
39
|
+
|
40
|
+
@system_arguments[:tag] = "local-time"
|
41
|
+
@system_arguments[:datetime] = datetime
|
42
|
+
|
43
|
+
@initial_text = initial_text
|
44
|
+
|
45
|
+
@system_arguments[:weekday] = fetch_or_fallback(TEXT_TYPE_OPTIONS, weekday, DEFAULT_TEXT_TYPE)
|
46
|
+
@system_arguments[:year] = fetch_or_fallback(DIGIT_TYPE_OPTIONS, year, DEFAULT_DIGIT_TYPE)
|
47
|
+
@system_arguments[:month] = fetch_or_fallback(TEXT_TYPE_OPTIONS, month, DEFAULT_TEXT_TYPE)
|
48
|
+
@system_arguments[:day] = fetch_or_fallback(DIGIT_TYPE_OPTIONS, day, DEFAULT_DIGIT_TYPE)
|
49
|
+
@system_arguments[:hour] = fetch_or_fallback(DIGIT_TYPE_OPTIONS, hour, DEFAULT_DIGIT_TYPE)
|
50
|
+
@system_arguments[:minute] = fetch_or_fallback(DIGIT_TYPE_OPTIONS, minute, DEFAULT_DIGIT_TYPE)
|
51
|
+
@system_arguments[:second] = fetch_or_fallback(DIGIT_TYPE_OPTIONS, second, DEFAULT_DIGIT_TYPE)
|
52
|
+
@system_arguments[:"time-zone-name"] = fetch_or_fallback(TEXT_TYPE_OPTIONS, time_zone_name, DEFAULT_TEXT_TYPE)
|
53
|
+
end
|
54
|
+
|
55
|
+
def call
|
56
|
+
render(Primer::BaseComponent.new(**@system_arguments).with_content(@initial_text || @datetime.strftime("%B %-d, %Y %H:%M %Z")))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/time-elements'
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Primer
|
4
|
-
# Use
|
5
|
-
class
|
4
|
+
# Use `Markdown` to wrap markdown content
|
5
|
+
class Markdown < Primer::Component
|
6
|
+
status :beta
|
6
7
|
# @example Default
|
7
|
-
# <%= render(Primer::
|
8
|
+
# <%= render(Primer::Markdown.new) do %>
|
8
9
|
# <p>Text can be <b>bold</b>, <i>italic</i>, or <s>strikethrough</s>. <a href="https://github.com">Links </a> should be blue with no underlines (unless hovered over).</p>
|
9
10
|
#
|
10
11
|
# <p>There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs.</p>
|
@@ -235,11 +236,11 @@ module Primer
|
|
235
236
|
#
|
236
237
|
# <p>Code can also use syntax highlighting.</p>
|
237
238
|
#
|
238
|
-
# <pre><code
|
239
|
+
# <pre><code>var foo = "bar";</code></pre>
|
239
240
|
#
|
240
241
|
# <pre><code>Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.</code></pre>
|
241
242
|
#
|
242
|
-
# <pre><code
|
243
|
+
# <pre><code>var foo = "The same thing is true for code with syntax highlighting. A single line of code should horizontally scroll if it is really long.";</code></pre>
|
243
244
|
#
|
244
245
|
# <p>Inline code inside table cells should still be distinguishable.</p>
|
245
246
|
#
|
@@ -4,7 +4,13 @@ module Primer
|
|
4
4
|
module Navigation
|
5
5
|
# This component is part of navigation components such as `Primer::TabNavComponent`
|
6
6
|
# and `Primer::UnderlineNavComponent` and should not be used by itself.
|
7
|
+
#
|
8
|
+
# @accessibility
|
9
|
+
# `TabComponent` renders the selected anchor tab with `aria-current="page"` by default.
|
10
|
+
# When the selected tab does not correspond to the current page, such as in a nested inner tab, make sure to use aria-current="true"
|
7
11
|
class TabComponent < Primer::Component
|
12
|
+
DEFAULT_ARIA_CURRENT_FOR_ANCHOR = :page
|
13
|
+
ARIA_CURRENT_OPTIONS_FOR_ANCHOR = [true, DEFAULT_ARIA_CURRENT_FOR_ANCHOR].freeze
|
8
14
|
# Panel controlled by the Tab. This will not render anything in the tab itself.
|
9
15
|
# It will provide a accessor for the Tab's parent to call and render the panel
|
10
16
|
# content in the appropriate place.
|
@@ -105,7 +111,8 @@ module Primer
|
|
105
111
|
return unless @selected
|
106
112
|
|
107
113
|
if @system_arguments[:tag] == :a
|
108
|
-
@system_arguments[:"aria-current"]
|
114
|
+
aria_current = @system_arguments[:"aria-current"] || @system_arguments.dig(:aria, :current) || DEFAULT_ARIA_CURRENT_FOR_ANCHOR
|
115
|
+
@system_arguments[:"aria-current"] = fetch_or_fallback(ARIA_CURRENT_OPTIONS_FOR_ANCHOR, aria_current, DEFAULT_ARIA_CURRENT_FOR_ANCHOR)
|
109
116
|
else
|
110
117
|
@system_arguments[:"aria-selected"] = true
|
111
118
|
end
|
@@ -1,46 +1,80 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "octicons"
|
4
|
+
|
3
5
|
module Primer
|
4
|
-
#
|
6
|
+
# `Octicon` renders an <%= link_to_octicons %> with <%= link_to_system_arguments_docs %>.
|
7
|
+
# `Octicon` can also be rendered with the `primer_octicon` helper, which accepts the same arguments.
|
5
8
|
class OcticonComponent < Primer::Component
|
6
9
|
status :beta
|
7
10
|
|
8
11
|
SIZE_DEFAULT = :small
|
12
|
+
SIZE_MEDIUM = :medium
|
13
|
+
|
9
14
|
SIZE_MAPPINGS = {
|
10
15
|
SIZE_DEFAULT => 16,
|
11
|
-
|
12
|
-
:large => 64
|
16
|
+
SIZE_MEDIUM => 24
|
13
17
|
}.freeze
|
14
18
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
15
19
|
|
16
20
|
# @example Default
|
17
|
-
# <%= render(Primer::OcticonComponent.new(
|
18
|
-
# <%= render(Primer::OcticonComponent.new(icon:
|
21
|
+
# <%= render(Primer::OcticonComponent.new(:check)) %>
|
22
|
+
# <%= render(Primer::OcticonComponent.new(icon: :check)) %>
|
19
23
|
#
|
20
24
|
# @example Medium
|
21
|
-
# <%= render(Primer::OcticonComponent.new(
|
25
|
+
# <%= render(Primer::OcticonComponent.new(:people, size: :medium)) %>
|
22
26
|
#
|
23
|
-
# @example
|
24
|
-
# <%=
|
27
|
+
# @example Helper
|
28
|
+
# <%= primer_octicon(:check) %>
|
25
29
|
#
|
26
|
-
# @param icon [
|
30
|
+
# @param icon [Symbol] Name of <%= link_to_octicons %> to use.
|
27
31
|
# @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
|
32
|
+
# @param use_symbol [Boolean] EXPERIMENTAL (May change or be removed) - Set to true when using with <%= link_to_component(Primer::OcticonSymbolsComponent) %>.
|
28
33
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
29
|
-
def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, **system_arguments)
|
30
|
-
|
34
|
+
def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, use_symbol: false, **system_arguments)
|
35
|
+
icon_key = icon_name || icon
|
36
|
+
|
37
|
+
# Don't allow sizes under 16px
|
38
|
+
if system_arguments[:height].present? && system_arguments[:height] < 16 || system_arguments[:width].present? && system_arguments[:width] < 16
|
39
|
+
system_arguments.delete(:height)
|
40
|
+
system_arguments.delete(:width)
|
41
|
+
end
|
42
|
+
|
43
|
+
cache_key = Primer::Octicon::Cache.get_key(symbol: icon_key, size: size, **system_arguments.slice(:height, :width))
|
44
|
+
|
31
45
|
@system_arguments = system_arguments
|
46
|
+
@system_arguments[:tag] = :svg
|
47
|
+
@system_arguments[:aria] ||= {}
|
48
|
+
@use_symbol = use_symbol
|
49
|
+
|
50
|
+
if @system_arguments[:aria][:label] || @system_arguments[:"aria-label"]
|
51
|
+
@system_arguments[:role] = "img"
|
52
|
+
else
|
53
|
+
@system_arguments[:aria][:hidden] = true
|
54
|
+
end
|
55
|
+
|
56
|
+
if (cache_icon = Primer::Octicon::Cache.read(cache_key))
|
57
|
+
@icon = cache_icon
|
58
|
+
else
|
59
|
+
# Filter out classify options to prevent them from becoming invalid html attributes.
|
60
|
+
# Note height and width are both classify options and valid html attributes.
|
61
|
+
octicon_options = {
|
62
|
+
height: SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, SIZE_DEFAULT)]
|
63
|
+
}.merge(@system_arguments.slice(:height, :width))
|
32
64
|
|
33
|
-
|
34
|
-
|
65
|
+
@icon = Octicons::Octicon.new(icon_key, octicon_options)
|
66
|
+
Primer::Octicon::Cache.set(cache_key, @icon)
|
67
|
+
end
|
35
68
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
69
|
+
@system_arguments[:classes] = class_names(
|
70
|
+
@icon.options[:class],
|
71
|
+
@system_arguments[:classes]
|
72
|
+
)
|
73
|
+
@system_arguments.merge!(@icon.options.except(:class, :'aria-hidden'))
|
40
74
|
end
|
41
75
|
|
42
|
-
def
|
43
|
-
|
76
|
+
def self._after_compile
|
77
|
+
Primer::Octicon::Cache.preload!
|
44
78
|
end
|
45
79
|
end
|
46
80
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "octicons"
|
4
|
+
|
5
|
+
module Primer
|
6
|
+
# OcticonSymbols renders a symbol dictionary using a list of <%= link_to_octicons %>.
|
7
|
+
class OcticonSymbolsComponent < Primer::Component
|
8
|
+
# @example Symbol dictionary
|
9
|
+
# <%= render(Primer::OcticonComponent.new(icon: :check, use_symbol: true, color: :icon_success)) %>
|
10
|
+
# <%= render(Primer::OcticonComponent.new(icon: :check, use_symbol: true, color: :text_danger)) %>
|
11
|
+
# <%= render(Primer::OcticonComponent.new(icon: :check, use_symbol: true, size: :medium)) %>
|
12
|
+
# <%= render(Primer::OcticonSymbolsComponent.new(icons: [{ symbol: :check }, { symbol: :check, size: :medium }])) %>
|
13
|
+
#
|
14
|
+
# @param icons [Array<Hash>] List of icons to render, in the format { symbol: :icon_name, size: :small }
|
15
|
+
def initialize(icons: [])
|
16
|
+
@icons = {}
|
17
|
+
icons.each do |icon|
|
18
|
+
symbol = icon[:symbol]
|
19
|
+
size = Primer::OcticonComponent::SIZE_MAPPINGS[
|
20
|
+
fetch_or_fallback(Primer::OcticonComponent::SIZE_OPTIONS, icon[:size] || Primer::OcticonComponent::SIZE_DEFAULT, Primer::OcticonComponent::SIZE_DEFAULT)
|
21
|
+
]
|
22
|
+
|
23
|
+
cache_key = Primer::Octicon::Cache.get_key(symbol: symbol, size: size)
|
24
|
+
|
25
|
+
if (cache_icon = Primer::Octicon::Cache.read(cache_key))
|
26
|
+
icon_instance = cache_icon
|
27
|
+
else
|
28
|
+
icon_instance = Octicons::Octicon.new(symbol, height: size)
|
29
|
+
|
30
|
+
Primer::Octicon::Cache.set(cache_key, icon_instance)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Don't put the same icon twice
|
34
|
+
@icons[[symbol, icon_instance.height]] = icon_instance if @icons[[symbol, icon_instance.height]].nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def render?
|
39
|
+
@icons.any?
|
40
|
+
end
|
41
|
+
|
42
|
+
def self._after_compile
|
43
|
+
Primer::Octicon::Cache.preload!
|
44
|
+
end
|
45
|
+
|
46
|
+
def symbol_tags
|
47
|
+
safe_join(
|
48
|
+
@icons.values.map do |icon|
|
49
|
+
content_tag(
|
50
|
+
:symbol,
|
51
|
+
icon.path.html_safe, # rubocop:disable Rails/OutputSafety
|
52
|
+
id: "octicon_#{icon.symbol}_#{icon.height}",
|
53
|
+
viewBox: icon.options[:viewBox],
|
54
|
+
width: icon.width,
|
55
|
+
height: icon.height
|
56
|
+
)
|
57
|
+
end
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|