primer_view_components 0.0.27 → 0.0.32

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/README.md +1 -1
  4. data/app/assets/javascripts/primer_view_components.js +1 -1
  5. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  6. data/app/components/primer/auto_complete_component.d.ts +1 -0
  7. data/app/components/primer/auto_complete_component.html.erb +5 -0
  8. data/app/components/primer/auto_complete_component.rb +96 -0
  9. data/app/components/primer/auto_complete_component.ts +1 -0
  10. data/app/components/primer/auto_complete_item_component.rb +38 -0
  11. data/app/components/primer/avatar_component.rb +6 -5
  12. data/app/components/primer/avatar_stack_component.rb +0 -2
  13. data/app/components/primer/base_component.rb +2 -2
  14. data/app/components/primer/blankslate_component.html.erb +1 -5
  15. data/app/components/primer/blankslate_component.rb +0 -2
  16. data/app/components/primer/border_box_component.rb +29 -3
  17. data/app/components/primer/box_component.rb +1 -1
  18. data/app/components/primer/breadcrumb_component.rb +0 -1
  19. data/app/components/primer/button_group_component.rb +0 -2
  20. data/app/components/primer/component.rb +2 -1
  21. data/app/components/primer/counter_component.rb +15 -5
  22. data/app/components/primer/details_component.rb +1 -1
  23. data/app/components/primer/dropdown/menu_component.rb +0 -2
  24. data/app/components/primer/dropdown_component.rb +0 -2
  25. data/app/components/primer/flash_component.html.erb +2 -2
  26. data/app/components/primer/flash_component.rb +0 -2
  27. data/app/components/primer/flex_component.rb +16 -16
  28. data/app/components/primer/heading_component.rb +1 -1
  29. data/app/components/primer/label_component.rb +3 -7
  30. data/app/components/primer/layout_component.rb +0 -2
  31. data/app/components/primer/link_component.rb +37 -7
  32. data/app/components/primer/menu_component.rb +2 -4
  33. data/app/components/primer/navigation/tab_component.html.erb +9 -0
  34. data/app/components/primer/navigation/tab_component.rb +102 -0
  35. data/app/components/primer/octicon_component.rb +5 -5
  36. data/app/components/primer/popover_component.html.erb +3 -7
  37. data/app/components/primer/popover_component.rb +75 -63
  38. data/app/components/primer/primer.d.ts +3 -0
  39. data/app/components/primer/primer.js +1 -0
  40. data/app/components/primer/primer.ts +1 -0
  41. data/app/components/primer/progress_bar_component.rb +5 -6
  42. data/app/components/primer/spinner_component.html.erb +1 -3
  43. data/app/components/primer/spinner_component.rb +1 -0
  44. data/app/components/primer/subhead_component.rb +0 -2
  45. data/app/components/primer/tab_container_component.d.ts +1 -0
  46. data/app/components/primer/tab_nav_component.html.erb +9 -11
  47. data/app/components/primer/tab_nav_component.rb +46 -73
  48. data/app/components/primer/text_component.rb +3 -1
  49. data/app/components/primer/time_ago_component.d.ts +1 -0
  50. data/app/components/primer/time_ago_component.rb +2 -1
  51. data/app/components/primer/timeline_item_component.rb +3 -3
  52. data/app/components/primer/underline_nav_component.html.erb +19 -7
  53. data/app/components/primer/underline_nav_component.rb +80 -14
  54. data/app/lib/primer/classify.rb +15 -18
  55. data/app/lib/primer/classify/cache.rb +8 -3
  56. data/app/lib/primer/classify/functional_background_colors.rb +61 -0
  57. data/app/lib/primer/classify/functional_border_colors.rb +51 -0
  58. data/app/lib/primer/classify/functional_colors.rb +68 -0
  59. data/app/lib/primer/classify/functional_text_colors.rb +62 -0
  60. data/app/lib/primer/fetch_or_fallback_helper.rb +17 -4
  61. data/app/lib/primer/tabbed_component_helper.rb +37 -0
  62. data/app/lib/primer/view_helper.rb +10 -12
  63. data/lib/primer/view_components/engine.rb +4 -0
  64. data/lib/primer/view_components/version.rb +1 -1
  65. data/static/statuses.json +1 -1
  66. metadata +31 -5
  67. data/app/components/primer/slot.rb +0 -10
  68. data/app/lib/primer/classify/functional_colors.rb.orig +0 -124
  69. data/app/lib/primer/view_helper/dsl.rb +0 -34
