playbook_ui 16.2.0.pre.alpha.faiconbuttonfix14520 → 16.2.0.pre.alpha.iconfixes14578

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_button/_button.scss +2 -3
  3. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +4 -1
  4. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -2
  5. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +2 -0
  6. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
  7. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +1 -1
  8. data/app/pb_kits/playbook/pb_icon/icon.rb +168 -19
  9. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -0
  10. data/app/pb_kits/playbook/pb_passphrase/_passphrase.tsx +4 -0
  11. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +2 -0
  12. data/app/pb_kits/playbook/pb_select/_select.tsx +2 -0
  13. data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
  14. data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +1 -1
  15. data/app/pb_kits/playbook/pb_star_rating/subcomponents/_star_rating_interactive.tsx +1 -0
  16. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +2 -0
  17. data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +2 -2
  18. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +4 -1
  19. data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +2 -2
  20. data/app/pb_kits/playbook/pb_textarea/textarea.test.js +1 -1
  21. data/app/pb_kits/playbook/pb_time_picker/_time_picker.tsx +6 -0
  22. data/app/pb_kits/playbook/pb_time_picker/time_picker.test.jsx +2 -2
  23. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +1 -1
  24. data/dist/chunks/{_typeahead-DXIBDeMj.js → _typeahead-COVN8XN7.js} +1 -1
  25. data/dist/chunks/vendor.js +3 -3
  26. data/dist/playbook-rails-react-bindings.js +1 -1
  27. data/dist/playbook-rails.js +1 -1
  28. data/dist/playbook.css +1 -1
  29. data/lib/playbook/forms/builder/checkbox_field.rb +1 -1
  30. data/lib/playbook/version.rb +1 -1
  31. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ab15b5936d85e9fe352d2293813967937694dc61e985fafb0ec9d21d6df752d
4
- data.tar.gz: 6bab9ca4069487ba52e762667f86f663a2a27c3c300c537a073996c9016cea49
3
+ metadata.gz: 7ea3eb503ddb54ca40d789a5d83867846c64bfb055c359b3fe0ee5997f9e33dd
4
+ data.tar.gz: 2404e05c9718ede9c7b72290b31d3e45e16d60bc66aad702bf6f6d042f1a7bf2
5
5
  SHA512:
