primer_view_components 0.1.4 → 0.1.5
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 +14 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +2 -2
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/heading.html.erb +1 -1
- data/app/components/primer/alpha/action_list/heading.rb +5 -3
- data/app/components/primer/alpha/action_list/item.html.erb +9 -0
- data/app/components/primer/alpha/action_list/item.rb +31 -10
- data/app/components/primer/alpha/action_list.css +1 -1
- data/app/components/primer/alpha/action_list.css.json +4 -41
- data/app/components/primer/alpha/action_list.css.map +1 -1
- data/app/components/primer/alpha/action_list.pcss +19 -20
- data/app/components/primer/alpha/action_list.rb +54 -6
- data/app/components/primer/alpha/action_menu/action_menu_element.d.ts +22 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.js +139 -0
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +137 -0
- data/app/components/primer/alpha/action_menu/list.rb +81 -0
- data/app/components/primer/alpha/action_menu.html.erb +26 -0
- data/app/components/primer/alpha/action_menu.rb +322 -0
- data/app/components/primer/alpha/auto_complete.css.json +0 -11
- data/app/components/primer/alpha/banner.css.json +0 -14
- data/app/components/primer/alpha/button_marketing.css.json +0 -10
- data/app/components/primer/alpha/dialog.css.json +0 -63
- data/app/components/primer/alpha/dialog.rb +6 -2
- data/app/components/primer/alpha/dropdown.css.json +0 -21
- data/app/components/primer/alpha/layout.css.json +0 -27
- data/app/components/primer/alpha/menu.css.json +0 -11
- data/app/components/primer/alpha/nav_list/item.rb +5 -0
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +0 -3
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/overlay.pcss +1 -0
- data/app/components/primer/alpha/overlay.rb +14 -18
- data/app/components/primer/alpha/segmented_control.css.json +0 -15
- data/app/components/primer/alpha/tab_nav.css.json +0 -10
- data/app/components/primer/alpha/text_field.css.json +0 -38
- data/app/components/primer/alpha/toggle_switch.css.json +0 -16
- data/app/components/primer/alpha/underline_nav.css.json +0 -13
- data/app/components/primer/beta/avatar.css.json +0 -14
- data/app/components/primer/beta/avatar_stack.css.json +0 -9
- data/app/components/primer/beta/blankslate.css.json +0 -12
- data/app/components/primer/beta/border_box.css.json +0 -32
- data/app/components/primer/beta/border_box.rb +3 -3
- data/app/components/primer/beta/breadcrumbs.css.json +0 -4
- data/app/components/primer/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +0 -22
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.pcss +3 -3
- data/app/components/primer/beta/counter.css.json +0 -6
- data/app/components/primer/beta/flash.css.json +0 -15
- data/app/components/primer/beta/label.css.json +0 -20
- data/app/components/primer/beta/link.css.json +0 -8
- data/app/components/primer/beta/popover.css.json +0 -18
- data/app/components/primer/beta/progress_bar.css.json +0 -6
- data/app/components/primer/beta/state.css.json +0 -10
- data/app/components/primer/beta/subhead.css.json +0 -8
- data/app/components/primer/beta/timeline_item.css.json +0 -9
- data/app/components/primer/beta/truncate.css.json +0 -6
- data/app/components/primer/focus_group.d.ts +19 -0
- data/app/components/primer/focus_group.js +144 -0
- data/app/components/primer/focus_group.ts +137 -0
- data/app/components/primer/icon_button.rb +1 -1
- data/app/components/primer/primer.d.ts +2 -0
- data/app/components/primer/primer.js +2 -0
- data/app/components/primer/primer.ts +2 -0
- data/app/components/primer/truncate.css.json +0 -7
- data/app/lib/primer/css/layout.css.json +0 -263
- data/app/lib/primer/css/utilities.css.json +0 -1636
- data/lib/primer/static/generate_arguments.rb +55 -0
- data/lib/primer/static/generate_audited_at.rb +17 -0
- data/lib/primer/static/generate_constants.rb +19 -0
- data/lib/primer/static/generate_info_arch.rb +156 -0
- data/lib/primer/static/generate_previews.rb +45 -0
- data/lib/primer/static/generate_statuses.rb +17 -0
- data/lib/primer/static.rb +72 -0
- data/lib/primer/view_components/linters/disallow_component_css_counter.rb +43 -4
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/primer/view_components.rb +0 -48
- data/lib/primer/yard/component_manifest.rb +1 -0
- data/lib/primer/yard/component_ref.rb +14 -0
- data/lib/primer/yard/docs_helper.rb +3 -0
- data/lib/primer/yard/info_arch_docs_helper.rb +31 -0
- data/lib/primer/yard/legacy_gatsby_backend.rb +3 -35
- data/lib/primer/yard/registry.rb +2 -1
- data/lib/primer/yard.rb +1 -0
- data/lib/tasks/docs.rake +10 -12
- data/lib/tasks/static.rake +20 -28
- data/previews/primer/alpha/action_list_preview.rb +4 -1
- data/previews/primer/alpha/action_menu_preview/align_end.html.erb +6 -0
- data/previews/primer/alpha/action_menu_preview/opens_dialog.html.erb +21 -0
- data/previews/primer/alpha/action_menu_preview.rb +238 -0
- data/previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb +2 -2
- data/previews/primer/alpha/dialog_preview/custom_header.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/nested_dialog.html.erb +4 -4
- data/previews/primer/alpha/dialog_preview/test.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/with_footer.html.erb +3 -3
- data/previews/primer/alpha/dialog_preview/with_form.html.erb +1 -1
- data/previews/primer/alpha/dialog_preview/with_text_input.html.erb +2 -2
- data/previews/primer/alpha/dialog_preview.rb +7 -2
- data/previews/primer/beta/auto_complete_item_preview.rb +1 -0
- data/static/arguments.json +3078 -1404
- data/static/audited_at.json +2 -0
- data/static/classes.json +576 -311
- data/static/constants.json +42 -2
- data/static/info_arch.json +8859 -0
- data/static/previews.json +221 -101
- data/static/statuses.json +2 -0
- metadata +23 -2
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Primer
|
|
8
|
+
module Static
|
|
9
|
+
# :nodoc:
|
|
10
|
+
module GenerateArguments
|
|
11
|
+
class << self
|
|
12
|
+
def call(view_context: self.view_context)
|
|
13
|
+
Primer::Component.descendants.sort_by(&:name).map do |component|
|
|
14
|
+
docs = registry.find(component)
|
|
15
|
+
ref = Primer::Yard::ComponentManifest.ref_for(component)
|
|
16
|
+
|
|
17
|
+
args = docs.params.map do |tag|
|
|
18
|
+
default_value = Primer::Yard::DocsHelper.pretty_default_value(tag, component)
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
"name" => tag.name,
|
|
22
|
+
"type" => tag.types.join(", "),
|
|
23
|
+
"default" => default_value,
|
|
24
|
+
"description" => view_context.render(inline: tag.text.squish)
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
"component" => docs.metadata[:title],
|
|
30
|
+
"status" => component.status.to_s,
|
|
31
|
+
"a11y_reviewed" => docs.metadata[:a11y_reviewed] == "true",
|
|
32
|
+
"short_name" => docs.short_name,
|
|
33
|
+
"source" => ref.source_url,
|
|
34
|
+
"lookbook" => ref.lookbook_url,
|
|
35
|
+
"parameters" => args
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def view_context
|
|
43
|
+
@view_context ||= ApplicationController.new.tap { |c| c.request = ActionDispatch::TestRequest.create }.view_context.tap do |vc|
|
|
44
|
+
vc.singleton_class.include(Primer::Yard::DocsHelper)
|
|
45
|
+
vc.singleton_class.include(Primer::ViewHelper)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def registry
|
|
50
|
+
@registry ||= Primer::Yard::Registry.make
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
module Primer
|
|
5
|
+
module Static
|
|
6
|
+
# :nodoc:
|
|
7
|
+
module GenerateAuditedAt
|
|
8
|
+
class << self
|
|
9
|
+
def call
|
|
10
|
+
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
11
|
+
mem[component.to_s] = component.audited_at.to_s
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
module Primer
|
|
5
|
+
module Static
|
|
6
|
+
# :nodoc:
|
|
7
|
+
module GenerateConstants
|
|
8
|
+
class << self
|
|
9
|
+
def call
|
|
10
|
+
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
11
|
+
mem[component.to_s] = component.constants(false).sort.each_with_object({}) do |constant, h|
|
|
12
|
+
h[constant] = component.const_get(constant)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Primer
|
|
8
|
+
module Static
|
|
9
|
+
# :nodoc:
|
|
10
|
+
module GenerateInfoArch
|
|
11
|
+
SKIP_METHODS = %i[call before_render].freeze
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def call
|
|
15
|
+
components = Primer::Component.descendants.sort_by(&:name) - [Primer::BaseComponent]
|
|
16
|
+
|
|
17
|
+
component_docs = components.each_with_object({}) do |component, memo|
|
|
18
|
+
docs = registry.find(component)
|
|
19
|
+
|
|
20
|
+
preview_data = previews.find do |preview|
|
|
21
|
+
preview["component"] == docs.metadata[:title] &&
|
|
22
|
+
preview["status"] == component.status.to_s
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
arg_data = args.find do |component_args|
|
|
26
|
+
component_args["component"] == docs.metadata[:title] &&
|
|
27
|
+
component_args["status"] == component.status.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
slot_docs = docs.slot_methods.map do |slot_method|
|
|
31
|
+
param_tags = slot_method.tags(:param)
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
"name" => slot_method.name,
|
|
35
|
+
# rubocop:disable Style/IfUnlessModifier
|
|
36
|
+
"description" =>
|
|
37
|
+
if slot_method.base_docstring.to_s.present?
|
|
38
|
+
view_context.render(inline: slot_method.base_docstring)
|
|
39
|
+
end,
|
|
40
|
+
# rubocop:enable Style/IfUnlessModifier
|
|
41
|
+
"parameters" => serialize_params(param_tags, component)
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
mtds = docs.non_slot_methods.select do |mtd|
|
|
46
|
+
next false if mtd.base_docstring.to_s.blank?
|
|
47
|
+
next false if SKIP_METHODS.include?(mtd.name)
|
|
48
|
+
|
|
49
|
+
method_location, = mtd.files.first
|
|
50
|
+
class_location, = docs.docs.files.first
|
|
51
|
+
|
|
52
|
+
method_location == class_location
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
method_docs = mtds.map do |mtd|
|
|
56
|
+
param_tags = mtd.tags(:param)
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
"name" => mtd.name,
|
|
60
|
+
"description" => view_context.render(inline: mtd.base_docstring),
|
|
61
|
+
"parameters" => serialize_params(param_tags, component)
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
description =
|
|
66
|
+
if component == Primer::BaseComponent
|
|
67
|
+
docs.base_docstring
|
|
68
|
+
else
|
|
69
|
+
view_context.render(inline: docs.base_docstring)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
memo[component] = {
|
|
73
|
+
"fully_qualified_name" => component.name,
|
|
74
|
+
"description" => description,
|
|
75
|
+
**arg_data,
|
|
76
|
+
"slots" => slot_docs,
|
|
77
|
+
"methods" => method_docs,
|
|
78
|
+
"previews" => (preview_data || {}).fetch("examples", []),
|
|
79
|
+
"subcomponents" => []
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
statuses = Primer::Status::Dsl::STATUSES.keys.map(&:to_s).map(&:capitalize)
|
|
84
|
+
|
|
85
|
+
Primer::Component.descendants.each do |component|
|
|
86
|
+
fq_class = component.name.to_s.split("::")
|
|
87
|
+
fq_class.shift # remove Primer::
|
|
88
|
+
status = fq_class.shift if statuses.include?(fq_class.first) # remove Status::
|
|
89
|
+
|
|
90
|
+
parent, *child = *fq_class
|
|
91
|
+
|
|
92
|
+
next if child.empty?
|
|
93
|
+
|
|
94
|
+
parent_class = Primer
|
|
95
|
+
parent_class = parent_class.const_get(status) if status
|
|
96
|
+
parent_class = parent_class.const_get(parent)
|
|
97
|
+
|
|
98
|
+
parent_docs = component_docs[parent_class]
|
|
99
|
+
next unless parent_docs
|
|
100
|
+
|
|
101
|
+
if (child_docs = component_docs.delete(component))
|
|
102
|
+
parent_docs["subcomponents"] << child_docs
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
component_docs.values + [system_args_docs]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def system_args_docs
|
|
112
|
+
docs = registry.find(Primer::BaseComponent)
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
component: "BaseComponent",
|
|
116
|
+
fully_qualified_name: "Primer::BaseComponent",
|
|
117
|
+
description_md: docs.base_docstring,
|
|
118
|
+
args_md: view_context.render(inline: docs.constructor.base_docstring)
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def serialize_params(param_tags, component)
|
|
123
|
+
param_tags.map do |tag|
|
|
124
|
+
default_value = Primer::Yard::DocsHelper.pretty_default_value(tag, component)
|
|
125
|
+
|
|
126
|
+
{
|
|
127
|
+
"name" => tag.name,
|
|
128
|
+
"type" => tag.types&.join(", ") || "",
|
|
129
|
+
"default" => default_value,
|
|
130
|
+
"description" => view_context.render(inline: tag.text.squish)
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def previews
|
|
136
|
+
@previews ||= JSON.parse(Static.read(:previews))
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def args
|
|
140
|
+
@args ||= Primer::Static::GenerateArguments.call(view_context: view_context)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def view_context
|
|
144
|
+
@view_context ||= ApplicationController.new.tap { |c| c.request = ActionDispatch::TestRequest.create }.view_context.tap do |vc|
|
|
145
|
+
vc.singleton_class.include(Primer::Yard::InfoArchDocsHelper)
|
|
146
|
+
vc.singleton_class.include(Primer::ViewHelper)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def registry
|
|
151
|
+
@registry ||= Primer::Yard::Registry.make
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Primer
|
|
8
|
+
module Static
|
|
9
|
+
# :nodoc:
|
|
10
|
+
module GeneratePreviews
|
|
11
|
+
class << self
|
|
12
|
+
def call
|
|
13
|
+
Lookbook.previews.filter_map do |preview|
|
|
14
|
+
next if preview.preview_class.name.start_with?("Docs::")
|
|
15
|
+
next if preview.preview_class == Primer::Forms::FormsPreview
|
|
16
|
+
|
|
17
|
+
component = preview.components.first&.component_class
|
|
18
|
+
|
|
19
|
+
# rubocop:disable Style/IfUnlessModifier
|
|
20
|
+
unless component
|
|
21
|
+
raise "Could not determine which component `#{preview.preview_class}` is designed to preview. Please add a `@component` annotation."
|
|
22
|
+
end
|
|
23
|
+
# rubocop:enable Style/IfUnlessModifier
|
|
24
|
+
|
|
25
|
+
_, _, class_name = Primer::Yard::DocsHelper.status_module_and_short_name(component)
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
name: preview.name,
|
|
29
|
+
component: class_name,
|
|
30
|
+
status: component.status.to_s,
|
|
31
|
+
lookup_path: preview.lookup_path,
|
|
32
|
+
examples: preview.examples.map do |example|
|
|
33
|
+
{
|
|
34
|
+
inspect_path: example.url_path,
|
|
35
|
+
preview_path: example.url_path.sub("/inspect/", "/preview/"),
|
|
36
|
+
name: example.name
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
module Primer
|
|
5
|
+
module Static
|
|
6
|
+
# :nodoc:
|
|
7
|
+
module GenerateStatuses
|
|
8
|
+
class << self
|
|
9
|
+
def call
|
|
10
|
+
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
11
|
+
mem[component.to_s] = component.status.to_s
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Primer
|
|
8
|
+
# :nodoc:
|
|
9
|
+
module Static
|
|
10
|
+
DEFAULT_STATIC_PATH = File.expand_path("static").freeze
|
|
11
|
+
|
|
12
|
+
FILE_NAMES = {
|
|
13
|
+
statuses: "statuses.json",
|
|
14
|
+
constants: "constants.json",
|
|
15
|
+
audited_at: "audited_at.json",
|
|
16
|
+
arguments: "arguments.json",
|
|
17
|
+
previews: "previews.json",
|
|
18
|
+
info_arch: "info_arch.json"
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
# Returns a hash mapping component names to component statuses (alpha, beta, etc),
|
|
22
|
+
# sorted alphabetically by the component name.
|
|
23
|
+
def self.generate_statuses
|
|
24
|
+
Static::GenerateStatuses.call
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns a hash mapping component names to the date on which the component passed
|
|
28
|
+
# an accessibility audit.
|
|
29
|
+
def self.generate_audited_at
|
|
30
|
+
Static::GenerateAuditedAt.call
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns a hash mapping component names to an array of the constants defined inside
|
|
34
|
+
# the component's class.
|
|
35
|
+
def self.generate_constants
|
|
36
|
+
Static::GenerateConstants.call
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns an array of hashes, one per Primer component, that contains some metadata and
|
|
40
|
+
# a list of the arguments accepted by the component's constructor. Arguments are enumerated
|
|
41
|
+
# with their value, data type, and docstring.
|
|
42
|
+
def self.generate_arguments
|
|
43
|
+
Static::GenerateArguments.call
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns an array of hashes, one per Primer component, that contains some metadata and
|
|
47
|
+
# an array of all the component's previews. The preview data contains the Lookbook URL
|
|
48
|
+
# to each preview and its name.
|
|
49
|
+
def self.generate_previews
|
|
50
|
+
Static::GeneratePreviews.call
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns an array of hashes, one per Primer component, that contains all the data needed
|
|
54
|
+
# for the new primer.style docsite.
|
|
55
|
+
def self.generate_info_arch
|
|
56
|
+
Static::GenerateInfoArch.call
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Generates the requested stat hash and outputs it to a file.
|
|
60
|
+
def self.dump(stats)
|
|
61
|
+
File.open(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]), "w") do |f|
|
|
62
|
+
f.write(JSON.pretty_generate(send("generate_#{stats}")))
|
|
63
|
+
f.write($INPUT_RECORD_SEPARATOR)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the contents of the stat file.
|
|
68
|
+
def self.read(stats)
|
|
69
|
+
File.read(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]))
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -13,18 +13,57 @@ module ERBLint
|
|
|
13
13
|
module Linters
|
|
14
14
|
# Counts the number of times a class reserved for ViewComponents is used
|
|
15
15
|
class DisallowComponentCssCounter < BaseLinter
|
|
16
|
+
CLASSES_COVERED_BY_OTHER_LINTERS =
|
|
17
|
+
BaseLinter.subclasses.reduce([]) do |html_classes, klass|
|
|
18
|
+
html_classes.concat(klass.const_get(:CLASSES))
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
CLASSES = (
|
|
17
22
|
JSON.parse(
|
|
18
23
|
File.read(
|
|
19
24
|
File.join(__dir__, "..", "..", "..", "..", "static", "classes.json")
|
|
20
25
|
)
|
|
21
|
-
)
|
|
22
|
-
|
|
26
|
+
).reject do |html_class, _ruby_classes|
|
|
27
|
+
CLASSES_COVERED_BY_OTHER_LINTERS.include?(html_class)
|
|
23
28
|
end
|
|
24
29
|
).freeze
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
def run(processed_source)
|
|
32
|
+
@total_offenses = 0
|
|
33
|
+
@offenses_not_corrected = 0
|
|
34
|
+
|
|
35
|
+
processed_source
|
|
36
|
+
.parser
|
|
37
|
+
.nodes_with_type(:tag)
|
|
38
|
+
.each do |node|
|
|
39
|
+
tag = BetterHtml::Tree::Tag.from_node(node)
|
|
40
|
+
|
|
41
|
+
tag.attributes["class"]&.value&.split(/\s+/)&.each do |class_name|
|
|
42
|
+
if CLASSES.key? class_name
|
|
43
|
+
@total_offenses += 1
|
|
44
|
+
@offenses_not_corrected += 1
|
|
45
|
+
add_offense(
|
|
46
|
+
processed_source.to_source_range(tag.loc),
|
|
47
|
+
format_message(class_name)
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
counter_correct?(processed_source)
|
|
54
|
+
|
|
55
|
+
dump_data(processed_source) if ENV["DUMP_LINT_DATA"] == "1"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def format_message(class_name)
|
|
61
|
+
"DisallowComponentCssCounter:HTML class \"#{class_name}\" is reserved for Primer ViewComponents. It might disappear or have different styles in the future. You might want to use #{ruby_classes_sentence_string(class_name)} from Primer ViewComponents instead."
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def ruby_classes_sentence_string(class_name)
|
|
65
|
+
CLASSES[class_name].to_sentence(last_word_connector: ", or ", two_words_connector: " or ")
|
|
66
|
+
end
|
|
28
67
|
end
|
|
29
68
|
end
|
|
30
69
|
end
|
|
@@ -7,54 +7,6 @@ require "primer/view_components/engine"
|
|
|
7
7
|
module Primer
|
|
8
8
|
# :nodoc:
|
|
9
9
|
module ViewComponents
|
|
10
|
-
DEFAULT_STATIC_PATH = File.expand_path("static")
|
|
11
|
-
FILE_NAMES = {
|
|
12
|
-
statuses: "statuses.json",
|
|
13
|
-
constants: "constants.json",
|
|
14
|
-
audited_at: "audited_at.json"
|
|
15
|
-
}.freeze
|
|
16
|
-
|
|
17
|
-
# generate_statuses returns a hash mapping component name to
|
|
18
|
-
# the component's status sorted alphabetically by the component name.
|
|
19
|
-
def self.generate_statuses
|
|
20
|
-
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
21
|
-
mem[component.to_s] = component.status.to_s
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# generate_audited_at returns a hash mapping component name to
|
|
26
|
-
# the day the component has passed an accessibility audit.
|
|
27
|
-
def self.generate_audited_at
|
|
28
|
-
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
29
|
-
mem[component.to_s] = component.audited_at.to_s
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# generate_constants returns a hash mapping component name to
|
|
34
|
-
# all of its constants.
|
|
35
|
-
def self.generate_constants
|
|
36
|
-
Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
|
|
37
|
-
mem[component.to_s] = component.constants(false).sort.each_with_object({}) do |constant, h|
|
|
38
|
-
h[constant] = component.const_get(constant)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# dump generates the requested stat hash and outputs it to a file.
|
|
44
|
-
def self.dump(stats)
|
|
45
|
-
require "json"
|
|
46
|
-
|
|
47
|
-
File.open(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]), "w") do |f|
|
|
48
|
-
f.write(JSON.pretty_generate(send("generate_#{stats}")))
|
|
49
|
-
f.write($INPUT_RECORD_SEPARATOR)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# read returns a JSON string matching the output of the corresponding stat.
|
|
54
|
-
def self.read(stats)
|
|
55
|
-
File.read(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]))
|
|
56
|
-
end
|
|
57
|
-
|
|
58
10
|
# primer/view_components root directory.
|
|
59
11
|
def self.root
|
|
60
12
|
Pathname(File.expand_path(File.join("..", ".."), __dir__))
|
|
@@ -65,6 +65,7 @@ module Primer
|
|
|
65
65
|
Primer::Alpha::Tooltip => { js: true },
|
|
66
66
|
Primer::Alpha::ToggleSwitch => { js: true },
|
|
67
67
|
Primer::Alpha::Overlay => { js: true },
|
|
68
|
+
Primer::Alpha::ActionMenu => { js: true },
|
|
68
69
|
|
|
69
70
|
# Examples can be seen in the NavList docs
|
|
70
71
|
Primer::Alpha::NavList => { js: true },
|
|
@@ -34,6 +34,20 @@ module Primer
|
|
|
34
34
|
def form_component?
|
|
35
35
|
@attrs.fetch(:form_component, ATTR_DEFAULTS[:form_component])
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
def source_url
|
|
39
|
+
@source_url ||= begin
|
|
40
|
+
path = klass.name.split("::").map(&:underscore).join("/")
|
|
41
|
+
"https://github.com/primer/view_components/tree/main/app/components/#{path}.rb"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def lookbook_url
|
|
46
|
+
@lookbook_url ||= begin
|
|
47
|
+
path = klass.name.underscore.gsub("_component", "")
|
|
48
|
+
"https://primer.style/view-components/lookbook/inspect/#{path}/default/"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
37
51
|
end
|
|
38
52
|
end
|
|
39
53
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :nocov:
|
|
4
|
+
module Primer
|
|
5
|
+
module Yard
|
|
6
|
+
# Helper methods to use for info arch yard documentation
|
|
7
|
+
module InfoArchDocsHelper
|
|
8
|
+
include DocsHelper
|
|
9
|
+
|
|
10
|
+
def link_to_component(component)
|
|
11
|
+
"{{#link_to_component}}#{component}{{/link_to_component}}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def link_to_system_arguments_docs
|
|
15
|
+
"{{link_to_system_arguments_docs}}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def link_to_typography_docs
|
|
19
|
+
"{{link_to_typography_docs}}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def link_to_accessibility
|
|
23
|
+
"{{link_to_accessibility}}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def link_to_octicons
|
|
27
|
+
"{{link_to_octicons}}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -33,7 +33,6 @@ module Primer
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def generate
|
|
36
|
-
args_for_components = []
|
|
37
36
|
errors = []
|
|
38
37
|
|
|
39
38
|
each_component do |component_ref|
|
|
@@ -42,8 +41,8 @@ module Primer
|
|
|
42
41
|
status_path = docs.status_module.nil? ? "" : "#{docs.status_module}/"
|
|
43
42
|
|
|
44
43
|
metadata = docs.metadata.merge(
|
|
45
|
-
source: source_url
|
|
46
|
-
lookbook: lookbook_url
|
|
44
|
+
source: component_ref.source_url,
|
|
45
|
+
lookbook: component_ref.lookbook_url,
|
|
47
46
|
path: "docs/content/components/#{status_path}#{docs.short_name.downcase}.md",
|
|
48
47
|
example_path: example_path(component),
|
|
49
48
|
require_js_path: require_js_path(component)
|
|
@@ -113,30 +112,11 @@ module Primer
|
|
|
113
112
|
errors << { component.name => err }
|
|
114
113
|
end
|
|
115
114
|
|
|
116
|
-
args = []
|
|
117
115
|
docs.params.each do |tag|
|
|
118
116
|
default_value = pretty_default_value(tag, component)
|
|
119
|
-
|
|
120
|
-
args << {
|
|
121
|
-
"name" => tag.name,
|
|
122
|
-
"type" => tag.types.join(", "),
|
|
123
|
-
"default" => default_value,
|
|
124
|
-
"description" => view_context.render(inline: tag.text.squish)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
117
|
f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{default_value} | #{view_context.render(inline: tag.text.squish)} |")
|
|
128
118
|
end
|
|
129
119
|
|
|
130
|
-
component_args = {
|
|
131
|
-
"component" => metadata[:title],
|
|
132
|
-
"status" => component.status.to_s,
|
|
133
|
-
"source" => metadata[:source],
|
|
134
|
-
"lookbook" => metadata[:lookbook],
|
|
135
|
-
"parameters" => args
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
args_for_components << component_args
|
|
139
|
-
|
|
140
120
|
if docs.slot_methods.any?
|
|
141
121
|
f.puts
|
|
142
122
|
f.puts("## Slots")
|
|
@@ -190,7 +170,7 @@ module Primer
|
|
|
190
170
|
f.puts(view_context.render(inline: system_args_docs.constructor.base_docstring))
|
|
191
171
|
end
|
|
192
172
|
|
|
193
|
-
|
|
173
|
+
errors
|
|
194
174
|
end
|
|
195
175
|
|
|
196
176
|
private
|
|
@@ -220,18 +200,6 @@ module Primer
|
|
|
220
200
|
manifest.each(&block)
|
|
221
201
|
end
|
|
222
202
|
|
|
223
|
-
def source_url(component)
|
|
224
|
-
path = component.name.split("::").map(&:underscore).join("/")
|
|
225
|
-
|
|
226
|
-
"https://github.com/primer/view_components/tree/main/app/components/#{path}.rb"
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def lookbook_url(component)
|
|
230
|
-
path = component.name.underscore.gsub("_component", "")
|
|
231
|
-
|
|
232
|
-
"https://primer.style/view-components/lookbook/inspect/#{path}/default/"
|
|
233
|
-
end
|
|
234
|
-
|
|
235
203
|
def example_path(component)
|
|
236
204
|
example_path = "../../src/@primer/gatsby-theme-doctocat/components/example"
|
|
237
205
|
example_path = "../#{example_path}" if status_module?(component)
|
data/lib/primer/yard/registry.rb
CHANGED
|
@@ -28,6 +28,7 @@ module Primer
|
|
|
28
28
|
|
|
29
29
|
{
|
|
30
30
|
title: class_name,
|
|
31
|
+
class_name: class_name,
|
|
31
32
|
component_id: short_name.underscore,
|
|
32
33
|
status: status.capitalize,
|
|
33
34
|
status_module: status_module,
|
|
@@ -42,7 +43,7 @@ module Primer
|
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def params
|
|
45
|
-
constructor
|
|
46
|
+
constructor&.tags(:param) || []
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def slot_methods
|