primer_view_components 0.0.23 → 0.0.28

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -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/javascripts/primer_view_components.js.map.orig +5 -0
  6. data/app/assets/javascripts/primer_view_components.js.orig +6 -0
  7. data/app/components/primer/auto_complete_component.d.ts +1 -0
  8. data/app/components/primer/auto_complete_component.html.erb +5 -0
  9. data/app/components/primer/auto_complete_component.js +1 -0
  10. data/app/components/primer/auto_complete_component.rb +98 -0
  11. data/app/components/primer/auto_complete_component.ts +1 -0
  12. data/app/components/primer/auto_complete_item_component.rb +40 -0
  13. data/app/components/primer/avatar_component.rb +8 -9
  14. data/app/components/primer/base_component.rb +7 -15
  15. data/app/components/primer/blankslate_component.html.erb +1 -5
  16. data/app/components/primer/blankslate_component.rb +2 -0
  17. data/app/components/primer/border_box_component.rb +32 -6
  18. data/app/components/primer/box_component.rb +3 -5
  19. data/app/components/primer/breadcrumb_component.html.erb +1 -2
  20. data/app/components/primer/breadcrumb_component.rb +24 -12
  21. data/app/components/primer/component.rb +1 -13
  22. data/app/components/primer/counter_component.rb +17 -9
  23. data/app/components/primer/details_component.rb +3 -3
  24. data/app/components/primer/dropdown_menu_component.rb +2 -4
  25. data/app/components/primer/flash_component.html.erb +2 -2
  26. data/app/components/primer/flash_component.rb +2 -4
  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 +9 -9
  30. data/app/components/primer/layout_component.html.erb +3 -9
  31. data/app/components/primer/layout_component.rb +30 -5
  32. data/app/components/primer/link_component.rb +37 -9
  33. data/app/components/primer/octicon_component.rb +4 -7
  34. data/app/components/primer/popover_component.html.erb +3 -7
  35. data/app/components/primer/popover_component.rb +58 -62
  36. data/app/components/primer/primer.d.ts +3 -0
  37. data/app/components/primer/primer.js +2 -0
  38. data/app/components/primer/primer.ts +2 -0
  39. data/app/components/primer/progress_bar_component.html.erb +1 -1
  40. data/app/components/primer/progress_bar_component.rb +24 -27
  41. data/app/components/primer/spinner_component.rb +2 -4
  42. data/app/components/primer/state_component.rb +2 -4
  43. data/app/components/primer/subhead_component.rb +2 -0
  44. data/app/components/primer/tab_container_component.d.ts +1 -0
  45. data/app/components/primer/text_component.rb +3 -1
  46. data/app/components/primer/time_ago_component.d.ts +1 -0
  47. data/app/components/primer/time_ago_component.js +1 -0
  48. data/app/components/primer/time_ago_component.rb +47 -0
  49. data/app/components/primer/time_ago_component.ts +1 -0
  50. data/app/components/primer/timeline_item_component.rb +2 -1
  51. data/app/components/primer/underline_nav_component.html.erb +5 -5
  52. data/app/components/primer/underline_nav_component.rb +24 -5
  53. data/app/lib/primer/classify.rb +9 -14
  54. data/app/lib/primer/classify/cache.rb +7 -2
  55. data/app/lib/primer/classify/functional_background_colors.rb +61 -0
  56. data/app/lib/primer/classify/functional_border_colors.rb +51 -0
  57. data/app/lib/primer/classify/functional_colors.rb +66 -0
  58. data/app/lib/primer/classify/functional_text_colors.rb +62 -0
  59. data/app/lib/primer/fetch_or_fallback_helper.rb +13 -4
  60. data/app/lib/primer/status/dsl.rb +43 -0
  61. data/app/lib/primer/test_selector_helper.rb +20 -0
  62. data/app/lib/primer/view_helper.rb +9 -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 +37 -4
  67. data/app/lib/primer/view_helper/dsl.rb +0 -34
@@ -1,11 +1,11 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <% if actions && @align == :right %>
2
+ <% if @align == :right %>
3
3
  <%= actions %>