@@ -3,7 +3,7 @@
3
3
  module Primer
4
4
  # Use DetailsComponent to reveal content after clicking a button.
5
5
  class DetailsComponent < Primer::Component
6
- include ViewComponent::SlotableV2
6
+ status :beta
7
7
 
8
8
  NO_OVERLAY = :none
9
9
  OVERLAY_MAPPINGS = {
@@ -5,8 +5,6 @@ module Primer
5
5
  # This component is part of `Primer::DropdownComponent` and should not be
6
6
  # used as a standalone component.
7
7
  class MenuComponent < Primer::Component
8
- include ViewComponent::SlotableV2
9
-
10
8
  SCHEME_DEFAULT = :default
11
9
  SCHEME_MAPPINGS = {
12
10
  SCHEME_DEFAULT => "",
@@ -4,8 +4,6 @@ module Primer
4
4
  # Dropdowns are lightweight context menus for housing navigation and actions.
5
5
  # They're great for instances where you don't need the full power (and code) of the select menu.
6
6
  class DropdownComponent < Primer::Component
7
- include ViewComponent::SlotableV2
8
-
9
7
  # Required trigger for the dropdown. Only accepts a content.
10
8
  # Its classes can be customized by the `summary_classes` param in the parent component
11
9
  renders_one :button
@@ -1,9 +1,9 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <%= primer(:octicon, icon: @icon) if @icon %>
2
+ <%= primer_octicon @icon if @icon %>
3
3
  <%= content %>
4
4
  <% if @dismissible %>
5
5
  <button class="flash-close js-flash-close" type="button" aria-label="Close">
6
- <%= primer(:octicon, icon: "x") %>
6
+ <%= primer_octicon "x" %>
7
7
  </button>
8
8
  <% end %>
9
9
 
@@ -5,8 +5,6 @@ module Primer
5
5
  class FlashComponent < Primer::Component
6
6
  status :beta
7
7
 
8
- include ViewComponent::SlotableV2
9
-
10
8
  # Optional action content showed on the right side of the component.
11
9
  #
12
10
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -36,31 +36,31 @@ module Primer
36
36
  ALLOWED_DIRECTIONS = [DEFAULT_DIRECTION, :column, :column_reverse, :row, :row_reverse].freeze
37
37
 
38
38
  # @example Default
39
- # <%= render(Primer::FlexComponent.new(bg: :gray)) do %>
40
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
41
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
42
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
39
+ # <%= render(Primer::FlexComponent.new(bg: :tertiary)) do %>
40
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
41
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
42
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
43
43
  # <% end %>
44
44
  #
45
45
  # @example Justify center
46
- # <%= render(Primer::FlexComponent.new(justify_content: :center, bg: :gray)) do %>
47
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
48
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
49
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
46
+ # <%= render(Primer::FlexComponent.new(justify_content: :center, bg: :tertiary)) do %>
47
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
48
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
49
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
50
50
  # <% end %>
51
51
  #
52
52
  # @example Align end
53
- # <%= render(Primer::FlexComponent.new(align_items: :end, bg: :gray)) do %>
54
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
55
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
56
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
53
+ # <%= render(Primer::FlexComponent.new(align_items: :end, bg: :tertiary)) do %>
54
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
55
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
56
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
57
57
  # <% end %>
58
58
  #
59
59
  # @example Direction column
60
- # <%= render(Primer::FlexComponent.new(direction: :column, bg: :gray)) do %>
61
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
62
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
63
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
60
+ # <%= render(Primer::FlexComponent.new(direction: :column, bg: :tertiary)) do %>
61
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
62
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
63
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
64
64
  # <% end %>
65
65
  #
66
66
  # @param justify_content [Symbol] Use this param to distribute space between and around flex items along the main axis of the container. <%= one_of(Primer::FlexComponent::JUSTIFY_CONTENT_OPTIONS) %>
@@ -3,7 +3,7 @@
3
3
  module Primer
4
4
  # Use the Heading component to wrap a component that will create a heading element
5
5
  class HeadingComponent < Primer::Component
6
- view_helper :heading
6
+ status :beta
7
7
 
8
8
  # @example Default
9
9
  # <%= render(Primer::HeadingComponent.new) { "H1 Text" } %>
@@ -16,7 +16,8 @@ module Primer
16
16
  orange: "Label--orange",
17
17
  purple: "Label--purple"
18
18
  }.freeze
19
- SCHEME_OPTIONS = SCHEME_MAPPINGS.keys << nil
19
+ DEPRECATED_SCHEME_OPTIONS = [:orange, :purple].freeze
20
+ SCHEME_OPTIONS = ([*SCHEME_MAPPINGS.keys, nil] - DEPRECATED_SCHEME_OPTIONS).freeze
20
21
 
21
22
  VARIANT_MAPPINGS = {
22
23
  large: "Label--large",
@@ -37,23 +38,18 @@ module Primer
37
38
  # <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "Default" } %>
38
39
  # <%= render(Primer::LabelComponent.new(title: "Label: Label", variant: :large)) { "Large" } %>
39
40
  #
40
- # @example Deprecated schemes
41
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :orange)) { "Orange" } %>
42
- # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :purple)) { "Purple" } %>
43
- #
44
41
  # @param title [String] `title` attribute for the component element.
