primer_view_components 0.0.43 → 0.0.44
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 +52 -4
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/components/primer/alpha/button_marketing.rb +70 -0
- data/app/components/primer/auto_complete.rb +97 -41
- data/app/components/primer/auto_complete/auto_complete.html.erb +1 -0
- data/app/components/primer/beta/text.rb +27 -0
- data/app/components/primer/blankslate_component.rb +2 -1
- data/app/components/primer/button_component.rb +3 -2
- data/app/components/primer/details_component.rb +12 -1
- data/app/components/primer/dropdown.d.ts +1 -0
- data/app/components/primer/{dropdown_component.html.erb → dropdown.html.erb} +2 -1
- data/app/components/primer/dropdown.js +1 -0
- data/app/components/primer/dropdown.rb +149 -0
- data/app/components/primer/dropdown.ts +1 -0
- data/app/components/primer/dropdown/menu.d.ts +1 -0
- data/app/components/primer/dropdown/menu.html.erb +25 -0
- data/app/components/primer/dropdown/menu.js +1 -0
- data/app/components/primer/dropdown/menu.rb +99 -0
- data/app/components/primer/dropdown/menu.ts +1 -0
- data/app/components/primer/heading_component.rb +1 -1
- data/app/components/primer/icon_button.rb +1 -1
- data/app/components/primer/navigation/tab_component.rb +2 -2
- data/app/components/primer/octicon_component.rb +3 -2
- data/app/components/primer/primer.d.ts +1 -0
- data/app/components/primer/primer.js +1 -0
- data/app/components/primer/primer.ts +1 -0
- data/app/components/primer/spinner_component.rb +2 -0
- data/lib/primer/view_components/linters/argument_mappers/button.rb +82 -0
- data/lib/primer/view_components/linters/argument_mappers/conversion_error.rb +10 -0
- data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +46 -0
- data/lib/primer/view_components/linters/button_component_migration_counter.rb +20 -1
- data/lib/primer/view_components/linters/flash_component_migration_counter.rb +1 -1
- data/lib/primer/view_components/linters/helpers.rb +7 -3
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/docs.rake +111 -96
- data/lib/yard/docs_helper.rb +12 -2
- data/static/statuses.json +6 -4
- metadata +17 -8
- data/app/components/primer/button_marketing_component.rb +0 -68
- data/app/components/primer/dropdown/menu_component.html.erb +0 -12
- data/app/components/primer/dropdown/menu_component.rb +0 -46
- data/app/components/primer/dropdown_component.rb +0 -73
- data/app/components/primer/text_component.rb +0 -25
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative "conversion_error"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ERBLint
         | 
| 6 | 
            +
              module Linters
         | 
| 7 | 
            +
                module ArgumentMappers
         | 
| 8 | 
            +
                  # Maps element attributes to system arguments.
         | 
| 9 | 
            +
                  class SystemArguments
         | 
| 10 | 
            +
                    STRING_PARAETERS = %w[aria- data-].freeze
         | 
| 11 | 
            +
                    TEST_SELECTOR_REGEX = /test_selector\((?<selector>.+)\)$/.freeze
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    attr_reader :attribute
         | 
| 14 | 
            +
                    def initialize(attribute)
         | 
| 15 | 
            +
                      @attribute = attribute
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    def to_args
         | 
| 19 | 
            +
                      if attribute.erb?
         | 
| 20 | 
            +
                        _, _, code_node = *attribute.node
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                        raise ConversionError, "Cannot convert erb block" if code_node.nil?
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                        code = code_node.loc.source.strip
         | 
| 25 | 
            +
                        m = code.match(TEST_SELECTOR_REGEX)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                        raise ConversionError, "Cannot convert erb block" if m.blank?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                        { test_selector: m[:selector].tr("'", '"') }
         | 
| 30 | 
            +
                      elsif attr_name == "data-test-selector"
         | 
| 31 | 
            +
                        { test_selector: attribute.value.to_json }
         | 
| 32 | 
            +
                      elsif attr_name.start_with?(*STRING_PARAETERS)
         | 
