primer_view_components 0.0.36 → 0.0.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -24
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/components/primer/auto_complete.rb +3 -1
  6. data/app/components/primer/auto_complete/item.rb +1 -1
  7. data/app/components/primer/avatar_component.rb +22 -3
  8. data/app/components/primer/avatar_stack_component.rb +8 -5
  9. data/app/components/primer/base_button.rb +47 -0
  10. data/app/components/primer/base_component.rb +14 -10
  11. data/app/components/primer/blankslate_component.rb +10 -7
  12. data/app/components/primer/border_box_component.rb +1 -1
  13. data/app/components/primer/box_component.rb +1 -1
  14. data/app/components/primer/breadcrumb_component.rb +1 -1
  15. data/app/components/primer/button_component.html.erb +9 -0
  16. data/app/components/primer/button_component.rb +39 -21
  17. data/app/components/primer/{button_group_component.html.erb → button_group.html.erb} +0 -0
  18. data/app/components/primer/button_group.rb +61 -0
  19. data/app/components/primer/button_marketing_component.rb +4 -9
  20. data/app/components/primer/clipboard_copy.html.erb +8 -0
  21. data/app/components/primer/clipboard_copy.rb +26 -0
  22. data/app/components/primer/clipboard_copy_component.d.ts +1 -0
  23. data/app/components/primer/clipboard_copy_component.js +34 -0
  24. data/app/components/primer/clipboard_copy_component.ts +39 -0
  25. data/app/components/primer/close_button.rb +11 -2
  26. data/app/components/primer/component.rb +21 -2
  27. data/app/components/primer/counter_component.rb +6 -1
  28. data/app/components/primer/details_component.rb +1 -1
  29. data/app/components/primer/dropdown/menu_component.rb +1 -1
  30. data/app/components/primer/dropdown_component.rb +1 -1
  31. data/app/components/primer/flash_component.rb +3 -3
  32. data/app/components/primer/flex_component.rb +28 -1
  33. data/app/components/primer/flex_item_component.rb +20 -1
  34. data/app/components/primer/heading_component.rb +25 -4
  35. data/app/components/primer/hidden_text_expander.rb +2 -4
  36. data/app/components/primer/icon_button.rb +65 -0
  37. data/app/components/primer/image.rb +46 -0
  38. data/app/components/primer/image_crop.d.ts +1 -0
  39. data/app/components/primer/image_crop.html.erb +12 -0
  40. data/app/components/primer/image_crop.js +1 -0
  41. data/app/components/primer/image_crop.rb +36 -0
  42. data/app/components/primer/image_crop.ts +1 -0
  43. data/app/components/primer/label_component.rb +7 -3
  44. data/app/components/primer/layout_component.rb +1 -1
  45. data/app/components/primer/link_component.rb +1 -1
  46. data/app/components/primer/local_time.d.ts +1 -0
  47. data/app/components/primer/local_time.js +1 -0
  48. data/app/components/primer/local_time.rb +59 -0
  49. data/app/components/primer/local_time.ts +1 -0
  50. data/app/components/primer/{markdown_component.rb → markdown.rb} +6 -5
  51. data/app/components/primer/menu_component.rb +1 -1
  52. data/app/components/primer/navigation/tab_component.rb +8 -1
  53. data/app/components/primer/octicon_component.html.erb +7 -0
  54. data/app/components/primer/octicon_component.rb +53 -19
  55. data/app/components/primer/octicon_symbols_component.html.erb +3 -0
  56. data/app/components/primer/octicon_symbols_component.rb +61 -0
  57. data/app/components/primer/popover_component.rb +1 -1
  58. data/app/components/primer/primer.d.ts +3 -0
  59. data/app/components/primer/primer.js +3 -0
  60. data/app/components/primer/primer.ts +3 -0
  61. data/app/components/primer/progress_bar_component.rb +1 -1
  62. data/app/components/primer/spinner_component.rb +3 -3
  63. data/app/components/primer/state_component.rb +2 -2
  64. data/app/components/primer/subhead_component.rb +34 -4
  65. data/app/components/primer/tab_container_component.rb +1 -1
  66. data/app/components/primer/tab_nav_component.html.erb +2 -0
  67. data/app/components/primer/tab_nav_component.rb +23 -10
  68. data/app/components/primer/text_component.rb +6 -3
  69. data/app/components/primer/time_ago_component.rb +1 -1
  70. data/app/components/primer/timeline_item_component.rb +1 -1
  71. data/app/components/primer/{tooltip_component.rb → tooltip.rb} +11 -9
  72. data/app/components/primer/truncate.rb +1 -1
  73. data/app/components/primer/underline_nav_component.rb +1 -1
  74. data/app/lib/primer/classify.rb +11 -36
  75. data/app/lib/primer/classify/cache.rb +20 -15
  76. data/app/lib/primer/classify/flex.rb +111 -0
  77. data/app/lib/primer/classify/functional_border_colors.rb +1 -2
  78. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -2
  79. data/app/lib/primer/octicon/cache.rb +42 -0
  80. data/app/lib/primer/view_helper.rb +2 -1
  81. data/lib/primer/view_components.rb +1 -1
  82. data/lib/primer/view_components/version.rb +1 -1
  83. data/lib/tasks/coverage.rake +14 -0
  84. data/lib/tasks/docs.rake +315 -0
  85. data/lib/tasks/statuses.rake +12 -0
  86. data/lib/yard/docs_helper.rb +57 -0
  87. data/static/statuses.json +54 -1
  88. metadata +50 -11
  89. data/app/components/primer/button_group_component.rb +0 -35
  90. data/app/components/primer/foo_bar.d.ts +0 -1
  91. data/app/components/primer/foo_bar.js +0 -1