45
42
  # @param scheme [Symbol] <%= one_of(Primer::LabelComponent::SCHEME_MAPPINGS.keys) %>
46
43
  # @param variant [Symbol] <%= one_of(Primer::LabelComponent::VARIANT_OPTIONS) %>
47
44
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
48
45
  def initialize(title:, scheme: nil, variant: nil, **system_arguments)
49
46
  @system_arguments = system_arguments
50
- @system_arguments[:bg] = :blue if scheme.nil?
51
47
  @system_arguments[:tag] ||= :span
52
48
  @system_arguments[:title] = title
53
49
  @system_arguments[:classes] = class_names(
54
50
  "Label",
55
51
  system_arguments[:classes],
56
- SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme)],
52
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, deprecated_values: DEPRECATED_SCHEME_OPTIONS)],
57
53
  VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant)]
58
54
  )
59
55
  end
@@ -3,8 +3,6 @@
3
3
  module Primer
4
4
  # Use Layout to build a main/sidebar layout.
5
5
  class LayoutComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
-
8
6
  # The main content
9
7
  #
10
8
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -5,27 +5,57 @@ module Primer
5
5
  class LinkComponent < Primer::Component
6
6
  status :beta
7
7
 
8
+ DEFAULT_VARIANT = :default
9
+ VARIANT_MAPPINGS = {
10
+ DEFAULT_VARIANT => "",
11
+ :primary => "Link--primary",
12
+ :secondary => "Link--secondary"
13
+ }.freeze
14
+
15
+ DEFAULT_TAG = :a
16
+ TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
17
+
8
18
  # @example Default
9
- # <%= render(Primer::LinkComponent.new(href: "http://www.google.com")) { "Link" } %>
19
+ # <%= render(Primer::LinkComponent.new(href: "#")) { "Link" } %>
10
20
  #
11
21
  # @example Muted
12
- # <%= render(Primer::LinkComponent.new(href: "http://www.google.com", muted: true)) { "Link" } %>
22
+ # <%= render(Primer::LinkComponent.new(href: "#", muted: true)) { "Link" } %>
23
+ #
24
+ # @example Variants
25
+ # <%= render(Primer::LinkComponent.new(href: "#", variant: :primary)) { "Primary" } %>
26
+ # <%= render(Primer::LinkComponent.new(href: "#", variant: :secondary)) { "Secondary" } %>
27
+ #
28
+ # @example Without underline
29
+ # <%= render(Primer::LinkComponent.new(href: "#", underline: false)) { "Link" } %>
13
30
  #