| 33 | 
            +
                        # if attribute has no value_node, it means it is a boolean attribute.
         | 
| 34 | 
            +
                        { "\"#{attr_name}\"" => attribute.value_node ? attribute.value.to_json : true }
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        raise ConversionError, "Cannot convert attribute \"#{attr_name}\""
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def attr_name
         | 
| 41 | 
            +
                      attribute.name
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative "helpers"
         | 
| 4 | 
            +
            require_relative "argument_mappers/button"
         | 
| 4 5 |  | 
| 5 6 | 
             
            module ERBLint
         | 
| 6 7 | 
             
              module Linters
         | 
| @@ -9,8 +10,26 @@ module ERBLint | |
| 9 10 | 
             
                  include Helpers
         | 
| 10 11 |  | 
| 11 12 | 
             
                  TAGS = %w[button summary a].freeze
         | 
| 12 | 
            -
                   | 
| 13 | 
            +
                  CLASSES = %w[btn btn-link].freeze
         | 
| 13 14 | 
             
                  MESSAGE = "We are migrating buttons to use [Primer::ButtonComponent](https://primer.style/view-components/components/button), please try to use that instead of raw HTML."
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  private
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def map_arguments(tag)
         | 
| 19 | 
            +
                    ArgumentMappers::Button.new(tag).to_s
         | 
| 20 | 
            +
                  rescue ArgumentMappers::ConversionError
         | 
| 21 | 
            +
                    nil
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def message(tag)
         | 
| 25 | 
            +
                    args = map_arguments(tag)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    return MESSAGE if args.nil?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    msg = "#{MESSAGE}\n\nTry using:\n\n<%= render Primer::ButtonComponent.new"
         | 
| 30 | 
            +
                    msg += "(#{args})" if args.present?
         | 
| 31 | 
            +
                    "#{msg} %>\n\nInstead of:\n"
         | 
| 32 | 
            +
                  end
         | 
| 14 33 | 
             
                end
         | 
| 15 34 | 
             
              end
         | 
| 16 35 | 
             
            end
         | 
| @@ -9,7 +9,7 @@ module ERBLint | |
| 9 9 | 
             
                  include Helpers
         | 
| 10 10 |  | 
| 11 11 | 
             
                  TAGS = %w[div].freeze
         | 
| 12 | 
            -
                   | 
| 12 | 
            +
                  CLASSES = %w[flash].freeze
         | 
| 13 13 | 
             
                  MESSAGE = "We are migrating flashes to use [Primer::FlashComponent](https://primer.style/view-components/components/flash), please try to use that instead of raw HTML."
         | 
| 14 14 | 
             
                end
         | 
| 15 15 | 
             
              end
         | 
| @@ -8,7 +8,7 @@ module ERBLint | |
| 8 8 | 
             
                # Helper methods for linting ERB.
         | 
| 9 9 | 
             
                module Helpers
         | 
| 10 10 | 
             
                  def self.included(base)
         | 
| 11 | 
            -
                    base.include(LinterRegistry)
         | 
| 11 | 
            +
                    base.include(ERBLint::LinterRegistry)
         | 
| 12 12 |  | 
| 13 13 | 
             
                    define_method "run" do |processed_source|
         | 
| 14 14 | 
             
                      tags(processed_source).each do |tag|
         | 
| @@ -17,9 +17,9 @@ module ERBLint | |
| 17 17 |  | 
| 18 18 | 
             
                        classes = tag.attributes["class"]&.value&.split(" ")
         | 
| 19 19 |  | 
| 20 | 
            -
                        next  | 
| 20 | 
            +
                        next if self.class::CLASSES.any? && (classes & self.class::CLASSES).blank?
         | 