@@ -40,18 +40,18 @@ module Primer
40
40
  )
41
41
 
42
42
  preload(
43
- keys: Primer::Classify::DIRECTION_KEY,
44
- values: [:row, :column]
43
+ keys: Primer::Classify::Flex::DIRECTION_KEY,
44
+ values: Primer::Classify::Flex::DIRECTION_VALUES
45
45
  )
46
46
 
47
47
  preload(
48
- keys: Primer::Classify::JUSTIFY_CONTENT_KEY,
49
- values: [:flex_start, :flex_end, :center, :space_between, :space_around]
48
+ keys: Primer::Classify::Flex::JUSTIFY_CONTENT_KEY,
49
+ values: Primer::Classify::Flex::JUSTIFY_CONTENT_VALUES
50
50
  )
51
51
 
52
52
  preload(
53
- keys: Primer::Classify::ALIGN_ITEMS_KEY,
54
- values: [:flex_start, :flex_end, :center, :baseline, :stretch]
53
+ keys: Primer::Classify::Flex::ALIGN_ITEMS_KEY,
54
+ values: Primer::Classify::Flex::ALIGN_ITEMS_VALUES
55
55
  )
56
56
 
57
57
  preload(
@@ -61,12 +61,12 @@ module Primer
61
61
 
62
62
  preload(
63
63
  keys: [Primer::Classify::COLOR_KEY],
64
- values: [*Primer::Classify::FunctionalTextColors::OPTIONS, *Primer::Classify::FunctionalTextColors::DEPRECATED_OPTIONS]
64
+ values: Primer::Classify::FunctionalTextColors::OPTIONS
65
65
  )
66
66
 
67
67
  preload(
68
68
  keys: [Primer::Classify::BG_KEY],
69
- values: [*Primer::Classify::FunctionalBackgroundColors::OPTIONS, *Primer::Classify::FunctionalBackgroundColors::DEPRECATED_OPTIONS]
69
+ values: Primer::Classify::FunctionalBackgroundColors::OPTIONS
70
70
  )
71
71
 
72
72
  preload(
@@ -90,23 +90,28 @@ module Primer
90
90
  )
91
91
 
92
92
  preload(
93
- keys: Primer::Classify::FLEX_KEY,
94
- values: [1, :auto]
93
+ keys: Primer::Classify::Flex::FLEX_KEY,
94
+ values: Primer::Classify::Flex::FLEX_VALUES
95
95
  )
96
96
 
97
97
  preload(
98
- keys: [Primer::Classify::FLEX_GROW_KEY, Primer::Classify::FLEX_SHRINK_KEY],
99
- values: [0]
98
+ keys: Primer::Classify::Flex::GROW_KEY,
99
+ values: Primer::Classify::Flex::GROW_VALUES
100
100
  )
101
101
 
102
102
  preload(
103
- keys: [Primer::Classify::ALIGN_SELF_KEY],
104
- values: [:auto, :start, :end, :center, :baseline, :stretch]
103
+ keys: Primer::Classify::Flex::SHRINK_KEY,
104
+ values: Primer::Classify::Flex::SHRINK_VALUES
105
+ )
106
+
107
+ preload(
108
+ keys: Primer::Classify::Flex::ALIGN_SELF_KEY,
109
+ values: Primer::Classify::Flex::ALIGN_SELF_VALUES
105
110
  )
106
111
 
107
112
  preload(
108
113
  keys: [Primer::Classify::WIDTH_KEY, Primer::Classify::HEIGHT_KEY],
109
- values: [:fit, :fill]
114
+ values: [:fit]
110
115
  )
111
116
 
112
117
  preload(
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Classify
5
+ # Handler for PrimerCSS flex classes.
6
+ class Flex
7
+ extend Primer::FetchOrFallbackHelper
8
+
9
+ FLEX_KEY = :flex
10
+ FLEX_VALUES = [1, :auto].freeze
11
+
12
+ WRAP_KEY = :flex_wrap
13
+ WRAP_MAPPINGS = {
14
+ wrap: "flex-wrap",
15
+ nowrap: "flex-nowrap",
16
+ reverse: "flex-wrap-reverse"
17
+ }.freeze
18
+
19
+ SHRINK_KEY = :flex_shrink
20
+ SHRINK_VALUES = [0].freeze
21
+
22
+ GROW_KEY = :flex_grow
23
+ GROW_VALUES = [0].freeze
24
+
25
+ ALIGN_SELF_KEY = :align_self
26
+ ALIGN_SELF_VALUES = [:auto, :start, :end, :center, :baseline, :stretch].freeze
27
+
28
+ DIRECTION_KEY = :direction
29
+ DIRECTION_VALUES = [:column, :column_reverse, :row, :row_reverse].freeze
30
+
31
+ JUSTIFY_CONTENT_KEY = :justify_content
32
+ JUSTIFY_CONTENT_VALUES = [:flex_start, :flex_end, :center, :space_between, :space_around].freeze
33
+
34
+ ALIGN_ITEMS_KEY = :align_items
35
+ ALIGN_ITEMS_VALUES = [:flex_start, :flex_end, :center, :baseline, :stretch].freeze
36
+
37
+ KEYS = [FLEX_KEY, WRAP_KEY, SHRINK_KEY, GROW_KEY, ALIGN_SELF_KEY, DIRECTION_KEY, JUSTIFY_CONTENT_KEY, ALIGN_ITEMS_KEY].freeze
38
+ RESPONSIVE_KEYS = [DIRECTION_KEY, JUSTIFY_CONTENT_KEY, ALIGN_ITEMS_KEY].freeze
39
+
40
+ class << self
41
+ def classes(key, value, breakpoint)
42
+ send(key, value, breakpoint)
43
+ end
44
+
45
+ private
46
+
47
+ def flex(value, _breakpoint)
48
+ generate(
49
+ value: value,
50
+ allowed_values: FLEX_VALUES,
51
+ prefix: "flex"
52
+ )
53
+ end
54
+
55
+ def flex_shrink(value, _breakpoint)
56
+ generate(
57
+ value: value,
58
+ allowed_values: SHRINK_VALUES,
59
+ prefix: "flex-shrink"
60
+ )
61
+ end
62
+
63
+ def flex_grow(value, _breakpoint)
64
+ generate(
65
+ value: value,
66
+ allowed_values: GROW_VALUES,
67
+ prefix: "flex-grow"
68
+ )
69
+ end
70
+
71
+ def align_self(value, _breakpoint)
72
+ generate(
73
+ value: value,
74
+ allowed_values: ALIGN_SELF_VALUES,
75
+ prefix: "flex-self"
76
+ )
77
+ end
78
+
79
+ def flex_wrap(value, _breakpoint)
80
+ WRAP_MAPPINGS[fetch_or_fallback(WRAP_MAPPINGS.keys, value)]
81
+ end
82
+
83
+ def direction(value, breakpoint)
84
+ val = fetch_or_fallback(DIRECTION_VALUES, value)
85
+
86
+ "flex#{breakpoint}-#{val.to_s.dasherize}"
87
+ end
88
+
89
+ def justify_content(value, breakpoint)
90
+ val = fetch_or_fallback(JUSTIFY_CONTENT_VALUES, value)
91
+
92
+ formatted_value = val.to_s.gsub(/(flex\_|space\_)/, "")
93
+ "flex#{breakpoint}-justify-#{formatted_value}"
94
+ end
95
+
96
+ def align_items(value, breakpoint)
97
+ val = fetch_or_fallback(ALIGN_ITEMS_VALUES, value)
98
+
99
+ formatted_value = val.to_s.gsub("flex_", "")
100
+ "flex#{breakpoint}-items-#{formatted_value}"
101
+ end
102
+
103
+ def generate(value:, allowed_values:, prefix:)
104
+ val = fetch_or_fallback(allowed_values, value)
105
+
106
+ "#{prefix}-#{val}"
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -13,8 +13,7 @@ module Primer
13
13
  success: :success,
14
14
  warning: :warning,
15
15
  danger: :danger,
16
- inverse: :inverse,
17
- overlay: :overlay
16
+ inverse: :inverse
18
17
  }.freeze
19
18
 
20
19
  MAPPINGS = {
@@ -25,10 +25,10 @@ module Primer
25
25
 
26
26
  InvalidValueError = Class.new(StandardError)
27
27
 
28
- def fetch_or_fallback(allowed_values, given_value, fallback = nil, deprecated_values: [])
28
+ def fetch_or_fallback(allowed_values, given_value, fallback = nil, deprecated_values: nil)
29
29
  if allowed_values.include?(given_value)
30
30
  given_value
31
- elsif deprecated_values.include?(given_value)
31
+ elsif deprecated_values&.include?(given_value)
32
32
  ActiveSupport::Deprecation.warn("#{given_value} is deprecated and will be removed in a future version.") unless Rails.env.production? || silence_deprecations?
33
33
 
34
34
  given_value
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Octicon
5
+ # :nodoc:
6
+ class Cache
7
+ LOOKUP = {} # rubocop:disable Style/MutableConstant
8
+ # Preload the top 20 used icons.
9
+ PRELOADED_ICONS = [:alert, :check, :"chevron-down", :clippy, :clock, :"dot-fill", :info, :"kebab-horizontal", :link, :lock, :mail, :pencil, :plus, :question, :repo, :search, :"shield-lock", :star, :trash, :x].freeze
10
+
11
+ class << self
12
+ def get_key(symbol:, size:, width: nil, height: nil)
13
+ [symbol, size, width, height].join("_")
14
+ end
15
+
16
+ def read(key)
17
+ LOOKUP[key]
18
+ end
19
+
20
+ # Cache size limit.
21
+ def limit
22
+ 500
23
+ end
24
+
25
+ def set(key, value)
26
+ LOOKUP[key] = value
27
+
28
+ # Remove first item when the cache is too large.
29
+ LOOKUP.shift if LOOKUP.size > limit
30
+ end
31
+
32
+ def clear!
33
+ LOOKUP.clear
34
+ end
35
+
36
+ def preload!
37
+ PRELOADED_ICONS.each { |icon| Primer::OcticonComponent.new(icon: icon) }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -8,7 +8,8 @@ module Primer
8
8
  HELPERS = {
9
9
  octicon: "Primer::OcticonComponent",
10
10
  heading: "Primer::HeadingComponent",
11
- time_ago: "Primer::TimeAgoComponent"
11
+ time_ago: "Primer::TimeAgoComponent",
12
+ image: "Primer::Image"
12
13
  }.freeze
13
14
 
14
15
  HELPERS.each do |name, component|
@@ -27,7 +27,7 @@ module Primer
27
27
  statuses = generate_statuses
28
28
 
29
29
  File.open(File.join(path, DEFAULT_STATUS_FILE_NAME), "w") do |f|
30
- f.write(statuses.to_json)
30
+ f.write(JSON.pretty_generate(statuses))
31
31
  f.write($INPUT_RECORD_SEPARATOR)
32
32
  end
33
33
  end
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 36
8
+ PATCH = 41
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :coverage do
4
+ task :report do
5
+ require "simplecov"
6
+ require "simplecov-console"
7
+
8
+ SimpleCov.minimum_coverage 100
9
+
10
+ SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"], "rails" do
11
+ formatter SimpleCov::Formatter::Console
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,315 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :docs do
4
+ task :livereload do
5
+ require "listen"
6
+
7
+ Rake::Task["docs:build"].execute
8
+
9
+ puts "Listening for changes to documentation..."
10
+
11
+ listener = Listen.to("app") do |modified, added, removed|
12
+ puts "modified absolute path: #{modified}"
13
+ puts "added absolute path: #{added}"
14
+ puts "removed absolute path: #{removed}"
15
+
16
+ Rake::Task["docs:build"].execute
17
+ end
18
+ listener.start # not blocking
19
+ sleep
20
+ end
21
+
22
+ task :build do
23
+ require File.expand_path("./../../demo/config/environment.rb", __dir__)
24
+ require "primer/view_components"
25
+ require "yard/docs_helper"
26
+ require "view_component/test_helpers"
27
+ include ViewComponent::TestHelpers
28
+ include Primer::ViewHelper
29
+ include YARD::DocsHelper
30
+
31
+ Dir["./app/components/primer/**/*.rb"].sort.each { |file| require file }
32
+
33
+ YARD::Rake::YardocTask.new
34
+
35
+ # Custom tags for yard
36
+ YARD::Tags::Library.define_tag("Accessibility", :accessibility)
37
+ YARD::Tags::Library.define_tag("Deprecation", :deprecation)
38
+
39
+ puts "Building YARD documentation."
40
+ Rake::Task["yard"].execute
41
+
42
+ puts "Converting YARD documentation to Markdown files."
43
+
44
+ # Rails controller for rendering arbitrary ERB
45
+ view_context = ApplicationController.new.tap { |c| c.request = ActionDispatch::TestRequest.create }.view_context
46
+
47
+ registry = YARD::RegistryStore.new
48
+ registry.load!(".yardoc")
49
+ components = [
50
+ Primer::Image,
51
+ Primer::LocalTime,
52
+ Primer::OcticonSymbolsComponent,
53
+ Primer::ImageCrop,
54
+ Primer::IconButton,
55
+ Primer::AutoComplete,
56
+ Primer::AutoComplete::Item,
57
+ Primer::AvatarComponent,
58
+ Primer::AvatarStackComponent,
59
+ Primer::BaseButton,
60
+ Primer::BlankslateComponent,
61
+ Primer::BorderBoxComponent,
62
+ Primer::BoxComponent,
63
+ Primer::BreadcrumbComponent,
64
+ Primer::ButtonComponent,
65
+ Primer::ButtonGroup,
66
+ Primer::ButtonMarketingComponent,
67
+ Primer::ClipboardCopy,
68
+ Primer::CloseButton,
69
+ Primer::CounterComponent,
70
+ Primer::DetailsComponent,
71
+ Primer::DropdownComponent,
72
+ Primer::DropdownMenuComponent,
73
+ Primer::FlashComponent,
74
+ Primer::FlexComponent,
75
+ Primer::FlexItemComponent,
76
+ Primer::HeadingComponent,
77
+ Primer::HiddenTextExpander,
78
+ Primer::LabelComponent,
79
+ Primer::LayoutComponent,
80
+ Primer::LinkComponent,
81
+ Primer::Markdown,
82
+ Primer::MenuComponent,
83
+ Primer::Navigation::TabComponent,
84
+ Primer::OcticonComponent,
85
+ Primer::PopoverComponent,
86
+ Primer::ProgressBarComponent,
87
+ Primer::StateComponent,
88
+ Primer::SpinnerComponent,
89
+ Primer::SubheadComponent,
90
+ Primer::TabContainerComponent,
91
+ Primer::TabNavComponent,
92
+ Primer::TextComponent,
93
+ Primer::TimeAgoComponent,
94
+ Primer::TimelineItemComponent,
95
+ Primer::Tooltip,
96
+ Primer::Truncate,
97
+ Primer::UnderlineNavComponent
98
+ ]
99
+
100
+ js_components = [
101
+ Primer::LocalTime,
102
+ Primer::ImageCrop,
103
+ Primer::AutoComplete,
104
+ Primer::ClipboardCopy,
105
+ Primer::TabContainerComponent,
106
+ Primer::TabNavComponent,
107
+ Primer::TimeAgoComponent,
108
+ Primer::UnderlineNavComponent
109
+ ]
110
+
111
+ all_components = Primer::Component.descendants - [Primer::BaseComponent]
112
+ components_needing_docs = all_components - components
113
+
114
+ components_without_examples = []
115
+ args_for_components = []
116
+ classes_found_in_examples = []
117
+
118
+ components.each do |component|
119
+ documentation = registry.get(component.name)
120
+
121
+ # Primer::AvatarComponent => Avatar
122
+ short_name = component.name.gsub(/Primer|::|Component/, "")
123
+
124
+ path = Pathname.new("docs/content/components/#{short_name.downcase}.md")
125
+ path.dirname.mkdir unless path.dirname.exist?
126
+ File.open(path, "w") do |f|
127
+ f.puts("---")
128
+ f.puts("title: #{short_name}")
129
+ f.puts("status: #{component.status.to_s.capitalize}")
130
+ f.puts("source: https://github.com/primer/view_components/tree/main/app/components/primer/#{component.to_s.demodulize.underscore}.rb")
131
+ f.puts("storybook: https://primer.style/view-components/stories/?path=/story/primer-#{short_name.underscore.dasherize}-component")
132
+ f.puts("---")
133
+ f.puts
134
+ f.puts("import Example from '../../src/@primer/gatsby-theme-doctocat/components/example'")
135
+
136
+ if js_components.include?(component)
137
+ f.puts("import RequiresJSFlash from '../../src/@primer/gatsby-theme-doctocat/components/requires-js-flash'")
138
+ f.puts
139
+ f.puts("<RequiresJSFlash />")
140
+ end
141
+
142
+ f.puts
143
+ f.puts("<!-- Warning: AUTO-GENERATED file, do not edit. Add code comments to your Ruby instead <3 -->")
144
+ f.puts
145
+ f.puts(view_context.render(inline: documentation.base_docstring))
146
+
147
+ if documentation.tags(:accessibility).any?
148
+ f.puts
149
+ f.puts("## Accessibility")
150
+ documentation.tags(:accessibility).each do |tag|
151
+ f.puts
152
+ f.puts view_context.render(inline: tag.text)
153
+ end
154
+ end
155
+
156
+ if documentation.tags(:deprecated).any?
157
+ f.puts
158
+ f.puts("## Deprecation")
159
+ documentation.tags(:deprecated).each do |tag|
160
+ f.puts
161
+ f.puts view_context.render(inline: tag.text)
162
+ end
163
+ end
164
+
165
+ initialize_method = documentation.meths.find(&:constructor?)
166
+
167
+ if initialize_method.tags(:example).any?
168
+ f.puts
169
+ f.puts("## Examples")
170
+ else
171
+ components_without_examples << component
172
+ end
173
+
174
+ initialize_method.tags(:example).each do |tag|
175
+ (name, description) = tag.name.split("|")
176
+ f.puts
177
+ f.puts("### #{name}")
178
+ if description
179
+ f.puts
180
+ f.puts(description)
181
+ end
182
+ f.puts
183
+ html = view_context.render(inline: tag.text)
184
+ html.scan(/class="([^"]*)"/) do |classnames|
185
+ classes_found_in_examples.concat(classnames[0].split(" ").reject { |c| c.starts_with?("octicon", "js", "my-") }.map { ".#{_1}"})
186
+ end
187
+ f.puts("<Example src=\"#{html.tr('"', "\'").delete("\n")}\" />")
188
+ f.puts
189
+ f.puts("```erb")
190
+ f.puts(tag.text.to_s)
191
+ f.puts("```")
192
+ end
193
+
194
+ params = initialize_method.tags(:param)
195
+ if params.any?
196
+ f.puts
197
+ f.puts("## Arguments")
198
+ f.puts
199
+ f.puts("| Name | Type | Default | Description |")
200
+ f.puts("| :- | :- | :- | :- |")
201
+
202
+ args = []
203
+ params.each do |tag|
204
+ params = tag.object.parameters.find { |param| [tag.name.to_s, tag.name.to_s + ":"].include?(param[0]) }
205
+
206
+ default =
207
+ if params && params[1]
208
+ constant_name = "#{component.name}::#{params[1]}"
209
+ constant_value = constant_name.safe_constantize
210
+ if constant_value.nil?
211
+ pretty_value(params[1])
212
+ else
213
+ pretty_value(constant_value)
214
+ end
215
+ else
216
+ "N/A"
217
+ end
218
+
219
+ args << {
220
+ "name" => tag.name,
221
+ "type" => tag.types.join(", "),
222
+ "default" => default,
223
+ "description" => view_context.render(inline: tag.text)
224
+ }
225
+
226
+ f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{default} | #{view_context.render(inline: tag.text)} |")
227
+ end
228
+
229
+ component_args = {
230
+ "component" => short_name,
231
+ "source" => "https://github.com/primer/view_components/tree/main/app/components/primer/#{component.to_s.demodulize.underscore}.rb",
232
+ "parameters" => args
233
+ }
234
+
235
+ args_for_components << component_args
236
+ end
237
+
238
+ # Slots V2 docs
239
+ slot_v2_methods = documentation.meths.select { |x| x[:renders_one] || x[:renders_many] }
240
+
241
+ if slot_v2_methods.any?
242
+ f.puts
243
+ f.puts("## Slots")
244
+
245
+ slot_v2_methods.each do |slot_documentation|
246
+ f.puts
247
+ f.puts("### `#{slot_documentation.name.to_s.capitalize}`")
248
+
249
+ if slot_documentation.base_docstring.present?
250
+ f.puts
251
+ f.puts(view_context.render(inline: slot_documentation.base_docstring))
252
+ end
253
+
254
+ param_tags = slot_documentation.tags(:param)
255
+ if param_tags.any?
256
+ f.puts
257
+ f.puts("| Name | Type | Default | Description |")
258
+ f.puts("| :- | :- | :- | :- |")
259
+ end
260
+
261
+ param_tags.each do |tag|
262
+ params = tag.object.parameters.find { |param| [tag.name.to_s, tag.name.to_s + ":"].include?(param[0]) }
263
+
264
+ default =
265
+ if params && params[1]
266
+ "`#{params[1]}`"
267
+ else
268
+ "N/A"
269
+ end
270
+
271
+ f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{default} | #{view_context.render(inline: tag.text)} |")
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+ File.open("static/classes.yml", "w") do |f|
279
+ f.puts YAML.dump(classes_found_in_examples.sort.uniq)
280
+ end
281
+
282
+ File.open("static/arguments.yml", "w") do |f|
283
+ f.puts YAML.dump(args_for_components)
284
+ end
285
+
286
+ # Build system arguments docs from BaseComponent
287
+ documentation = registry.get(Primer::BaseComponent.name)
288
+ File.open("docs/content/system-arguments.md", "w") do |f|
289
+ f.puts("---")
290
+ f.puts("title: System arguments")
291
+ f.puts("---")
292
+ f.puts
293
+ f.puts("<!-- Warning: AUTO-GENERATED file, do not edit. Add code comments to your Ruby instead <3 -->")
294
+ f.puts
295
+ f.puts(documentation.base_docstring)
296
+ f.puts
297
+
298
+ initialize_method = documentation.meths.find(&:constructor?)
299
+
300
+ f.puts(view_context.render(inline: initialize_method.base_docstring))
301
+ end
302
+
303
+ puts "Markdown compiled."
304
+
305
+ if components_without_examples.any?
306
+ puts
307
+ puts "The following components have no examples defined: #{components_without_examples.map(&:name).join(', ')}. Consider adding an example?"
308
+ end
309
+
310
+ if components_needing_docs.any?
311
+ puts
312
+ puts "The following components needs docs. Care to contribute them? #{components_needing_docs.map(&:name).join(', ')}"
313
+ end
314
+ end
315
+ end