playbook_ui 15.6.0 → 15.7.0.pre.alpha.play258013248

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +3 -2
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +4 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +95 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_colors_rails.html.erb +43 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_colors_rails.md +1 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.html.erb +11 -5
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.md +7 -1
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background.jsx +54 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background.md +9 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_multi.jsx +80 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_multi.md +3 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +4 -1
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +3 -1
  16. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +2 -2
  17. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +57 -0
  18. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +6 -0
  19. data/app/pb_kits/playbook/pb_card/docs/_card_header.md +1 -1
  20. data/app/pb_kits/playbook/pb_card/docs/_card_highlight.md +1 -1
  21. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.tsx +6 -0
  22. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +2 -2
  23. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleIcon.tsx +10 -8
  24. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_icons.jsx +0 -1
  25. data/app/pb_kits/playbook/pb_collapsible/docs/_collapsible_state.jsx +0 -3
  26. data/app/pb_kits/playbook/pb_contact/_contact.tsx +51 -24
  27. data/app/pb_kits/playbook/pb_contact/contact.html.erb +53 -19
  28. data/app/pb_kits/playbook/pb_contact/contact.rb +11 -1
  29. data/app/pb_kits/playbook/pb_contact/contact.test.js +76 -0
  30. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled.html.erb +33 -0
  31. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled.jsx +46 -0
  32. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled_rails.md +2 -0
  33. data/app/pb_kits/playbook/pb_contact/docs/_contact_unstyled_react.md +2 -0
  34. data/app/pb_kits/playbook/pb_contact/docs/example.yml +2 -0
  35. data/app/pb_kits/playbook/pb_contact/docs/index.js +1 -0
  36. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +24 -0
  37. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +197 -7
  38. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range_pattern_rails.html.erb +23 -14
  39. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range_pattern_rails.md +1 -1
  40. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +2 -1
  41. data/app/pb_kits/playbook/pb_dialog/dialog.html.erb +1 -1
  42. data/app/pb_kits/playbook/pb_dialog/dialog.rb +1 -0
  43. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +14 -0
  44. data/app/pb_kits/playbook/pb_dialog/dialog_header.html.erb +5 -4
  45. data/app/pb_kits/playbook/pb_dialog/dialog_header.rb +2 -0
  46. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.html.erb +24 -0
  47. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.jsx +60 -0
  48. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_closeable.md +3 -0
  49. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible.html.erb +71 -0
  50. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible.jsx +57 -0
  51. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible_rails.md +1 -0
  52. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_overflow_visible_react.md +1 -0
  53. data/app/pb_kits/playbook/pb_dialog/docs/example.yml +4 -0
  54. data/app/pb_kits/playbook/pb_dialog/docs/index.js +3 -1
  55. data/app/pb_kits/playbook/pb_distribution_bar/docs/_distribution_bar_custom_colors.md +1 -1
  56. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +316 -15
  57. data/app/pb_kits/playbook/pb_draggable/context/types.ts +1 -1
  58. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +7 -5
  59. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_default_dates.html.erb +19 -0
  60. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_rails.html.erb +12 -0
  61. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_rails.md +26 -0
  62. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_range_end_rails.html.erb +19 -0
  63. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_range_end_rails.md +1 -0
  64. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_default_rails.html.erb +30 -0
  65. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_default_rails.md +3 -0
  66. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_rails.html.erb +29 -0
  67. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_with_date_pickers_rails.md +13 -0
  68. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +3 -1
  69. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +5 -0
  70. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +4 -0
  71. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +39 -5
  72. data/app/pb_kits/playbook/pb_dropdown/index.js +171 -3
  73. data/app/pb_kits/playbook/pb_dropdown/quickpick_helper.rb +75 -0
  74. data/app/pb_kits/playbook/pb_filter/Filter/FilterBackground.tsx +3 -3
  75. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +9 -7
  76. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/index.js +3 -8
  77. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -1
  78. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +2 -1
  79. data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +14 -0
  80. data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.md +3 -0
  81. data/app/pb_kits/playbook/pb_form/docs/example.yml +1 -0
  82. data/app/pb_kits/playbook/pb_gauge/_gauge.tsx +6 -0
  83. data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +6 -0
  84. data/app/pb_kits/playbook/pb_popover/docs/_popover_append_to.html.erb +2 -2
  85. data/app/pb_kits/playbook/pb_popover/docs/_popover_append_to.jsx +3 -2
  86. data/app/pb_kits/playbook/pb_radio/docs/_radio_error.md +1 -1
  87. data/app/pb_kits/playbook/pb_select/_select.tsx +8 -3
  88. data/app/pb_kits/playbook/pb_select/docs/_select_error.md +1 -1
  89. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.html.erb +16 -0
  90. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.jsx +30 -0
  91. data/app/pb_kits/playbook/pb_select/docs/_select_input_options.md +1 -0
  92. data/app/pb_kits/playbook/pb_select/docs/example.yml +2 -0
  93. data/app/pb_kits/playbook/pb_select/docs/index.js +1 -0
  94. data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
  95. data/app/pb_kits/playbook/pb_select/select.rb +3 -1
  96. data/app/pb_kits/playbook/pb_select/select.test.js +23 -0
  97. data/app/pb_kits/playbook/pb_table/_table.tsx +187 -33
  98. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant.jsx +134 -0
  99. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant.md +34 -0
  100. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_rails.html.erb +101 -0
  101. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_rails.md +33 -0
  102. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination.jsx +180 -0
  103. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination.md +3 -0
  104. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination_rails.html.erb +122 -0
  105. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_with_pagination_rails.md +3 -0
  106. data/app/pb_kits/playbook/pb_table/docs/example.yml +4 -0
  107. data/app/pb_kits/playbook/pb_table/docs/index.js +2 -0
  108. data/app/pb_kits/playbook/pb_table/table.html.erb +68 -12
  109. data/app/pb_kits/playbook/pb_table/table.rb +22 -3
  110. data/app/pb_kits/playbook/pb_table/table.test.js +143 -0
  111. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +15 -3
  112. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.md +1 -1
  113. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_required_indicator.html.erb +6 -0
  114. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_required_indicator.jsx +25 -0
  115. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_required_indicator.md +3 -0
  116. data/app/pb_kits/playbook/pb_text_input/docs/example.yml +3 -0
  117. data/app/pb_kits/playbook/pb_text_input/docs/index.js +1 -0
  118. data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +6 -0
  119. data/app/pb_kits/playbook/pb_text_input/text_input.rb +2 -0
  120. data/app/pb_kits/playbook/pb_text_input/text_input.test.js +16 -0
  121. data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.md +1 -1
  122. data/app/pb_kits/playbook/pb_time_picker/_time_picker.scss +296 -0
  123. data/app/pb_kits/playbook/pb_time_picker/_time_picker.tsx +822 -0
  124. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_24_hour.html.erb +2 -0
  125. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_24_hour.jsx +16 -0
  126. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_24_hour.md +1 -0
  127. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default.html.erb +1 -0
  128. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default.jsx +13 -0
  129. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default.md +1 -0
  130. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default_time.html.erb +4 -0
  131. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default_time.jsx +29 -0
  132. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_default_time.md +1 -0
  133. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_disabled.html.erb +13 -0
  134. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_disabled.jsx +23 -0
  135. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_error.html.erb +5 -0
  136. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_error.jsx +15 -0
  137. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_input_options.html.erb +14 -0
  138. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_label.html.erb +2 -0
  139. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_label.jsx +15 -0
  140. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_min_max_time.html.erb +42 -0
  141. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_min_max_time.jsx +52 -0
  142. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_min_max_time.md +1 -0
  143. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_on_handler.jsx +45 -0
  144. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_on_handler.md +1 -0
  145. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_timezone.html.erb +3 -0
  146. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_timezone.jsx +21 -0
  147. data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_timezone.md +1 -0
  148. data/app/pb_kits/playbook/pb_time_picker/docs/example.yml +24 -0
  149. data/app/pb_kits/playbook/pb_time_picker/docs/index.js +9 -0
  150. data/app/pb_kits/playbook/pb_time_picker/index.ts +40 -0
  151. data/app/pb_kits/playbook/pb_time_picker/time_picker.html.erb +1 -0
  152. data/app/pb_kits/playbook/pb_time_picker/time_picker.rb +80 -0
  153. data/app/pb_kits/playbook/pb_time_picker/time_picker.test.jsx +114 -0
  154. data/app/pb_kits/playbook/pb_time_picker/time_picker_helper.ts +662 -0
  155. data/app/pb_kits/playbook/pb_timeline/_item.tsx +3 -0
  156. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.html.erb +60 -0
  157. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.jsx +118 -0
  158. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_show_current_year.md +1 -0
  159. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_date.md +1 -1
  160. data/app/pb_kits/playbook/pb_timeline/docs/example.yml +2 -0
  161. data/app/pb_kits/playbook/pb_timeline/docs/index.js +1 -0
  162. data/app/pb_kits/playbook/pb_timeline/item.html.erb +1 -1
  163. data/app/pb_kits/playbook/pb_timeline/item.rb +2 -0
  164. data/app/pb_kits/playbook/pb_timeline/label.html.erb +2 -1
  165. data/app/pb_kits/playbook/pb_timeline/label.rb +2 -0
  166. data/app/pb_kits/playbook/pb_timeline/subcomponents/Label.tsx +3 -0
  167. data/app/pb_kits/playbook/pb_timeline/timeline.test.js +51 -0
  168. data/app/pb_kits/playbook/tokens/_colors.scss +2 -1
  169. data/app/pb_kits/playbook/utilities/deprecated.ts +73 -0
  170. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -0
  171. data/dist/chunks/_typeahead-Ckz1ce-2.js +6 -0
  172. data/dist/chunks/lib-DxDBrGZX.js +29 -0
  173. data/dist/chunks/vendor.js +3 -3
  174. data/dist/menu.yml +16 -9
  175. data/dist/playbook-rails-react-bindings.js +1 -1
  176. data/dist/playbook-rails.js +1 -1
  177. data/dist/playbook.css +1 -1
  178. data/lib/playbook/forms/builder/collection_select_field.rb +9 -1
  179. data/lib/playbook/forms/builder/form_field_builder.rb +13 -2
  180. data/lib/playbook/forms/builder/select_field.rb +9 -1
  181. data/lib/playbook/forms/builder/time_picker_field.rb +24 -0
  182. data/lib/playbook/forms/builder/time_zone_select_field.rb +9 -1
  183. data/lib/playbook/forms/builder.rb +1 -0
  184. data/lib/playbook/pb_doc_helper.rb +3 -0
  185. data/lib/playbook/pb_kit_helper.rb +35 -0
  186. data/lib/playbook/version.rb +2 -2
  187. metadata +85 -4
  188. data/dist/chunks/_typeahead-DecTL7bt.js +0 -6
  189. data/dist/chunks/lib-Dk4GKPut.js +0 -29