4
4
  <% end %>
5
- <%= render Primer::BaseComponent.new(tag: :ul, classes: "UnderlineNav-body list-style-none") do %>
6
- <%= body %>
7
- <% end %>
8
- <% if actions && @align == :left %>
5
+
6
+ <%= body %>
7
+
8
+ <% if @align == :left %>
9
9
  <%= actions %>
10
10
  <% end %>
11
11
  <% end %>
@@ -5,27 +5,46 @@ module Primer
5
5
  # underlined selected state, typically used for navigation placed at the top
6
6
  # of the page.
7
7
  class UnderlineNavComponent < Primer::Component
8
+ include ViewComponent::SlotableV2
9
+
8
10
  ALIGN_DEFAULT = :left
9
11
  ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
10
12
 
11
- with_content_areas :body, :actions
13
+ # Use the body for the navigation items
14
+ #
15
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
16
+ renders_one :body, lambda { |**system_arguments|
17
+ system_arguments[:classes] = class_names("UnderlineNav-body", "list-style-none", system_arguments[:classes])
18
+ system_arguments[:tag] ||= :ul
19
+
20
+ Primer::BaseComponent.new(**system_arguments) { content }
21
+ }
22
+
23
+ # Use actions for a call to action
24
+ #
25
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
26
+ renders_one :actions, lambda { |**system_arguments|
27
+ system_arguments[:tag] ||= :div
28
+ system_arguments[:classes] = class_names("UnderlineNav-actions", system_arguments[:classes])
29
+ Primer::BaseComponent.new(**system_arguments) { content }
30
+ }
12
31
 
13
32
  # @example Default
14
33
  # <%= render(Primer::UnderlineNavComponent.new) do |component| %>
15
- # <% component.with(:body) do %>
34
+ # <% component.body do %>
16
35
  # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
17
36
  # <% end %>
18
- # <% component.with(:actions) do %>
37
+ # <% component.actions do %>
19
38
  # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
20
39
  # <% end %>
21
40
  # <% end %>
22
41
  #
23
42
  # @example Align right
24
43
  # <%= render(Primer::UnderlineNavComponent.new(align: :right)) do |component| %>
25
- # <% component.with(:body) do %>
44
+ # <% component.body do %>
26
45
  # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
27
46
  # <% end %>
28
- # <% component.with(:actions) do %>
47
+ # <% component.actions do %>
29
48
  # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
30
49
  # <% end %>
31
50
  # <% end %>
@@ -17,7 +17,6 @@ module Primer
17
17
 
18
18
  INVALID_CLASS_NAME_PREFIXES =
19
19
  (["bg-", "color-", "text-", "d-", "v-align-", "wb-", "text-", "box-shadow-"] + CONCAT_KEYS.map { |k| "#{k}-" }).freeze
20
- FUNCTIONAL_COLOR_REGEX = /(primary|secondary|tertiary|link|success|warning|danger|info)/.freeze
21
20
 
22
21
  COLOR_KEY = :color
23
22
  BG_KEY = :bg
@@ -80,18 +79,20 @@ module Primer
80
79
  ]
81
80
  }
82
81
  }.freeze
83
- BORDER_KEYS = %i[border border_color].freeze
82
+ BORDER_KEY = :border
83
+ BORDER_COLOR_KEY = :border_color
84
84
  BORDER_MARGIN_KEYS = %i[border_top border_bottom border_left border_right].freeze
85
85
  BORDER_RADIUS_KEY = :border_radius
86
86
  TYPOGRAPHY_KEYS = [:font_size].freeze