| 21 21 |  | 
| 22 | 
            -
                        generate_offense(self.class, processed_source, tag,  | 
| 22 | 
            +
                        generate_offense(self.class, processed_source, tag, message(tag))
         | 
| 23 23 | 
             
                      end
         | 
| 24 24 |  | 
| 25 25 | 
             
                      counter_correct?(processed_source)
         | 
| @@ -42,6 +42,10 @@ module ERBLint | |
| 42 42 |  | 
| 43 43 | 
             
                  private
         | 
| 44 44 |  | 
| 45 | 
            +
                  def message(_tag)
         | 
| 46 | 
            +
                    self.class::MESSAGE
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 45 49 | 
             
                  def tags(processed_source)
         | 
| 46 50 | 
             
                    processed_source.parser.nodes_with_type(:tag).map { |tag_node| BetterHtml::Tree::Tag.from_node(tag_node) }
         | 
| 47 51 | 
             
                  end
         | 
    
        data/lib/tasks/docs.rake
    CHANGED
    
    | @@ -43,12 +43,12 @@ namespace :docs do | |
| 43 43 | 
             
                  Primer::BreadcrumbComponent,
         | 
| 44 44 | 
             
                  Primer::ButtonComponent,
         | 
| 45 45 | 
             
                  Primer::ButtonGroup,
         | 
| 46 | 
            -
                  Primer:: | 
| 46 | 
            +
                  Primer::Alpha::ButtonMarketing,
         | 
| 47 47 | 
             
                  Primer::ClipboardCopy,
         | 
| 48 48 | 
             
                  Primer::CloseButton,
         | 
| 49 49 | 
             
                  Primer::CounterComponent,
         | 
| 50 50 | 
             
                  Primer::DetailsComponent,
         | 
| 51 | 
            -
                  Primer:: | 
| 51 | 
            +
                  Primer::Dropdown,
         | 
| 52 52 | 
             
                  Primer::DropdownMenuComponent,
         | 
| 53 53 | 
             
                  Primer::FlashComponent,
         | 
| 54 54 | 
             
                  Primer::FlexComponent,
         | 
| @@ -69,7 +69,7 @@ namespace :docs do | |
| 69 69 | 
             
                  Primer::SubheadComponent,
         | 
| 70 70 | 
             
                  Primer::TabContainerComponent,
         | 
| 71 71 | 
             
                  Primer::TabNavComponent,
         | 
| 72 | 
            -
                  Primer:: | 
| 72 | 
            +
                  Primer::Beta::Text,
         | 
| 73 73 | 
             
                  Primer::TimeAgoComponent,
         | 
| 74 74 | 
             
                  Primer::TimelineItemComponent,
         | 
| 75 75 | 
             
                  Primer::Tooltip,
         | 
| @@ -78,6 +78,7 @@ namespace :docs do | |
| 78 78 | 
             
                ]
         | 