14
- # @param href [String] URL to be used for the Link
15
- # @param muted [Boolean] Uses light gray for Link color, and blue on hover
31
+ # @example Span as link
32
+ # <%= render(Primer::LinkComponent.new(tag: :span)) { "Span as a link" } %>
33
+ #
34
+ # @param tag [String] <%= one_of(Primer::LinkComponent::TAG_OPTIONS) %>
35
+ # @param href [String] URL to be used for the Link. Required if tag is `:a`. If the requirements are not met an error will be raised in non production environments. In production, an empty link element will be rendered.
36
+ # @param variant [Symbol] <%= one_of(Primer::LinkComponent::VARIANT_MAPPINGS.keys) %>
37
+ # @param muted [Boolean] Uses light gray for Link color, and blue on hover.
38
+ # @param underline [Boolean] Whether or not to underline the link.
16
39
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
17
- def initialize(href:, muted: false, **system_arguments)
40
+ def initialize(href: nil, tag: DEFAULT_TAG, variant: DEFAULT_VARIANT, muted: false, underline: true, **system_arguments)
18
41
  @system_arguments = system_arguments
19
- @system_arguments[:tag] = :a
42
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
20
43
  @system_arguments[:href] = href
21
44
  @system_arguments[:classes] = class_names(
22
45
  @system_arguments[:classes],
23
- "muted-link" => fetch_or_fallback_boolean(muted, false)
46
+ VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_MAPPINGS.keys, variant, DEFAULT_VARIANT)],
47
+ "Link" => tag == :span,
48
+ "Link--muted" => muted,
49
+ "no-underline" => !underline
24
50
  )
25
51
  end
26
52
 
27
53
  def call
28
54
  render(Primer::BaseComponent.new(**@system_arguments)) { content }
29
55
  end
56
+
57
+ def before_render
58
+ raise ArgumentError, "href is required when using <a> tag" if @system_arguments[:tag] == :a && @system_arguments[:href].nil? && !Rails.env.production?
59
+ end
30
60
  end
31
61
  end
@@ -3,8 +3,6 @@
3
3
  module Primer
4
4
  # Use menus to create vertical lists of navigational links.
5
5
  class MenuComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
-
8
6
  # Optional menu heading
9
7
  #
10
8
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -44,11 +42,11 @@ module Primer
44
42
  # Item 1
45
43
  # <% end %>
46
44
  # <% c.item(href: "#url") do %>
47
- # <%= render(Primer::OcticonComponent.new(icon: "check")) %>
45
+ # <%= render(Primer::OcticonComponent.new("check")) %>
48
46
  # With Icon
49
47
  # <% end %>
50
48
  # <% c.item(href: "#url") do %>
51
- # <%= render(Primer::OcticonComponent.new(icon: "check")) %>
49
+ # <%= render(Primer::OcticonComponent.new("check")) %>
52
50
  # With Icon and Counter
53
51
  # <%= render(Primer::CounterComponent.new(count: 25)) %>
54
52
  # <% end %>
