primer_view_components 0.0.27 → 0.0.32

Sign up to get free protection for your applications and to get access to all the features.
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