87
87
  VALID_KEYS = (
88
88
  CONCAT_KEYS +
89
89
  BOOLEAN_MAPPINGS.keys +
90
- BORDER_KEYS +
91
90
  BORDER_MARGIN_KEYS +
92
91
  TYPOGRAPHY_KEYS +
93
92
  TEXT_KEYS +
94
93
  [
94
+ BORDER_KEY,
95
+ BORDER_COLOR_KEY,
95
96
  BORDER_RADIUS_KEY,
96
97
  COLOR_KEY,
97
98
  BG_KEY,
@@ -198,25 +199,17 @@ module Primer
198
199
  if val.to_s.start_with?("#")
199
200
  memo[:styles] << "background-color: #{val};"
200
201
  else
201
- memo[:classes] << "bg-#{val.to_s.dasherize}"
202
+ memo[:classes] << Primer::Classify::FunctionalBackgroundColors.color(val)
202
203
  end
203
204
  elsif key == COLOR_KEY
204
- char_code = val[-1].ord
205
- # Does this string end in a character that is NOT a number?
206
- memo[:classes] <<
207
- if (char_code >= 48 && char_code <= 57) || # 48 is the charcode for 0; 57 is the charcode for 9
208
- FUNCTIONAL_COLOR_REGEX.match?(val)
209
- "color-#{val.to_s.dasherize}"
210
- else
211
- "text-#{val.to_s.dasherize}"
212
- end
205
+ memo[:classes] << Primer::Classify::FunctionalTextColors.color(val)
213
206
  elsif key == DISPLAY_KEY
214
207
  memo[:classes] << "d#{breakpoint}-#{val.to_s.dasherize}"
215
208
  elsif key == VERTICAL_ALIGN_KEY
216
209
  memo[:classes] << "v-align-#{val.to_s.dasherize}"
217
210
  elsif key == WORD_BREAK_KEY
218
211
  memo[:classes] << "wb-#{val.to_s.dasherize}"
219
- elsif BORDER_KEYS.include?(key)
212
+ elsif key == BORDER_KEY
220
213
  border_value = if val == true
221
214
  "border"
222
215
  else
@@ -224,6 +217,8 @@ module Primer
224
217
  end
225
218
 
226
219
  memo[:classes] << border_value
220
+ elsif key == BORDER_COLOR_KEY
221
+ memo[:classes] << Primer::Classify::FunctionalBorderColors.color(val)
227
222
  elsif BORDER_MARGIN_KEYS.include?(key)
228
223
  memo[:classes] << "#{key.to_s.dasherize}-#{val}"
229
224
  elsif key == BORDER_RADIUS_KEY
@@ -50,8 +50,13 @@ module Primer
50
50
  )
51
51
 
52
52
  preload(
53
- keys: [Primer::Classify::COLOR_KEY, Primer::Classify::BG_KEY],
54
- values: [:blue, :gray_dark, :gray, :gray_light, :red, :orange, :orange_light, :yellow, :green, :purple, :white, :pink]
53
+ keys: [Primer::Classify::COLOR_KEY],
54
+ values: [*Primer::Classify::FunctionalTextColors::OPTIONS, *Primer::Classify::FunctionalTextColors::DEPRECATED_OPTIONS]
55
+ )
56
+
57
+ preload(
58
+ keys: [Primer::Classify::BG_KEY],
59
+ values: [*Primer::Classify::FunctionalBackgroundColors::OPTIONS, *Primer::Classify::FunctionalBackgroundColors::DEPRECATED_OPTIONS]
55
60
  )
56
61
 
57
62
  preload(
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Classify
5
+ # Background specific functional colors
6
+ # https://primer-css-git-mkt-color-modes-docs-primer.vercel.app/css/support/v16-migration#background
7
+ class FunctionalBackgroundColors < FunctionalColors
8
+ FUNCTIONAL_OPTIONS = {
9
+ primary: :primary,
10
+ secondary: :secondary,
11
+ tertiary: :tertiary,
12
+ canvas: :canvas,
13
+ canvas_inset: :canvas_inset,
14
+ canvas_inverse: :canvas_inverse,
15
+ info: :info,
16
+ info_inverse: :info_inverse,
17
+ success: :success,
18
+ success_inverse: :success_inverse,
19
+ warning: :warning,
20
+ warning_inverse: :warning_inverse,
21
+ danger: :danger,
22
+ danger_inverse: :danger_inverse,
23
+ overlay: :overlay
24
+ }.freeze
25
+
26
+ MAPPINGS = {
27
+ white: FUNCTIONAL_OPTIONS[:primary],
28
+ gray_light: FUNCTIONAL_OPTIONS[:secondary],
29
+ gray: FUNCTIONAL_OPTIONS[:tertiary],
30
+ gray_dark: FUNCTIONAL_OPTIONS[:canvas_inverse],
31
+ blue_light: FUNCTIONAL_OPTIONS[:info],
32
+ blue: FUNCTIONAL_OPTIONS[:info_inverse],
33
+ green_light: FUNCTIONAL_OPTIONS[:success],
34
+ green: FUNCTIONAL_OPTIONS[:success_inverse],
35
+ yellow_light: FUNCTIONAL_OPTIONS[:warning],
36
+ yellow: FUNCTIONAL_OPTIONS[:warning_inverse],
37
+ red_light: FUNCTIONAL_OPTIONS[:danger],
38
+ red: FUNCTIONAL_OPTIONS[:danger_inverse]
39
+ }.freeze
40
+
41
+ OPTIONS = FUNCTIONAL_OPTIONS.values.freeze
42
+ OPTIONS_WITHOUT_MAPPINGS = [:purple_light, :purple, :yellow_dark, :orange, :pink].freeze
43
+ DEPRECATED_OPTIONS = [*MAPPINGS.keys, *OPTIONS_WITHOUT_MAPPINGS].freeze
44
+
45
+ class << self
46
+ def color(val)
47
+ functional_color(
48
+ key: "background",
49
+ value: val,
50
+ mappings: MAPPINGS,
51
+ non_functional_prefix: "bg",
52
+ functional_prefix: "color-bg",
53
+ number_prefix: "bg",
54
+ functional_options: OPTIONS,
55
+ options_without_mappigs: OPTIONS_WITHOUT_MAPPINGS
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Classify
5
+ # Border specific functional colors
6
+ # https://primer-css-git-mkt-color-modes-docs-primer.vercel.app/css/support/v16-migration#border
7
+ class FunctionalBorderColors < FunctionalColors
8
+ FUNCTIONAL_OPTIONS = {
9
+ primary: :primary,
10
+ secondary: :secondary,
11
+ tertiary: :tertiary,
12
+ info: :info,
13
+ success: :success,
14
+ warning: :warning,
15
+ danger: :danger,
16
+ inverse: :inverse,
17
+ overlay: :overlay
18
+ }.freeze
19
+
20
+ MAPPINGS = {
21
+ gray: FUNCTIONAL_OPTIONS[:primary],
22
+ gray_light: FUNCTIONAL_OPTIONS[:secondary],
23
+ gray_dark: FUNCTIONAL_OPTIONS[:tertiary],
24
+ blue: FUNCTIONAL_OPTIONS[:info],
25
+ green: FUNCTIONAL_OPTIONS[:success],
26
+ yellow: FUNCTIONAL_OPTIONS[:warning],
27
+ red: FUNCTIONAL_OPTIONS[:danger],
28
+ white: FUNCTIONAL_OPTIONS[:inverse]
29
+ }.freeze
30
+
31
+ OPTIONS = FUNCTIONAL_OPTIONS.values.freeze
32
+ OPTIONS_WITHOUT_MAPPINGS = [:gray_darker, :blue_light, :red_light, :purple, :black_fade, :white_fade].freeze
33
+ DEPRECATED_OPTIONS = [*MAPPINGS.keys, *OPTIONS_WITHOUT_MAPPINGS].freeze
34
+
35
+ class << self
36
+ def color(val)
37
+ functional_color(
38
+ key: "border",
39
+ value: val,
40
+ mappings: MAPPINGS,
41
+ non_functional_prefix: "border",
42
+ functional_prefix: "color-border",
43
+ number_prefix: "border",
44
+ functional_options: OPTIONS,
45
+ options_without_mappigs: OPTIONS_WITHOUT_MAPPINGS
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Classify
5
+ # https://primer-css-git-mkt-color-modes-docs-primer.vercel.app/css/support/v16-migration
6
+ class FunctionalColors
7
+ class << self
8
+ def color(val)
9
+ # Implemented by class' childrens.
10
+ end
11
+
12
+ private
13
+
14
+ # @param key [String|Symbol] Option name.
15
+ # @param value [String|Symbol] Option value.
16
+ # @param mappings [Hash] A `color` => `functional_color` mapping hash.
17
+ # @param non_functional_prefix [String] The prefix to use for the non-functional color classes. E.g. "text" would create "text-value".
18
+ # @param functional_prefix [String] The prefix to use for the functional color classes. E.g. "color-text" would create "color-text-value".
19
+ # @param number_prefix [String] The prefix to use for colors ending with number. E.g. "text" would create "text-value-1".
20
+ # @param functional_options [Array] All the acceptable functional values.
21
+ # @param options_without_mappigs [Array] Non functional values that don't have an associated functional color.
22
+ def functional_color(
23
+ key:,
24
+ value:,
25
+ mappings:,
26
+ non_functional_prefix:,
27
+ functional_prefix: "",
28
+ number_prefix: "",
29
+ functional_options:,
30
+ options_without_mappigs: []
31
+ )
32
+ # the value is a functional color
33
+ return "#{number_prefix}-#{value.to_s.dasherize}" if ends_with_number?(value)
34
+ return "#{functional_prefix}-#{value.to_s.dasherize}" if functional_options.include?(value)
35
+ # if the app still allows non functional colors
36
+ return "#{non_functional_prefix}-#{value.to_s.dasherize}" unless force_functional_colors?
37
+
38
+ if mappings.key?(value) || options_without_mappigs.include?(value)
39
+ functional_color = mappings[value]
40
+ # colors without functional mapping stay the same
41
+ return "#{non_functional_prefix}-#{value.to_s.dasherize}" if functional_color.blank?
42
+
43
+ ActiveSupport::Deprecation.warn("#{key} #{value} is deprecated. Please use #{functional_color} instead.") unless Rails.env.production? || silence_color_deprecations?
44
+
45
+ return "#{functional_prefix}-#{functional_color.to_s.dasherize}"
46
+ end
47
+
48
+ raise ArgumentError, "#{key} #{value} does not exist." unless Rails.env.production?
49
+ end
50
+
51
+ def ends_with_number?(val)
52
+ char_code = val[-1].ord
53
+ char_code >= 48 && char_code <= 57
54
+ end
55
+
56
+ def force_functional_colors?
57
+ Rails.application.config.primer_view_components.force_functional_colors
58
+ end
59
+
60
+ def silence_color_deprecations?
61
+ Rails.application.config.primer_view_components.silence_color_deprecations
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ class Classify
5
+ # Text specific functional colors.
6
+ # https://primer-css-git-mkt-color-modes-docs-primer.vercel.app/css/support/v16-migration#text
7
+ class FunctionalTextColors < FunctionalColors
8
+ FUNCTIONAL_OPTIONS = {
9
+ primary: :text_primary,
10
+ secondary: :text_secondary,
11
+ tertiary: :text_tertiary,
12
+ link: :text_link,
13
+ success: :text_success,
14
+ warning: :text_warning,
15
+ danger: :text_danger,
16
+ white: :text_white,
17
+ inverse: :text_inverse
18
+ }.freeze
19
+
20
+ # colors mapping to `nil` will preserve the old classes.
21
+ # e.g. `text: :orange` will generate `text-orange`.
22
+ MAPPINGS = {
23
+ gray_dark: FUNCTIONAL_OPTIONS[:primary],
24
+ gray: FUNCTIONAL_OPTIONS[:secondary],
25
+ gray_light: FUNCTIONAL_OPTIONS[:tertiary],
26
+ blue: FUNCTIONAL_OPTIONS[:link],
27
+ green: FUNCTIONAL_OPTIONS[:success],
28
+ yellow: FUNCTIONAL_OPTIONS[:warning],
29
+ red: FUNCTIONAL_OPTIONS[:danger],
30
+ white: FUNCTIONAL_OPTIONS[:white]
31
+ }.freeze
32
+
33
+ OPTIONS = [
34
+ :icon_primary,
35
+ :icon_secondary,
36
+ :icon_tertiary,
37
+ :icon_info,
38
+ :icon_success,
39
+ :icon_warning,
40
+ :icon_danger,
41
+ *FUNCTIONAL_OPTIONS.values
42
+ ].freeze
43
+ OPTIONS_WITHOUT_MAPPINGS = [:black, :orange, :orange_light, :purple, :pink, :inherit].freeze
44
+ DEPRECATED_OPTIONS = [*MAPPINGS.keys, *OPTIONS_WITHOUT_MAPPINGS].freeze
45
+
46
+ class << self
47
+ def color(val)
48
+ functional_color(
49
+ key: "color",
50
+ value: val,
51
+ mappings: MAPPINGS,
52
+ non_functional_prefix: "text",
53
+ functional_prefix: "color",
54
+ number_prefix: "color",
55
+ functional_options: OPTIONS,
56
+ options_without_mappigs: OPTIONS_WITHOUT_MAPPINGS
57
+ )
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -6,13 +6,18 @@
6
6
  # Use this helper to quietly ensure a value is
7
7
  # one that you expect:
8
8
  #
9
- # allowed_values - allowed options for *value*
10
- # given_value - input being coerced
11
- # fallback - returned if *given_value* is not included in *allowed_values*
9
+ # allowed_values - allowed options for *value*
10
+ # given_value - input being coerced
11
+ # fallback - returned if *given_value* is not included in *allowed_values*
12
+ # deprecated_values - deprecated options for *value*. Will warn of deprecation if not in production
12
13
  #
13
14
  # fetch_or_fallback([1,2,3], 5, 2) => 2
14
15
  # fetch_or_fallback([1,2,3], 1, 2) => 1
15
16
  # fetch_or_fallback([1,2,3], nil, 2) => 2
17
+ #
18
+ # With deprecations:
19
+ # fetch_or_fallback([1,2], 3, 2, deprecated_values: [3]) => 3
20
+ # fetch_or_fallback([1,2], nil, 2, deprecated_values: [3]) => 2
16
21
  module Primer
17
22
  # :nodoc:
18
23
  module FetchOrFallbackHelper
@@ -20,8 +25,12 @@ module Primer
20
25
 
21
26
  InvalidValueError = Class.new(StandardError)
22
27
 
23
- def fetch_or_fallback(allowed_values, given_value, fallback = nil)
28
+ def fetch_or_fallback(allowed_values, given_value, fallback = nil, deprecated_values: [])
24
29
  if allowed_values.include?(given_value)
30
+ given_value
31
+ elsif deprecated_values.include?(given_value)
32
+ ActiveSupport::Deprecation.warn("#{given_value} is deprecated and will be removed in a future version.") unless Rails.env.production?
33
+
25
34
  given_value
26
35
  else
27
36
  if fallback_raises && ENV["RAILS_ENV"] != "production" && ENV["STORYBOOK"] != "true"
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Primer
6
+ # :nodoc:
7
+ module Status
8
+ # DSL to allow components to register their status.
9
+ #
10
+ # Example:
11
+ #
12
+ # class MyComponent < ViewComponent::Base
13
+ # include Primer::Status::Dsl
14
+ # status :beta
15
+ # end
16
+ module Dsl
17
+ extend ActiveSupport::Concern
18
+
19
+ STATUSES = {
20
+ alpha: :alpha,
21
+ beta: :beta,
22
+ stable: :stable,
23
+ deprecated: :deprecated
24
+ }.freeze
25
+
26
+ class UnknownStatusError < StandardError; end
27
+
28
+ included do
29
+ class_attribute :component_status, instance_writer: false, default: STATUSES[:alpha]
30
+ end
31
+
32
+ class_methods do
33
+ def status(status = nil)
34
+ return component_status if status.nil?
35
+
36
+ raise UnknownStatusError, "status #{status} does not exist" if STATUSES[status].nil?
37
+
38
+ self.component_status = STATUSES[status]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end