primer_view_components 0.0.25 → 0.0.30

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +90 -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 -14
  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.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 +3 -3
  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 +58 -62
  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