@@ -0,0 +1,9 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <%= icon %>
3
+ <% if text.present? %>
4
+ <%= text %>
5
+ <% else %>
6
+ <%= content %>
7
+ <% end %>
8
+ <%= counter %>
9
+ <% end %>
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Navigation
5
+ # This component is part of navigation components such as `Primer::TabNavComponent`
6
+ # and `Primer::UnderlineNavComponent` and should not be used by itself.
7
+ class TabComponent < Primer::Component
8
+ # Panel controlled by the Tab. This will not render anything in the tab itself.
9
+ # It will provide a accessor for the Tab's parent to call and render the panel
10
+ # content in the appropriate place.
11
+ # Refer to `UnderlineNavComponent` and `TabNavComponent` implementations for examples.
12
+ #
13
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
14
+ renders_one :panel, lambda { |**system_arguments|
15
+ system_arguments[:tag] ||= :div
16
+ system_arguments[:role] ||= :tabpanel
17
+ system_arguments[:hidden] = true unless @selected
18
+
19
+ Primer::BaseComponent.new(**system_arguments)
20
+ }
21
+
22
+ # Icon to be rendered in the Tab left.
23
+ #
24
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
25
+ renders_one :icon, lambda { |icon = nil, **system_arguments|
26
+ system_arguments[:classes] = class_names(
27
+ @icon_classes,
28
+ system_arguments[:classes]
29
+ )
30
+ Primer::OcticonComponent.new(icon, **system_arguments)
31
+ }
32
+
33
+ # The Tab's text.
34
+ #
35
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::TextComponent) %>.
36
+ renders_one :text, Primer::TextComponent
37
+
38
+ # Counter to be rendered in the Tab right.
39
+ #
40
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::CounterComponent) %>.
41
+ renders_one :counter, Primer::CounterComponent
42
+
43
+ attr_reader :selected
44
+
45
+ # @example Default
46
+ # <%= render(Primer::Navigation::TabComponent.new(selected: true)) do |c| %>
47
+ # <% c.text { "Selected" } %>
48
+ # <% end %>
49
+ # <%= render(Primer::Navigation::TabComponent.new) do |c| %>
50
+ # <% c.text { "Not selected" } %>
51
+ # <% end %>
52
+ #
53
+ # @example With icons and counters
54
+ # <%= render(Primer::Navigation::TabComponent.new) do |c| %>
55
+ # <% c.icon(:star) %>
56
+ # <% c.text { "Tab" } %>
57
+ # <% end %>
58
+ # <%= render(Primer::Navigation::TabComponent.new) do |c| %>
59
+ # <% c.icon(:star) %>
60
+ # <% c.text { "Tab" } %>
61
+ # <% c.counter(count: 10) %>
62
+ # <% end %>
63
+ # <%= render(Primer::Navigation::TabComponent.new) do |c| %>
64
+ # <% c.text { "Tab" } %>
65
+ # <% c.counter(count: 10) %>
66
+ # <% end %>
67
+ #
68
+ # @example With custom HTML
69
+ # <%= render(Primer::Navigation::TabComponent.new) do |c| %>
70
+ # <div>
71
+ # This is my <strong>custom HTML</strong>
72
+ # </div>
73
+ # <% end %>
74
+ #
75
+ # @param selected [Boolean] Whether the Tab is selected or not.
76
+ # @param with_panel [Boolean] Whether the Tab has an associated panel.
77
+ # @param icon_classes [Boolean] Classes that must always be applied to icons.
78
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
79
+ def initialize(selected: false, with_panel: false, icon_classes: "", **system_arguments)
80
+ @selected = selected
81
+ @icon_classes = icon_classes
82
+ @system_arguments = system_arguments
83
+ @system_arguments[:role] = :tab
84
+
85
+ if with_panel
86
+ @system_arguments[:tag] ||= :button
87
+ @system_arguments[:type] = :button
88
+ else
89
+ @system_arguments[:tag] ||= :a
90
+ end
91
+
92
+ return unless @selected
93
+
94
+ if @system_arguments[:tag] == :a
95
+ @system_arguments[:"aria-current"] = :page
96
+ else
97
+ @system_arguments[:"aria-selected"] = true
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -3,7 +3,6 @@
3
3
  module Primer
4
4
  # Renders an [Octicon](https://primer.style/octicons/) with <%= link_to_system_arguments_docs %>.
5
5
  class OcticonComponent < Primer::Component
6
- view_helper :octicon
7
6
  status :beta
8
7
 
9
8
  include ClassNameHelper
@@ -19,19 +18,20 @@ module Primer
19
18
  SIZE_OPTIONS = SIZE_MAPPINGS.keys
20
19
 
21
20
  # @example Default
21
+ # <%= render(Primer::OcticonComponent.new("check")) %>
22
22
  # <%= render(Primer::OcticonComponent.new(icon: "check")) %>
23
23
  #
24
24
  # @example Medium
25
- # <%= render(Primer::OcticonComponent.new(icon: "people", size: :medium)) %>
25
+ # <%= render(Primer::OcticonComponent.new("people", size: :medium)) %>
26
26
  #
27
27
  # @example Large