@@ -184,3 +184,146 @@ test("when headerStyle is floating", () => {
184
184
  const kit = renderKit(Table, props, { headerStyle: "floating" })
185
185
  expect(kit).toHaveClass("pb_table table-sm table-responsive-collapse table-card header-floating table-collapse-sm")
186
186
  })
187
+
188
+ test("renders withFilter variant with Card wrapper", () => {
189
+ const { container } = render(
190
+ <Table
191
+ data={{testid: "table-with-filter"}}
192
+ filterContent={<div>{"Mock Filter"}</div>}
193
+ title="Test Table"
194
+ variant="withFilter"
195
+ >
196
+ <Table.Head>
197
+ <Table.Row>
198
+ <Table.Header>{"Column 1"}</Table.Header>
199
+ </Table.Row>
200
+ </Table.Head>
201
+ <Table.Body>
202
+ <Table.Row>
203
+ <Table.Cell>{"Value 1"}</Table.Cell>
204
+ </Table.Row>
205
+ </Table.Body>
206
+ </Table>
207
+ )
208
+
209
+ const card = container.querySelector('.pb_card_kit')
210
+ expect(card).toBeInTheDocument()
211
+ const filter = container.querySelector('.pb_filter_kit')
212
+ expect(filter).toBeInTheDocument()
213
+ })
214
+
215
+ test("renders title when provided with withFilter variant", () => {
216
+ render(
217
+ <Table
218
+ filterContent={<div>{"Mock Filter"}</div>}
219
+ title="Test Title"
220
+ variant="withFilter"
221
+ >
222
+ <Table.Head>
223
+ <Table.Row>
224
+ <Table.Header>{"Column 1"}</Table.Header>
225
+ </Table.Row>
226
+ </Table.Head>
227
+ <Table.Body>
228
+ <Table.Row>
229
+ <Table.Cell>{"Value 1"}</Table.Cell>
230
+ </Table.Row>
231
+ </Table.Body>
232
+ </Table>
233
+ )
234
+
235
+ expect(screen.getByText("Test Title")).toBeInTheDocument()
236
+ })
237
+
238
+ test("renders filter component in withFilter variant", () => {
239
+ const { container } = render(
240
+ <Table
241
+ filterContent={<div data-testid="test-filter">{"Filter inputs"}</div>}
242
+ variant="withFilter"
243
+ >
244
+ <Table.Head>
245
+ <Table.Row>
246
+ <Table.Header>{"Column 1"}</Table.Header>
247
+ </Table.Row>
248
+ </Table.Head>
249
+ <Table.Body>
250
+ <Table.Row>
251
+ <Table.Cell>{"Value 1"}</Table.Cell>
252
+ </Table.Row>
253
+ </Table.Body>
254
+ </Table>
255
+ )
256
+
257
+ const filter = container.querySelector('.pb_filter_kit')
258
+ expect(filter).toBeInTheDocument()
259
+ })
260
+
261
+ test("renders SectionSeparator between filter and table in withFilter variant", () => {
262
+ const { container } = render(
263
+ <Table
264
+ filterContent={<div>{"Filter content"}</div>}
265
+ variant="withFilter"
266
+ >
267
+ <Table.Head>
268
+ <Table.Row>
269
+ <Table.Header>{"Column 1"}</Table.Header>
270
+ </Table.Row>
271
+ </Table.Head>
272
+ <Table.Body>
273
+ <Table.Row>
274
+ <Table.Cell>{"Value 1"}</Table.Cell>
275
+ </Table.Row>
276
+ </Table.Body>
277
+ </Table>
278
+ )
279
+
280
+ const separator = container.querySelector('.pb_section_separator_kit')
281
+ expect(separator).toBeInTheDocument()
282
+ })
283
+
284
+ test("does not render title when not provided with withFilter variant", () => {
285
+ const { container } = render(
286
+ <Table
287
+ filterContent={<div>{"Filter content"}</div>}
288
+ variant="withFilter"
289
+ >
290
+ <Table.Head>
291
+ <Table.Row>
292
+ <Table.Header>{"Column 1"}</Table.Header>
293
+ </Table.Row>
294
+ </Table.Head>
295
+ <Table.Body>
296
+ <Table.Row>
297
+ <Table.Cell>{"Value 1"}</Table.Cell>
298
+ </Table.Row>
299
+ </Table.Body>
300
+ </Table>
301
+ )
302
+
303
+ const title = container.querySelector('.pb_title_kit')
304
+ expect(title).not.toBeInTheDocument()
305
+ })
306
+
307
+ test("renders default variant without Card wrapper", () => {
308
+ render(
309
+ <Table
310
+ data={{testid: "default-table"}}
311
+ variant="default"
312
+ >
313
+ <Table.Head>
314
+ <Table.Row>
315
+ <Table.Header>{"Column 1"}</Table.Header>
316
+ </Table.Row>
317
+ </Table.Head>
318
+ <Table.Body>
319
+ <Table.Row>
320
+ <Table.Cell>{"Value 1"}</Table.Cell>
321
+ </Table.Row>
322
+ </Table.Body>
323
+ </Table>
324
+ )
325
+
326
+ const table = screen.getByTestId("default-table")
327
+ expect(table).toBeInTheDocument()
328
+ expect(table.closest('.pb_card_kit')).not.toBeInTheDocument()
329
+ })
@@ -9,6 +9,7 @@ import Card from '../pb_card/_card'
9
9
  import Caption from '../pb_caption/_caption'
