primer_view_components 0.0.26 → 0.0.31

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -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 +6 -18
  15. data/app/components/primer/blankslate_component.html.erb +1 -5
  16. data/app/components/primer/blankslate_component.rb +2 -4
  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.rb +1 -0
  20. data/app/components/primer/component.rb +1 -13
  21. data/app/components/primer/counter_component.rb +17 -9
  22. data/app/components/primer/details_component.rb +1 -0
  23. data/app/components/primer/dropdown_menu_component.rb +2 -4
  24. data/app/components/primer/flash_component.html.erb +2 -2
  25. data/app/components/primer/flash_component.rb +2 -4
  26. data/app/components/primer/flex_component.rb +16 -16
  27. data/app/components/primer/heading_component.rb +1 -1
  28. data/app/components/primer/label_component.rb +5 -11
  29. data/app/components/primer/layout_component.html.erb +3 -9
  30. data/app/components/primer/layout_component.rb +30 -5
  31. data/app/components/primer/link_component.rb +37 -9
  32. data/app/components/primer/octicon_component.rb +4 -7
  33. data/app/components/primer/popover_component.html.erb +3 -7
  34. data/app/components/primer/popover_component.rb +76 -63
  35. data/app/components/primer/primer.d.ts +3 -0
  36. data/app/components/primer/primer.js +2 -0
  37. data/app/components/primer/primer.ts +2 -0
  38. data/app/components/primer/progress_bar_component.rb +6 -5
  39. data/app/components/primer/spinner_component.rb +2 -4
  40. data/app/components/primer/state_component.rb +2 -4
  41. data/app/components/primer/subhead_component.rb +2 -4
  42. data/app/components/primer/tab_container_component.d.ts +1 -0
  43. data/app/components/primer/text_component.rb +3 -1
  44. data/app/components/primer/time_ago_component.d.ts +1 -0
  45. data/app/components/primer/time_ago_component.js +1 -0
  46. data/app/components/primer/time_ago_component.rb +47 -0
  47. data/app/components/primer/time_ago_component.ts +1 -0
  48. data/app/components/primer/timeline_item_component.rb +2 -1
  49. data/app/components/primer/underline_nav_component.html.erb +5 -5
  50. data/app/components/primer/underline_nav_component.rb +24 -5
  51. data/app/lib/primer/classify.rb +13 -16
  52. data/app/lib/primer/classify/cache.rb +8 -3
  53. data/app/lib/primer/classify/functional_background_colors.rb +61 -0
  54. data/app/lib/primer/classify/functional_border_colors.rb +51 -0
  55. data/app/lib/primer/classify/functional_colors.rb +68 -0
  56. data/app/lib/primer/classify/functional_text_colors.rb +62 -0
  57. data/app/lib/primer/fetch_or_fallback_helper.rb +17 -4
  58. data/app/lib/primer/status/dsl.rb +43 -0
  59. data/app/lib/primer/test_selector_helper.rb +20 -0
  60. data/app/lib/primer/view_helper.rb +10 -12
  61. data/lib/primer/view_components/engine.rb +4 -0
  62. data/lib/primer/view_components/version.rb +1 -1
  63. data/static/statuses.json +1 -1
  64. metadata +37 -4
  65. data/app/lib/primer/view_helper/dsl.rb +0 -34
@@ -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
@@ -257,9 +252,11 @@ module Primer
257
252
  memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-n#{val.abs}"
258
253
  elsif key == BOX_SHADOW_KEY
259
254
  memo[:classes] << if val == true
260
- "box-shadow"
255
+ "color-shadow-small"
256
+ elsif val == :none || val.blank?
257
+ "box-shadow-none"
261
258
  else
262
- "box-shadow-#{val.to_s.dasherize}"
259
+ "color-shadow-#{val.to_s.dasherize}"
263
260
  end
264
261
  elsif key == VISIBILITY_KEY
265
262
  memo[:classes] << "v-#{val.to_s.dasherize}"
@@ -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(
@@ -96,7 +101,7 @@ module Primer
96
101
 
97
102
  preload(
98
103
  keys: Primer::Classify::BOX_SHADOW_KEY,
99
- values: [true, :medium, :large, :extra_large, :none]
104
+ values: [true, :small, :medium, :large, :extra_large, :none]
100
105
  )
101
106
 
102
107
  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,68 @@
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
+ sym_value = value.to_sym
33
+ dasherized_value = value.to_s.dasherize
34
+ # the value is a functional color
35
+ return "#{number_prefix}-#{dasherized_value}" if ends_with_number?(sym_value)
36
+ return "#{functional_prefix}-#{dasherized_value}" if functional_options.include?(sym_value)
37
+ # if the app still allows non functional colors
38
+ return "#{non_functional_prefix}-#{dasherized_value}" unless force_functional_colors?
39
+
40
+ if mappings.key?(sym_value) || options_without_mappigs.include?(sym_value)
41
+ functional_color = mappings[sym_value]
42
+ # colors without functional mapping stay the same
43
+ return "#{non_functional_prefix}-#{dasherized_value}" if functional_color.blank?
44
+
45
+ ActiveSupport::Deprecation.warn("#{key} #{value} is deprecated. Please use #{functional_color} instead.") unless Rails.env.production? || silence_deprecations?
46
+
47
+ return "#{functional_prefix}-#{functional_color.to_s.dasherize}"
48
+ end
49
+
50
+ raise ArgumentError, "#{key} #{value} does not exist." unless Rails.env.production?
51
+ end
52
+
53
+ def ends_with_number?(val)
54
+ char_code = val[-1].ord
55
+ char_code >= 48 && char_code <= 57
56
+ end
57
+
58
+ def force_functional_colors?
59
+ Rails.application.config.primer_view_components.force_functional_colors
60
+ end
61
+
62
+ def silence_deprecations?
63
+ Rails.application.config.primer_view_components.silence_deprecations
64
+ end
65
+ end
66
+ end
67
+ end
68
+ 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? || silence_deprecations?
33
+
25
34
  given_value
26
35
  else
27
36
  if fallback_raises && ENV["RAILS_ENV"] != "production" && ENV["STORYBOOK"] != "true"
@@ -46,5 +55,9 @@ module Primer
46
55
  fallback
47
56
  end
48
57
  end
58
+
59
+ def silence_deprecations?
60
+ Rails.application.config.primer_view_components.silence_deprecations
61
+ end
49
62
  end
50
63
  end
@@ -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
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Module to allow components to deal with the `test_selector` argument.
5
+ # It will only add the selector if env is not Production.
6
+ #
7
+ # test_selecotr: "foo" => data-test-selector="foo"
8
+ module TestSelectorHelper
9
+ TEST_SELECTOR_TAG = :test_selector
10
+
11
+ def add_test_selector(args)
12
+ if args.key?(TEST_SELECTOR_TAG) && !Rails.env.production?
13
+ args[:data] ||= {}
14
+ args[:data][TEST_SELECTOR_TAG] = args[TEST_SELECTOR_TAG]
15
+ end
16
+
17
+ args.except(TEST_SELECTOR_TAG)
18
+ end
19
+ end
20
+ end