6
- metadata.gz: 14144c41830ccabcc9cb3a7572e6197cd970ca4300b28aa2d4285ff06bae722b261f8613e50b38424caa67d801a9928a00abff1acb3bf2ebeef7355f9bf14f8a
7
- data.tar.gz: d6d1f2dc9c37b53d0211b5bccbd0cd2af1594c9cdf2b20eb907814ec40be28edcfc677bb0a2c27ecbb36d728c06aff220529a52d42d1b60152d60e9ab4400281
6
+ metadata.gz: 0ca2b19d3e4c25c13d1d7fe866f56fded40ae2aa264f1606fdad81210f115b19240317b6eb501de0451455acd1b020679cbb88226e105a2994b1b70a992840ee
7
+ data.tar.gz: 46a15f5b53ae54799987907fc916344790c9d35cbaf5b033530b1e30e1f58476cac3ed8fd938ca614a8ecce3b016c0a11d0cc0c211fb48258ee9a28cb9874f28
@@ -115,10 +115,9 @@ $pb_button_sizes: (
115
115
 
116
116
  // Icon-only button (icon prop set, no text) - square with equal padding
117
117
  // Rails: uses .pb_button_icon_only class
118
- // React: when pb_button_content is empty (no text). Do not match when content has
119
- // text + icon (e.g. "Exit Fullscreen" + FA icon) which can include empty spans.
118
+ // React: detects when pb_button_content has an empty text span
120
119
  &.pb_button_icon_only,
121
- &:has(.pb_button_content:empty) {
120
+ &:has(.pb_button_content > span:empty) {
122
121
  aspect-ratio: 1;
123
122
  min-width: auto;
124
123
  width: auto;
@@ -221,11 +221,14 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
221
221
  {!hideLabel && (
222
222
  <label htmlFor={pickerId}>
223
223
  {requiredIndicator ? (
224
- <Caption className="pb_date_picker_kit_label">
224
+ <Caption className="pb_date_picker_kit_label"
225
+ color="lighter"
226
+ >
225
227
  {label} <span style={{ color: `${colors.error}` }}>*</span>
226
228
  </Caption>
227
229
  ) : (
228
230
  <Caption className="pb_date_picker_kit_label"
231
+ color="lighter"
229
232
  text={label}
230
233
  />
231
234
  )}
@@ -7,11 +7,11 @@
7
7
  <% if !object.hide_label && object.label %>
8
8
  <label for="<%= object.picker_id %>">
9
9
  <% if object.required_indicator %>
10
- <%= pb_rails("caption", props: { dark: object.dark, classname: "pb_date_picker_kit_label" }) do %>
10
+ <%= pb_rails("caption", props: { dark: object.dark, classname: "pb_date_picker_kit_label", color: "lighter" }) do %>
11
11
  <%= object.label %><span style="color: #DA0014;"> *</span>
12
12
  <% end %>
13
13
  <% else %>
14
- <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_date_picker_kit_label" }) %>
14
+ <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_date_picker_kit_label", color: "lighter" }) %>
15
15
  <% end %>
16
16
  </label>
17
17
  <% end %>
@@ -479,6 +479,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
479
479
  {requiredIndicator ? (
480
480
  <Caption
481
481
  className="pb_dropdown_kit_label"
482
+ color="lighter"
482
483
  dark={dark}
483
484
  marginBottom="xs"
484
485
  >
@@ -487,6 +488,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
487
488
  ) : (
488
489
  <Caption
489
490
  className="pb_dropdown_kit_label"
491
+ color="lighter"
490
492
  dark={dark}
491
493
  marginBottom="xs"
492
494
  text={label}
@@ -2,11 +2,11 @@
2
2
  <% if object.label.present? %>
3
3
  <label for="<%= object.select_id %>" data-dropdown="pb-dropdown-label">
4
4
  <% if object.required_indicator %>
5
- <%= pb_rails("caption", props: { margin_bottom: "xs", classname: "pb_dropdown_kit_label", dark: object.dark }) do %>
5
+ <%= pb_rails("caption", props: { margin_bottom: "xs", classname: "pb_dropdown_kit_label", color: "lighter", dark: object.dark }) do %>
6
6
  <%= object.label %><span style="color: #DA0014;"> *</span>
7
7
  <% end %>
8
8
  <% else %>
9
- <%= pb_rails("caption", props: { text: object.label, margin_bottom: "xs", classname: "pb_dropdown_kit_label", dark: object.dark }) %>
9
+ <%= pb_rails("caption", props: { text: object.label, margin_bottom: "xs", classname: "pb_dropdown_kit_label", color: "lighter", dark: object.dark }) %>
10
10
  <% end %>
11
11
  </label>
12
12
  <% end %>
@@ -212,7 +212,7 @@ test('generated label prop', () => {
212
212
  )
213
213
 
214
214
  const kit = screen.getByTestId(testId)
215
- const label = kit.querySelector('.pb_caption_kit_md')
215
+ const label = kit.querySelector('.pb_caption_kit_md_lighter')
216
216
  expect(label).toHaveTextContent('Countries')
217
217
  })
218
218
 
@@ -2,10 +2,14 @@
2
2
 
3
3
  require "open-uri"
4
4
  require "json"
5
+ require "digest"
5
6
 
6
7
  module Playbook
7
8
  module PbIcon
8
9
  class Icon < Playbook::KitBase
10
+ ICON_PATH_DEV_CACHE_TTL_SECONDS = 2
11
+ ICON_PATH_PROD_CACHE_TTL_SECONDS = 60
12
+
9
13
  prop :border, type: Playbook::Props::Boolean,
10
14
  default: false
11
15
  prop :fixed_width, type: Playbook::Props::Boolean,
@@ -82,30 +86,35 @@ module Playbook
82
86
  )
83
87
  end
84
88
 
89
+ # Instance-level memoization of alias map lookup result
85
90
  def icon_alias_map
86
- return unless Rails.application.config.respond_to?(:icon_alias_path)
91
+ return @icon_alias_map if defined?(@icon_alias_map)
87
92
 
88
- base_path = Rails.application.config.icon_alias_path
89
- json = File.read(Rails.root.join(base_path))
90
- JSON.parse(json)["aliases"].freeze
93
+ @icon_alias_map = self.class.icon_alias_map
91
94
  end
92
95
 
96
+ # Instance-level memoization of resolved asset path
93
97
  def asset_path
94
- return unless Rails.application.config.respond_to?(:icon_path)
98
+ return @asset_path if defined?(@asset_path)
99
+
100
+ @asset_path =
101
+ if Rails.application.config.respond_to?(:icon_path)
102
+ resolved_icon = resolve_alias(icon)
103
+ path = self.class.icon_path_index[resolved_icon]
104
+ path if path && File.exist?(path)
105
+ end
106
+ end
107
+
108
+ def is_svg?
109
+ return @is_svg if defined?(@is_svg)
95
110
 
96
- base_path = Rails.application.config.icon_path
97
- resolved_icon = resolve_alias(icon)
98
- icon_path = Dir.glob(Rails.root.join(base_path, "**", "#{resolved_icon}.svg")).first
99
- icon_path if icon_path && File.exist?(icon_path)
111
+ @is_svg = (icon || custom_icon.to_s).include?(".svg") || asset_path.present?
100
112
  end
101
113
 
102
114
  def render_svg
103
115
  doc = Nokogiri::XML(URI.open(asset_path || icon || custom_icon)) # rubocop:disable Security/Open
104
- svg = doc.at_css "svg"
105
-
106
- unless svg
107
- return "" # Return an empty string if SVG element is not found
108
- end
116
+ svg = doc.at_css("svg")
117
+ return "" unless svg
109
118
 
110
119
  svg["class"] = %w[pb_custom_icon svg-inline--fa].concat([object.custom_icon_classname]).join(" ")
111
120
  svg["id"] = object.id
@@ -113,7 +122,9 @@ module Playbook
113
122
  svg["width"] = "auto"
114
123
  svg["tabindex"] = object.tabindex
115
124
  fill_color = object.color || "currentColor"
116
- doc.at_css("path")["fill"] = fill_color
125
+
126
+ # Safely apply fill to all paths (avoids nil errors + handles multi-path icons)
127
+ doc.css("path").each { |p| p["fill"] = fill_color }
117
128
 
118
129
  if object.data.present?
119
130
  object.data.each do |key, value|
@@ -135,14 +146,152 @@ module Playbook
135
146
  ""
136
147
  end
137
148
 
138
- def is_svg?
139
- (icon || custom_icon.to_s).include?(".svg") || asset_path.present?
149
+ # Class-level caches
150
+ class << self
151
+ @cache_mutex = Mutex.new
152
+
153
+ # Cache aliases.json across the process, but invalidate when the file changes (dev-safe)
154
+ def icon_alias_map
155
+ return @icon_alias_map if alias_cache_fresh?
156
+
157
+ cache_mutex.synchronize do
158
+ return @icon_alias_map if alias_cache_fresh?
159
+
160
+ @icon_alias_map =
161
+ if Rails.application.config.respond_to?(:icon_alias_path)
162
+ base_path = Rails.application.config.icon_alias_path
163
+ full_path = Rails.root.join(base_path)
164
+ @icon_alias_map_mtime = safe_mtime(full_path)
165
+
166
+ json = File.read(full_path)
167
+ parsed = JSON.parse(json)
168
+ parsed.fetch("aliases", {}).freeze
169
+ end
170
+ end
171
+
172
+ @icon_alias_map
173
+ end
174
+
175
+ # Cache an index of icon_name to file path for all SVGs in the configured directory, with invalidation based on directory mtime
176
+ # Avoids recursive Dir.glob for every icon render
177
+ def icon_path_index
178
+ return @icon_path_index if index_cache_fresh?
179
+
180
+ cache_mutex.synchronize do
181
+ return @icon_path_index if index_cache_fresh?
182
+
183
+ @icon_path_index =
184
+ if Rails.application.config.respond_to?(:icon_path)
185
+ base_path = Rails.application.config.icon_path
186
+ root = Rails.root.join(base_path)
187
+
188
+ # If path doesn't exist, keep behavior aligned (no path resolution)
189
+ if Dir.exist?(root)
190
+ @icon_path_index_cache_key = icon_path_cache_key(root)
191
+
192
+ # One scan builds the map for O(1) lookups
193
+ # Key is the filename (without .svg) to match existing usage
194
+ index = {}
195
+ Dir.glob(File.join(root.to_s, "**", "*.svg")).sort.each do |p|
196
+ name = File.basename(p, ".svg")
197
+ index[name] ||= p
198
+ end
199
+ index.freeze
200
+ else
201
+ @icon_path_index_cache_key = nil
202
+ {}
203
+ end
204
+ else
205
+ {}
206
+ end
207
+
208
+ @icon_path_index_checked_at = monotonic_now
209
+ end
210
+
211
+ @icon_path_index
212
+ end
213
+
214
+ private
215
+
216
+ def cache_mutex
217
+ @cache_mutex ||= Mutex.new
218
+ end
219
+
220
+ def alias_cache_fresh?
221
+ return false unless defined?(@icon_alias_map)
222
+
223
+ return true unless Rails.application.config.respond_to?(:icon_alias_path)
224
+
225
+ full_path = Rails.root.join(Rails.application.config.icon_alias_path)
226
+ safe_mtime(full_path) == @icon_alias_map_mtime
227
+ rescue
228
+ false
229
+ end
230
+
231
+ def index_cache_fresh?
232
+ return false unless defined?(@icon_path_index)
233
+
234
+ return true unless Rails.application.config.respond_to?(:icon_path)
235
+
236
+ # In development and production, skip re-checks for a short TTL window
237
+ # to avoid repeated tree scans on hot paths.
238
+ return true if Rails.env.development? && within_icon_index_ttl?(ICON_PATH_DEV_CACHE_TTL_SECONDS)
239
+ return true if Rails.env.production? && within_icon_index_ttl?(ICON_PATH_PROD_CACHE_TTL_SECONDS)
240
+
241
+ root = Rails.root.join(Rails.application.config.icon_path)
242
+ fresh = icon_path_cache_key(root) == @icon_path_index_cache_key
243
+ @icon_path_index_checked_at = monotonic_now
244
+ fresh
245
+ rescue
246
+ false
247
+ end
248
+
249
+ def within_icon_index_ttl?(ttl_seconds)
250
+ return false unless defined?(@icon_path_index_checked_at)
251
+
252
+ (monotonic_now - @icon_path_index_checked_at) < ttl_seconds
253
+ rescue
254
+ false
255
+ end
256
+
257
+ def monotonic_now
258
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
259
+ end
260
+
261
+ def icon_path_cache_key(root)
262
+ return safe_mtime(root) unless Rails.env.development? || Rails.env.production?
263
+
264
+ digest = Digest::SHA1.new
265
+ root_prefix = "#{root}/"
266
+
267
+ Dir.glob(File.join(root.to_s, "**", "*.svg")).sort.each do |path|
268
+ digest << path.delete_prefix(root_prefix)
269
+ next unless Rails.env.development?
270
+
271
+ # Development tracks file metadata for rapid local edits.
272
+ # Production only needs path-set change detection during periodic checks.
273
+ stat = File.stat(path)
274
+ digest << stat.mtime.to_f.to_s
275
+ digest << stat.size.to_s
276
+ end
277
+
278
+ digest.hexdigest
279
+ rescue
280
+ nil
281
+ end
282
+
283
+ def safe_mtime(path)
284
+ File.exist?(path) ? File.mtime(path) : nil
285
+ rescue
286
+ nil
287
+ end
140
288
  end
141
289
 
142
290
  private
143
291
 
144
292
  def resolve_alias(icon)
145
293
  return icon unless icon_alias_map
294
+ return icon if icon.nil?
146
295
 
147
296
  aliases = icon_alias_map[icon]
148
297
  return icon unless aliases
@@ -155,8 +304,8 @@ module Playbook
155
304
  end
156
305
 
157
306
  def file_exists?(alias_name)
158
- base_path = Rails.application.config.icon_path
159
- File.exist?(Dir.glob(Rails.root.join(base_path, "**", "#{alias_name}.svg")).first)
307
+ # Use the cached index (no recursive glob)
308
+ self.class.icon_path_index.key?(alias_name)
160
309
  end
161
310
 
162
311
  def svg_size
@@ -532,6 +532,7 @@ const MultiLevelSelect = forwardRef<HTMLInputElement, MultiLevelSelectProps>(
532
532
  {requiredIndicator ? (
533
533
  <Caption
534
534
  className="pb_multi_level_select_kit_label"
535
+ color="lighter"
535
536
  marginBottom="xs"
536
537
  >
537
538
  {label} <span className="required_indicator">*</span>
@@ -539,6 +540,7 @@ const MultiLevelSelect = forwardRef<HTMLInputElement, MultiLevelSelectProps>(
539
540
  ) : (
540
541
  <Caption
541
542
  className="pb_multi_level_select_kit_label"
543
+ color="lighter"
542
544
  marginBottom="xs"
543
545
  text={label}
544
546
  />
@@ -119,12 +119,14 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
119
119
  {hasLabel && (requiredIndicator ? (
120
120
  <Caption
121
121
  className="passphrase-label"
122
+ color="lighter"
122
123
  >
123
124
  {label} <span className="required_indicator">*</span>
124
125
  </Caption>
125
126
  ) : (
126
127
  <Caption
127
128
  className="passphrase-label"
129
+ color="lighter"
128
130
  text={label}
129
131
  />
130
132
  ))}
@@ -142,12 +144,14 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
142
144
  orientation="column"
143
145
  >
144
146
  <Caption
147
+ color="lighter"
145
148
  marginBottom="xs"
146
149
  text="Tips for a good passphrase"
147
150
  />
148
151
  <div>
149
152
  {tips.map((tip, i) => (
150
153
  <Caption
154
+ color="lighter"
151
155
  key={i}
152
156
  marginBottom="xs"
153
157
  size="xs"
@@ -262,6 +262,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
262
262
  {
263
263
  requiredIndicator ? (
264
264
  <Caption className="pb_text_input_kit_label"
265
+ color="lighter"
265
266
  marginBottom="xs"
266
267
  >
267
268
  {label} <span style={{ color: `${colors.error}` }}>*</span>
@@ -269,6 +270,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
269
270
  ) : (
270
271
  <Caption
271
272
  className="pb_text_input_kit_label"
273
+ color="lighter"
272
274
  marginBottom="xs"
273
275
  text={label}
274
276
  />
@@ -134,12 +134,14 @@ const Select = ({
134
134
  >
135
135
  {requiredIndicator ? (
136
136
  <Caption
137
+ color="lighter"
137
138
  dark={props.dark}>
138
139
  {label}
139
140
  <span style={{ color: "#DA0014" }}> *</span>
140
141
  </Caption>
141
142
  ) : (
142
143
  <Caption
144
+ color="lighter"
143
145
  dark={props.dark}
144
146
  text={label}
145
147
  />
@@ -4,11 +4,11 @@
4
4
  <% if object.label %>
5
5
  <label class="pb_select_kit_label" for="<%= object.input_options[:id] || object.name %>">
6
6
  <% if object.required_indicator %>
7
- <%= pb_rails("caption", props: { dark: object.dark }) do %>
7
+ <%= pb_rails("caption", props: { color: "lighter", dark: object.dark }) do %>
8
8
  <%= object.label %><span style="color: #DA0014;"> *</span>
9
9
  <% end %>
10
10
  <% else %>
11
- <%= pb_rails("caption", props: { text: object.label, dark: object.dark }) %>
11
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, dark: object.dark }) %>
12
12
  <% end %>
13
13
  </label>
14
14
  <% end %>
@@ -37,7 +37,7 @@
37
37
  <% else %>
38
38
  <%= pb_rails("flex", props: { data: {"pb-star-rating-wrapper": "true" }, orientation: "column" }) do %>
39
39
  <% if object.label.present? %>
40
- <%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %>
40
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, margin_bottom:"xs"}) %>
41
41
  <% end %>
42
42
 
43
43
  <%= hidden_input_tag %>
@@ -54,6 +54,7 @@ const StarRatingInteractive = (props: StarRatingInteractiveProps) => {
54
54
  {label &&
55
55
  <Caption
56
56
  className="pb_star_rating_kit_label"
57
+ color="lighter"
57
58
  marginBottom="xs"
58
59
  text={label}
59
60
  />
@@ -253,6 +253,7 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
253
253
  requiredIndicator ? (
254
254
  <Caption
255
255
  className="pb_text_input_kit_label"
256
+ color="lighter"
256
257
  dark={dark}
257
258
  >
258
259
  {label} <span style={{ color: dark ? colors.text_error_dark : colors.text_error }}>*</span>
@@ -260,6 +261,7 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
260
261
  ) : (
261
262
  <Caption
262
263
  className="pb_text_input_kit_label"
264
+ color="lighter"
263
265
  dark={dark}
264
266
  text={label}
265
267
  />
@@ -2,11 +2,11 @@
2
2
  <% if object.label.present? %>
3
3
  <label for="<%= object.input_options[:id] || object.id %>">
4
4
  <% if object.required_indicator %>
5
- <%= pb_rails("caption", props: { dark: object.dark, classname: "pb_text_input_kit_label" }) do %>
5
+ <%= pb_rails("caption", props: { dark: object.dark, classname: "pb_text_input_kit_label", color: "lighter" }) do %>
6
6
  <%= object.label %><span style="color: #DA0014;"> *</span>
7
7
  <% end %>
8
8
  <% else %>
9
- <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_text_input_kit_label" }) %>
9
+ <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_text_input_kit_label", color: "lighter" }) %>
10
10
  <% end %>
11
11
  </label>
12
12
  <% end %>
@@ -133,11 +133,14 @@ const Textarea = ({
133
133
  <label htmlFor={id}>
134
134
  {
135
135
  requiredIndicator ? (
136
- <Caption className="pb_text_input_kit_label">
136
+ <Caption className="pb_text_input_kit_label"
137
+ color="lighter"
138
+ >
137
139
  {label} <span style={{ color: `${colors.text_error}` }}>*</span>
138
140
  </Caption>
139
141
  ) : (
140
142
  <Caption className="pb_text_input_kit_label"
143
+ color="lighter"
141
144
  text={label}
142
145
  />
143
146
  )
@@ -2,11 +2,11 @@
2
2
  <% if object.label.present? %>
3
3
  <label for="<%= object.input_options[:id] || object.id %>" >
4
4
  <% if object.required_indicator %>
5
- <%= pb_rails("caption", props: { text: object.label, dark: object.dark }) do %>
5
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, dark: object.dark }) do %>
6
6
  <%= object.label %><span style="color: #DA0014;"> *</span>
7
7
  <% end %>
8
8
  <% else %>
9
- <%= pb_rails("caption", props: {text: object.label, dark: object.dark}) %>
9
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, dark: object.dark }) %>
10
10
  <% end %>
11
11
  </label>
12
12
  <% end %>
@@ -149,7 +149,7 @@ describe("TextArea Kit Props", () => {
149
149
  )
150
150
 
151
151
  const kit = screen.getByTestId(testId)
152
- const error = kit.querySelector(".pb_caption_kit_md")
152
+ const error = kit.querySelector(".pb_caption_kit_md_lighter")
153
153
 
154
154
  expect(error.innerHTML).toBe("Test Label")
155
155
  })
@@ -707,6 +707,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
707
707
  {requiredIndicator ? (
708
708
  <Caption
709
709
  className="pb_time_picker_kit_label"
710
+ color="lighter"
710
711
  dark={dark}
711
712
  marginBottom="xs"
712
713
  size="md"
@@ -716,6 +717,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
716
717
  ) : (
717
718
  <Caption
718
719
  className="pb_time_picker_kit_label"
720
+ color="lighter"
719
721
  dark={dark}
720
722
  marginBottom="xs"
721
723
  size="md"
@@ -766,6 +768,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
766
768
  <label htmlFor={`${uniqueId}-hour`}>
767
769
  <Caption
768
770
  className="time_input_label"
771
+ color="lighter"
769
772
  dark={dark}
770
773
  size="sm"
771
774
  text="Hour"
@@ -813,6 +816,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
813
816
  <label htmlFor={`${uniqueId}-minute`}>
814
817
  <Caption
815
818
  className="time_input_label"
819
+ color="lighter"
816
820
  dark={dark}
817
821
  size="sm"
818
822
  text="Minute"
@@ -859,6 +863,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
859
863
  <div className="meridiem">
860
864
  <Caption
861
865
  className="time_input_label"
866
+ color="lighter"
862
867
  dark={dark}
863
868
  size="sm"
864
869
  text="Period"
@@ -905,6 +910,7 @@ const TimePicker = (props: TimePickerProps): JSX.Element => {
905
910
  )}
906
911
  {showTimezone && (
907
912
  <Caption
913
+ color="lighter"
908
914
  dark={dark}
909
915
  lineHeight="tight"
910
916
  marginTop="sm"
@@ -71,14 +71,14 @@ describe('TimePicker', () => {
71
71
  render(<TimePicker data={{ testid: 'clickable-picker' }} />)
72
72
  const input = screen.getByPlaceholderText('Select Time')
73
73
  fireEvent.click(input)
74
- expect(screen.getByText('Hour', { selector: '.pb_caption_kit_sm' })).toBeInTheDocument()
74
+ expect(screen.getByText('Hour', { selector: '.pb_caption_kit_sm_lighter' })).toBeInTheDocument()
75
75
  })
76
76
 
77
77
  test('does not open dropdown on input click when disabled', () => {
78
78
  render(<TimePicker disabled />)
79
79
  const input = screen.getByPlaceholderText('Select Time')
80
80
  fireEvent.click(input)
81
- expect(screen.queryByText('Hour', { selector: '.pb_caption_kit_sm' })).not.toBeInTheDocument()
81
+ expect(screen.queryByText('Hour', { selector: '.pb_caption_kit_sm_lighter' })).not.toBeInTheDocument()
82
82
  })
83
83
 
84
84
  test('renders with required attribute', () => {
@@ -20,7 +20,7 @@ test('typeahead classname + label renders as expected', () => {
20
20
  )
21
21
 
22
22
  const kit = screen.getByTestId('typeahead-test')
23
- const label = kit.querySelector(".pb_caption_kit_md.pb_text_input_kit_label")
23
+ const label = kit.querySelector(".pb_caption_kit_md_lighter.pb_text_input_kit_label")
24
24
  expect(kit).toHaveClass("pb_typeahead_kit")
25
25
  expect(label).toHaveTextContent("Colors")
26
26
  })