playbook_ui 14.23.0.pre.alpha.PLAY2329atstickypinnedborderbug9151 → 14.23.0.pre.alpha.PLAY2329atstickypinnedborderbug9195

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8849282c22bb4870841f96e110bc89eaca2ed4e4dfbef18b709b6c2e93a701b
4
- data.tar.gz: 6d844177bce8a58692b5e383ceae03ea8c607e29e357c37c2931a0b9df9ee02d
3
+ metadata.gz: b96d3a0381d1287381a4e4710195c3de301ad5111d253b7696bcc924ee07d64b
4
+ data.tar.gz: a7edecaa9a5b25b1ade245fcc75f676b81afba59a1854de383e21455a59cd457
5
5
  SHA512:
6
- metadata.gz: a4cfa9a835da85fbd7af7c6c5aacabf227d5e01e284f748e71eceb2c5d1c7337336e1a69a8d00ffce7cd32b903b9c0fa18ce7644cfe1faeea85fb65d6f32727f
7
- data.tar.gz: 8821b2b62bfc362fb5b688ba476489d8284bd22734102d00829097f05024ac5400b11c22216d4a14d03abb60e9a03d2360b68804b726c5c7c8e6835278db93c8
6
+ metadata.gz: 423154dcdaf011bd7a264a4d8c99a8c39325369b06f1ff532b8441560efec2d5e160cd71280cc5666fa2cdf5dea1e442c434c7352fd940d148f83c346c3cda03
7
+ data.tar.gz: 29ed4759baa9ed51cc06f4aa1dc98996b9fed1ccb2b4da994be9cc4ef68055300cc19048751b7e8615a24ae9fd7930d129df8a60fc74ea02241b3213e0737b30
@@ -631,7 +631,6 @@
631
631
  // Specific fixes for vertical borders with sticky elements
632
632
  .pb_table.vertical-border {
633
633
 
634
- // Sticky header - apply borders to ALL cells including last
635
634
  &.sticky-header {
636
635
  thead th {
637
636
  border-right: 1px solid $border_light !important;
@@ -640,12 +639,10 @@
640
639
  }
641
640
  }
642
641
 
643
- // Regular pinned rows
644
642
  .pinned-row {
645
643
  td,
646
644
  .pb_table_td {
647
645
  border-right: 1px solid var(--column-border-color, $border_light) !important;
648
- // Ensure no unwanted borders
649
646
  border-left: none !important;
650
647
  border-top: none !important;
651
648
  }
@@ -679,12 +676,29 @@
679
676
  .pinned-row {
680
677
  td,
681
678
  .pb_table_td {
679
+ border: none !important;
680
+ // Use box-shadow for right border on ALL cells including last
681
+ box-shadow: inset -1px 0 0 0 var(--column-border-color, $border_light) !important;
682
+ }
683
+ }
684
+
685
+ // Override regular table cells to use consistent border method
686
+ &:not(.table-card) {
687
+ td:not(.pinned-row td),
688
+ .pb_table_td:not(.pinned-row .pb_table_td) {
689
+ // Remove conflicting borders and use box-shadow instead
682
690
  border-right: none !important;
683
691
  border-left: none !important;
684
692
  border-top: none !important;
685
- box-shadow: inset -1px 0 0 0 var(--column-border-color, $border_light) !important;
693
+ // Apply consistent right border using box-shadow
694
+ box-shadow: inset -1px 0 0 0 $border_light !important;
686
695
  }
687
696
  }
697
+
698
+ // Override the original left border shadow from main style, but keep other shadows
699
+ .pb_table_td:nth-child(2) {
700
+ box-shadow: none !important;
701
+ }
688
702
  }
689
703
  }
690
704
 