| 79 79 |  | 
| 80 80 | 
             
                js_components = [
         | 
| 81 | 
            +
                  Primer::Dropdown,
         | 
| 81 82 | 
             
                  Primer::LocalTime,
         | 
| 82 83 | 
             
                  Primer::ImageCrop,
         | 
| 83 84 | 
             
                  Primer::AutoComplete,
         | 
| @@ -91,10 +92,11 @@ namespace :docs do | |
| 91 92 | 
             
                all_components = Primer::Component.descendants - [Primer::BaseComponent]
         | 
| 92 93 | 
             
                components_needing_docs = all_components - components
         | 
| 93 94 |  | 
| 94 | 
            -
                components_without_examples = []
         | 
| 95 95 | 
             
                args_for_components = []
         | 
| 96 96 | 
             
                classes_found_in_examples = []
         | 
| 97 97 |  | 
| 98 | 
            +
                errors = []
         | 
| 99 | 
            +
             | 
| 98 100 | 
             
                components.each do |component|
         | 
| 99 101 | 
             
                  documentation = registry.get(component.name)
         | 
| 100 102 |  | 
| @@ -113,6 +115,8 @@ namespace :docs do | |
| 113 115 | 
             
                    f.puts
         | 
| 114 116 | 
             
                    f.puts("import Example from '../../src/@primer/gatsby-theme-doctocat/components/example'")
         | 
| 115 117 |  | 
| 118 | 
            +
                    initialize_method = documentation.meths.find(&:constructor?)
         | 
| 119 | 
            +
             | 
| 116 120 | 
             
                    if js_components.include?(component)
         | 
| 117 121 | 
             
                      f.puts("import RequiresJSFlash from '../../src/@primer/gatsby-theme-doctocat/components/requires-js-flash'")
         | 
| 118 122 | 
             
                      f.puts
         | 
| @@ -124,108 +128,68 @@ namespace :docs do | |
| 124 128 | 
             
                    f.puts
         | 
| 125 129 | 
             
                    f.puts(view_context.render(inline: documentation.base_docstring))
         | 
| 126 130 |  | 
| 127 | 
            -
                    if documentation.tags(: | 
| 131 | 
            +
                    if documentation.tags(:deprecated).any?
         | 
| 128 132 | 
             
                      f.puts
         | 
| 129 | 
            -
                      f.puts("##  | 
| 130 | 
            -
                      documentation.tags(: | 
| 133 | 
            +
                      f.puts("## Deprecation")
         | 
| 134 | 
            +
                      documentation.tags(:deprecated).each do |tag|
         | 
| 131 135 | 
             
                        f.puts
         | 
| 132 136 | 
             
                        f.puts view_context.render(inline: tag.text)
         | 
| 133 137 | 
             
                      end
         | 
| 134 138 | 
             
                    end
         | 
| 135 139 |  | 
| 136 | 
            -
                    if documentation.tags(: | 
| 140 | 
            +
                    if documentation.tags(:accessibility).any?
         | 
| 137 141 | 
             
                      f.puts
         | 
| 138 | 
            -
                      f.puts("##  | 
| 139 | 
            -
                      documentation.tags(: | 
| 142 | 
            +
                      f.puts("## Accessibility")
         | 
| 143 | 
            +
                      documentation.tags(:accessibility).each do |tag|
         | 
| 140 144 | 
             
                        f.puts
         | 
| 141 145 | 
             
                        f.puts view_context.render(inline: tag.text)
         | 
| 142 146 | 
             
                      end
         | 
| 143 147 | 
             
                    end
         | 
| 144 148 |  | 
| 145 | 
            -
                     | 
| 149 | 
            +
                    params = initialize_method.tags(:param)
         | 
| 146 150 |  | 
| 147 | 
            -
                     | 
| 148 | 
            -
                      f.puts
         | 
| 149 | 
            -
                      f.puts("## Examples")
         | 
| 150 | 
            -
                    else
         | 
| 151 | 
            -
                      components_without_examples << component
         | 
| 152 | 
            -
                    end
         | 
| 151 | 
            +
                    errors << { component.name => { arguments: "No argument documentation found" } } unless params.any?
         | 
| 153 152 |  | 
| 154 | 
            -
                     | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 153 | 
            +
                    f.puts
         | 
| 154 | 
            +
                    f.puts("## Arguments")
         | 
| 155 | 
            +
                    f.puts
         | 
| 156 | 
            +
                    f.puts("| Name | Type | Default | Description |")
         | 
| 157 | 
            +
                    f.puts("| :- | :- | :- | :- |")
         | 
| 158 158 |  | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
                        description = splitted.second.gsub(/^[ \t]{2}/, "").strip
         | 
| 162 | 
            -
                        code = splitted.last.gsub(/^[ \t]{2}/, "").strip
         | 
| 163 | 
            -
                      else
         | 
| 164 | 
            -
                        code = tag.text
         | 
| 165 | 
            -
                      end
         | 
| 159 | 
            +
                    docummented_params = params.map(&:name)
         | 
| 160 | 
            +
                    component_params = component.instance_method(:initialize).parameters.map { |p| p.last.to_s }
         | 
| 166 161 |  | 
| 167 | 
            -
             | 
| 168 | 
            -
                       | 
| 169 | 
            -
                       | 
| 170 | 
            -
                         | 
| 171 | 
            -
                        f.puts(description)
         | 
| 162 | 
            +
                    if (docummented_params & component_params).size != component_params.size
         | 
| 163 | 
            +
                      err = { arguments: {} }
         | 
| 164 | 
            +
                      (component_params - docummented_params).each do |arg|
         | 
| 165 | 
            +
                        err[:arguments][arg] = "Not documented"
         | 
| 172 166 | 
             
                      end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                       | 
| 175 | 
            -
                      html.scan(/class="([^"]*)"/) do |classnames|
         | 
| 176 | 
            -
                        classes_found_in_examples.concat(classnames[0].split(" ").reject { |c| c.starts_with?("octicon", "js", "my-") }.map { ".#{_1}"})
         | 
| 177 | 
            -
                      end
         | 
| 178 | 
            -
                      f.puts("<Example src=\"#{html.tr('"', "\'").delete("\n")}\" />")
         | 
| 179 | 
            -
                      f.puts
         | 
| 180 | 
            -
                      f.puts("```erb")
         | 
| 181 | 
            -
                      f.puts(code.to_s)
         | 
| 182 | 
            -
                      f.puts("```")
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                      errors << { component.name => err }
         | 
| 183 169 | 
             
                    end
         | 
| 184 170 |  | 
| 185 | 
            -
                     | 
| 186 | 
            -
                     | 
| 187 | 
            -
                       | 
| 188 | 
            -
                      f.puts("## Arguments")
         | 
| 189 | 
            -
                      f.puts
         | 
| 190 | 
            -
                      f.puts("| Name | Type | Default | Description |")
         | 
| 191 | 
            -
                      f.puts("| :- | :- | :- | :- |")
         | 
| 192 | 
            -
             | 
| 193 | 
            -
                      args = []
         | 
| 194 | 
            -
                      params.each do |tag|
         | 
| 195 | 
            -
                        params = tag.object.parameters.find { |param| [tag.name.to_s, tag.name.to_s + ":"].include?(param[0]) }
         | 
| 196 | 
            -
             | 
| 197 | 
            -
                        default =
         | 
| 198 | 
            -
                          if params && params[1]
         | 
| 199 | 
            -
                            constant_name = "#{component.name}::#{params[1]}"
         | 
| 200 | 
            -
                            constant_value = constant_name.safe_constantize
         | 
| 201 | 
            -
                            if constant_value.nil?
         | 
| 202 | 
            -
                              pretty_value(params[1])
         | 
| 203 | 
            -
                            else
         | 
| 204 | 
            -
                              pretty_value(constant_value)
         | 
| 205 | 
            -
                            end
         | 
| 206 | 
            -
                          else
         | 
| 207 | 
            -
                            "N/A"
         | 
| 208 | 
            -
                          end
         | 
| 209 | 
            -
             | 
| 210 | 
            -
                        args << {
         | 
| 211 | 
            -
                          "name" => tag.name,
         | 
| 212 | 
            -
                          "type" => tag.types.join(", "),
         | 
| 213 | 
            -
                          "default" => default,
         | 
| 214 | 
            -
                          "description" => view_context.render(inline: tag.text)
         | 
| 215 | 
            -
                        }
         | 
| 216 | 
            -
             | 
| 217 | 
            -
                        f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{default} | #{view_context.render(inline: tag.text)} |")
         | 
| 218 | 
            -
                      end
         | 
| 171 | 
            +
                    args = []
         | 
| 172 | 
            +
                    params.each do |tag|
         | 
| 173 | 
            +
                      default_value = pretty_default_value(tag, component)
         | 
| 219 174 |  | 
| 220 | 
            -
                       | 
| 221 | 
            -
                        " | 
| 222 | 
            -
                        " | 
| 223 | 
            -
                        " | 
| 175 | 
            +
                      args << {
         | 
| 176 | 
            +
                        "name" => tag.name,
         | 
| 177 | 
            +
                        "type" => tag.types.join(", "),
         | 
| 178 | 
            +
                        "default" => default_value,
         | 
| 179 | 
            +
                        "description" => view_context.render(inline: tag.text)
         | 
| 224 180 | 
             
                      }
         | 
| 225 181 |  | 
| 226 | 
            -
                       | 
| 182 | 
            +
                      f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{default_value} | #{view_context.render(inline: tag.text)} |")
         | 
| 227 183 | 
             
                    end
         | 
| 228 184 |  | 
| 185 | 
            +
                    component_args = {
         | 
| 186 | 
            +
                      "component" => short_name,
         | 
| 187 | 
            +
                      "source" => "https://github.com/primer/view_components/tree/main/app/components/primer/#{component.to_s.demodulize.underscore}.rb",
         | 
| 188 | 
            +
                      "parameters" => args
         | 
| 189 | 
            +
                    }
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                    args_for_components << component_args
         | 
| 192 | 
            +
             | 
| 229 193 | 
             
                    # Slots V2 docs
         | 
| 230 194 | 
             
                    slot_v2_methods = documentation.meths.select { |x| x[:renders_one] || x[:renders_many] }
         | 
| 231 195 |  | 
| @@ -250,22 +214,61 @@ namespace :docs do | |
| 250 214 | 
             
                        end
         | 
| 251 215 |  | 
| 252 216 | 
             
                        param_tags.each do |tag|
         | 
| 253 | 
            -
                           | 
| 217 | 
            +
                          f.puts("| `#{tag.name}` | `#{tag.types.join(', ')}` | #{pretty_default_value(tag, component)} | #{view_context.render(inline: tag.text)} |")
         | 
| 218 | 
            +
                        end
         | 
| 219 | 
            +
                      end
         | 
| 220 | 
            +
                    end
         | 
| 254 221 |  | 
| 255 | 
            -
             | 
| 256 | 
            -
                            if params && params[1]
         | 
| 257 | 
            -
                              "`#{params[1]}`"
         | 
| 258 | 
            -
                            else
         | 
| 259 | 
            -
                              "N/A"
         | 
| 260 | 
            -
                            end
         | 
| 222 | 
            +
                    errors << { component.name => { example: "No examples found" } } unless initialize_method.tags(:example).any?
         | 
| 261 223 |  | 
| 262 | 
            -
             | 
| 263 | 
            -
             | 
| 224 | 
            +
                    f.puts
         | 
| 225 | 
            +
                    f.puts("## Examples")
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                    initialize_method.tags(:example).each do |tag|
         | 
| 228 | 
            +
                      name = tag.name
         | 
| 229 | 
            +
                      description = nil
         | 
| 230 | 
            +
                      code = nil
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                      if tag.text.include?("@description")
         | 
| 233 | 
            +
                        splitted = tag.text.split(/@description|@code/)
         | 
| 234 | 
            +
                        description = splitted.second.gsub(/^[ \t]{2}/, "").strip
         | 
| 235 | 
            +
                        code = splitted.last.gsub(/^[ \t]{2}/, "").strip
         | 
| 236 | 
            +
                      else
         | 
| 237 | 
            +
                        code = tag.text
         | 
| 238 | 
            +
                      end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                      f.puts
         | 
| 241 | 
            +
                      f.puts("### #{name}")
         | 
| 242 | 
            +
                      if description
         | 
| 243 | 
            +
                        f.puts
         | 
| 244 | 
            +
                        f.puts(description)
         | 
| 245 | 
            +
                      end
         | 
| 246 | 
            +
                      f.puts
         | 
| 247 | 
            +
                      html = view_context.render(inline: code)
         | 
| 248 | 
            +
                      html.scan(/class="([^"]*)"/) do |classnames|
         | 
| 249 | 
            +
                        classes_found_in_examples.concat(classnames[0].split(" ").reject { |c| c.starts_with?("octicon", "js", "my-") }.map { ".#{_1}"})
         | 
| 264 250 | 
             
                      end
         | 
| 251 | 
            +
                      f.puts("<Example src=\"#{html.tr('"', "\'").delete("\n")}\" />")
         | 
| 252 | 
            +
                      f.puts
         | 
| 253 | 
            +
                      f.puts("```erb")
         | 
| 254 | 
            +
                      f.puts(code.to_s)
         | 
| 255 | 
            +
                      f.puts("```")
         | 
| 265 256 | 
             
                    end
         | 
| 266 257 | 
             
                  end
         | 
| 267 258 | 
             
                end
         | 
| 268 259 |  | 
| 260 | 
            +
                unless errors.empty?
         | 
| 261 | 
            +
                  puts "==============================================="
         | 
| 262 | 
            +
                  puts "===================== ERRORS =================="
         | 
| 263 | 
            +
                  puts "===============================================\n\n"
         | 
| 264 | 
            +
                  puts JSON.pretty_generate(errors)
         | 
| 265 | 
            +
                  puts "\n\n==============================================="
         | 
| 266 | 
            +
                  puts "==============================================="
         | 
| 267 | 
            +
                  puts "==============================================="
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                  raise
         | 
| 270 | 
            +
                end
         | 
| 271 | 
            +
             | 
| 269 272 | 
             
                File.open("static/classes.yml", "w") do |f|
         | 
| 270 273 | 
             
                  f.puts YAML.dump(classes_found_in_examples.sort.uniq)
         | 
| 271 274 | 
             
                end
         | 
| @@ -293,11 +296,6 @@ namespace :docs do | |
| 293 296 |  | 
| 294 297 | 
             
                puts "Markdown compiled."
         | 
| 295 298 |  | 
| 296 | 
            -
                if components_without_examples.any?
         | 
| 297 | 
            -
                  puts
         | 
| 298 | 
            -
                  puts "The following components have no examples defined: #{components_without_examples.map(&:name).join(', ')}. Consider adding an example?"
         | 
| 299 | 
            -
                end
         | 
| 300 | 
            -
             | 
| 301 299 | 
             
                if components_needing_docs.any?
         | 
| 302 300 | 
             
                  puts
         | 
| 303 301 | 
             
                  puts "The following components needs docs. Care to contribute them? #{components_needing_docs.map(&:name).join(', ')}"
         | 
| @@ -307,6 +305,8 @@ namespace :docs do | |
| 307 305 | 
             
              task :preview do
         | 
| 308 306 | 
             
                registry = generate_yard_registry
         | 
| 309 307 |  | 
| 308 | 
            +
                FileUtils.rm_rf("demo/test/components/previews/primer/docs/")
         | 
| 309 | 
            +
             | 
| 310 310 | 
             
                components = Primer::Component.descendants
         | 
| 311 311 |  | 
| 312 312 | 
             
                # Generate previews from documentation examples
         | 
| @@ -361,6 +361,7 @@ namespace :docs do | |
| 361 361 | 
             
                # Custom tags for yard
         | 
| 362 362 | 
             
                YARD::Tags::Library.define_tag("Accessibility", :accessibility)
         | 
| 363 363 | 
             
                YARD::Tags::Library.define_tag("Deprecation", :deprecation)
         | 
| 364 | 
            +
                YARD::Tags::Library.define_tag("Parameter", :param, :with_types_name_and_default)
         | 
| 364 365 |  | 
| 365 366 | 
             
                puts "Building YARD documentation."
         | 
| 366 367 | 
             
                Rake::Task["yard"].execute
         | 
| @@ -369,4 +370,18 @@ namespace :docs do | |
| 369 370 | 
             
                registry.load!(".yardoc")
         | 
| 370 371 | 
             
                registry
         | 
| 371 372 | 
             
              end
         | 
| 373 | 
            +
             | 
| 374 | 
            +
              def pretty_default_value(tag, component)
         | 
| 375 | 
            +
                params = tag.object.parameters.find { |param| [tag.name.to_s, tag.name.to_s + ":"].include?(param[0]) }
         | 
| 376 | 
            +
                default = tag.defaults&.first || params&.second
         | 
| 377 | 
            +
             | 
| 378 | 
            +
                return "N/A" unless default
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                constant_name = "#{component.name}::#{default}"
         | 
| 381 | 
            +
                constant_value = default.safe_constantize || constant_name.safe_constantize
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                return pretty_value(default) if constant_value.nil?
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                pretty_value(constant_value)
         | 
| 386 | 
            +
              end
         | 
| 372 387 | 
             
            end
         |