primer_view_components 0.0.104 → 0.0.105

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -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/assets/styles/primer_view_components.css +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/item.rb +2 -2
  8. data/app/components/primer/alpha/action_list.rb +2 -0
  9. data/app/components/primer/alpha/image.rb +50 -0
  10. data/app/components/primer/{image_crop.d.ts → alpha/image_crop.d.ts} +0 -0
  11. data/app/components/primer/{image_crop.html.erb → alpha/image_crop.html.erb} +0 -0
  12. data/app/components/primer/{image_crop.js → alpha/image_crop.js} +0 -0
  13. data/app/components/primer/alpha/image_crop.rb +39 -0
  14. data/app/components/primer/{image_crop.ts → alpha/image_crop.ts} +0 -0
  15. data/app/components/primer/alpha/nav_list/item.rb +2 -0
  16. data/app/components/primer/alpha/nav_list/section.rb +2 -0
  17. data/app/components/primer/alpha/segmented_control/item.html.erb +13 -0
  18. data/app/components/primer/alpha/segmented_control/item.rb +29 -0
  19. data/app/components/primer/alpha/segmented_control.css +1 -0
  20. data/app/components/primer/alpha/segmented_control.css.map +1 -0
  21. data/app/components/primer/alpha/segmented_control.d.ts +11 -0
  22. data/app/components/primer/alpha/segmented_control.html.erb +7 -0
  23. data/app/components/primer/alpha/segmented_control.js +48 -0
  24. data/app/components/primer/alpha/segmented_control.pcss +121 -0
  25. data/app/components/primer/alpha/segmented_control.rb +92 -0
  26. data/app/components/primer/alpha/segmented_control.ts +41 -0
  27. data/app/components/primer/alpha/tooltip.rb +2 -2
  28. data/app/components/primer/beta/auto_complete/item.rb +2 -2
  29. data/app/components/primer/beta/avatar.rb +1 -1
  30. data/app/components/primer/beta/blankslate.rb +4 -4
  31. data/app/components/primer/beta/breadcrumbs.rb +1 -1
  32. data/app/components/primer/beta/button.rb +1 -1
  33. data/app/components/primer/beta/label.rb +100 -0
  34. data/app/components/primer/beta/link.rb +99 -0
  35. data/app/components/primer/component.rb +1 -0
  36. data/app/components/primer/image.rb +2 -41
  37. data/app/components/primer/image_crop.rb +2 -32
  38. data/app/components/primer/label_component.rb +2 -93
  39. data/app/components/primer/link_component.rb +2 -92
  40. data/app/components/primer/primer.d.ts +2 -1
  41. data/app/components/primer/primer.js +2 -1
  42. data/app/components/primer/primer.pcss +1 -0
  43. data/app/components/primer/primer.ts +2 -1
  44. data/app/components/primer/subhead_component.rb +1 -1
  45. data/app/components/primer/time_ago_component.rb +2 -0
  46. data/app/helpers/primer/form_helper.rb +1 -0
  47. data/app/lib/primer/view_helper.rb +1 -1
  48. data/lib/primer/deprecations.rb +4 -0
  49. data/lib/primer/form_components.rb +1 -0
  50. data/lib/primer/view_components/linters/argument_mappers/label.rb +4 -4
  51. data/lib/primer/view_components/linters/label_component_migration_counter.rb +3 -3
  52. data/lib/primer/view_components/version.rb +1 -1
  53. data/lib/rubocop/config/default.yml +0 -3
  54. data/lib/rubocop/cop/primer/deprecated_label_schemes.rb +3 -3
  55. data/lib/rubocop/cop/primer/deprecated_label_variants.rb +5 -5
  56. data/lib/tasks/docs.rake +12 -7
  57. data/lib/tasks/test.rake +23 -26
  58. data/previews/primer/alpha/action_list_preview.rb +29 -0
  59. data/previews/primer/alpha/auto_complete_preview.rb +10 -0
  60. data/previews/primer/alpha/button_marketing_preview.rb +9 -0
  61. data/previews/primer/alpha/dialog_preview.rb +18 -1
  62. data/previews/primer/alpha/hidden_text_expander_preview.rb +7 -0
  63. data/previews/primer/alpha/image_crop_preview.rb +31 -0
  64. data/previews/primer/alpha/layout_preview.rb +15 -0
  65. data/previews/primer/alpha/nav_list_preview.rb +29 -0
  66. data/previews/primer/alpha/segmented_control_preview.rb +75 -0
  67. data/previews/primer/alpha/tab_panels_preview.rb +15 -0
  68. data/previews/primer/alpha/text_field_preview.rb +58 -0
  69. data/previews/primer/alpha/toggle_switch_preview.rb +4 -0
  70. data/previews/primer/alpha/tooltip_preview.rb +13 -3
  71. data/previews/primer/alpha/underline_nav_preview/playground.html.erb +8 -0
  72. data/previews/primer/alpha/underline_nav_preview.rb +15 -0
  73. data/previews/primer/alpha/underline_panels_preview.rb +15 -0
  74. data/previews/primer/beta/auto_complete_item_preview/playground.html.erb +9 -0
  75. data/previews/primer/beta/auto_complete_item_preview.rb +14 -0
  76. data/previews/primer/beta/auto_complete_preview.rb +20 -0
  77. data/previews/primer/beta/avatar_preview.rb +9 -0
  78. data/previews/primer/beta/avatar_stack_preview.rb +15 -0
  79. data/previews/primer/beta/base_button_preview.rb +9 -0
  80. data/previews/primer/beta/blankslate_preview.rb +12 -0
  81. data/previews/primer/beta/border_box_preview.rb +14 -0
  82. data/previews/primer/beta/breadcrumbs_preview.rb +11 -0
  83. data/previews/primer/beta/button_group_preview.rb +12 -0
  84. data/previews/primer/beta/close_button_preview.rb +7 -0
  85. data/previews/primer/beta/counter_preview.rb +11 -0
  86. data/previews/primer/beta/details_preview.rb +15 -0
  87. data/previews/primer/beta/flash_preview.rb +12 -0
  88. data/previews/primer/beta/heading_preview.rb +8 -0
  89. data/previews/primer/beta/label_preview.rb +26 -0
  90. data/previews/primer/beta/link_preview.rb +41 -0
  91. data/previews/primer/beta/text_preview.rb +8 -0
  92. data/previews/primer/beta/truncate_preview.rb +7 -0
  93. data/previews/primer/clipboard_copy_preview.rb +8 -0
  94. data/previews/primer/dropdown_preview.rb +18 -0
  95. data/previews/primer/hellip_button_preview.rb +8 -0
  96. data/previews/primer/layout_component_preview.rb +13 -1
  97. data/previews/primer/local_time_component_preview.rb +13 -0
  98. data/previews/primer/markdown_preview.rb +277 -266
  99. data/previews/primer/menu_component_preview/playground.html.erb +17 -0
  100. data/previews/primer/menu_component_preview.rb +4 -1
  101. data/previews/primer/octicon_component_preview.rb +8 -0
  102. data/previews/primer/popover_component_preview.rb +15 -1
  103. data/previews/primer/progress_bar_component_preview.rb +12 -1
  104. data/previews/primer/spinner_component_preview.rb +7 -0
  105. data/previews/primer/state_component_preview.rb +11 -1
  106. data/previews/primer/subhead_component_preview.rb +17 -0
  107. data/previews/primer/time_ago_component_preview.rb +8 -0
  108. data/previews/primer/timeline_item_component_preview.rb +12 -1
  109. data/static/arguments.json +300 -138
  110. data/static/audited_at.json +6 -0
  111. data/static/constants.json +86 -71
  112. data/static/statuses.json +10 -4
  113. metadata +27 -9
  114. data/previews/primer/image_crop_preview.rb +0 -22
  115. data/previews/primer/label_component_preview.rb +0 -15
  116. data/previews/primer/link_component_preview.rb +0 -29