@@ -889,6 +903,7 @@
889
903
  .pinned-row {
890
904
  &.pb_table_tr,
891
905
  tr {
906
+ // Apply right border to ALL cells including last one in dark mode
892
907
  td,
893
908
  .pb_table_td {
894
909
  border-right: 1px solid var(--column-border-color, $border_dark) !important;
@@ -933,20 +948,35 @@
933
948
  .pinned-row {
934
949
  td,
935
950
  .pb_table_td {
951
+ border: none !important;
952
+ // Use box-shadow for right border on ALL cells including last
953
+ box-shadow: inset -1px 0 0 0 var(--column-border-color, $border_dark) !important;
954
+ }
955
+ }
956
+
957
+ // Override regular table cells to use consistent border method in dark mode
958
+ &:not(.table-card) {
959
+ td:not(.pinned-row td),
960
+ .pb_table_td:not(.pinned-row .pb_table_td) {
961
+ // Remove conflicting borders and use box-shadow instead
936
962
  border-right: none !important;
937
963
  border-left: none !important;
938
964
  border-top: none !important;
939
- box-shadow: inset -1px 0 0 0 var(--column-border-color, $border_dark) !important;
965
+ // Apply consistent right border using box-shadow
966
+ box-shadow: inset -1px 0 0 0 $border_dark !important;
940
967
  }
941
968
  }
969
+
970
+ // Override the original left border shadow from main CSS, but keep other shadows
971
+ .pb_table_td:nth-child(2) {
972
+ box-shadow: none !important;
973
+ }
942
974
  }
943
975
  }
944
976
 
945
977
  // Apply border colors in dark mode
946
978
  &[class*="column-group-border-"] {
947
- // For top-level column groups (ENROLLMENT DATA, PERFORMANCE DATA)
948
979
  .pb_advanced_table_header {
949
- // The main column group headers - NOT the last column
950
980
  > tr:first-child {
951
981
  th[colspan]:not([colspan="1"]):not(:last-child) {
952
982
  border-right: 1px solid var(--column-border-color) !important;
@@ -31,9 +31,8 @@
31
31
  border-radius: 0 0 0 0;
32
32
  }
33
33
 
34
+ // Only apply sticky positioning to specific elements
34
35
  .table-header-cells:first-child,
35
- td:first-child,
36
- .pb_table_td:first-child,
37
36
  .checkbox-cell.checkbox-cell-header:first-child,
38
37
  .table-header-cells.sticky-left,
39
38
  [class*="pinned-left"] {
@@ -44,11 +43,21 @@
44
43
  z-index: 2;
45
44
  }
46
45
 
46
+ // Only apply to pinned rows
47
+ .pinned-row {
48
+ td:first-child,
49
+ .pb_table_td:first-child {
50
+ background-color: $bg-main;
51
+ box-shadow: $shadow_deep !important;
52
+ position: sticky !important;
53
+ left: 0;
54
+ z-index: 3; // Higher z-index for pinned rows
55
+ }
56
+ }
57
+
47
58
  // For tables with verticalBorder, ensure sticky elements maintain their borders
48
59
  [class^="pb_table"].vertical-border {
49
60
  .table-header-cells:first-child,
50
- td:first-child,
51
- .pb_table_td:first-child,
52
61
  .checkbox-cell.checkbox-cell-header:first-child,
53
62
  .table-header-cells.sticky-left {
54
63
  // Maintain right border for vertical border styling when sticky
@@ -74,35 +83,47 @@
74
83
  }
75
84
 
76
85
  .bg-silver {
77
- td:first-child,
86
+ .table-header-cells:first-child,
87
+ .pinned-row td:first-child,
88
+ .pinned-row .pb_table_td:first-child,
78
89
  .sticky-left {
79
90
  background-color: $bg-secondary;
80
91
  }
81
92
  }
82
93
 
83
94
  .bg-row-selection {
84
- td:first-child,
95
+ .table-header-cells:first-child,
96
+ .pinned-row td:first-child,
97
+ .pinned-row .pb_table_td:first-child,
85
98
  .sticky-left {
86
99
  background-color: $highlight;
87
100
  }
88
101
  }
89
102
 
90
103
  .bg-white {
91
- td:first-child,
104
+ .table-header-cells:first-child,
105
+ .pinned-row td:first-child,
106
+ .pinned-row .pb_table_td:first-child,
92
107
  .sticky-left {
93
108
  background-color: $bg-main;
94
109
  }
95
110
  }
96
111
 
97
112
  .virtualized-table-row {
98
- &.bg-silver td:first-child {
99
- background-color: $bg-secondary;
113
+ &.bg-silver {
114
+ &.pinned-row td:first-child {
115
+ background-color: $bg-secondary;
116
+ }
100
117
  }
101
- &.bg-white td:first-child {
102
- background-color: $bg-main;
118
+ &.bg-white {
119
+ &.pinned-row td:first-child {
120
+ background-color: $bg-main;
121
+ }
103
122
  }
104
- &.bg-row-selection td:first-child {
105
- background-color: $highlight;
123
+ &.bg-row-selection {
124
+ &.pinned-row td:first-child {
125
+ background-color: $highlight;
126
+ }
106
127
  }
107
128
  }
108
129
 
@@ -140,14 +161,17 @@
140
161
 
141
162
  &.dark {
142
163
  .bg-row-selection {
143
- td:first-child,
164
+ .pinned-row td:first-child,
165
+ .pinned-row .pb_table_td:first-child,
144
166
  .sticky-left {
145
167
  background-color: $highlight-dark;
146
168
  }
147
169
  }
148
170
  .virtualized-table-row {
149
- &.bg-row-selection td:first-child {
150
- background-color: $highlight-dark;
171
+ &.bg-row-selection {
172
+ &.pinned-row td:first-child {
173
+ background-color: $highlight-dark;
174
+ }
151
175
  }
152
176
  }
153
177
  }
@@ -8,6 +8,7 @@
8
8
  @import "../pb_textarea/textarea_mixin";
9
9
 
10
10
  @import "./scss_partials/dropdown_animation";
11
+ @import "dropdown_mixin";
11
12
 
12
13
  [class*="pb_dropdown"] {
13
14
  .dropdown_wrapper {
@@ -98,9 +99,23 @@
98
99
  [class^="pb_title_kit"], a {
99
100
  color: $white !important;
100
101
  }
102
+ border-bottom: 1px solid $border_light;
101
103
  &:hover {
102
- background-color: $product_1_background !important;
104
+ background-color: $product_1_background;
105
+ }
106
+
107
+ // activeStyle font color map
108
+ @each $name, $color in $font-colors {
109
+ &.font-#{$name} {
110
+ @include apply-font-color($color);
111
+ }
103
112
  }
113
+ // activeStyle background color map (no difference between selected and selected+hover custom colors)
114
+ @each $name, $bg in $background-colors {
115
+ &.bg-#{$name} {
116
+ background-color: $bg;
117
+ }
118
+ }
104
119
  }
105
120
  }
106
121
 
@@ -267,6 +282,7 @@
267
282
  }
268
283
  &[class*="selected"] {
269
284
  background-color: $primary;
285
+ border-bottom: rgba($white, 0.15);
270
286
  }
271
287
  }
272
288
  }
@@ -39,6 +39,10 @@ type DropdownProps = {
39
39
  options: GenericObject;
40
40
  separators?: boolean;
41
41
  variant?: "default" | "subtle";
42
+ activeStyle?: {
43
+ backgroundColor?: string;
44
+ fontColor?: string;
45
+ };
42
46
  };
43
47
 
44
48
  interface DropdownComponent
@@ -69,6 +73,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
69
73
  options,
70
74
  separators = true,
71
75
  variant = "default",
76
+ activeStyle,
72
77
  } = props;
73
78
 
74
79
  const ariaProps = buildAriaProps(aria);
@@ -251,6 +256,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
251
256
  >
252
257
  <DropdownContext.Provider
253
258
  value={{
259
+ activeStyle,
254
260
  autocomplete,
255
261
  dropdownContainerRef,
256
262
  filteredOptions,
@@ -0,0 +1,36 @@
1
+ @import "../tokens/colors";
2
+
3
+ // activeStyle fontColor sass map to go through text colors + set of custom colors
4
+ $custom-font-colors: (
5
+ primary: $primary
6
+ );
7
+
8
+ $merged-font-colors: map-merge($text_colors, $custom-font-colors);
9
+
10
+ $font-colors: ();
11
+
12
+ @each $key, $val in $merged-font-colors {
13
+ $font-colors: map-merge($font-colors, ($key: $val));
14
+ }
15
+
16
+ @mixin apply-font-color($color) {
17
+ color: $color;
18
+
19
+ [class^="pb_body"],
20
+ [class^="pb_title_kit"],
21
+ a {
22
+ color: $color !important;
23
+ }
24
+ }
25
+
26
+ // activeStyle backgroundColor map (set of custom colors)
27
+ $custom-background-colors: (
28
+ "bg_light": $bg_light,
29
+ "white": $white,
30
+ );
31
+
32
+ $background-colors: ();
33
+
34
+ @each $key, $val in $custom-background-colors {
35
+ $background-colors: map-merge($background-colors, ($key: $val));
36
+ }
@@ -0,0 +1,90 @@
1
+ import React from 'react'
2
+ import Dropdown from '../_dropdown'
3
+
4
+ const DropdownCustomActiveStyleOptions = (props) => {
5
+
6
+
7
+ const options = [
8
+ {
9
+ label: "United States",
10
+ value: "unitedStates",
11
+ id: "us"
12
+ },
13
+ {
14
+ label: "Canada",
15
+ value: "canada",
16
+ id: "ca"
17
+ },
18
+ {
19
+ label: "Pakistan",
20
+ value: "pakistan",
21
+ id: "pk"
22
+ }
23
+ ];
24
+
25
+
26
+ return (
27
+ <div>
28
+ <Dropdown
29
+ activeStyle={{
30
+ backgroundColor: "bg_light",
31
+ fontColor: "primary",
32
+ }}
33
+ label="Background Color: bg_light; Font Color: primary"
34
+ marginBottom="sm"
35
+ options={options}
36
+ {...props}
37
+ >
38
+ <Dropdown.Trigger/>
39
+ <Dropdown.Container>
40
+ {options.map((option) => (
41
+ <Dropdown.Option key={option.id}
42
+ option={option}
43
+ />
44
+ ))}
45
+ </Dropdown.Container>
46
+ </Dropdown>
47
+ <Dropdown
48
+ activeStyle={{
49
+ backgroundColor: "white",
50
+ fontColor: "primary",
51
+ }}
52
+ label="Background Color: white; Font Color: primary"
53
+ marginBottom="sm"
54
+ options={options}
55
+ {...props}
56
+ />
57
+ <Dropdown
58
+ activeStyle={{
59
+ backgroundColor: "bg_light",
60
+ fontColor: "text_lt_default",
61
+ }}
62
+ autocomplete
63
+ label="Background Color: bg_light; Font Color: text_lt_default"
64
+ marginBottom="sm"
65
+ options={options}
66
+ {...props}
67
+ />
68
+ <Dropdown
69
+ activeStyle={{
70
+ fontColor: "text_lt_lighter",
71
+ }}
72
+ label="Font Color: text_lt_lighter"
73
+ marginBottom="sm"
74
+ options={options}
75
+ {...props}
76
+ >
77
+ <Dropdown.Trigger/>
78
+ <Dropdown.Container>
79
+ {options.map((option) => (
80
+ <Dropdown.Option key={option.id}
81
+ option={option}
82
+ />
83
+ ))}
84
+ </Dropdown.Container>
85
+ </Dropdown>
86
+ </div>
87
+ )
88
+ }
89
+
90
+ export default DropdownCustomActiveStyleOptions
@@ -0,0 +1,4 @@
1
+ The `activeStyle` prop can be used to customize the appearance of the dropdown selection indicator. It accepts an object with the following keys: `backgroundColor` sets the background color of the selected item (and its hover state); `fontColor` sets the font color of the selected item.
2
+
3
+ `backgroundColor` **Type**: String | **Values**: bg_light | white | **Default**: (no selection) is primary
4
+ `fontColor` **Type**: String | **Values**: primary | all [Playbook Text Colors](https://playbook.powerapp.cloud/visual_guidelines/colors) | **Default**: (no selection) is white
@@ -18,6 +18,7 @@ const DropdownCustomRadioOptions = (props) => {
18
18
  return (
19
19
  <div>
20
20
  <Dropdown
21
+ activeStyle={{ backgroundColor: "bg_light", fontColor: "text_lt_default" }}
21
22
  label="Select Item"
22
23
  onSelect={(selectedItem) => setSelectedValue(selectedItem?.value)}
23
24
  options={options}
@@ -1 +1 @@
1
- Radio inputs can be used inside `Dropdown.Option` for a custom layout that mimics form-like selection within a dropdown.
1
+ Radio inputs can be used inside `Dropdown.Option` for a custom layout that mimics form-like selection within a dropdown. Use the [activeStyle](https://playbook.powerapp.cloud/kits/dropdown/react#custom-active-style-options) `backgroundColor` and `fontColor` props to create contrast between the Radio selection indicator and the Dropdown selection background indicator.
@@ -16,7 +16,7 @@ examples:
16
16
  - dropdown_with_search_rails: Custom Trigger Dropdown with Search
17
17
  - dropdown_with_custom_padding: Custom Option Padding
18
18
  - dropdown_with_custom_icon_options: Custom Icon Options
19
- # - dropdown_with_custom_radio_options: Custom Radio Options # TODO: Update and publish doc ex in [PLAY-2146](https://runway.powerhrg.com/backlog_items/PLAY-2146) (remove this comment afterwards)
19
+ # - dropdown_with_custom_radio_options: Custom Radio Options # TODO: Update and publish doc ex in the Rails follow up to [PLAY-2146](https://runway.powerhrg.com/backlog_items/PLAY-2146) (remove this comment afterwards)
20
20
  - dropdown_error: Dropdown with Error
21
21
  - dropdown_default_value: Default Value
22
22
  - dropdown_multi_select_with_default: Multi Select Default Value
@@ -39,8 +39,9 @@ examples:
39
39
  - dropdown_with_custom_trigger: Custom Trigger
40
40
  - dropdown_with_search: Custom Trigger Dropdown with Search
41
41
  - dropdown_with_custom_padding: Custom Option Padding
42
+ - dropdown_with_custom_active_style_options: Custom Active Style Options
42
43
  - dropdown_with_custom_icon_options: Custom Icon Options
43
- # - dropdown_with_custom_radio_options: Custom Radio Options # TODO: Update and publish doc ex in [PLAY-2146](https://runway.powerhrg.com/backlog_items/PLAY-2146) (remove this comment afterwards)
44
+ - dropdown_with_custom_radio_options: Custom Radio Options
44
45
  - dropdown_error: Dropdown with Error
45
46
  - dropdown_default_value: Default Value
46
47
  - dropdown_multi_select_with_default: Multi Select Default Value
@@ -21,4 +21,5 @@ export { default as DropdownMultiSelectWithAutocomplete } from './_dropdown_mult
21
21
  export { default as DropdownMultiSelectWithDefault } from './_dropdown_multi_select_with_default.jsx'
22
22
  export { default as DropdownMultiSelectWithCustomOptions } from './_dropdown_multi_select_with_custom_options.jsx'
23
23
  export {default as DropdownWithCustomIconOptions} from './_dropdown_with_custom_icon_options.jsx'
24
- export {default as DropdownWithCustomRadioOptions} from './_dropdown_with_custom_radio_options.jsx'
24
+ export {default as DropdownWithCustomRadioOptions} from './_dropdown_with_custom_radio_options.jsx'
25
+ export {default as DropdownWithCustomActiveStyleOptions} from './_dropdown_with_custom_active_style_options.jsx'
@@ -369,4 +369,28 @@ test("defaultValue works with multiSelect", () => {
369
369
  const option2 = Array.from(kit.querySelectorAll(".pb_dropdown_option_list"));
370
370
  const firstOpt = options[0].label
371
371
  expect(option2[0]).not.toHaveTextContent(firstOpt)
372
+ })
373
+
374
+ test("applies activeStyle backgroundColor and fontColor when selected", () => {
375
+ render(
376
+ <Dropdown
377
+ activeStyle={{
378
+ backgroundColor: "bg_light",
379
+ fontColor: "primary",
380
+ }}
381
+ data={{ testid: testId }}
382
+ options={options}
383
+ />
384
+ )
385
+
386
+ const kit = screen.getByTestId(testId)
387
+ const option = kit.querySelectorAll(".pb_dropdown_option_list")[1]
388
+
389
+ fireEvent.click(option)
390
+
391
+ const selected = kit.querySelector(".pb_dropdown_option_selected")
392
+
393
+ expect(selected).toBeInTheDocument()
394
+ expect(selected).toHaveClass("bg-bg_light")
395
+ expect(selected).toHaveClass("font-primary")
372
396
  })
@@ -41,6 +41,7 @@ const DropdownOption = (props: DropdownOptionProps) => {
41
41
  } = props;
42
42
 
43
43
  const {
44
+ activeStyle,
44
45
  filteredOptions,
45
46
  filterItem,
46
47
  focusedOptionIndex,
@@ -59,7 +60,6 @@ const DropdownOption = (props: DropdownOptionProps) => {
59
60
  ? selected.some((item) => item.label === option?.label)
60
61
  : (selected as GenericObject)?.label === option?.label;
61
62
 
62
-
63
63
  if (!isItemMatchingFilter(option) || (multiSelect && isSelected)) {
64
64
  return null;
65
65
  }
@@ -70,6 +70,14 @@ const DropdownOption = (props: DropdownOptionProps) => {
70
70
 
71
71
  const selectedClass = isSelected ? "selected" : "list";
72
72
 
73
+
74
+ const bgTokenClass = activeStyle?.backgroundColor
75
+ ? `bg-${activeStyle.backgroundColor}`
76
+ : "";
77
+ const fontTokenClass = activeStyle?.fontColor
78
+ ? `font-${activeStyle.fontColor}`
79
+ : "";
80
+
73
81
  const ariaProps = buildAriaProps(aria);
74
82
  const dataProps = buildDataProps(data);
75
83
  const htmlProps = buildHtmlProps(htmlOptions);
@@ -79,6 +87,8 @@ const DropdownOption = (props: DropdownOptionProps) => {
79
87
  selectedClass,
80
88
  focusedClass,
81
89
  ),
90
+ bgTokenClass,
91
+ fontTokenClass,
82
92
  globalProps(props),
83
93
  className
84
94
  );
@@ -24,7 +24,9 @@ module Playbook
24
24
  prop :validation_message, type: Playbook::Props::String, default: ""
25
25
 
26
26
  def classnames
27
- classname + inline_class + compact_class + show_arrow_class
27
+ ([classname] + [inline_class, compact_class, show_arrow_class])
28
+ .reject(&:empty?)
29
+ .join(" ")
28
30
  end
29
31
 
30
32
  def all_attributes
@@ -44,7 +46,7 @@ module Playbook
44
46
  end
45
47
 
46
48
  def inline_class
47
- inline ? " inline " : " "
49
+ inline ? "inline" : ""
48
50
  end
49
51
 
50
52
  def compact_class