28
- # <%= render(Primer::OcticonComponent.new(icon: "x", size: :large)) %>
28
+ # <%= render(Primer::OcticonComponent.new("x", size: :large)) %>
29
29
  #
30
30
  # @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
31
31
  # @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
32
32
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
33
- def initialize(icon:, size: SIZE_DEFAULT, **system_arguments)
34
- @icon = icon
33
+ def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, **system_arguments)
34
+ @icon = icon_name || icon
35
35
  @system_arguments = system_arguments
36
36
 
37
37
  @system_arguments[:class] = Primer::Classify.call(**@system_arguments)[:class]
@@ -1,10 +1,6 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <%= render body.component do %>
3
- <% if heading %>
4
- <%= render heading.component do %>
5
- <%= heading.content %>
6
- <% end %>
7
- <% end %>
8
- <%= body.content %>
2
+ <%= render(body_component) do %>
3
+ <%= heading %>
4
+ <%= body %>
9
5
  <% end %>
10
6
  <% end %>
@@ -5,38 +5,101 @@ module Primer
5
5
  #
6
6
  # By default, the popover renders with absolute positioning, meaning it should usually be wrapped in an element with a relative position in order to be positioned properly. To render the popover with relative positioning, use the relative property.
7
7
  class PopoverComponent < Primer::Component
8
- include ViewComponent::Slotable
8
+ status :beta
9
9
 
10
- with_slot :heading, class_name: "Heading"
11
- with_slot :body, class_name: "Body"
10
+ CARET_DEFAULT = :top
11
+ CARET_MAPPINGS = {
12
+ CARET_DEFAULT => "",
13
+ :bottom => "Popover-message--bottom",
14
+ :bottom_right => "Popover-message--bottom-right",
15
+ :bottom_left => "Popover-message--bottom-left",
16
+ :left => "Popover-message--left",
17
+ :left_bottom => "Popover-message--left-bottom",
18
+ :left_top => "Popover-message--left-top",
19
+ :right => "Popover-message--right",
20
+ :right_bottom => "Popover-message--right-bottom",
21
+ :right_top => "Popover-message--right-top",
22
+ :top_left => "Popover-message--top-left",
23
+ :top_right => "Popover-message--top-right"
24
+ }.freeze
25
+
26
+ # The heading
27
+ #
28
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
29
+ renders_one :heading, lambda { |**system_arguments|
30
+ system_arguments[:mb] ||= 2
31
+ system_arguments[:tag] ||= :h4
32
+
33
+ Primer::HeadingComponent.new(**system_arguments)
34
+ }
35
+
36
+ # The body
37
+ #
38
+ # @param caret [Symbol] <%= one_of(Primer::PopoverComponent::CARET_MAPPINGS.keys) %>
39
+ # @param large [Boolean] Whether to use the large version of the component.
40
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
41
+ renders_one :body, lambda { |caret: CARET_DEFAULT, large: false, **system_arguments, &block|
42
+ system_arguments[:classes] = class_names(
43
+ system_arguments[:classes],
44
+ "Popover-message Box",
45
+ CARET_MAPPINGS[fetch_or_fallback(CARET_MAPPINGS.keys, caret, CARET_DEFAULT)],
46
+ "Popover-message--large" => large
47
+ )
48
+ system_arguments[:p] ||= 4
49
+ system_arguments[:mt] ||= 2
50
+ system_arguments[:mx] ||= :auto
51
+ system_arguments[:text_align] ||= :left
52
+ system_arguments[:box_shadow] ||= :large
53
+
54
+ # This is a hack to allow the parent to set the slot's content
55
+ @body_arguments = system_arguments
56
+ view_context.capture { block&.call }
57
+ }
12
58
 
13
59
  # @example Default
14
60
  # <%= render Primer::PopoverComponent.new do |component| %>
15
- # <% component.slot(:heading) do %>
61
+ # <% component.heading do %>
16
62
  # Activity feed
17
63
  # <% end %>
18
- # <% component.slot(:body) do %>
64
+ # <% component.body do %>
19
65
  # This is the Popover body.
20
66
  # <% end %>
