primer_view_components 0.0.119 → 0.0.121

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  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/alpha/modal_dialog.js +2 -0
  6. data/app/components/primer/alpha/modal_dialog.ts +2 -0
  7. data/app/components/primer/alpha/segmented_control/item.rb +1 -0
  8. data/app/components/primer/alpha/segmented_control.rb +30 -0
  9. data/app/components/primer/alpha/text_field.rb +1 -0
  10. data/app/components/primer/base_component.rb +3 -3
  11. data/app/components/primer/beta/close_button.rb +1 -1
  12. data/app/components/primer/{local_time.d.ts → beta/relative_time.d.ts} +0 -0
  13. data/app/components/primer/{local_time.js → beta/relative_time.js} +0 -0
  14. data/app/components/primer/{local_time.ts → beta/relative_time.ts} +0 -0
  15. data/app/components/primer/component.rb +2 -1
  16. data/app/components/primer/primer.d.ts +1 -2
  17. data/app/components/primer/primer.js +1 -2
  18. data/app/components/primer/primer.ts +1 -2
  19. data/app/forms/example_toggle_switch_form.rb +1 -1
  20. data/app/lib/primer/view_helper.rb +0 -1
  21. data/lib/primer/deprecations.yml +0 -91
  22. data/lib/primer/forms/acts_as_component.rb +12 -1
  23. data/lib/primer/forms/toggle_switch_form.rb +10 -3
  24. data/lib/primer/view_components/linters/button_component_migration_counter.rb +2 -2
  25. data/lib/primer/view_components/version.rb +1 -1
  26. data/lib/primer/view_components.rb +5 -0
  27. data/lib/primer/yard/backend.rb +38 -0
  28. data/lib/primer/yard/component_manifest.rb +121 -0
  29. data/lib/primer/yard/docs_helper.rb +81 -0
  30. data/lib/primer/yard/legacy_gatsby_backend.rb +271 -0
  31. data/lib/primer/yard/registry.rb +146 -0
  32. data/lib/primer/yard/renders_many_handler.rb +23 -0
  33. data/lib/primer/yard/renders_one_handler.rb +23 -0
  34. data/lib/rubocop/config/default.yml +3 -0
  35. data/lib/rubocop/cop/primer/test_selector.rb +48 -0
  36. data/lib/tasks/docs.rake +37 -405
  37. data/lib/tasks/static.rake +22 -0
  38. data/previews/primer/alpha/auto_complete_preview.rb +6 -6
  39. data/previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb +9 -0
  40. data/previews/primer/alpha/dialog_preview.rb +15 -0
  41. data/previews/primer/alpha/segmented_control_preview/with_label_and_caption.html.erb +9 -0
  42. data/previews/primer/alpha/segmented_control_preview/with_subhead_actions.html.erb +11 -0
  43. data/previews/primer/alpha/segmented_control_preview.rb +7 -1
  44. data/previews/primer/alpha/text_field_preview.rb +14 -0
  45. data/previews/primer/alpha/toggle_switch_preview.rb +9 -9
  46. data/previews/primer/beta/auto_complete_preview.rb +17 -17
  47. data/previews/primer/url_helpers.rb +1 -1
  48. data/static/arguments.json +6 -132
  49. data/static/audited_at.json +2 -24
  50. data/static/constants.json +0 -71
  51. data/static/previews.json +1634 -0
  52. data/static/statuses.json +0 -22
  53. metadata +23 -40
  54. data/app/components/primer/box_component.rb +0 -7
  55. data/app/components/primer/clipboard_copy.rb +0 -7
  56. data/app/components/primer/dropdown/menu.rb +0 -14
  57. data/app/components/primer/dropdown.rb +0 -7
  58. data/app/components/primer/dropdown_menu_component.html.erb +0 -8
  59. data/app/components/primer/dropdown_menu_component.rb +0 -58
  60. data/app/components/primer/hellip_button.rb +0 -7
  61. data/app/components/primer/label_component.rb +0 -7
  62. data/app/components/primer/link_component.rb +0 -7
  63. data/app/components/primer/local_time.rb +0 -63
  64. data/app/components/primer/markdown.rb +0 -7
  65. data/app/components/primer/menu_component.rb +0 -7
  66. data/app/components/primer/octicon_component.rb +0 -7
  67. data/app/components/primer/octicon_symbols_component.rb +0 -7
  68. data/app/components/primer/popover_component.rb +0 -8
  69. data/app/components/primer/spinner_component.rb +0 -7
  70. data/app/components/primer/state_component.rb +0 -7
  71. data/app/components/primer/subhead_component.rb +0 -7
  72. data/app/components/primer/tab_container_component.rb +0 -7
  73. data/app/components/primer/time_ago_component.d.ts +0 -1
  74. data/app/components/primer/time_ago_component.js +0 -1
  75. data/app/components/primer/time_ago_component.rb +0 -51
  76. data/app/components/primer/time_ago_component.ts +0 -1
  77. data/app/components/primer/timeline_item_component.rb +0 -13
  78. data/lib/yard/docs_helper.rb +0 -79
  79. data/lib/yard/renders_many_handler.rb +0 -19
  80. data/lib/yard/renders_one_handler.rb +0 -19
  81. data/previews/primer/local_time_component_preview.rb +0 -57
  82. data/previews/primer/time_ago_component_preview.rb +0 -27
