primer_view_components 0.0.23 → 0.0.28

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