21
67
  # <% end %>
22
68
  #
23
69
  # @example Large
24
70
  # <%= render Primer::PopoverComponent.new do |component| %>
25
- # <% component.slot(:heading) do %>
71
+ # <% component.heading do %>
26
72
  # Activity feed
27
73
  # <% end %>
28
- # <% component.slot(:body, large: true) do %>
74
+ # <% component.body(large: true) do %>
29
75
  # This is the large Popover body.
30
76
  # <% end %>
31
77
  # <% end %>
32
78
  #
33
79
  # @example Caret position
34
80
  # <%= render Primer::PopoverComponent.new do |component| %>
35
- # <% component.slot(:heading) do %>
81
+ # <% component.heading do %>
36
82
  # Activity feed
37
83
  # <% end %>
38
- # <% component.slot(:body, caret: :left) do %>
39
- # This is the large Popover body.
84
+ # <% component.body(caret: :left) do %>
85
+ # This is the Popover body.
86
+ # <% end %>
87
+ # <% end %>
88
+ #
89
+ # @example With HTML body
90
+ # <%= render Primer::PopoverComponent.new do |component| %>
91
+ # <% component.heading do %>
92
+ # Activity feed
93
+ # <% end %>
94
+ # <% component.body(caret: :left) do %>
95
+ # <p> This is the Popover body.</p>
96
+ # <div>
97
+ # This is using HTML.
98
+ # <ul>
99
+ # <li>Thing #1</li>
100
+ # <li>Thing #2</li>
101
+ # </ul>
102
+ # </div>
40
103
  # <% end %>
41
104
  # <% end %>
42
105
  #
@@ -57,59 +120,8 @@ module Primer
57
120
  body.present?
58
121
  end
59
122
 
60
- # :nodoc:
61
- class Heading < Primer::Slot
62
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
63
- def initialize(**system_arguments)
64
- @system_arguments = system_arguments
65
- @system_arguments[:mb] ||= 2
66
- @system_arguments[:tag] ||= :h4
67
- end
68
-
69
- def component
70
- Primer::HeadingComponent.new(**@system_arguments)
71
- end
72
- end
73
-
74
- # :nodoc:
75
- class Body < Slot
76
- CARET_DEFAULT = :top
77
- CARET_MAPPINGS = {
78
- CARET_DEFAULT => "",
79
- :bottom => "Popover-message--bottom",
80
- :bottom_right => "Popover-message--bottom-right",
81
- :bottom_left => "Popover-message--bottom-left",
82
- :left => "Popover-message--left",
83
- :left_bottom => "Popover-message--left-bottom",
84
- :left_top => "Popover-message--left-top",
85
- :right => "Popover-message--right",
86
- :right_bottom => "Popover-message--right-bottom",
87
- :right_top => "Popover-message--right-top",
88
- :top_left => "Popover-message--top-left",
89
- :top_right => "Popover-message--top-right"
90
- }.freeze
91
-
92
- # @param caret [Symbol] <%= one_of(Primer::PopoverComponent::Body::CARET_MAPPINGS.keys) %>
93
- # @param large [Boolean] Whether to use the large version of the component.
94
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
95
- def initialize(caret: CARET_DEFAULT, large: false, **system_arguments)
96
- @system_arguments = system_arguments
97
- @system_arguments[:classes] = class_names(
98
- system_arguments[:classes],
99
- "Popover-message Box",
100
- CARET_MAPPINGS[fetch_or_fallback(CARET_MAPPINGS.keys, caret, CARET_DEFAULT)],
101
- "Popover-message--large" => large
102
- )
103
- @system_arguments[:p] ||= 4
104
- @system_arguments[:mt] ||= 2
105
- @system_arguments[:mx] ||= :auto
106
- @system_arguments[:text_align] ||= :left
107
- @system_arguments[:box_shadow] ||= :large
108
- end
109
-
110
- def component
111
- Primer::BoxComponent.new(**@system_arguments)
112
- end
123
+ def body_component
124
+ Primer::BoxComponent.new(**@body_arguments)
113
125
  end
114
126
  end
115
127
  end