10
10
  import Body from '../pb_body/_body'
11
11
  import Icon from '../pb_icon/_icon'
12
+ import colors from '../tokens/exports/_colors.module.scss'
12
13
 
13
14
  import { INPUTMASKS } from './inputMask'
14
15
 
@@ -28,6 +29,7 @@ type TextInputProps = {
28
29
  onChange: (e: React.FormEvent<HTMLInputElement>, sanitizedValue?: string) => void,
29
30
  placeholder: string,
30
31
  required?: boolean,
32
+ requiredIndicator?: boolean,
31
33
  type: string,
32
34
  value: string | number,
33
35
  children: React.ReactElement,
@@ -60,6 +62,7 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
60
62
  type = 'text',
61
63
  value = '',
62
64
  children = null,
65
+ requiredIndicator = false,
63
66
  autoComplete = true,
64
67
  } = props
65
68
 
@@ -208,9 +211,18 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
208
211
  >
209
212
  {label && (
210
213
  <label htmlFor={id}>
211
- <Caption className="pb_text_input_kit_label"
212
- text={label}
213
- />
214
+ {
215
+ requiredIndicator ? (
216
+ <Caption className="pb_text_input_kit_label">
217
+ {label} <span style={{ color: `${colors.error}` }}>*</span>
218
+ </Caption>
219
+ ) : (
220
+ <Caption className="pb_text_input_kit_label"
221
+ text={label}
222
+ />
223
+ )
224
+ }
225
+
214
226
  </label>
215
227
  )}
