primer_view_components 0.0.36 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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