@@ -86,6 +86,7 @@ export class ModalDialogElement extends HTMLElement {
86
86
  return;
87
87
  this.setAttribute('open', '');
88
88
  (_a = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay--hidden');
89
+ document.body.style.paddingRight = `${window.innerWidth - document.body.clientWidth}px`;
89
90
  document.body.style.overflow = 'hidden';
90
91
  if (__classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal.aborted) {
91
92
  __classPrivateFieldSet(this, _ModalDialogElement_focusAbortController, new AbortController(), "f");
@@ -98,6 +99,7 @@ export class ModalDialogElement extends HTMLElement {
98
99
  return;
99
100
  this.removeAttribute('open');
100
101
  (_b = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _b === void 0 ? void 0 : _b.classList.add('Overlay--hidden');
102
+ document.body.style.paddingRight = '0';
101
103
  document.body.style.overflow = 'initial';
102
104
  __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").abort();
103
105
  // if #openButton is a child of a menu, we need to focus a suitable child of the menu
@@ -81,6 +81,7 @@ export class ModalDialogElement extends HTMLElement {
81
81
  if (this.open) return
82
82
  this.setAttribute('open', '')
83
83
  this.#overlayBackdrop?.classList.remove('Overlay--hidden')
84
+ document.body.style.paddingRight = `${window.innerWidth - document.body.clientWidth}px`
84
85
  document.body.style.overflow = 'hidden'
85
86
  if (this.#focusAbortController.signal.aborted) {
86
87
  this.#focusAbortController = new AbortController()
@@ -91,6 +92,7 @@ export class ModalDialogElement extends HTMLElement {
91
92
  if (!this.open) return
92
93
  this.removeAttribute('open')
93
94
  this.#overlayBackdrop?.classList.add('Overlay--hidden')
95
+ document.body.style.paddingRight = '0'
94
96
  document.body.style.overflow = 'initial'
95
97
  this.#focusAbortController.abort()
96
98
  // if #openButton is a child of a menu, we need to focus a suitable child of the menu
@@ -7,6 +7,7 @@ module Primer
7
7
  # It wraps the Button and IconButton components to provide the correct styles
8
8
  class Item < Primer::BaseComponent
9
9
  status :alpha
10
+ audited_at "2023-02-01"
10
11
 
11
12
  # @param label [String] The label to use
12
13
  # @param selected [Boolean] Whether the item is selected
@@ -3,8 +3,12 @@
3
3
  module Primer
4
4
  module Alpha
5
5
  # Use a segmented control to let users select an option from a short list and immediately apply the selection
6
+ # @accessibility
7
+ # A `SegmentedControl` should not be used in a form as a replacement for something like a radio group or select.
8
+ # See the [Accessibility section](https://primer.style/design/components/segmented-control#accessibility) of the SegmentedControl interface guidelines for more details.
6
9
  class SegmentedControl < Primer::Component
7
10
  status :alpha
11
+ audited_at "2023-02-01"
8
12
 
9
13
  FULL_WIDTH_DEFAULT = false
10
14
  HIDE_LABELS_DEFAULT = false
@@ -24,6 +28,30 @@ module Primer
24
28
  )
25
29
  }
26
30
 
31
+ # @example With a label above and caption below
32
+ # <%= render(Primer::Box.new(display: :flex, direction: :column)) do %>
33
+ # <%= render(Primer::BaseComponent.new(tag: "span", id: "scLabel-horiz")) { "File view" } %>
34
+ # <%= render(Primer::Alpha::SegmentedControl.new("aria-labelledby": "scLabel-horiz", "aria-describedby": "scCaption-horiz")) do |component| %>
35
+ # <% component.with_item(label: "Preview", selected: true) %>
36
+ # <% component.with_item(label: "Raw") %>
37
+ # <% component.with_item(label: "Blame") %>
38
+ # <% end %>
39
+ # <%= render(Primer::Beta::Text.new(font_size: :small, mt: 1, color: :muted, id: "scCaption-horiz")) { "Change the way the file is viewed" } %>
40
+ # <% end %>
41
+ #
42
+ # @example With a label and caption on the left
43
+ # <%= render(Primer::Beta::Subhead.new) do |component| %>
44
+ # <% component.with_heading(id: "scLabel-vert") { "File view" } %>
45
+ # <% component.with_description(id: "scCaption-vert") { "Change the way the file is viewed" } %>
46
+ # <% component.with_actions do %>
47
+ # <%= render(Primer::Alpha::SegmentedControl.new("aria-labelledby": "scLabel-vert", "aria-describedby": "scCaption-vert")) do |component| %>
48
+ # <% component.with_item(label: "Preview", selected: true) %>
49
+ # <% component.with_item(label: "Raw") %>
50
+ # <% component.with_item(label: "Blame") %>
51
+ # <% end %>
52
+ # <% end %>
53
+ # <% end %>
54
+ #
27
55
  # @example Basic usage
28
56
  #
29
57
  # <%= render(Primer::Alpha::SegmentedControl.new("aria-label": "File view")) do |component| %>
@@ -79,6 +107,8 @@ module Primer
79
107
  "SegmentedControl--iconOnly": hide_labels,
80
108
  "SegmentedControl--fullWidth": full_width
81
109
  )
110
+
111
+ validate_aria_label
82
112
  end
83
113
 
84
114
  def render?
@@ -98,6 +98,7 @@ module Primer
98
98
  # @param leading_visual [Hash] Renders a leading visual icon before the text field's cursor. The hash will be passed to Primer's [Octicon component](https://primer.style/view-components/components/octicon).
99
99
  # @param validation_message [String] A validation message to display beneath the input. Implicitly sets `invalid` to `true`.
100
100
  # @param label_arguments [Hash] System arugments passed to the Rails builder's `#label` method. These arguments will appear as HTML attributes on the `<label>` tag.
101
+ # @param auto_check_src [String] When provided, makes a request to the given URL whenever the contents of the text field changes. If the server responds with a non-2xx status code, the response body is used as the validation message.
101
102
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
102
103
  # @param block [Proc] Unused.
103
104
  end
@@ -134,12 +134,12 @@ module Primer
134
134
  #
135
135
  # | Name | Type | Description |
136
136
  # | :- | :- | :- |
137
- # | `font_family` | Symbol | Font weight. <%= one_of([:mono]) %> |
137
+ # | `font_family` | Symbol | Font family. <%= one_of([:mono]) %> |
138
138
  # | `font_size` | String, Integer, Symbol | <%= one_of(["00", 0, 1, 2, 3, 4, 5, 6, :small, :normal]) %> |
139
- # | `font_style` | Symbol | Font weight. <%= one_of([:italic]) %> |
139
+ # | `font_style` | Symbol | Font style. <%= one_of([:italic]) %> |
140
140
  # | `font_weight` | Symbol | Font weight. <%= one_of([:light, :normal, :bold, :emphasized]) %> |
141
141
  # | `text_align` | Symbol | Text alignment. <%= one_of([:left, :right, :center]) %> |
142
- # | `text_transform` | Symbol | Text alignment. <%= one_of([:uppercase]) %> |
142
+ # | `text_transform` | Symbol | Text transformation. <%= one_of([:uppercase]) %> |
143
143
  # | `underline` | Boolean | Whether text should be underlined. |
144
144
  # | `word_break` | Symbol | Whether to break words on line breaks. <%= one_of(Primer::Classify::Utilities.mappings(:word_break)) %> |
145
145
  #
@@ -28,7 +28,7 @@ module Primer
28
28
  "close-button",
29
29
  system_arguments[:classes]
30
30
  )
31
- @system_arguments[:"aria-label"] ||= "Close"
31
+ @system_arguments[:"aria-label"] = aria("label", system_arguments) || "Close"
32
32
  end
33
33
 
34
34
  def call
@@ -52,7 +52,8 @@ module Primer
52
52
 
53
53
  def validate_aria_label
54
54
  aria_label = aria("label", @system_arguments)
55
- raise ArgumentError, "`aria-label` is required." if aria_label.nil? && !Rails.env.production?
55
+ aria_labelledby = aria("labelledby", @system_arguments)
56
+ raise ArgumentError, "`aria-label` or `aria-labelledby` is required." if aria_label.nil? && aria_labelledby.nil? && !Rails.env.production?
56
57
  end
57
58
 
58
59
  def silence_deprecations?
@@ -8,9 +8,8 @@ import './alpha/tool_tip';
8
8
  import './alpha/x_banner';
9
9
  import './beta/auto_complete/auto_complete';
10
10
  import './beta/clipboard_copy';
11
- import './local_time';
11
+ import './beta/relative_time';
12
12
  import './alpha/tab_container';
13
- import './time_ago_component';
14
13
  import '../../../lib/primer/forms/primer_multi_input';
15
14
  import '../../../lib/primer/forms/primer_text_field';
16
15
  import '../../../lib/primer/forms/toggle_switch_input';
@@ -8,9 +8,8 @@ import './alpha/tool_tip';
8
8
  import './alpha/x_banner';
9
9
  import './beta/auto_complete/auto_complete';
10
10
  import './beta/clipboard_copy';
11
- import './local_time';
11
+ import './beta/relative_time';
12
12
  import './alpha/tab_container';
13
- import './time_ago_component';
14
13
  import '../../../lib/primer/forms/primer_multi_input';
15
14
  import '../../../lib/primer/forms/primer_text_field';
16
15
  import '../../../lib/primer/forms/toggle_switch_input';
@@ -8,9 +8,8 @@ import './alpha/tool_tip'
8
8
  import './alpha/x_banner'
9
9
  import './beta/auto_complete/auto_complete'
10
10
  import './beta/clipboard_copy'
11
- import './local_time'
11
+ import './beta/relative_time'
12
12
  import './alpha/tab_container'
13
- import './time_ago_component'
14
13
  import '../../../lib/primer/forms/primer_multi_input'
15
14
  import '../../../lib/primer/forms/primer_text_field'
16
15
  import '../../../lib/primer/forms/toggle_switch_input'
@@ -3,6 +3,6 @@
3
3
  # :nodoc:
4
4
  class ExampleToggleSwitchForm < Primer::Forms::ToggleSwitchForm
5
5
  def initialize(**system_arguments)
6
- super(name: :example_field, label: "Example", caption: "This is an example toggle switch.", **system_arguments)
6
+ super(name: :example_field, label: "Example", **system_arguments)
7
7
  end
8
8
  end
@@ -9,7 +9,6 @@ module Primer
9
9
  HELPERS = {
10
10
  octicon: "Primer::Beta::Octicon",
11
11
  heading: "Primer::Beta::Heading",
12
- time_ago: "Primer::TimeAgoComponent",
13
12
  image: "Primer::Alpha::Image"
14
13
  }.freeze
15
14
 
@@ -17,106 +17,15 @@ deprecations:
17
17
  autocorrect: true
18
18
  replacement: "Primer::Beta::Blankslate"
19
19
 
20
- - component: "Primer::BoxComponent"
21
- autocorrect: true
22
- replacement: "Primer::Box"
23
-
24
20
  - component: "Primer::ButtonComponent"
25
21
  autocorrect: false
26
22
  replacement: "Primer::Beta::Button"
27
23
  guide: "https://primer.style/view-components/guides/primer_button_component"
28
24
 
29
- - component: "Primer::ClipboardCopy"
30
- autocorrect: true
31
- replacement: "Primer::Beta::ClipboardCopy"
32
-
33
- - component: "Primer::DropdownMenuComponent"
34
- autocorrect: false
35
- replacement: "Primer::Beta::Dropdown"
36
- guide: "https://primer.style/view-components/guides/primer_dropdown_menu_component"
37
-
38
- - component: "Primer::Dropdown"
39
- autocorrect: true
40
- replacement: "Primer::Alpha::Dropdown"
41
-
42
- - component: "Primer::Dropdown::Menu"
43
- autocorrect: true
44
- replacement: "Primer::Alpha::Dropdown::Menu"
45
-
46
- - component: "Primer::Dropdown::Menu::Item"
47
- autocorrect: true
48
- replacement: "Primer::Alpha::Dropdown::Menu::Item"
49
-
50
- - component: "Primer::HellipButton"
51
- autocorrect: true
52
- replacement: "Primer::Alpha::HellipButton"
53
-
54
25
  - component: "Primer::IconButton"
55
26
  autocorrect: true
56
27
  replacement: "Primer::Beta::IconButton"
57
28
 
58
- - component: "Primer::LabelComponent"
59
- autocorrect: true
60
- replacement: "Primer::Beta::Label"
61
-
62
- - component: "Primer::LocalTime"
63
- autocorrect: false
64
- replacement: "Primer::Beta::RelativeTime"
65
- guide: "https://primer.style/view-components/guides/primer_local_time"
66
-
67
- - component: "Primer::LinkComponent"
68
- autocorrect: true
69
- replacement: "Primer::Beta::Link"
70
-
71
- - component: "Primer::Markdown"
72
- autocorrect: true
73
- replacement: "Primer::Beta::Markdown"
74
-
75
- - component: "Primer::MenuComponent"
76
- autocorrect: true
77
- replacement: "Primer::Alpha::Menu"
78
-
79
- - component: "Primer::OcticonComponent"
80
- autocorrect: true
81
- replacement: "Primer::Beta::Octicon"
82
-
83
- - component: "Primer::OcticonSymbolsComponent"
84
- autocorrect: true
85
- replacement: "Primer::Alpha::OcticonSymbols"
86
-
87
- - component: "Primer::PopoverComponent"
88
- autocorrect: true
89
- replacement: "Primer::Beta::Popover"
90
-
91
- - component: "Primer::SpinnerComponent"
92
- autocorrect: true
93
- replacement: "Primer::Beta::Spinner"
94
-
95
- - component: "Primer::StateComponent"
96
- autocorrect: true
97
- replacement: "Primer::Beta::State"
98
-
99
- - component: "Primer::SubheadComponent"
100
- autocorrect: true
101
- replacement: "Primer::Beta::Subhead"
102
-
103
- - component: "Primer::TabContainerComponent"
104
- autocorrect: true
105
- replacement: "Primer::Alpha::TabContainer"
106
-
107
- - component: "Primer::TimeAgoComponent"
108
- autocorrect: false
109
- replacement: "Primer::Beta::RelativeTime"
110
- guide: "https://primer.style/view-components/guides/primer_time_ago"
111
-
112
- - component: "Primer::TimelineItemComponent"
113
- autocorrect: true
114
- replacement: "Primer::Beta::TimelineItem"
115
-
116
- - component: "Primer::TimelineItemComponent::BadgeComponent"
117
- autocorrect: true
118
- replacement: "Primer::Beta::TimelineItem::Badge"
119
-
120
29
  - component: "Primer::Tooltip"
121
30
  autocorrect: true
122
31
  replacement: "Primer::Alpha::Tooltip"
@@ -8,7 +8,7 @@ module Primer
8
8
  module ActsAsComponent
9
9
  # :nodoc:
10
10
  module InstanceMethods
11
- delegate :render, :content_tag, :output_buffer, :capture, to: :@view_context
11
+ delegate :render, :content_tag, :output_buffer, to: :@view_context
12
12
 
13
13
  def render_in(view_context, &block)
14
14
  @view_context = view_context
@@ -16,6 +16,17 @@ module Primer
16
16
  perform_render(&block)
17
17
  end
18
18
 
19
+ # This is necessary to restore the functionality changed by https://github.com/rails/rails/pull/47194.
20
+ # I would love to remove this at some point, perhaps if we ever decide to replace
21
+ # ActsAsComponent with view component.
22
+ def capture(*args, &block)
23
+ old_buffer = @view_context.output_buffer
24
+ @view_context.output_buffer = ActionView::OutputBuffer.new
25
+ @view_context.capture(*args, &block)
26
+ ensure
27
+ @view_context.output_buffer = old_buffer
28
+ end
29
+
19
30
  # :nocov:
20
31
  def perform_render(&_block)
21
32
  raise NotImplementedError, "subclasses must implement ##{__method__}."
@@ -32,8 +32,10 @@ module Primer
32
32
  #
33
33
  class ToggleSwitchForm < Primer::Forms::Base
34
34
  # Define the form on subclasses so render(Subclass.new) works as expected.
35
- def self.inherited(base)
36
- base.form do |toggle_switch_form|
35
+ # (this is called directly on this class, but also on classes
36
+ # that inherit from this class)
37
+ def self.define_form_on(klass)
38
+ klass.form do |toggle_switch_form|
37
39
  input = Dsl::ToggleSwitchInput.new(
38
40
  builder: toggle_switch_form.builder, form: self, **@system_arguments
39
41
  )
@@ -42,8 +44,13 @@ module Primer
42
44
  end
43
45
  end
44
46
 
47
+ def self.inherited(base)
48
+ super
49
+ define_form_on(base)
50
+ end
51
+
45
52
  # Define the form on self so render(ToggleSwitchForm.new) works as expected.
46
- inherited(self)
53
+ define_form_on(self)
47
54
 
48
55
  # Override to avoid accepting a builder argument. We create our own builder
49
56
  # on render. See the implementation of render_in below.
@@ -18,9 +18,9 @@ module ERBLint
18
18
  # CloseButton component has preference when this class is seen in conjunction with `btn`.
19
19
  DISALLOWED_CLASSES = %w[close-button].freeze
20
20
  CLASSES = %w[btn btn-link].freeze
21
- 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."
21
+ MESSAGE = "We are migrating buttons to use [Primer::Beta::Button](https://primer.style/view-components/components/beta/button), please try to use that instead of raw HTML."
22
22
  ARGUMENT_MAPPER = ArgumentMappers::Button
23
- COMPONENT = "Primer::ButtonComponent"
23
+ COMPONENT = "Primer::Beta::Button"
24
24
  end
25
25
  end
26
26
  end
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 0
9
- PATCH = 119
9
+ PATCH = 121
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -54,5 +54,10 @@ module Primer
54
54
  def self.read(stats)
55
55
  File.read(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]))
56
56
  end
57
+
58
+ # primer/view_components root directory.
59
+ def self.root
60
+ Pathname(File.expand_path(File.join("..", ".."), __dir__))
61
+ end
57
62
  end
58
63
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+ module Primer
5
+ module YARD
6
+ # Shared functionality for generating documentation from YARD comments.
7
+ class Backend
8
+ include DocsHelper
9
+
10
+ private
11
+
12
+ def pretty_default_value(tag, component)
13
+ params = tag.object.parameters.find { |param| [tag.name.to_s, "#{tag.name}:"].include?(param[0]) }
14
+ default = tag.defaults&.first || params&.second
15
+
16
+ return "N/A" unless default
17
+
18
+ constant_name = "#{component.name}::#{default}"
19
+ constant_value = default.safe_constantize || constant_name.safe_constantize
20
+
21
+ return pretty_value(default) if constant_value.nil?
22
+
23
+ pretty_value(constant_value)
24
+ end
25
+
26
+ def view_context
27
+ @view_context ||= begin
28
+ # Rails controller for rendering arbitrary ERB
29
+ vc = ApplicationController.new.tap { |c| c.request = ActionDispatch::TestRequest.create }.view_context
30
+ vc.singleton_class.include(DocsHelper)
31
+ vc.singleton_class.include(Primer::ViewHelper)
32
+ vc
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ # :nocov:
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+ module Primer
5
+ module YARD
6
+ # The set of documented components (and associated metadata).
7
+ class ComponentManifest
8
+ COMPONENTS = {
9
+ Primer::Beta::RelativeTime => {},
10
+ Primer::Beta::IconButton => {},
11
+ Primer::Beta::Button => {},
12
+ Primer::Alpha::SegmentedControl => {},
13
+ Primer::Alpha::Layout => {},
14
+ Primer::Alpha::HellipButton => {},
15
+ Primer::Alpha::Image => {},
16
+ Primer::Alpha::OcticonSymbols => {},
17
+ Primer::Alpha::ImageCrop => { js: true },
18
+ Primer::IconButton => { js: true },
19
+ Primer::Beta::AutoComplete => { js: true },
20
+ Primer::Beta::AutoComplete::Item => {},
21
+ Primer::Beta::Avatar => {},
22
+ Primer::Beta::AvatarStack => {},
23
+ Primer::Beta::BaseButton => {},
24
+ Primer::Alpha::Banner => { js: true },
25
+ Primer::Beta::Blankslate => {},
26
+ Primer::Beta::BorderBox => {},
27
+ Primer::Beta::BorderBox::Header => {},
28
+ Primer::Box => {},
29
+ Primer::Beta::Breadcrumbs => {},
30
+ Primer::ButtonComponent => { js: true },
31
+ Primer::Beta::ButtonGroup => {},
32
+ Primer::Alpha::ButtonMarketing => {},
33
+ Primer::Beta::ClipboardCopy => { js: true },
34
+ Primer::Beta::CloseButton => {},
35
+ Primer::Beta::Counter => {},
36
+ Primer::Beta::Details => {},
37
+ Primer::Alpha::Dialog => {},
38
+ Primer::Alpha::Dropdown => { js: true },
39
+ Primer::Beta::Flash => {},
40
+ Primer::Beta::Heading => {},
41
+ Primer::Alpha::HiddenTextExpander => {},
42
+ Primer::Beta::Label => {},
43
+ Primer::LayoutComponent => {},
44
+ Primer::Beta::Link => { js: true },
45
+ Primer::Beta::Markdown => {},
46
+ Primer::Alpha::Menu => {},
47
+ Primer::Navigation::TabComponent => {},
48
+ Primer::Beta::Octicon => {},
49
+ Primer::Beta::Popover => {},
50
+ Primer::Beta::ProgressBar => {},
51
+ Primer::Beta::State => {},
52
+ Primer::Beta::Spinner => {},
53
+ Primer::Beta::Subhead => {},
54
+ Primer::Alpha::TabContainer => { js: true },
55
+ Primer::Beta::Text => {},
56
+ Primer::Beta::TimelineItem => {},
57
+ Primer::Tooltip => {},
58
+ Primer::Truncate => {},
59
+ Primer::Beta::Truncate => {},
60
+ Primer::Alpha::UnderlineNav => {},
61
+ Primer::Alpha::UnderlinePanels => { js: true },
62
+ Primer::Alpha::TabNav => {},
63
+ Primer::Alpha::TabPanels => { js: true },
64
+ Primer::Alpha::Tooltip => { js: true },
65
+ Primer::Alpha::ToggleSwitch => { js: true },
66
+
67
+ # Examples can be seen in the NavList docs
68
+ Primer::Alpha::NavList => { js: true },
69
+ Primer::Alpha::NavList::Item => { js: true, examples: false },
70
+ Primer::Alpha::NavList::Section => { js: true, examples: false },
71
+
72
+ # ActionList is a base component that should not be used by itself, and thus
73
+ # does not have examples of its own
74
+ Primer::Alpha::ActionList => { js: true, examples: false },
75
+ Primer::Alpha::ActionList::Divider => { examples: false },
76
+ Primer::Alpha::ActionList::Heading => { examples: false },
77
+ Primer::Alpha::ActionList::Item => { examples: false },
78
+
79
+ # Forms
80
+ Primer::Alpha::TextField => { form_component: true }
81
+ }.freeze
82
+
83
+ class << self
84
+ def each(&block)
85
+ COMPONENTS.keys.each(&block)
86
+ end
87
+
88
+ def components_with_docs
89
+ @components_with_docs ||= COMPONENTS.keys
90
+ end
91
+
92
+ def all_components
93
+ @all_components ||= Primer::Component.descendants - [Primer::BaseComponent]
94
+ end
95
+
96
+ def components_without_docs
97
+ @components_without_docs ||= all_components - components_with_docs
98
+ end
99
+
100
+ def components_with_examples
101
+ @components_with_examples ||= COMPONENTS.keys.select do |c|
102
+ COMPONENTS[c].fetch(:examples, true)
103
+ end
104
+ end
105
+
106
+ def components_requiring_js
107
+ @components_requiring_js ||= COMPONENTS.keys.select do |c|
108
+ COMPONENTS[c].fetch(:js, false)
109
+ end
110
+ end
111
+
112
+ def form_components
113
+ @form_components ||= COMPONENTS.keys.select do |c|
114
+ COMPONENTS[c].fetch(:form_component, false)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ # :nocov:
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+
5
+ module Primer
6
+ module YARD
7
+ # Helper methods to use for yard documentation
8
+ module DocsHelper
9
+ def one_of(enumerable, lower: false, sort: true)
10
+ # Sort the array if requested
11
+ if sort
12
+ enumerable = enumerable.sort do |a, b|
13
+ a.instance_of?(b.class) ? a <=> b : a.class.to_s <=> b.class.to_s
14
+ end
15
+ end
16
+
17
+ values =
18
+ case enumerable
19
+ when Hash
20
+ enumerable.map do |key, value|
21
+ "#{pretty_value(key)} (#{pretty_value(value)})"
22
+ end
23
+ else
24
+ enumerable.map do |key|
25
+ pretty_value(key)
26
+ end
27
+ end
28
+
29
+ prefix = "One of"
30
+ prefix = prefix.downcase if lower
31
+
32
+ "#{prefix} #{values.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}."
33
+ end
34
+
35
+ def link_to_accessibility
36
+ "[Accessibility](#accessibility)"
37
+ end
38
+
39
+ def link_to_system_arguments_docs
40
+ "[System arguments](/system-arguments)"
41
+ end
42
+
43
+ def link_to_typography_docs
44
+ "[Typography](/system-arguments#typography)"
45
+ end
46
+
47
+ def link_to_component(component)
48
+ status_module, short_name, class_name = status_module_and_short_name(component)
49
+ status_path = status_module.nil? ? "" : "#{status_module}/"
50
+
51
+ "[#{class_name}](/components/#{status_path}#{short_name.downcase})"
52
+ end
53
+
54
+ def link_to_octicons
55
+ "[Octicon](https://primer.style/octicons/)"
56
+ end
57
+
58
+ def link_to_heading_practices
59
+ "[Learn more about best heading practices (WAI Headings)](https://www.w3.org/WAI/tutorials/page-structure/headings/)"
60
+ end
61
+
62
+ def status_module_and_short_name(component)
63
+ name_with_status = component.name.gsub(/Primer::|Component/, "")
64
+
65
+ m = name_with_status.match(/(?<status>Beta|Alpha|Deprecated)?(?<_colons>::)?(?<name>.*)/)
66
+ [m[:status]&.downcase, m[:name].gsub("::", ""), m[:name]]
67
+ end
68
+
69
+ def pretty_value(val)
70
+ case val
71
+ when nil
72
+ "`nil`"
73
+ when Symbol
74
+ "`:#{val}`"
75
+ else
76
+ "`#{val}`"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end