@@ -0,0 +1,121 @@
1
+ /* SegmentedControl */
2
+
3
+ .SegmentedControl {
4
+ display: inline-flex;
5
+ list-style: none;
6
+ background-color: var(--color-segmented-control-bg);
7
+ border-radius: var(--primer-borderRadius-medium, 6px);
8
+ box-shadow: var(--primer-borderInset-thin, inset 0 0 0 max(1px, 0.0625rem)) var(--color-border-default);
9
+ }
10
+
11
+ .SegmentedControl-item {
12
+ position: relative;
13
+ display: inline-flex;
14
+ border: var(--primer-borderWidth-thin, max(1px, 0.0625rem)) solid transparent;
15
+ border-radius: var(--primer-borderRadius-medium, 6px);
16
+ padding: var(--primer-control-xsmall-paddingInline-condensed, 4px);
17
+
18
+ /* Selected ---------------------------------------- */
19
+ &.SegmentedControl-item--selected {
20
+ background-color: var(--color-btn-bg);
21
+ border-color: var(--color-segmented-control-button-selected-border);
22
+
23
+ & .Button {
24
+ font-weight: var(--base-text-weight-semibold, 600);
25
+
26
+ &:hover {
27
+ background-color: transparent;
28
+ }
29
+ }
30
+
31
+ &::before {
32
+ border-color: transparent;
33
+ }
34
+
35
+ & + .SegmentedControl-item::before {
36
+ border-color: transparent;
37
+ }
38
+ }
39
+
40
+ /* renders a visibly hidden "copy" of the text in bold, reserving box space for when text becomes bold on selected */
41
+ & .Button-label[data-content]::before {
42
+ display: block;
43
+ height: 0;
44
+ font-weight: var(--base-text-weight-semibold, 600);
45
+ visibility: hidden;
46
+ content: attr(data-content);
47
+ }
48
+
49
+ /* Separator lines */
50
+ &::before {
51
+ position: absolute;
52
+ inset: 0 0 0 -1px;
53
+ margin-top: var(--primer-control-medium-paddingBlock, 6px);
54
+ margin-bottom: var(--primer-control-medium-paddingBlock, 6px);
55
+ content: '';
56
+ border-left: var(--primer-borderWidth-thin, max(1px, 0.0625rem)) solid var(--color-border-default);
57
+ }
58
+
59
+ /* Button ----------------------------------------- */
60
+ & .Button {
61
+ border: 0;
62
+ font-weight: var(--base-text-weight-normal, 400);
63
+ transition: none;
64
+ color: var(--color-btn-text);
65
+
66
+ &:focus-visible {
67
+ outline-offset: calc(var(--primer-control-xsmall-paddingInline-condensed, 4px) - var(--primer-borderWidth-thin, 1px));
68
+ border-radius: calc(var(--primer-borderRadius-medium, 6px) - 5px);
69
+ }
70
+ }
71
+
72
+ & .Button--small {
73
+ height: calc(var(--primer-control-small-size, 28px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
74
+ padding: 0 calc(var(--primer-control-small-paddingInline-condensed, 8px) - var(--primer-control-xsmall-paddingInline-condensed, 4px));
75
+
76
+ &.Button--iconOnly {
77
+ width: calc(var(--primer-control-medium-size, 32px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
78
+ }
79
+ }
80
+
81
+ & .Button--medium {
82
+ height: calc(var(--primer-control-medium-size, 32px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
83
+ padding: 0 calc(var(--primer-control-medium-paddingInline-normal, 12px) - var(--primer-control-xsmall-paddingInline-condensed, 4px));
84
+
85
+ &.Button--iconOnly {
86
+ width: calc(var(--primer-control-medium-size, 32px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
87
+ }
88
+ }
89
+
90
+ & .Button--large {
91
+ height: calc(var(--primer-control-large-size, 40px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
92
+ padding: 0 calc(var(--primer-control-large-paddingInline-spacious, 16px) - var(--primer-control-xsmall-paddingInline-condensed, 4px));
93
+
94
+ &.Button--iconOnly {
95
+ width: calc(var(--primer-control-large-size, 40px) - var(--primer-control-xsmall-paddingInline-condensed, 4px) * 2 - var(--primer-borderWidth-thin, 1px) * 2);
96
+ }
97
+ }
98
+
99
+ & .Button--iconOnly {
100
+ padding: initial;
101
+ }
102
+
103
+ & .Button--invisible.Button--invisible-noVisuals .Button-label {
104
+ color: var(--color-btn-text);
105
+ }
106
+ }
107
+
108
+ /* fullWidth */
109
+ .SegmentedControl--fullWidth {
110
+ display: flex;
111
+
112
+ & .SegmentedControl-item {
113
+ flex: 1;
114
+ justify-content: center;
115
+ }
116
+
117
+ & .Button--iconOnly,
118
+ & .Button-withTooltip {
119
+ width: 100%;
120
+ }
121
+ }
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ # Use a segmented control to let users select an option from a short list and immediately apply the selection
6
+ class SegmentedControl < Primer::Component
7
+ status :alpha
8
+
9
+ FULL_WIDTH_DEFAULT = false
10
+ HIDE_LABELS_DEFAULT = false
11
+
12
+ # Use to render an item in the segmented control
13
+ #
14
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
15
+ renders_many :items, lambda { |label:, selected: false, icon: nil, **system_arguments|
16
+ Primer::Alpha::SegmentedControl::Item.new(
17
+ label: label,
18
+ selected: selected,
19
+ icon: icon,
20
+ hide_labels: @hide_labels,
21
+ size: @size,
22
+ block: @full_width,
23
+ **system_arguments
24
+ )
25
+ }
26
+
27
+ # @example Basic usage
28
+ #
29
+ # <%= render(Primer::Alpha::SegmentedControl.new) do |c| %>
30
+ # <%= c.with_item(label: "Preview", selected: true) %>
31
+ # <%= c.with_item(label: "Raw") %>
32
+ # <%= c.with_item(label: "Blame") %>
33
+ # <% end %>
34
+ #
35
+ # @example Small
36
+ #
37
+ # <%= render(Primer::Alpha::SegmentedControl.new(size: :small)) do |c| %>
38
+ # <%= c.with_item(label: "Preview", selected: true) %>
39
+ # <%= c.with_item(label: "Raw") %>
40
+ # <%= c.with_item(label: "Blame") %>
41
+ # <% end %>
42
+ #
43
+ # @example With icons
44
+ # <%= render(Primer::Alpha::SegmentedControl.new) do |c| %>
45
+ # <%= c.with_item(label: "Preview", icon: :eye, selected: true) %>
46
+ # <%= c.with_item(label: "Raw", icon: :"file-code") %>
47
+ # <%= c.with_item(label: "Blame", icon: :people) %>
48
+ # <% end %>
49
+ #
50
+ # @example With icons only
51
+ # <%= render(Primer::Alpha::SegmentedControl.new(hide_labels: true)) do |c| %>
52
+ # <%= c.with_item(label: "Preview", icon: :eye, selected: true) %>
53
+ # <%= c.with_item(label: "Raw", icon: :"file-code") %>
54
+ # <%= c.with_item(label: "Blame", icon: :people) %>
55
+ # <% end %>
56
+ #
57
+ # @example Fill width of parent
58
+ # <%= render(Primer::Alpha::SegmentedControl.new(full_width: true)) do |c| %>
59
+ # <%= c.with_item(label: "Preview", icon: :eye, selected: true) %>
60
+ # <%= c.with_item(label: "Raw", icon: :"file-code") %>
61
+ # <%= c.with_item(label: "Blame", icon: :people) %>
62
+ # <% end %>
63
+ #
64
+ # @param hide_labels [Boolean] Whether to hide the labels and only show the icons
65
+ # @param full_width [Boolean] If the component should be full width
66
+ # @param size [Symbol] <%= one_of(Primer::Beta::Button::SIZE_OPTIONS) %>
67
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
68
+ def initialize(hide_labels: HIDE_LABELS_DEFAULT, full_width: FULL_WIDTH_DEFAULT, size: Primer::Beta::Button::DEFAULT_SIZE, **system_arguments)
69
+ @full_width = full_width
70
+ @size = size
71
+ @hide_labels = hide_labels
72
+
73
+ @system_arguments = system_arguments
74
+ @system_arguments[:tag] = :ul
75
+ @system_arguments[:role] = "list"
76
+ @system_arguments[:classes] = class_names(
77
+ system_arguments[:classes],
78
+ "SegmentedControl",
79
+ "SegmentedControl--iconOnly": hide_labels,
80
+ "SegmentedControl--fullWidth": full_width
81
+ )
82
+ end
83
+
84
+ def render?
85
+ valid_items_count = items.count <= (@hide_labels ? 6 : 5) && items.count >= 2
86
+ raise ArgumentError, "A segmented control should have 2–5 choices with text labels, or up to 6 icon-only buttons." if !valid_items_count && !Rails.env.production?
87
+
88
+ valid_items_count
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,41 @@
1
+ import {controller, targets} from '@github/catalyst'
2
+
3
+ @controller
4
+ export class SegmentedControlElement extends HTMLElement {
5
+ @targets items: HTMLElement[]
6
+
7
+ connectedCallback() {
8
+ this.#updateButtonLabels()
9
+ }
10
+
11
+ select(event: Event) {
12
+ const button = event.currentTarget as HTMLButtonElement
13
+ for (const item of this.items) {
14
+ item.classList.remove('SegmentedControl-item--selected')
15
+ item.querySelector('[aria-current]')?.setAttribute('aria-current', 'false')
16
+ }
17
+
18
+ button.closest('li.SegmentedControl-item')?.classList.add('SegmentedControl-item--selected')
19
+ button.setAttribute('aria-current', 'true')
20
+ }
21
+
22
+ // Updates the button labels to have a data-content attribute with the text
23
+ // This is for selection styling to avoid the text jumping. It only needs to be
24
+ // setup when the component is first loaded.
25
+ #updateButtonLabels() {
26
+ for (const label of this.querySelectorAll('.Button-label')) {
27
+ label.setAttribute('data-content', label.textContent || '')
28
+ }
29
+ }
30
+ }
31
+
32
+ declare global {
33
+ interface Window {
34
+ SegmentedControlElement: typeof SegmentedControlElement
35
+ }
36
+ }
37
+
38
+ if (!window.customElements.get('segmented-control')) {
39
+ window.SegmentedControlElement = SegmentedControlElement
40
+ window.customElements.define('segmented-control', SegmentedControlElement)
41
+ }
@@ -7,12 +7,12 @@ module Primer
7
7
  #
8
8
  # When using a tooltip, follow the provided guidelines to avoid accessibility issues:
9
9
  # - Tooltips should contain only **non-essential text**. Tooltips can easily be missed and are not accessible on touch devices so never use tooltips to convey critical information.
10
- # - `Tooltip` should be rendered through the API of <%= link_to_component(Primer::ButtonComponent)%>, <%= link_to_component(Primer::LinkComponent)%>, or <%= link_to_component(Primer::IconButton)%>. Avoid using `Tooltip` a standalone component unless absolutely necessary (and **only** on interactive elements).
10
+ # - `Tooltip` should be rendered through the API of <%= link_to_component(Primer::ButtonComponent)%>, <%= link_to_component(Primer::Beta::Link)%>, or <%= link_to_component(Primer::IconButton)%>. Avoid using `Tooltip` a standalone component unless absolutely necessary (and **only** on interactive elements).
11
11
  # @accessibility
12
12
  # - Tooltip text must be brief and concise whether it is a label or a description.
13
13
  # - Tooltip can only hold string content.
14
14
  # - **Never set tooltips on static, non-interactive elements** like `span` or `div`. Tooltips should only be used on interactive elements like buttons or links to avoid excluding keyboard-only users
15
- # and screen reader users. Use of tooltip through <%= link_to_component(Primer::ButtonComponent) %>, <%= link_to_component(Primer::LinkComponent) %>, or <%= link_to_component(Primer::IconButton) %> will guarantee this.
15
+ # and screen reader users. Use of tooltip through <%= link_to_component(Primer::ButtonComponent) %>, <%= link_to_component(Primer::Beta::Link) %>, or <%= link_to_component(Primer::IconButton) %> will guarantee this.
16
16
  # - If you must use `Tooltip` as a standalone component, place it adjacent after the trigger element in the DOM. This allows screen reader users to navigate to and copy the tooltip
17
17
  # content.
18
18
  # ### Which type should I set?
@@ -22,10 +22,10 @@ module Primer
22
22
 
23
23
  # The trailing visual rendered after the link.
24
24
  #
25
- # @param kwargs [Hash] The arguments accepted by <%= link_to_component(Primer::OcticonComponent) %>, <%= link_to_component(Primer::LabelComponent) %>, or <%= link_to_component(Primer::Beta::Counter) %>
25
+ # @param kwargs [Hash] The arguments accepted by <%= link_to_component(Primer::OcticonComponent) %>, <%= link_to_component(Primer::Beta::Label) %>, or <%= link_to_component(Primer::Beta::Counter) %>
26
26
  renders_one :trailing_visual, types: {
27
27
  icon: Primer::OcticonComponent,
28
- label: Primer::LabelComponent,
28
+ label: Primer::Beta::Label,
29
29
  counter: Primer::Beta::Counter
30
30
  }
31
31
 
@@ -72,7 +72,7 @@ module Primer
72
72
 
73
73
  def call
74
74
  if @href
75
- render(Primer::LinkComponent.new(href: @href, classes: @system_arguments[:classes])) do
75
+ render(Primer::Beta::Link.new(href: @href, classes: @system_arguments[:classes])) do
76
76
  render(Primer::BaseComponent.new(**@system_arguments.except(:classes))) { content }
77
77
  end
78
78
  else
@@ -20,7 +20,7 @@ module Primer
20
20
  # Use:
21
21
  #
22
22
  # - `visual_icon` for an <%= link_to_component(Primer::OcticonComponent) %>.
23
- # - `visual_image` for an <%= link_to_component(Primer::Image) %>.
23
+ # - `visual_image` for an <%= link_to_component(Primer::Alpha::Image) %>.
24
24
  # - `visual_spinner` for a <%= link_to_component(Primer::SpinnerComponent) %>.
25
25
  #
26
26
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -40,7 +40,7 @@ module Primer
40
40
  system_arguments[:size] = "56x56"
41
41
  system_arguments[:classes] = class_names("blankslate-image", system_arguments[:classes])
42
42
 
43
- Primer::Image.new(**system_arguments)
43
+ Primer::Alpha::Image.new(**system_arguments)
44
44
  }
45
45
  }
46
46
 
@@ -83,7 +83,7 @@ module Primer
83
83
  system_arguments[:size] = :medium
84
84
  system_arguments[:scheme] ||= :primary
85
85
 
86
- Primer::ButtonComponent.new(**system_arguments) # rubocop:disable Primer/ComponentNameMigration
86
+ Primer::ButtonComponent.new(**system_arguments)
87
87
  }
88
88
 
89
89
  # Optional secondary action
@@ -96,7 +96,7 @@ module Primer
96
96
  renders_one :secondary_action, lambda { |href:, **system_arguments|
97
97
  system_arguments[:href] = href
98
98
 
99
- Primer::LinkComponent.new(**system_arguments)
99
+ Primer::Beta::Link.new(**system_arguments)
100
100
  }
101
101
 
102
102
  # @example Basic
@@ -73,7 +73,7 @@ module Primer
73
73
  end
74
74
 
75
75
  render(Primer::BaseComponent.new(**@system_arguments)) do
76
- render(Primer::LinkComponent.new(**link_arguments)) { content }
76
+ render(Primer::Beta::Link.new(**link_arguments)) { content }
77
77
  end
78
78
  end
79
79
  end
@@ -57,7 +57,7 @@ module Primer
57
57
  # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::Beta::Counter) %>.
58
58
  renders_one :trailing_visual, types: {
59
59
  icon: Primer::OcticonComponent,
60
- label: Primer::LabelComponent,
60
+ label: Primer::Beta::Label,
61
61
  counter: Primer::CounterComponent
62
62
  }
63
63
 
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # Use `Label` to add contextual metadata to a design.
6
+ #
7
+ # @accessibility
8
+ # Use `aria-label` if the `Label` or the context around it don't explain the label.
9
+ class Label < Primer::Component
10
+ status :beta
11
+
12
+ DEFAULT_TAG = :span
13
+ TAG_OPTIONS = [DEFAULT_TAG, :summary, :a, :div].freeze
14
+
15
+ DEFAULT_SCHEME = :default
16
+ SCHEME_MAPPINGS = {
17
+ DEFAULT_SCHEME => "",
18
+ :primary => "Label--primary",
19
+ :secondary => "Label--secondary",
20
+ :accent => "Label--accent",
21
+ :success => "Label--success",
22
+ :attention => "Label--attention",
23
+ :danger => "Label--danger",
24
+ :severe => "Label--severe",
25
+ :done => "Label--done",
26
+ :sponsors => "Label--sponsors",
27
+ # deprecated
28
+ :info => "Label--info",
29
+ :warning => "Label--warning",
30
+ :orange => "Label--orange",
31
+ :purple => "Label--purple"
32
+ }.freeze
33
+ DEPRECATED_SCHEME_OPTIONS = [:info, :warning, :orange, :purple].freeze
34
+ SCHEME_OPTIONS = (SCHEME_MAPPINGS.keys - DEPRECATED_SCHEME_OPTIONS).freeze
35
+
36
+ DEFAULT_SIZE = :medium
37
+ SIZE_MAPPINGS = {
38
+ DEFAULT_SIZE => nil,
39
+ :large => "Label--large"
40
+ }.freeze
41
+ SIZE_OPTIONS = SIZE_MAPPINGS.keys
42
+
43
+ DEFAULT_VARIANT = :none
44
+ VARIANT_OPTIONS = [DEFAULT_VARIANT].freeze
45
+ DEPRECATED_VARIANT_OPTIONS = [:large, :inline].freeze
46
+
47
+ INLINE_CLASS = "Label--inline"
48
+
49
+ # @example Schemes
50
+ # <%= render(Primer::Beta::Label.new) { "Default" } %>
51
+ # <%= render(Primer::Beta::Label.new(scheme: :primary)) { "Primary" } %>
52
+ # <%= render(Primer::Beta::Label.new(scheme: :secondary)) { "Secondary" } %>
53
+ # <%= render(Primer::Beta::Label.new(scheme: :accent)) { "Accent" } %>
54
+ # <%= render(Primer::Beta::Label.new(scheme: :success)) { "Success" } %>
55
+ # <%= render(Primer::Beta::Label.new(scheme: :attention)) { "Attention" } %>
56
+ # <%= render(Primer::Beta::Label.new(scheme: :danger)) { "Danger" } %>
57
+ # <%= render(Primer::Beta::Label.new(scheme: :severe)) { "Severe" } %>
58
+ # <%= render(Primer::Beta::Label.new(scheme: :done)) { "Done" } %>
59
+ # <%= render(Primer::Beta::Label.new(scheme: :sponsors)) { "Sponsors" } %>
60
+ #
61
+ # @example Sizes
62
+ # <%= render(Primer::Beta::Label.new) { "Medium" } %>
63
+ # <%= render(Primer::Beta::Label.new(size: :large)) { "Large" } %>
64
+ #
65
+ # @example Inline
66
+ # <%= render(Primer::Beta::Label.new) { "Default" } %>
67
+ # <%= render(Primer::Beta::Label.new(inline: true)) { "Inline" } %>
68
+ #
69
+ # @param tag [Symbol] <%= one_of(Primer::Beta::Label::TAG_OPTIONS) %>
70
+ # @param scheme [Symbol] <%= one_of(Primer::Beta::Label::SCHEME_MAPPINGS.keys) %>
71
+ # @param size [Symbol] <%= one_of(Primer::Beta::Label::SIZE_OPTIONS) %>
72
+ # @param inline [Boolean] Whether or not to render this label inline.
73
+ # @param variant [Symbol] <%= one_of(Primer::Beta::Label::VARIANT_OPTIONS + Primer::Beta::Label::DEPRECATED_VARIANT_OPTIONS) %>
74
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
75
+
76
+ def initialize(tag: DEFAULT_TAG, scheme: DEFAULT_SCHEME, size: DEFAULT_SIZE, inline: false, variant: DEFAULT_VARIANT, **system_arguments)
77
+ @system_arguments = system_arguments
78
+
79
+ @variant = fetch_or_fallback(VARIANT_OPTIONS, variant, nil, deprecated_values: DEPRECATED_VARIANT_OPTIONS)
80
+ @scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME, deprecated_values: DEPRECATED_SCHEME_OPTIONS)
81
+ @size = fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)
82
+ @size = :large if @variant == :large
83
+ @inline = inline || @variant == :inline
84
+
85
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
86
+ @system_arguments[:classes] = class_names(
87
+ "Label",
88
+ system_arguments[:classes],
89
+ SCHEME_MAPPINGS[@scheme],
90
+ SIZE_MAPPINGS[@size],
91
+ @inline ? INLINE_CLASS : nil
92
+ )
93
+ end
94
+
95
+ def call
96
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # Use `Link` for navigating from one page to another. `Link` styles anchor tags with default blue styling and hover text-decoration.
6
+ class Link < Primer::Component
7
+ status :beta
8
+
9
+ DEFAULT_SCHEME = :default
10
+ SCHEME_MAPPINGS = {
11
+ DEFAULT_SCHEME => "",
12
+ :primary => "Link--primary",
13
+ :secondary => "Link--secondary"
14
+ }.freeze
15
+
16
+ DEFAULT_TAG = :a
17
+ TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
18
+
19
+ # `Tooltip` that appears on mouse hover or keyboard focus over the link. Use tooltips sparingly and as a last resort.
20
+ # **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
21
+ # The tooltip will appear adjacent to the anchor element. Both the tooltip and the anchor will be nested
22
+ # under a positioning wrapper.
23
+ # Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information.
24
+ #
25
+ # @param type [Symbol] (:description) <%= one_of(Primer::Alpha::Tooltip::TYPE_OPTIONS) %>
26
+ # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::Alpha::Tooltip) %>.
27
+ renders_one :tooltip, lambda { |**system_arguments|
28
+ raise ArgumentError, "Links with a tooltip must have a unique `id` set on the `LinkComponent`." if @id.blank? && !Rails.env.production?
29
+
30
+ system_arguments[:for_id] = @id
31
+ system_arguments[:type] ||= :description
32
+
33
+ Primer::Alpha::Tooltip.new(**system_arguments)
34
+ }
35
+
36
+ # @example Default
37
+ # <%= render(Primer::Beta::Link.new(href: "#")) { "Link" } %>
38
+ #
39
+ # @example Muted
40
+ # <%= render(Primer::Beta::Link.new(href: "#", muted: true)) { "Link" } %>
41
+ #
42
+ # @example Schemes
43
+ # <%= render(Primer::Beta::Link.new(href: "#", scheme: :primary)) { "Primary" } %>
44
+ # <%= render(Primer::Beta::Link.new(href: "#", scheme: :secondary)) { "Secondary" } %>
45
+ #
46
+ # @example Without underline
47
+ # <%= render(Primer::Beta::Link.new(href: "#", underline: false)) { "Link" } %>
48
+ #
49
+ # @example With tooltip
50
+ # @description
51
+ # Use tooltips sparingly and as a last resort. Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information.
52
+ # @code
53
+ # <%= render(Primer::Beta::Link.new(href: "#", id: "link-with-tooltip")) do |c| %>
54
+ # <% c.with_tooltip(text: "Tooltip text") %>
55
+ # Link
56
+ # <% end %>
57
+ #
58
+ # @param tag [String] <%= one_of(Primer::Beta::Link::TAG_OPTIONS) %>
59
+ # @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.
60
+ # @param scheme [Symbol] <%= one_of(Primer::Beta::Link::SCHEME_MAPPINGS.keys) %>
61
+ # @param muted [Boolean] Uses light gray for Link color, and blue on hover.
62
+ # @param underline [Boolean] Whether or not to underline the link.
63
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
64
+ def initialize(href: nil, tag: DEFAULT_TAG, scheme: DEFAULT_SCHEME, muted: false, underline: true, **system_arguments)
65
+ @system_arguments = system_arguments
66
+
67
+ @id = @system_arguments[:id]
68
+
69
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
70
+ @system_arguments[:href] = href
71
+ @system_arguments[:classes] = class_names(
72
+ @system_arguments[:classes],
73
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)],
74
+ "Link" => tag == :span,
75
+ "Link--muted" => muted,
76
+ "no-underline" => !underline
77
+ )
78
+ end
79
+
80
+ def before_render
81
+ raise ArgumentError, "href is required when using <a> tag" if @system_arguments[:tag] == :a && @system_arguments[:href].nil? && !Rails.env.production?
82
+ end
83
+
84
+ def call
85
+ if tooltip.present?
86
+ render Primer::BaseComponent.new(tag: :span, position: :relative) do
87
+ render(Primer::BaseComponent.new(**@system_arguments)) do
88
+ content
89
+ end.to_s + tooltip.to_s
90
+ end
91
+ else
92
+ render(Primer::BaseComponent.new(**@system_arguments)) do
93
+ content
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -4,6 +4,7 @@ require "view_component/version"
4
4
 
5
5
  module Primer
6
6
  # @private
7
+ # :nocov:
7
8
  class Component < ViewComponent::Base
8
9
  include ViewComponent::SlotableV2 unless ViewComponent::Base < ViewComponent::SlotableV2
9
10
  include ViewComponent::PolymorphicSlots unless ViewComponent::Base < ViewComponent::PolymorphicSlots
@@ -1,46 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use `Image` to render images.
5
- #
6
- # @accessibility
7
- # Always provide a meaningful `alt`.
8
- class Image < Primer::Component
9
- # @example Default
10
- #
11
- # <%= render(Primer::Image.new(src: Primer::ExampleImage::BASE64_SRC, alt: "GitHub")) %>
12
- #
13
- # @example Helper
14
- #
15
- # <%= primer_image(src: Primer::ExampleImage::BASE64_SRC, alt: "GitHub") %>
16
- #
17
- # @example Lazy loading
18
- #
19
- # <%= render(Primer::Image.new(src: Primer::ExampleImage::BASE64_SRC, alt: "GitHub", lazy: true)) %>
20
- #
21
- # @example Custom size
22
- #
23
- # <%= render(Primer::Image.new(src: Primer::ExampleImage::BASE64_SRC, alt: "GitHub", height: 100, width: 100)) %>
24
- #
25
- # @param src [String] The source url of the image.
26
- # @param alt [String] Specifies an alternate text for the image.
27
- # @param lazy [Boolean] Whether or not to lazily load the image.
28
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
29
- def initialize(src:, alt:, lazy: false, **system_arguments)
30
- @system_arguments = deny_tag_argument(**system_arguments)
31
-
32
- @src = src
33
- @system_arguments[:tag] = :img
34
- @system_arguments[:alt] = alt
35
-
36
- return unless lazy
37
-
38
- @system_arguments[:loading] = :lazy
39
- @system_arguments[:decoding] = :async
40
- end
41
-
42
- def call
43
- render(Primer::BaseComponent.new(src: image_path(@src), **@system_arguments))
44
- end
4
+ class Image < Primer::Alpha::Image
5
+ status :deprecated
45
6
  end
46
7
  end
@@ -1,37 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # A client-side mechanism to crop images.
5
- class ImageCrop < Primer::Component
6
- # A loading indicator that is shown while the image is loading.
7
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
8
- renders_one :loading, lambda { |**system_arguments|
9
- deny_tag_argument(**system_arguments)
10
- system_arguments[:tag] = :div
11
- system_arguments[:"data-loading-slot"] = true
12
-
13
- Primer::BaseComponent.new(**system_arguments)
14
- }
15
-
16
- # @example Simple cropper
17
- # <%= render(Primer::ImageCrop.new(src: Primer::ExampleImage::BASE64_SRC)) %>
18
- #
19
- # @example Square cropper
20
- # <%= render(Primer::ImageCrop.new(src: Primer::ExampleImage::BASE64_SRC, rounded: false)) %>
21
- #
22
- # @example Cropper with a custom loader
23
- # <%= render(Primer::ImageCrop.new(src: Primer::ExampleImage::BASE64_SRC, rounded: false)) do |cropper| %>
24
- # <% cropper.with_loading(style: "width: 120px").with_content("Loading...") %>
25
- # <% end %>
26
- #
27
- # @param src [String] The path of the image to crop.
28
- # @param rounded [Boolean] If the crop mask should be a circle. Defaults to true.
29
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
30
- def initialize(src:, rounded: true, **system_arguments)
31
- @system_arguments = deny_tag_argument(**system_arguments)
32
- @system_arguments[:tag] = "image-crop"
33
- @system_arguments[:src] = src
34
- @system_arguments[:rounded] = true if rounded
35
- end
4
+ class ImageCrop < Primer::Alpha::ImageCrop
5
+ status :deprecated
36
6
  end
37
7
  end