216
228
  <div className={`${addOnCss} text_input_wrapper`}>
@@ -1 +1 @@
1
- Text Input w/ Error shows that the radio option must be selected or is invalid (ie when used in a form it signals a user to fix an error).
1
+ Text Input w/ Error shows that the input must be filled out (i.e. when used in a form it signals a user to fix an error).
@@ -0,0 +1,6 @@
1
+ <%= pb_rails("text_input", props: {
2
+ label: "First Name",
3
+ placeholder: "Enter first name",
4
+ id: "text_input_required_indicator",
5
+ required_indicator: true,
6
+ }) %>
@@ -0,0 +1,25 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import TextInput from '../../pb_text_input/_text_input'
4
+
5
+ const TextInputDefault = (props) => {
6
+ const [firstName, setFirstName] = useState('')
7
+ const handleOnChangeFirstName = ({ target }) => {
8
+ setFirstName(target.value)
9
+ }
10
+
11
+ return (
12
+ <TextInput
13
+ id="text_input_required_indicator"
14
+ label="First Name"
15
+ name="firstName"
16
+ onChange={handleOnChangeFirstName}
17
+ placeholder="Enter first name"
18
+ requiredIndicator
19
+ value={firstName}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ export default TextInputDefault
@@ -0,0 +1,3 @@
1
+ The `requiredIndicator`/`required_indicator` prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
2
+
3
+ You can use `requiredIndicator`/`required_indicator` with any validation approach: HTML5 validation via the `required` prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the `required` prop.
@@ -10,6 +10,8 @@ examples:
10
10
  - text_input_options: Input Options
11
11
  - text_input_mask: Mask
12
12
  - text_input_autocomplete: Autocomplete
13
+ - text_input_required_indicator: Required Indicator
14
+
13
15
 
14
16
  react:
15
17
  - text_input_default: Default
@@ -22,6 +24,7 @@ examples:
22
24
  - text_input_mask: Mask
23
25
  - text_input_sanitize: Sanitized Masked Input
24
26
  - text_input_autocomplete: Autocomplete
27
+ - text_input_required_indicator: Required Indicator
25
28
 
26
29
 
27
30
  swift:
@@ -8,3 +8,4 @@ export { default as TextInputNoLabel } from './_text_input_no_label.jsx'
8
8
  export { default as TextInputMask } from './_text_input_mask.jsx'
9
9
  export { default as TextInputSanitize } from './_text_input_sanitize.jsx'
10
10
  export { default as TextInputAutocomplete } from './_text_input_autocomplete.jsx'
11
+ export { default as TextInputRequiredIndicator } from './_text_input_required_indicator.jsx'
@@ -1,7 +1,13 @@
1
1
  <%= pb_content_tag(:div, id: nil ) do %>
2
2
  <% if object.label.present? %>
3
3
  <label for="<%= object.input_options[:id] || object.id %>" >
4
+ <% if object.required_indicator %>
5
+ <%= pb_rails("caption", props: { dark: object.dark, classname: "pb_text_input_kit_label" }) do %>
6
+ <%= object.label %><span style="color: #DA0014;"> *</span>
7
+ <% end %>
8
+ <% else %>
4
9
  <%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_text_input_kit_label" }) %>
10
+ <% end %>
5
11
  </label>
6
12
  <% end %>
7
13
  <%= content_tag(:div, class: "#{add_on_class} text_input_wrapper") do %>
@@ -38,6 +38,8 @@ module Playbook
38
38
  prop :mask, type: Playbook::Props::Enum,
39
39
  values: ["currency", "zip_code", "postal_code", "ssn", "credit_card", "cvv", nil],
40
40
  default: nil
41
+ prop :required_indicator, type: Playbook::Props::Boolean,
42
+ default: false
41
43
 
42
44
  def classname
43
45
  default_margin_bottom = margin_bottom.present? ? "" : " mb_sm"
@@ -344,3 +344,19 @@ test('does not add autocomplete attribute otherwise', () => {
344
344
  const input = within(kit).getByRole('textbox')
345
345
  expect(input).not.toHaveAttribute("autocomplete")
346
346
  })
347
+
348
+ test('renders required indicator asterisk when requiredIndicator is true', () => {
349
+ render(
350
+ <TextInput
351
+ data={{ testid: testId }}
352
+ label="Email Address"
353
+ requiredIndicator
354
+ />
355
+ )
356
+
357
+ const kit = screen.getByTestId(testId)
358
+ const label = within(kit).getByText(/Email Address/)
359
+
360
+ expect(label).toBeInTheDocument()
361
+ expect(kit).toHaveTextContent('*')
362
+ })
@@ -1 +1 @@
1
- Textarea w/ Error shows that the radio option must be selected or is invalid (ie when used in a form it signals a user to fix an error).
1
+ Textarea w/ Error shows that the input must be filled out (i.e. when used in a form it signals a user to fix an error).
@@ -0,0 +1,296 @@
1
+ @import "../tokens/typography";
2
+ @import "../tokens/spacing";
3
+ @import "../tokens/colors";
4
+ @import "../tokens/border_radius";
5
+ @import "../tokens/shadows";
6
+ @import "../tokens/positioning";
7
+ @import "../pb_body/body_mixins";
8
+
9
+ .pb_time_picker {
10
+ > label {
11
+ cursor: pointer;
12
+ display: block;
13
+ }
14
+
15
+ .time_picker_wrapper {
16
+ position: relative;
17
+ }
18
+
19
+ .text_input_wrapper_add_on .add-on-card {
20
+ transition: background-color 0.3s ease-in-out 0s;
21
+ border-color: $border_light;
22
+ }
23
+
24
+ .text_input_wrapper_add_on:focus-within .add-on-card {
25
+ transition: background-color 0.3s ease-in-out 0s, border-color 0.15s ease-in-out 0s;
26
+ border-color: $primary;
27
+ }
28
+
29
+ @media (hover: hover) {
30
+ &:hover {
31
+ .text_input_wrapper_add_on .add-on-card {
32
+ cursor: pointer;
33
+ background-color: rgba($focus_input_light, $opacity_5);
34
+ }
35
+ }
36
+ }
37
+
38
+ .text_input_wrapper_add_on .add-on-right .text_input {
39
+ cursor: pointer;
40
+ }
41
+
42
+ &.error {
43
+ .text_input_wrapper_add_on .add-on-card {
44
+ border-color: $error;
45
+ }
46
+
47
+ .text_input_wrapper_add_on:focus-within .add-on-card {
48
+ transition: background-color 0.3s ease-in-out 0s, border-color 0.15s ease-in-out 0s;
49
+ border-color: $error;
50
+ }
51
+ }
52
+
53
+ &.disabled {
54
+ > label {
55
+ cursor: not-allowed;
56
+ }
57
+
58
+ .text_input_wrapper_add_on .add-on-card {
59
+ background-color: shade($white, 5%);
60
+ cursor: not-allowed;
61
+ opacity: 0.5;
62
+ }
63
+
64
+ .text_input_wrapper_add_on .add-on-right .text_input {
65
+ cursor: not-allowed;
66
+ }
67
+
68
+ }
69
+
70
+ .pb_time_picker_container {
71
+ position: absolute;
72
+ top: 100%;
73
+ background-color: $white;
74
+ overflow: visible;
75
+ box-shadow: $shadow_deep;
76
+ border-radius: $border_rad_heavier;
77
+ border: 1px solid $border_light;
78
+ margin-top: $space_xxs;
79
+ z-index: $z_1;
80
+ width: 314.2px;
81
+
82
+ &.pb_time_picker_container_24hour {
83
+ width: 170.4px;
84
+ }
85
+
86
+ .pb_time_selection {
87
+ color: inherit;
88
+ text-align: left;
89
+ margin: $space_sm;
90
+ display: flex;
91
+ flex-wrap: wrap;
92
+ align-items: center;
93
+
94
+ .time_input_wrapper {
95
+ position: relative;
96
+ display: inline-flex;
97
+ flex-direction: column;
98
+ align-items: flex-start;
99
+
100
+ > label {
101
+ margin-bottom: $space_xxs;
102
+ cursor: pointer;
103
+ }
104
+
105
+ input.time_input {
106
+ border: 1px solid $border_light;
107
+ border-radius: $border_radius_md;
108
+ text-align: center;
109
+ width: 60px;
110
+ margin-left: 0;
111
+ padding: $space_xs;
112
+ height: 45px;
113
+ font-size: 14px;
114
+ font-weight: $bolder;
115
+ background-color: $white;
116
+ cursor: pointer;
117
+ transition: border-color 0.2s ease, background-color 0.2s ease;
118
+ color: $text_lt_default;
119
+
120
+ appearance: textfield;
121
+ -moz-appearance: textfield;
122
+ &::-webkit-outer-spin-button,
123
+ &::-webkit-inner-spin-button {
124
+ appearance: none;
125
+ -webkit-appearance: none;
126
+ margin: 0;
127
+ }
128
+
129
+ &:focus {
130
+ border-color: $primary;
131
+ outline: none;
132
+ }
133
+
134
+ &:hover {
135
+ background-color: $focus_input_light;
136
+ }
137
+
138
+ &.invalid {
139
+ border-color: $error;
140
+ background-color: rgba($error, 0.05);
141
+ }
142
+ }
143
+
144
+ // Time Selection Dropdowns
145
+ .time_dropdown {
146
+ position: absolute;
147
+ top: 100%;
148
+ left: 0;
149
+ background-color: $white;
150
+ border: 1px solid $border_light;
151
+ border-radius: $border_rad_heavier;
152
+ box-shadow: $shadow_deep;
153
+ margin-top: $space_xxs;
154
+ max-height: 200px;
155
+ overflow-y: auto;
156
+ overflow-x: hidden;
157
+ z-index: $z_1;
158
+ width: 60px;
159
+
160
+ // Firefox Scrollbar Styles
161
+ scrollbar-width: thin;
162
+ scrollbar-color: rgba($text_lt_lighter, 0.5) transparent;
163
+
164
+ // Chrome/Safari/Edge (WebKit) Scrollbar Styles
165
+ &::-webkit-scrollbar {
166
+ width: 6px;
167
+ }
168
+ &::-webkit-scrollbar-track {
169
+ background: transparent;
170
+ }
171
+ &::-webkit-scrollbar-thumb {
172
+ background-color: rgba($text_lt_lighter, 0.5);
173
+ border-radius: 3px;
174
+
175
+ &:hover {
176
+ background-color: rgba($text_lt_lighter, 0.7);
177
+ }
178
+ }
179
+
180
+ .time_dropdown_option {
181
+ @include pb_body;
182
+ padding: $space_xs $space_sm;
183
+ text-align: center;
184
+ cursor: pointer;
185
+ transition: background-color 0.15s ease;
186
+ white-space: nowrap;
187
+
188
+ &:hover {
189
+ background-color: $bg_light;
190
+ }
191
+
192
+ &.selected {
193
+ background-color: $primary;
194
+ color: $white;
195
+
196
+ &:hover {
197
+ background-color: $product_1_background;
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ .time_range_error {
205
+ width: 100%;
206
+ flex-basis: 100%;
207
+ .time_range_error_text {
208
+ color: $error;
209
+ }
210
+ }
211
+ .pb_caption_kit_xs {
212
+ clear: both;
213
+ display: block;
214
+ width: 100%;
215
+ flex-basis: 100%;
216
+ }
217
+ .time-separator {
218
+ padding: 20px 6px 0 6px;
219
+ font-size: 14px;
220
+ font-weight: $bolder;
221
+ }
222
+ .meridiem {
223
+ display: flex;
224
+ flex-direction: column;
225
+ align-items: flex-start;
226
+ margin-left: $space_md;
227
+
228
+ > .time_input_label {
229
+ margin-bottom: $space_xxs;
230
+ }
231
+
232
+ .pb_form_group_kit {
233
+ margin-left: 0;
234
+ display: flex;
235
+ gap: 0;
236
+ }
237
+
238
+ .datePicker-AMPM {
239
+ display: none;
240
+ }
241
+ &:focus, &:hover {
242
+ background: transparent;
243
+ }
244
+
245
+ // Override SelectableCard's display:none to make radio inputs keyboard accessible using visually-hidden pattern to keep inputs focusable but not visible
246
+ .pb_selectable_card_kit_enabled,
247
+ .pb_selectable_card_kit_checked_enabled,
248
+ .pb_selectable_card_kit_disabled,
249
+ .pb_selectable_card_kit_checked_disabled {
250
+ > input[type="radio"] {
251
+ display: block;
252
+ position: absolute;
253
+ width: 1px;
254
+ height: 1px;
255
+ padding: 0;
256
+ margin: -1px;
257
+ overflow: hidden;
258
+ clip: rect(0, 0, 0, 0);
259
+ white-space: nowrap;
260
+ border: 0;
261
+ }
262
+
263
+ > input[type="radio"]:focus + label {
264
+ border-color: $primary;
265
+ }
266
+ }
267
+
268
+ .pb_selectable_card_kit_enabled > label,
269
+ .pb_selectable_card_kit_checked_enabled > label,
270
+ .pb_selectable_card_kit_disabled > label,
271
+ .pb_selectable_card_kit_checked_disabled > label {
272
+ padding: 0;
273
+ margin: 0;
274
+ width: 60px;
275
+ height: 45px;
276
+ text-align: center;
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ font-weight: $bolder;
281
+ }
282
+
283
+ .disabled_meridiem > label,
284
+ .pb_selectable_card_kit_disabled > label,
285
+ .pb_selectable_card_kit_checked_disabled > label {
286
+ opacity: 0.5;
287
+ cursor: not-allowed;
288
+ background-color: $bg_light;
289
+ &:hover {
290
+ background-color: $bg_light;
291
+ }
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }