primer_view_components 0.0.46 → 0.0.47
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/app/components/primer/avatar_stack_component.rb +2 -2
- data/app/components/primer/beta/auto_complete.rb +159 -0
- data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
- data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +0 -0
- data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
- data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
- data/app/components/primer/beta/auto_complete/item.rb +44 -0
- data/app/components/primer/beta/avatar.rb +77 -0
- data/app/components/primer/details_component.rb +7 -7
- data/app/components/primer/markdown.rb +9 -9
- data/app/components/primer/popover_component.rb +6 -3
- data/app/components/primer/primer.d.ts +1 -1
- data/app/components/primer/primer.js +1 -1
- data/app/components/primer/primer.ts +1 -1
- data/app/components/primer/timeline_item_component.rb +2 -2
- data/app/components/primer/truncate.rb +5 -0
- data/app/components/primer/underline_nav_component.rb +1 -1
- data/lib/primer/classify.rb +1 -11
- data/lib/primer/classify/utilities.rb +22 -11
- data/lib/primer/view_components/linters/helpers.rb +17 -0
- data/lib/primer/view_components/statuses.rb +14 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/docs.rake +70 -16
- data/lib/yard/docs_helper.rb +1 -1
- data/static/statuses.json +4 -4
- metadata +10 -7
- data/app/components/primer/auto_complete.rb +0 -157
- data/app/components/primer/auto_complete/item.rb +0 -42
- data/app/components/primer/avatar_component.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b0ba62c9f5f11df09d24b40ca5e61e7d618046aba651ad733c8db06c482fe26
|
4
|
+
data.tar.gz: 34c0b8066b85d5392dd241baeb3b654ba47d7de1f360b793ac893750989d99dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47e1bca34582e4406fcc268ac786a322cc3f99a62789aeece262b91e1ca26a15c145835ad60afbcd85a13b3a37da7a54541aedf8e2af5b60c43d7d6cf6767072
|
7
|
+
data.tar.gz: 2edfb035e82896ea22bec576a98b34eb2e3c18cccf2d3ba18744f7b77135f6a1310b466179025c216d396708fdf5fbe802a2dc436c57d1510632eb9567776df1
|
data/CHANGELOG.md
CHANGED
@@ -30,6 +30,51 @@ The category for changes related to documentation, testing and tooling. Also, fo
|
|
30
30
|
|
31
31
|
## main
|
32
32
|
|
33
|
+
## 0.0.47
|
34
|
+
|
35
|
+
### Breaking changes
|
36
|
+
|
37
|
+
* Restrict tag for `Popover` to `:div` and `Popover` heading slot to headings.
|
38
|
+
|
39
|
+
*Kate Higa*
|
40
|
+
|
41
|
+
* Renames:
|
42
|
+
* `Primer::AutoComplete` to `Primer::Beta::AutoComplete`
|
43
|
+
* `Primer::AutoComplete::Item` to `Primer::Beta::AutoComplete::Item`
|
44
|
+
* `Primer::AvatarComponent` to `Primer::Beta::Avatar`
|
45
|
+
|
46
|
+
*Manuel Puyol*
|
47
|
+
|
48
|
+
### Misc
|
49
|
+
|
50
|
+
* Update `doc_examples_axe_test` to exclude non-standalone components and fix `Markdown` example.
|
51
|
+
|
52
|
+
*Kate Higa*
|
53
|
+
|
54
|
+
* Update `DetailsComponent` examples.
|
55
|
+
|
56
|
+
*Manuel Puyol*
|
57
|
+
|
58
|
+
* Add linter to suggest system arguments instead of classes.
|
59
|
+
|
60
|
+
*Manuel Puyol*
|
61
|
+
|
62
|
+
* Update component generator to create components in the right status module.
|
63
|
+
|
64
|
+
*Manuel Puyol*
|
65
|
+
|
66
|
+
* Add example for truncating HTML to `Truncate`.
|
67
|
+
|
68
|
+
*Joel Hawksley*
|
69
|
+
|
70
|
+
* Update docs generation to point to the correct file sources.
|
71
|
+
|
72
|
+
*Manuel Puyol*
|
73
|
+
|
74
|
+
* Add ENV flag to dump linter data into a file.
|
75
|
+
|
76
|
+
*Manuel Puyol*
|
77
|
+
|
33
78
|
## 0.0.46
|
34
79
|
|
35
80
|
### Updates
|
@@ -15,8 +15,8 @@ module Primer
|
|
15
15
|
BODY_TAG_OPTIONS = TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
|
16
16
|
# Required list of stacked avatars.
|
17
17
|
#
|
18
|
-
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::
|
19
|
-
renders_many :avatars, Primer::
|
18
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Avatar) %>.
|
19
|
+
renders_many :avatars, "Primer::Beta::Avatar"
|
20
20
|
|
21
21
|
# @example Default
|
22
22
|
# <%= render(Primer::AvatarStackComponent.new) do |c| %>
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Beta
|
5
|
+
# Use `AutoComplete` to provide a user with a list of selectable suggestions that appear when they type into the
|
6
|
+
# input field. This list is populated by server search results.
|
7
|
+
# @accessibility
|
8
|
+
# Always set an accessible label to help the user interact with the component.
|
9
|
+
#
|
10
|
+
# * Set the `label` slot to render a visible label. Alternatively, associate an existing visible text element
|
11
|
+
# as a label by setting `aria-labelledby`.
|
12
|
+
# * If you must use a non-visible label, set `:"aria-label"` on `AutoComplete` and Primer
|
13
|
+
# will apply it to the correct elements. However, please note that a visible label should almost
|
14
|
+
# always be used unless there is compelling reason not to. A placeholder is not a label.
|
15
|
+
class AutoComplete < Primer::Component
|
16
|
+
status :beta
|
17
|
+
|
18
|
+
# Optionally render a visible label. See <%= link_to_accessibility %>
|
19
|
+
#
|
20
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
21
|
+
renders_one :label, lambda { |**system_arguments|
|
22
|
+
system_arguments[:for] = @input_id
|
23
|
+
system_arguments[:tag] = :label
|
24
|
+
Primer::BaseComponent.new(**system_arguments)
|
25
|
+
}
|
26
|
+
|
27
|
+
# Required input used to search for results
|
28
|
+
#
|
29
|
+
# @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
|
30
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
31
|
+
renders_one :input, lambda { |**system_arguments|
|
32
|
+
aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
|
33
|
+
if aria_label.present?
|
34
|
+
system_arguments[:"aria-label"] = aria_label
|
35
|
+
system_arguments[:aria]&.delete(:label)
|
36
|
+
end
|
37
|
+
|
38
|
+
name = system_arguments[:name] || @input_id
|
39
|
+
Input.new(id: @input_id, name: name, **system_arguments)
|
40
|
+
}
|
41
|
+
|
42
|
+
# Optional icon to be rendered before the input. Has the same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
|
43
|
+
#
|
44
|
+
renders_one :icon, Primer::OcticonComponent
|
45
|
+
|
46
|
+
# Customizable results list.
|
47
|
+
#
|
48
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
49
|
+
renders_one :results, lambda { |**system_arguments|
|
50
|
+
system_arguments[:tag] = :ul
|
51
|
+
system_arguments[:id] = @list_id
|
52
|
+
system_arguments[:classes] = class_names(
|
53
|
+
"autocomplete-results",
|
54
|
+
system_arguments[:classes]
|
55
|
+
)
|
56
|
+
|
57
|
+
aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
|
58
|
+
system_arguments[:"aria-label"] = aria_label if aria_label.present?
|
59
|
+
system_arguments[:aria]&.delete(:label)
|
60
|
+
|
61
|
+
Primer::BaseComponent.new(**system_arguments)
|
62
|
+
}
|
63
|
+
|
64
|
+
# @example Default
|
65
|
+
# <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-1", list_id: "fruits-popup-1", position: :relative)) do |c| %>
|
66
|
+
# <% c.label(classes:"").with_content("Fruits") %>
|
67
|
+
# <% c.input(type: :text) %>
|
68
|
+
# <% end %>
|
69
|
+
#
|
70
|
+
# @example With `aria-label`
|
71
|
+
# <%= render(Primer::Beta::AutoComplete.new("aria-label": "Fruits", src: "/auto_complete", input_id: "fruits-input-2", list_id: "fruits-popup-2", position: :relative)) do |c| %>
|
72
|
+
# <% c.input(type: :text) %>
|
73
|
+
# <% end %>
|
74
|
+
#
|
75
|
+
# @example With `aria-labelledby`
|
76
|
+
# <%= render(Primer::HeadingComponent.new(tag: :h2, id: "search-1")) { "Search" } %>
|
77
|
+
# <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-3", list_id: "fruits-popup-2", position: :relative)) do |c| %>
|
78
|
+
# <% c.input("aria-labelledby": "search-1") %>
|
79
|
+
# <% end %>
|
80
|
+
#
|
81
|
+
# @example With custom classes for the results
|
82
|
+
# <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-4", list_id: "fruits-popup-3", position: :relative)) do |c| %>
|
83
|
+
# <% c.label(classes:"").with_content("Fruits") %>
|
84
|
+
# <% c.input(type: :text) %>
|
85
|
+
# <% c.results(classes: "custom-class") do %>
|
86
|
+
# <%= render(Primer::Beta::AutoComplete::Item.new(selected: true, value: "apple")) do |c| %>
|
87
|
+
# Apple
|
88
|
+
# <% end %>
|
89
|
+
# <%= render(Primer::Beta::AutoComplete::Item.new(value: "orange")) do |c| %>
|
90
|
+
# Orange
|
91
|
+
# <% end %>
|
92
|
+
# <% end %>
|
93
|
+
# <% end %>
|
94
|
+
#
|
95
|
+
# @example With Icon
|
96
|
+
# <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", list_id: "fruits-popup-4", input_id: "fruits-input-4", position: :relative)) do |c| %>
|
97
|
+
# <% c.label(classes:"").with_content("Fruits") %>
|
98
|
+
# <% c.input(type: :text) %>
|
99
|
+
# <% c.icon(icon: :search) %>
|
100
|
+
# <% end %>
|
101
|
+
#
|
102
|
+
# @param src [String] The route to query.
|
103
|
+
# @param input_id [String] Id of the input element.
|
104
|
+
# @param list_id [String] Id of the list element.
|
105
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
106
|
+
def initialize(src:, list_id:, input_id:, **system_arguments)
|
107
|
+
@list_id = list_id
|
108
|
+
@input_id = input_id
|
109
|
+
@aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label)
|
110
|
+
|
111
|
+
system_arguments.delete(:"aria-label") && system_arguments[:aria]&.delete(:label)
|
112
|
+
|
113
|
+
@system_arguments = system_arguments
|
114
|
+
@system_arguments[:tag] = "auto-complete"
|
115
|
+
@system_arguments[:src] = src
|
116
|
+
@system_arguments[:for] = list_id
|
117
|
+
end
|
118
|
+
|
119
|
+
# add `results` without needing to explicitly call it in the view
|
120
|
+
def before_render
|
121
|
+
raise ArgumentError, "Missing `input` slot" if input.blank?
|
122
|
+
raise ArgumentError, "Accessible label is required." if label.blank? && input.missing_label?
|
123
|
+
|
124
|
+
results(classes: "") unless results
|
125
|
+
end
|
126
|
+
|
127
|
+
# This component is part of `Primer::Beta::AutoCompleteComponent` and should not be
|
128
|
+
# used as a standalone component.
|
129
|
+
class Input < Primer::Component
|
130
|
+
DEFAULT_TYPE = :text
|
131
|
+
TYPE_OPTIONS = [DEFAULT_TYPE, :search].freeze
|
132
|
+
|
133
|
+
# @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
|
134
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
135
|
+
def initialize(type: DEFAULT_TYPE, **system_arguments)
|
136
|
+
@system_arguments = system_arguments
|
137
|
+
@system_arguments[:tag] = :input
|
138
|
+
|
139
|
+
@aria_label = system_arguments[:"aria-label"]
|
140
|
+
@aria_labelledby = system_arguments[:"aria-labelledby"] || system_arguments.dig(:aria, :labelledby)
|
141
|
+
|
142
|
+
@system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
|
143
|
+
@system_arguments[:classes] = class_names(
|
144
|
+
"form-control",
|
145
|
+
system_arguments[:classes]
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
def missing_label?
|
150
|
+
@aria_label.blank? && @aria_labelledby.blank?
|
151
|
+
end
|
152
|
+
|
153
|
+
def call
|
154
|
+
render(Primer::BaseComponent.new(**@system_arguments))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/auto-complete-element';
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@github/auto-complete-element';
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Beta
|
5
|
+
class AutoComplete
|
6
|
+
# Use `AutoCompleteItem` to list results of an auto-completed search.
|
7
|
+
class Item < Primer::Component
|
8
|
+
status :beta
|
9
|
+
|
10
|
+
# @example Default
|
11
|
+
# <%= render(Primer::Beta::AutoComplete::Item.new(selected: true, value: "value")) do |c| %>
|
12
|
+
# Selected
|
13
|
+
# <% end %>
|
14
|
+
# <%= render(Primer::Beta::AutoComplete::Item.new(value: "value")) do |c| %>
|
15
|
+
# Not selected
|
16
|
+
# <% end %>
|
17
|
+
#
|
18
|
+
# @param value [String] Value of the item.
|
19
|
+
# @param selected [Boolean] Whether the item is selected.
|
20
|
+
# @param disabled [Boolean] Whether the item is disabled.
|
21
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
22
|
+
def initialize(value:, selected: false, disabled: false, **system_arguments)
|
23
|
+
@system_arguments = system_arguments
|
24
|
+
@system_arguments[:tag] = :li
|
25
|
+
@system_arguments[:role] = :option
|
26
|
+
@system_arguments[:"data-autocomplete-value"] = value
|
27
|
+
|
28
|
+
@system_arguments[:"aria-selected"] = true if selected
|
29
|
+
@system_arguments[:"aria-disabled"] = true if disabled
|
30
|
+
|
31
|
+
@system_arguments[:classes] = class_names(
|
32
|
+
"autocomplete-item",
|
33
|
+
system_arguments[:classes],
|
34
|
+
"disabled" => disabled
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def call
|
39
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Beta
|
5
|
+
# `Avatar` can be used to represent users and organizations on GitHub.
|
6
|
+
#
|
7
|
+
# - Use the default round avatar for users, and the `square` argument
|
8
|
+
# for organizations or any other non-human avatars.
|
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
|
+
# - 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) %>.
|
12
|
+
#
|
13
|
+
# @accessibility
|
14
|
+
# Images should have text alternatives that describe the information or function represented.
|
15
|
+
# If the avatar functions as a link, provide alt text that helps convey the function. For instance,
|
16
|
+
# if `Avatar` is a link to a user profile, the alt attribute should be `@kittenuser profile`
|
17
|
+
# rather than `@kittenuser`.
|
18
|
+
# [Learn more about best image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/)
|
19
|
+
class Avatar < Primer::Component
|
20
|
+
status :beta
|
21
|
+
|
22
|
+
SMALL_THRESHOLD = 24
|
23
|
+
|
24
|
+
# @example Default
|
25
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser")) %>
|
26
|
+
#
|
27
|
+
# @example Square
|
28
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", square: true)) %>
|
29
|
+
#
|
30
|
+
# @example Link
|
31
|
+
# <%= render(Primer::Beta::Avatar.new(href: "#", src: "http://placekitten.com/200/200", alt: "@kittenuser profile")) %>
|
32
|
+
#
|
33
|
+
# @example With size
|
34
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 16)) %>
|
35
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 20)) %>
|
36
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 24)) %>
|
37
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 28)) %>
|
38
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 32)) %>
|
39
|
+
# <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 36)) %>
|
40
|
+
#
|
41
|
+
# @param src [String] The source url of the avatar image.
|
42
|
+
# @param alt [String] Passed through to alt on img tag.
|
43
|
+
# @param size [Integer] Adds the avatar-small class if less than 24.
|
44
|
+
# @param square [Boolean] Used to create a square avatar.
|
45
|
+
# @param href [String] The URL to link to. If used, component will be wrapped by an `<a>` tag.
|
46
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
47
|
+
def initialize(src:, alt:, size: 20, square: false, href: nil, **system_arguments)
|
48
|
+
@href = href
|
49
|
+
@system_arguments = system_arguments
|
50
|
+
@system_arguments[:tag] = :img
|
51
|
+
@system_arguments[:src] = src
|
52
|
+
@system_arguments[:alt] = alt
|
53
|
+
@system_arguments[:size] = size
|
54
|
+
@system_arguments[:height] = size
|
55
|
+
@system_arguments[:width] = size
|
56
|
+
|
57
|
+
@system_arguments[:classes] = class_names(
|
58
|
+
system_arguments[:classes],
|
59
|
+
"avatar",
|
60
|
+
"avatar-small" => size < SMALL_THRESHOLD,
|
61
|
+
"circle" => !square,
|
62
|
+
"lh-0" => href # Addresses an overflow issue with linked avatars
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def call
|
67
|
+
if @href
|
68
|
+
render(Primer::LinkComponent.new(href: @href, classes: @system_arguments[:classes])) do
|
69
|
+
render(Primer::BaseComponent.new(**@system_arguments.except(:classes))) { content }
|
70
|
+
end
|
71
|
+
else
|
72
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -29,7 +29,7 @@ module Primer
|
|
29
29
|
|
30
30
|
# Use the Body slot as the main content to be shown when triggered by the Summary.
|
31
31
|
#
|
32
|
-
# @param tag [
|
32
|
+
# @param tag [Symbol] (Primer::DetailsComponent::BODY_TAG_DEFAULT) <%= one_of(Primer::DetailsComponent::BODY_TAG_OPTIONS) %>
|
33
33
|
# @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
|
34
34
|
renders_one :body, lambda { |tag: BODY_TAG_DEFAULT, **system_arguments|
|
35
35
|
system_arguments[:tag] = fetch_or_fallback(BODY_TAG_OPTIONS, tag, BODY_TAG_DEFAULT)
|
@@ -40,12 +40,12 @@ module Primer
|
|
40
40
|
# @example Default
|
41
41
|
#
|
42
42
|
# <%= render Primer::DetailsComponent.new do |c| %>
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# end
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# end
|
43
|
+
# <% c.summary do %>
|
44
|
+
# Summary
|
45
|
+
# <% end %>
|
46
|
+
# <% c.body do %>
|
47
|
+
# Body
|
48
|
+
# <% end %>
|
49
49
|
# <% end %>
|
50
50
|
#
|
51
51
|
# @param overlay [Symbol] Dictates the type of overlay to render with. <%= one_of(Primer::DetailsComponent::OVERLAY_MAPPINGS.keys) %>
|
@@ -99,17 +99,17 @@ module Primer
|
|
99
99
|
# <p>And an unordered task list:</p>
|
100
100
|
#
|
101
101
|
# <ul>
|
102
|
-
# <li><input type="checkbox" checked
|
103
|
-
# <li><input type="checkbox"
|
104
|
-
# <li><input type="checkbox"
|
102
|
+
# <li><input type="checkbox" id="create-markdown" checked /><label for="create-markdown">Create a sample markdown document</label><br></li>
|
103
|
+
# <li><input type="checkbox" id="tasks-list" checked /><label for="tasks-list">Add tasks list to it</label><br></li>
|
104
|
+
# <li><input type="checkbox" id="take-vacation" checked /><label for="take-vacation">Take a vacation</label><br></li>
|
105
105
|
# </ul>
|
106
106
|
#
|
107
107
|
# <p>And a "mixed" task list:</p>
|
108
108
|
#
|
109
109
|
# <ul>
|
110
|
-
# <li><input type="checkbox"
|
110
|
+
# <li><input type="checkbox"id="steal-underpants"/><label for="steal-underpants">Steal underpants</label></li>
|
111
111
|
# <li>?</li>
|
112
|
-
# <li><input type="checkbox"
|
112
|
+
# <li><input type="checkbox"id="profit"/><label for="profit">Profit!</label></li>
|
113
113
|
# </ul>
|
114
114
|
#
|
115
115
|
# And a nested list:
|
@@ -241,9 +241,9 @@ module Primer
|
|
241
241
|
#
|
242
242
|
# <pre><code>var foo = "bar";</code></pre>
|
243
243
|
#
|
244
|
-
# <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>
|
244
|
+
# <pre tabindex="0"><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>
|
245
245
|
#
|
246
|
-
# <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>
|
246
|
+
# <pre tabindex="0"><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>
|
247
247
|
#
|
248
248
|
# <p>Inline code inside table cells should still be distinguishable.</p>
|
249
249
|
#
|
@@ -270,11 +270,11 @@ module Primer
|
|
270
270
|
#
|
271
271
|
# <p>Small images should be shown at their actual size.</p>
|
272
272
|
#
|
273
|
-
# <p><img src="http://placekitten.com/g/300/200/"/></p>
|
273
|
+
# <p><img alt="kitten" src="http://placekitten.com/g/300/200/"/></p>
|
274
274
|
#
|
275
275
|
# <p>Large images should always scale down and fit in the content container.</p>
|
276
276
|
#
|
277
|
-
# <p><img src="http://placekitten.com/g/1200/800/"/></p>
|
277
|
+
# <p><img alt="kitten" src="http://placekitten.com/g/1200/800/"/></p>
|
278
278
|
#
|
279
279
|
# <pre><code>This is the final element on the page and there should be no margin below this.</code></pre>
|
280
280
|
# <% end %>
|
@@ -23,12 +23,15 @@ module Primer
|
|
23
23
|
:top_right => "Popover-message--top-right"
|
24
24
|
}.freeze
|
25
25
|
|
26
|
+
DEFAULT_HEADING_TAG = :h4
|
27
|
+
|
26
28
|
# The heading
|
27
29
|
#
|
30
|
+
# @param tag [Symbol] (Primer::PopoverComponent::DEFAULT_HEADING_TAG) <%= one_of(Primer::HeadingComponent::TAG_OPTIONS) %>
|
28
31
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
29
|
-
renders_one :heading, lambda {
|
32
|
+
renders_one :heading, lambda { |tag: DEFAULT_HEADING_TAG, **system_arguments|
|
33
|
+
system_arguments[:tag] = tag
|
30
34
|
system_arguments[:mb] ||= 2
|
31
|
-
system_arguments[:tag] ||= :h4 # rubocop:disable Primer/NoTagMemoize
|
32
35
|
|
33
36
|
Primer::HeadingComponent.new(**system_arguments)
|
34
37
|
}
|
@@ -106,7 +109,7 @@ module Primer
|
|
106
109
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
107
110
|
def initialize(**system_arguments)
|
108
111
|
@system_arguments = system_arguments
|
109
|
-
@system_arguments[:tag]
|
112
|
+
@system_arguments[:tag] = :div
|
110
113
|
@system_arguments[:classes] = class_names(
|
111
114
|
system_arguments[:classes],
|
112
115
|
"Popover"
|
@@ -7,14 +7,14 @@ module Primer
|
|
7
7
|
|
8
8
|
# Avatar to be rendered to the left of the Badge.
|
9
9
|
#
|
10
|
-
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::
|
10
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Avatar) %>.
|
11
11
|
renders_one :avatar, lambda { |src:, size: 40, square: true, **system_arguments|
|
12
12
|
system_arguments[:classes] = class_names(
|
13
13
|
"TimelineItem-avatar",
|
14
14
|
system_arguments[:classes]
|
15
15
|
)
|
16
16
|
|
17
|
-
Primer::
|
17
|
+
Primer::Beta::Avatar.new(src: src, size: size, square: square, **system_arguments)
|
18
18
|
}
|
19
19
|
|
20
20
|
# Badge that will be connected to other TimelineItems.
|
@@ -22,6 +22,11 @@ module Primer
|
|
22
22
|
# @example Custom size
|
23
23
|
# <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true, max_width: 100)) { "branch-name-that-is-really-long" } %>
|
24
24
|
#
|
25
|
+
# @example With HTML content
|
26
|
+
# <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true, max_width: 100)) do %>
|
27
|
+
# <span>branch-name-that-is-really-long</span>
|
28
|
+
# <% end %>
|
29
|
+
#
|
25
30
|
# @param tag [Symbol] <%= one_of(Primer::Truncate::TAG_OPTIONS) %>
|
26
31
|
# @param inline [Boolean] Whether the element is inline (or inline-block).
|
27
32
|
# @param expandable [Boolean] Whether the entire string should be revealed on hover. Can only be used in conjunction with `inline`.
|
@@ -38,7 +38,7 @@ module Primer
|
|
38
38
|
|
39
39
|
# Use actions for a call to action.
|
40
40
|
#
|
41
|
-
# @param tag [
|
41
|
+
# @param tag [Symbol] (Primer::UnderlineNavComponent::ACTIONS_TAG_DEFAULT) <%= one_of(Primer::UnderlineNavComponent::ACTIONS_TAG_OPTIONS) %>
|
42
42
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
43
43
|
renders_one :actions, lambda { |tag: ACTIONS_TAG_DEFAULT, **system_arguments|
|
44
44
|
system_arguments[:tag] = fetch_or_fallback(ACTIONS_TAG_OPTIONS, tag, ACTIONS_TAG_DEFAULT)
|
data/lib/primer/classify.rb
CHANGED
@@ -11,16 +11,6 @@ require_relative "classify/utilities"
|
|
11
11
|
module Primer
|
12
12
|
# :nodoc:
|
13
13
|
class Classify
|
14
|
-
# Load the utilities.yml file.
|
15
|
-
# Disabling because we want to load symbols, strings, and integers from the .yml file
|
16
|
-
# rubocop:disable Security/YAMLLoad
|
17
|
-
UTILITIES = YAML.load(
|
18
|
-
File.read(
|
19
|
-
File.join(File.dirname(__FILE__), "./classify/utilities.yml")
|
20
|
-
)
|
21
|
-
).freeze
|
22
|
-
# rubocop:enable Security/YAMLLoad
|
23
|
-
|
24
14
|
# Keys where we can simply translate { key: value } into ".key-value"
|
25
15
|
CONCAT_KEYS = %i[text box_shadow].freeze
|
26
16
|
|
@@ -90,7 +80,7 @@ module Primer
|
|
90
80
|
BORDER_RADIUS_KEY = :border_radius
|
91
81
|
TYPOGRAPHY_KEYS = [:font_size].freeze
|
92
82
|
VALID_KEYS = (
|
93
|
-
UTILITIES.keys +
|
83
|
+
Primer::Classify::Utilities::UTILITIES.keys +
|
94
84
|
CONCAT_KEYS +
|
95
85
|
BOOLEAN_MAPPINGS.keys +
|
96
86
|
BORDER_MARGIN_KEYS +
|
@@ -5,13 +5,24 @@ module Primer
|
|
5
5
|
class Classify
|
6
6
|
# Handler for PrimerCSS utility classes loaded from utilities.rake
|
7
7
|
class Utilities
|
8
|
+
# Load the utilities.yml file.
|
9
|
+
# Disabling because we want to load symbols, strings, and integers from the .yml file
|
10
|
+
# rubocop:disable Security/YAMLLoad
|
11
|
+
UTILITIES = YAML.load(
|
12
|
+
File.read(
|
13
|
+
File.join(File.dirname(__FILE__), "./utilities.yml")
|
14
|
+
)
|
15
|
+
).freeze
|
16
|
+
# rubocop:enable Security/YAMLLoad
|
17
|
+
BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
|
18
|
+
|
8
19
|
class << self
|
9
20
|
def classname(key, val, breakpoint = "")
|
10
21
|
if (valid = validate(key, val, breakpoint))
|
11
22
|
valid
|
12
23
|
else
|
13
24
|
# Get selector
|
14
|
-
|
25
|
+
UTILITIES[key][val][BREAKPOINTS.index(breakpoint)]
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
@@ -19,14 +30,14 @@ module Primer
|
|
19
30
|
#
|
20
31
|
# returns Boolean
|
21
32
|
def supported_key?(key)
|
22
|
-
|
33
|
+
UTILITIES[key].present?
|
23
34
|
end
|
24
35
|
|
25
36
|
# Does the Utilitiy class support the given key and value
|
26
37
|
#
|
27
38
|
# returns Boolean
|
28
39
|
def supported_value?(key, val)
|
29
|
-
supported_key?(key) &&
|
40
|
+
supported_key?(key) && UTILITIES[key][val].present?
|
30
41
|
end
|
31
42
|
|
32
43
|
# Does the given selector exist in the utilities file
|
@@ -34,7 +45,7 @@ module Primer
|
|
34
45
|
# returns Boolean
|
35
46
|
def supported_selector?(selector)
|
36
47
|
# This method is too slow to run in production
|
37
|
-
return false if
|
48
|
+
return false if ENV["RAILS_ENV"] == "production"
|
38
49
|
|
39
50
|
find_selector(selector).present?
|
40
51
|
end
|
@@ -43,7 +54,7 @@ module Primer
|
|
43
54
|
#
|
44
55
|
# returns Boolean
|
45
56
|
def responsive?(key, val)
|
46
|
-
supported_value?(key, val) &&
|
57
|
+
supported_value?(key, val) && UTILITIES[key][val].count > 1
|
47
58
|
end
|
48
59
|
|
49
60
|
# Get the options for the given key
|
@@ -52,13 +63,13 @@ module Primer
|
|
52
63
|
def mappings(key)
|
53
64
|
return unless supported_key?(key)
|
54
65
|
|
55
|
-
|
66
|
+
UTILITIES[key].keys
|
56
67
|
end
|
57
68
|
|
58
69
|
# Extract hash from classes ie. "mr-1 mb-2 foo" => { mr: 1, mb: 2, classes: "foo" }
|
59
70
|
def classes_to_hash(classes)
|
60
71
|
# This method is too slow to run in production
|
61
|
-
return { classes: classes } if
|
72
|
+
return { classes: classes } if ENV["RAILS_ENV"] == "production"
|
62
73
|
|
63
74
|
obj = {}
|
64
75
|
classes = classes.split(" ")
|
@@ -94,7 +105,7 @@ module Primer
|
|
94
105
|
|
95
106
|
def find_selector(selector)
|
96
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" ] }`
|
97
|
-
|
108
|
+
UTILITIES.each do |key, value_hash|
|
98
109
|
# Each value hash will also contain an array of classnames for breakpoints
|
99
110
|
# Key argument `0`, classes `[ "mr-0", "mr-sm-0", "mr-md-0", "mr-lg-0", "mr-xl-0" ]`
|
100
111
|
value_hash.each do |key_argument, classnames|
|
@@ -112,19 +123,19 @@ module Primer
|
|
112
123
|
|
113
124
|
def validate(key, val, breakpoint)
|
114
125
|
unless supported_key?(key)
|
115
|
-
raise ArgumentError, "#{key} is not a valid Primer utility key" unless
|
126
|
+
raise ArgumentError, "#{key} is not a valid Primer utility key" unless ENV["RAILS_ENV"] == "production"
|
116
127
|
|
117
128
|
return ""
|
118
129
|
end
|
119
130
|
|
120
131
|
unless breakpoint.empty? || responsive?(key, val)
|
121
|
-
raise ArgumentError, "#{key} does not support responsive values" unless
|
132
|
+
raise ArgumentError, "#{key} does not support responsive values" unless ENV["RAILS_ENV"] == "production"
|
122
133
|
|
123
134
|
return ""
|
124
135
|
end
|
125
136
|
|
126
137
|
unless supported_value?(key, val)
|
127
|
-
raise ArgumentError, "#{val} is not a valid value for :#{key}. Use one of #{mappings(key)}" unless
|
138
|
+
raise ArgumentError, "#{val} is not a valid value for :#{key}. Use one of #{mappings(key)}" unless ENV["RAILS_ENV"] == "production"
|
128
139
|
|
129
140
|
return ""
|
130
141
|
end
|
@@ -13,10 +13,13 @@ module ERBLint
|
|
13
13
|
link menuitem meta param source track wbr img
|
14
14
|
].freeze
|
15
15
|
|
16
|
+
DUMP_FILE = ".erblint-counter-ignore.json"
|
17
|
+
|
16
18
|
def self.included(base)
|
17
19
|
base.include(ERBLint::LinterRegistry)
|
18
20
|
|
19
21
|
define_method "run" do |processed_source|
|
22
|
+
@total_offenses = 0
|
20
23
|
@offenses_not_corrected = 0
|
21
24
|
tags = tags(processed_source)
|
22
25
|
tag_tree = build_tag_tree(tags)
|
@@ -43,6 +46,7 @@ module ERBLint
|
|
43
46
|
tag_tree.each do |tag, h|
|
44
47
|
next unless h[:offense]
|
45
48
|
|
49
|
+
@total_offenses += 1
|
46
50
|
# We always fix the offenses using blocks. The closing tag corresponds to `<% end %>`.
|
47
51
|
if h[:correctable]
|
48
52
|
add_offense(tag.loc, h[:message], h[:correction])
|
@@ -54,6 +58,8 @@ module ERBLint
|
|
54
58
|
end
|
55
59
|
|
56
60
|
counter_correct?(processed_source)
|
61
|
+
|
62
|
+
dump_data(processed_source) if ENV["DUMP_LINT_DATA"] == "1"
|
57
63
|
end
|
58
64
|
|
59
65
|
define_method "autocorrect" do |processed_source, offense|
|
@@ -186,6 +192,17 @@ module ERBLint
|
|
186
192
|
offense = ["#{klass_name}:#{message}", tag.node.loc.source].join("\n")
|
187
193
|
add_offense(processed_source.to_source_range(tag.loc), offense, replacement)
|
188
194
|
end
|
195
|
+
|
196
|
+
def dump_data(processed_source)
|
197
|
+
return if @total_offenses.zero?
|
198
|
+
|
199
|
+
data = File.exist?(DUMP_FILE) ? JSON.parse(File.read(DUMP_FILE)) : {}
|
200
|
+
|
201
|
+
data[processed_source.filename] ||= {}
|
202
|
+
data[processed_source.filename][self.class.name.demodulize] = @total_offenses
|
203
|
+
|
204
|
+
File.write(DUMP_FILE, JSON.pretty_generate(data))
|
205
|
+
end
|
189
206
|
end
|
190
207
|
end
|
191
208
|
end
|
data/lib/tasks/docs.rake
CHANGED
@@ -32,9 +32,9 @@ namespace :docs do
|
|
32
32
|
Primer::OcticonSymbolsComponent,
|
33
33
|
Primer::ImageCrop,
|
34
34
|
Primer::IconButton,
|
35
|
-
Primer::AutoComplete,
|
36
|
-
Primer::AutoComplete::Item,
|
37
|
-
Primer::
|
35
|
+
Primer::Beta::AutoComplete,
|
36
|
+
Primer::Beta::AutoComplete::Item,
|
37
|
+
Primer::Beta::Avatar,
|
38
38
|
Primer::AvatarStackComponent,
|
39
39
|
Primer::BaseButton,
|
40
40
|
Primer::BlankslateComponent,
|
@@ -81,7 +81,7 @@ namespace :docs do
|
|
81
81
|
Primer::Dropdown,
|
82
82
|
Primer::LocalTime,
|
83
83
|
Primer::ImageCrop,
|
84
|
-
Primer::AutoComplete,
|
84
|
+
Primer::Beta::AutoComplete,
|
85
85
|
Primer::ClipboardCopy,
|
86
86
|
Primer::TabContainerComponent,
|
87
87
|
Primer::TabNavComponent,
|
@@ -97,28 +97,30 @@ namespace :docs do
|
|
97
97
|
|
98
98
|
errors = []
|
99
99
|
|
100
|
-
|
100
|
+
# Deletes docs before regenerating them, guaranteeing that we don't keep stale docs.
|
101
|
+
FileUtils.rm_rf(Dir.glob("docs/content/components/**/*.md"))
|
102
|
+
|
103
|
+
components.sort_by(&:name).each do |component|
|
101
104
|
documentation = registry.get(component.name)
|
102
105
|
|
103
|
-
|
104
|
-
short_name = component.name.gsub(/Primer|::|Component/, "")
|
106
|
+
data = docs_metadata(component)
|
105
107
|
|
106
|
-
path = Pathname.new(
|
108
|
+
path = Pathname.new(data[:path])
|
107
109
|
path.dirname.mkdir unless path.dirname.exist?
|
108
110
|
File.open(path, "w") do |f|
|
109
111
|
f.puts("---")
|
110
|
-
f.puts("title: #{
|
111
|
-
f.puts("status: #{
|
112
|
-
f.puts("source:
|
113
|
-
f.puts("storybook:
|
112
|
+
f.puts("title: #{data[:title]}")
|
113
|
+
f.puts("status: #{data[:status]}")
|
114
|
+
f.puts("source: #{data[:source]}")
|
115
|
+
f.puts("storybook: #{data[:storybook]}")
|
114
116
|
f.puts("---")
|
115
117
|
f.puts
|
116
|
-
f.puts("import Example from '
|
118
|
+
f.puts("import Example from '#{data[:example_path]}'")
|
117
119
|
|
118
120
|
initialize_method = documentation.meths.find(&:constructor?)
|
119
121
|
|
120
122
|
if js_components.include?(component)
|
121
|
-
f.puts("import RequiresJSFlash from '
|
123
|
+
f.puts("import RequiresJSFlash from '#{data[:require_js_path]}'")
|
122
124
|
f.puts
|
123
125
|
f.puts("<RequiresJSFlash />")
|
124
126
|
end
|
@@ -183,8 +185,8 @@ namespace :docs do
|
|
183
185
|
end
|
184
186
|
|
185
187
|
component_args = {
|
186
|
-
"component" =>
|
187
|
-
"source" =>
|
188
|
+
"component" => data[:title],
|
189
|
+
"source" => data[:source],
|
188
190
|
"parameters" => args
|
189
191
|
}
|
190
192
|
|
@@ -346,6 +348,7 @@ namespace :docs do
|
|
346
348
|
end
|
347
349
|
|
348
350
|
def generate_yard_registry
|
351
|
+
ENV["SKIP_STORYBOOK_PRELOAD"] = "1"
|
349
352
|
require File.expand_path("./../../demo/config/environment.rb", __dir__)
|
350
353
|
require "primer/view_components"
|
351
354
|
require "yard/docs_helper"
|
@@ -384,4 +387,55 @@ namespace :docs do
|
|
384
387
|
|
385
388
|
pretty_value(constant_value)
|
386
389
|
end
|
390
|
+
|
391
|
+
def status_module_and_short_name(component)
|
392
|
+
name_with_status = component.name.gsub(/Primer::|Component/, "")
|
393
|
+
|
394
|
+
m = name_with_status.match(/(?<status>Beta|Alpha|Deprecated)?(::)?(?<name>.*)/)
|
395
|
+
[m[:status]&.downcase, m[:name].gsub("::", "")]
|
396
|
+
end
|
397
|
+
|
398
|
+
def docs_metadata(component)
|
399
|
+
(status_module, short_name) = status_module_and_short_name(component)
|
400
|
+
status_path = status_module.nil? ? "" : "#{status_module}/"
|
401
|
+
status = component.status.to_s
|
402
|
+
|
403
|
+
{
|
404
|
+
title: short_name,
|
405
|
+
status: status.capitalize,
|
406
|
+
source: source_url(component),
|
407
|
+
storybook: storybook_url(component),
|
408
|
+
path: "docs/content/components/#{status_path}#{short_name.downcase}.md",
|
409
|
+
example_path: example_path(component),
|
410
|
+
require_js_path: require_js_path(component)
|
411
|
+
}
|
412
|
+
end
|
413
|
+
|
414
|
+
def source_url(component)
|
415
|
+
path = component.name.split("::").map(&:underscore).join("/")
|
416
|
+
|
417
|
+
"https://github.com/primer/view_components/tree/main/app/components/#{path}.rb"
|
418
|
+
end
|
419
|
+
|
420
|
+
def storybook_url(component)
|
421
|
+
path = component.name.split("::").map { |n| n.underscore.dasherize }.join("-")
|
422
|
+
|
423
|
+
"https://primer.style/view-components/stories/?path=/story/#{path}"
|
424
|
+
end
|
425
|
+
|
426
|
+
def example_path(component)
|
427
|
+
example_path = "../../src/@primer/gatsby-theme-doctocat/components/example"
|
428
|
+
example_path = "../#{example_path}" if status_module?(component)
|
429
|
+
example_path
|
430
|
+
end
|
431
|
+
|
432
|
+
def require_js_path(component)
|
433
|
+
require_js_path = "../../src/@primer/gatsby-theme-doctocat/components/requires-js-flash"
|
434
|
+
require_js_path = "../#{require_js_path}" if status_module?(component)
|
435
|
+
require_js_path
|
436
|
+
end
|
437
|
+
|
438
|
+
def status_module?(component)
|
439
|
+
(%w[Alpha Beta] & component.name.split("::")).any?
|
440
|
+
end
|
387
441
|
end
|
data/lib/yard/docs_helper.rb
CHANGED
@@ -41,7 +41,7 @@ module YARD
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def link_to_component(component)
|
44
|
-
short_name = component.name.gsub(/Primer|::|Component/, "")
|
44
|
+
short_name = component.name.gsub(/Primer|::|Alpha|Beta|Component/, "")
|
45
45
|
"[#{short_name}](/components/#{short_name.downcase})"
|
46
46
|
end
|
47
47
|
|
data/static/statuses.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"Primer::Alpha::ButtonMarketing": "alpha",
|
3
|
-
"Primer::AutoComplete": "beta",
|
4
|
-
"Primer::AutoComplete::Input": "alpha",
|
5
|
-
"Primer::AutoComplete::Item": "beta",
|
6
|
-
"Primer::AvatarComponent": "beta",
|
7
3
|
"Primer::AvatarStackComponent": "beta",
|
8
4
|
"Primer::BaseButton": "beta",
|
9
5
|
"Primer::BaseComponent": "beta",
|
6
|
+
"Primer::Beta::AutoComplete": "beta",
|
7
|
+
"Primer::Beta::AutoComplete::Input": "alpha",
|
8
|
+
"Primer::Beta::AutoComplete::Item": "beta",
|
9
|
+
"Primer::Beta::Avatar": "beta",
|
10
10
|
"Primer::Beta::Text": "beta",
|
11
11
|
"Primer::BlankslateComponent": "beta",
|
12
12
|
"Primer::BorderBoxComponent": "beta",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: primer_view_components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.47
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionview
|
@@ -351,19 +351,21 @@ files:
|
|
351
351
|
- app/assets/javascripts/primer_view_components.js
|
352
352
|
- app/assets/javascripts/primer_view_components.js.map
|
353
353
|
- app/components/primer/alpha/button_marketing.rb
|
354
|
-
- app/components/primer/auto_complete.rb
|
355
354
|
- app/components/primer/auto_complete/auto_complete.d.ts
|
356
|
-
- app/components/primer/auto_complete/auto_complete.html.erb
|
357
355
|
- app/components/primer/auto_complete/auto_complete.js
|
358
|
-
- app/components/primer/auto_complete/auto_complete.ts
|
359
356
|
- app/components/primer/auto_complete/auto_component.d.ts
|
360
357
|
- app/components/primer/auto_complete/auto_component.js
|
361
|
-
- app/components/primer/auto_complete/item.rb
|
362
|
-
- app/components/primer/avatar_component.rb
|
363
358
|
- app/components/primer/avatar_stack_component.html.erb
|
364
359
|
- app/components/primer/avatar_stack_component.rb
|
365
360
|
- app/components/primer/base_button.rb
|
366
361
|
- app/components/primer/base_component.rb
|
362
|
+
- app/components/primer/beta/auto_complete.rb
|
363
|
+
- app/components/primer/beta/auto_complete/auto_complete.d.ts
|
364
|
+
- app/components/primer/beta/auto_complete/auto_complete.html.erb
|
365
|
+
- app/components/primer/beta/auto_complete/auto_complete.js
|
366
|
+
- app/components/primer/beta/auto_complete/auto_complete.ts
|
367
|
+
- app/components/primer/beta/auto_complete/item.rb
|
368
|
+
- app/components/primer/beta/avatar.rb
|
367
369
|
- app/components/primer/beta/text.rb
|
368
370
|
- app/components/primer/blankslate_component.html.erb
|
369
371
|
- app/components/primer/blankslate_component.rb
|
@@ -483,6 +485,7 @@ files:
|
|
483
485
|
- lib/primer/view_components/linters/button_component_migration_counter.rb
|
484
486
|
- lib/primer/view_components/linters/flash_component_migration_counter.rb
|
485
487
|
- lib/primer/view_components/linters/helpers.rb
|
488
|
+
- lib/primer/view_components/statuses.rb
|
486
489
|
- lib/primer/view_components/version.rb
|
487
490
|
- lib/tasks/coverage.rake
|
488
491
|
- lib/tasks/docs.rake
|
@@ -1,157 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Primer
|
4
|
-
# Use `AutoComplete` to provide a user with a list of selectable suggestions that appear when they type into the
|
5
|
-
# input field. This list is populated by server search results.
|
6
|
-
# @accessibility
|
7
|
-
# Always set an accessible label to help the user interact with the component.
|
8
|
-
#
|
9
|
-
# * Set the `label` slot to render a visible label. Alternatively, associate an existing visible text element
|
10
|
-
# as a label by setting `aria-labelledby`.
|
11
|
-
# * If you must use a non-visible label, set `:"aria-label"` on `AutoComplete` and Primer
|
12
|
-
# will apply it to the correct elements. However, please note that a visible label should almost
|
13
|
-
# always be used unless there is compelling reason not to. A placeholder is not a label.
|
14
|
-
class AutoComplete < Primer::Component
|
15
|
-
status :beta
|
16
|
-
|
17
|
-
# Optionally render a visible label. See <%= link_to_accessibility %>
|
18
|
-
#
|
19
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
20
|
-
renders_one :label, lambda { |**system_arguments|
|
21
|
-
system_arguments[:for] = @input_id
|
22
|
-
system_arguments[:tag] = :label
|
23
|
-
Primer::BaseComponent.new(**system_arguments)
|
24
|
-
}
|
25
|
-
|
26
|
-
# Required input used to search for results
|
27
|
-
#
|
28
|
-
# @param type [Symbol] <%= one_of(Primer::AutoComplete::Input::TYPE_OPTIONS) %>
|
29
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
30
|
-
renders_one :input, lambda { |**system_arguments|
|
31
|
-
aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
|
32
|
-
if aria_label.present?
|
33
|
-
system_arguments[:"aria-label"] = aria_label
|
34
|
-
system_arguments[:aria]&.delete(:label)
|
35
|
-
end
|
36
|
-
|
37
|
-
name = system_arguments[:name] || @input_id
|
38
|
-
Input.new(id: @input_id, name: name, **system_arguments)
|
39
|
-
}
|
40
|
-
|
41
|
-
# Optional icon to be rendered before the input. Has the same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
|
42
|
-
#
|
43
|
-
renders_one :icon, Primer::OcticonComponent
|
44
|
-
|
45
|
-
# Customizable results list.
|
46
|
-
#
|
47
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
48
|
-
renders_one :results, lambda { |**system_arguments|
|
49
|
-
system_arguments[:tag] = :ul
|
50
|
-
system_arguments[:id] = @list_id
|
51
|
-
system_arguments[:classes] = class_names(
|
52
|
-
"autocomplete-results",
|
53
|
-
system_arguments[:classes]
|
54
|
-
)
|
55
|
-
|
56
|
-
aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
|
57
|
-
system_arguments[:"aria-label"] = aria_label if aria_label.present?
|
58
|
-
system_arguments[:aria]&.delete(:label)
|
59
|
-
|
60
|
-
Primer::BaseComponent.new(**system_arguments)
|
61
|
-
}
|
62
|
-
|
63
|
-
# @example Default
|
64
|
-
# <%= render(Primer::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-1", list_id: "fruits-popup-1", position: :relative)) do |c| %>
|
65
|
-
# <% c.label(classes:"").with_content("Fruits") %>
|
66
|
-
# <% c.input(type: :text) %>
|
67
|
-
# <% end %>
|
68
|
-
#
|
69
|
-
# @example With `aria-label`
|
70
|
-
# <%= render(Primer::AutoComplete.new("aria-label": "Fruits", src: "/auto_complete", input_id: "fruits-input-2", list_id: "fruits-popup-2", position: :relative)) do |c| %>
|
71
|
-
# <% c.input(type: :text) %>
|
72
|
-
# <% end %>
|
73
|
-
#
|
74
|
-
# @example With `aria-labelledby`
|
75
|
-
# <%= render(Primer::HeadingComponent.new(tag: :h2, id: "search-1")) { "Search" } %>
|
76
|
-
# <%= render(Primer::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-3", list_id: "fruits-popup-2", position: :relative)) do |c| %>
|
77
|
-
# <% c.input("aria-labelledby": "search-1") %>
|
78
|
-
# <% end %>
|
79
|
-
#
|
80
|
-
# @example With custom classes for the results
|
81
|
-
# <%= render(Primer::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-4", list_id: "fruits-popup-3", position: :relative)) do |c| %>
|
82
|
-
# <% c.label(classes:"").with_content("Fruits") %>
|
83
|
-
# <% c.input(type: :text) %>
|
84
|
-
# <% c.results(classes: "custom-class") do %>
|
85
|
-
# <%= render(Primer::AutoComplete::Item.new(selected: true, value: "apple")) do |c| %>
|
86
|
-
# Apple
|
87
|
-
# <% end %>
|
88
|
-
# <%= render(Primer::AutoComplete::Item.new(value: "orange")) do |c| %>
|
89
|
-
# Orange
|
90
|
-
# <% end %>
|
91
|
-
# <% end %>
|
92
|
-
# <% end %>
|
93
|
-
#
|
94
|
-
# @example With Icon
|
95
|
-
# <%= render(Primer::AutoComplete.new(src: "/auto_complete", list_id: "fruits-popup-4", input_id: "fruits-input-4", position: :relative)) do |c| %>
|
96
|
-
# <% c.label(classes:"").with_content("Fruits") %>
|
97
|
-
# <% c.input(type: :text) %>
|
98
|
-
# <% c.icon(icon: :search) %>
|
99
|
-
# <% end %>
|
100
|
-
#
|
101
|
-
# @param src [String] The route to query.
|
102
|
-
# @param input_id [String] Id of the input element.
|
103
|
-
# @param list_id [String] Id of the list element.
|
104
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
105
|
-
def initialize(src:, list_id:, input_id:, **system_arguments)
|
106
|
-
@list_id = list_id
|
107
|
-
@input_id = input_id
|
108
|
-
@aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label)
|
109
|
-
|
110
|
-
system_arguments.delete(:"aria-label") && system_arguments[:aria]&.delete(:label)
|
111
|
-
|
112
|
-
@system_arguments = system_arguments
|
113
|
-
@system_arguments[:tag] = "auto-complete"
|
114
|
-
@system_arguments[:src] = src
|
115
|
-
@system_arguments[:for] = list_id
|
116
|
-
end
|
117
|
-
|
118
|
-
# add `results` without needing to explicitly call it in the view
|
119
|
-
def before_render
|
120
|
-
raise ArgumentError, "Missing `input` slot" if input.blank?
|
121
|
-
raise ArgumentError, "Accessible label is required." if label.blank? && input.missing_label?
|
122
|
-
|
123
|
-
results(classes: "") unless results
|
124
|
-
end
|
125
|
-
|
126
|
-
# This component is part of `Primer::AutoCompleteComponent` and should not be
|
127
|
-
# used as a standalone component.
|
128
|
-
class Input < Primer::Component
|
129
|
-
DEFAULT_TYPE = :text
|
130
|
-
TYPE_OPTIONS = [DEFAULT_TYPE, :search].freeze
|
131
|
-
|
132
|
-
# @param type [Symbol] <%= one_of(Primer::AutoComplete::Input::TYPE_OPTIONS) %>
|
133
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
134
|
-
def initialize(type: DEFAULT_TYPE, **system_arguments)
|
135
|
-
@system_arguments = system_arguments
|
136
|
-
@system_arguments[:tag] = :input
|
137
|
-
|
138
|
-
@aria_label = system_arguments[:"aria-label"]
|
139
|
-
@aria_labelledby = system_arguments[:"aria-labelledby"] || system_arguments.dig(:aria, :labelledby)
|
140
|
-
|
141
|
-
@system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
|
142
|
-
@system_arguments[:classes] = class_names(
|
143
|
-
"form-control",
|
144
|
-
system_arguments[:classes]
|
145
|
-
)
|
146
|
-
end
|
147
|
-
|
148
|
-
def missing_label?
|
149
|
-
@aria_label.blank? && @aria_labelledby.blank?
|
150
|
-
end
|
151
|
-
|
152
|
-
def call
|
153
|
-
render(Primer::BaseComponent.new(**@system_arguments))
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Primer
|
4
|
-
class AutoComplete
|
5
|
-
# Use `AutoCompleteItem` to list results of an auto-completed search.
|
6
|
-
class Item < Primer::Component
|
7
|
-
status :beta
|
8
|
-
|
9
|
-
# @example Default
|
10
|
-
# <%= render(Primer::AutoComplete::Item.new(selected: true, value: "value")) do |c| %>
|
11
|
-
# Selected
|
12
|
-
# <% end %>
|
13
|
-
# <%= render(Primer::AutoComplete::Item.new(value: "value")) do |c| %>
|
14
|
-
# Not selected
|
15
|
-
# <% end %>
|
16
|
-
#
|
17
|
-
# @param value [String] Value of the item.
|
18
|
-
# @param selected [Boolean] Whether the item is selected.
|
19
|
-
# @param disabled [Boolean] Whether the item is disabled.
|
20
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
21
|
-
def initialize(value:, selected: false, disabled: false, **system_arguments)
|
22
|
-
@system_arguments = system_arguments
|
23
|
-
@system_arguments[:tag] = :li
|
24
|
-
@system_arguments[:role] = :option
|
25
|
-
@system_arguments[:"data-autocomplete-value"] = value
|
26
|
-
|
27
|
-
@system_arguments[:"aria-selected"] = true if selected
|
28
|
-
@system_arguments[:"aria-disabled"] = true if disabled
|
29
|
-
|
30
|
-
@system_arguments[:classes] = class_names(
|
31
|
-
"autocomplete-item",
|
32
|
-
system_arguments[:classes],
|
33
|
-
"disabled" => disabled
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
def call
|
38
|
-
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Primer
|
4
|
-
# `Avatar` can be used to represent users and organizations on GitHub.
|
5
|
-
#
|
6
|
-
# - Use the default round avatar for users, and the `square` argument
|
7
|
-
# for organizations or any other non-human avatars.
|
8
|
-
# - 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>`.
|
9
|
-
# - Set `size` to update the height and width of the `Avatar` in pixels.
|
10
|
-
# - To stack multiple avatars together, use <%= link_to_component(Primer::AvatarStackComponent) %>.
|
11
|
-
#
|
12
|
-
# @accessibility
|
13
|
-
# Images should have text alternatives that describe the information or function represented.
|
14
|
-
# If the avatar functions as a link, provide alt text that helps convey the function. For instance,
|
15
|
-
# if `Avatar` is a link to a user profile, the alt attribute should be `@kittenuser profile`
|
16
|
-
# rather than `@kittenuser`.
|
17
|
-
# [Learn more about best image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/)
|
18
|
-
class AvatarComponent < Primer::Component
|
19
|
-
status :beta
|
20
|
-
|
21
|
-
SMALL_THRESHOLD = 24
|
22
|
-
|
23
|
-
# @example Default
|
24
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser")) %>
|
25
|
-
#
|
26
|
-
# @example Square
|
27
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", square: true)) %>
|
28
|
-
#
|
29
|
-
# @example Link
|
30
|
-
# <%= render(Primer::AvatarComponent.new(href: "#", src: "http://placekitten.com/200/200", alt: "@kittenuser profile")) %>
|
31
|
-
#
|
32
|
-
# @example With size
|
33
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 16)) %>
|
34
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 20)) %>
|
35
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 24)) %>
|
36
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 28)) %>
|
37
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 32)) %>
|
38
|
-
# <%= render(Primer::AvatarComponent.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 36)) %>
|
39
|
-
#
|
40
|
-
# @param src [String] The source url of the avatar image.
|
41
|
-
# @param alt [String] Passed through to alt on img tag.
|
42
|
-
# @param size [Integer] Adds the avatar-small class if less than 24.
|
43
|
-
# @param square [Boolean] Used to create a square avatar.
|
44
|
-
# @param href [String] The URL to link to. If used, component will be wrapped by an `<a>` tag.
|
45
|
-
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
46
|
-
def initialize(src:, alt:, size: 20, square: false, href: nil, **system_arguments)
|
47
|
-
@href = href
|
48
|
-
@system_arguments = system_arguments
|
49
|
-
@system_arguments[:tag] = :img
|
50
|
-
@system_arguments[:src] = src
|
51
|
-
@system_arguments[:alt] = alt
|
52
|
-
@system_arguments[:size] = size
|
53
|
-
@system_arguments[:height] = size
|
54
|
-
@system_arguments[:width] = size
|
55
|
-
|
56
|
-
@system_arguments[:classes] = class_names(
|
57
|
-
system_arguments[:classes],
|
58
|
-
"avatar",
|
59
|
-
"avatar-small" => size < SMALL_THRESHOLD,
|
60
|
-
"circle" => !square,
|
61
|
-
"lh-0" => href # Addresses an overflow issue with linked avatars
|
62
|
-
)
|
63
|
-
end
|
64
|
-
|
65
|
-
def call
|
66
|
-
if @href
|
67
|
-
render(Primer::LinkComponent.new(href: @href, classes: @system_arguments[:classes])) do
|
68
|
-
render(Primer::BaseComponent.new(**@system_arguments.except(:classes))) { content }
|
69
|
-
end
|
70
|
-
else
|
71
|
-
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|