@salesforcedevs/dx-components 1.40.4-final-alpha → 1.40.4-fix-alpha

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.40.4-final-alpha",
3
+ "version": "1.40.4-fix-alpha",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -20,6 +20,11 @@
20
20
  --dx-c-button-line-height: inherit;
21
21
  --dx-c-button-letter-spacing: inherit;
22
22
  --dx-c-button-display: flex;
23
+
24
+ /* Keyboard focus ring (WES): a 2px white band, then a 2px blue outline. */
25
+ --dx-c-button-focus-outline: 2px solid var(--dx-g-blue-vibrant-60);
26
+ --dx-c-button-focus-offset: 2px;
27
+ --dx-c-button-focus-shadow: 0 0 0 2px white;
23
28
  }
24
29
 
25
30
  .button {
@@ -32,7 +37,8 @@
32
37
  user-select: none;
33
38
  white-space: nowrap;
34
39
  font-size: var(--dx-c-button-font-size);
35
- transition: var(--dx-g-transition-hue-1x);
40
+ transition: var(--dx-g-transition-hue-1x),
41
+ var(--dx-g-transition-box-shadow-1x);
36
42
  padding: var(--dx-c-button-vertical-spacing, 0)
37
43
  var(--dx-c-button-horizontal-spacing, var(--dx-g-spacing-md));
38
44
  border-radius: var(--dx-g-spacing-xs);
@@ -60,7 +66,11 @@
60
66
  display: inline;
61
67
  vertical-align: var(--dx-c-button-icon-vertical-align, unset);
62
68
 
63
- --dx-c-icon-color: var(--dx-g-button-icon-color, currentcolor);
69
+ /* Component hook first; the global stays as the fallback for dark mode. */
70
+ --dx-c-icon-color: var(
71
+ --dx-c-button-icon-color,
72
+ var(--dx-g-button-icon-color, currentcolor)
73
+ );
64
74
  }
65
75
 
66
76
  .button.variant_inline dx-icon,
@@ -191,6 +201,7 @@
191
201
  }
192
202
 
193
203
  .button.variant_primary:hover,
204
+ .button.variant_primary:focus-visible,
194
205
  :host([aria-expanded="true"]) .button.variant_primary {
195
206
  background: var(--dx-c-button-primary-color-hover);
196
207
  border-color: var(--dx-c-button-primary-color-hover);
@@ -215,6 +226,8 @@
215
226
 
216
227
  .button.variant_secondary:hover,
217
228
  .button.variant_quaternary:hover,
229
+ .button.variant_secondary:focus-visible,
230
+ .button.variant_quaternary:focus-visible,
218
231
  :host([aria-expanded="true"]) .button.variant_secondary,
219
232
  :host([aria-expanded="true"]) .button.variant_quaternary {
220
233
  background: var(--dx-c-button-secondary-color-hover);
@@ -234,6 +247,7 @@
234
247
  }
235
248
 
236
249
  .button.variant_tertiary:hover,
250
+ .button.variant_tertiary:focus-visible,
237
251
  :host([aria-expanded="true"]) .button.variant_tertiary {
238
252
  background: var(--dx-c-button-secondary-color-hover);
239
253
  border-color: var(--dx-c-button-secondary-color-hover);
@@ -250,6 +264,8 @@
250
264
 
251
265
  .button.variant_inline:hover,
252
266
  .button.variant_inline-inherit:hover,
267
+ .button.variant_inline:focus-visible,
268
+ .button.variant_inline-inherit:focus-visible,
253
269
  :host([aria-expanded="true"])
254
270
  :is(.button.variant_inline, .button.variant_inline-inherit) {
255
271
  color: var(--dx-c-button-inline-color-hover);
@@ -277,10 +293,30 @@
277
293
  }
278
294
 
279
295
  .button.variant_custom:hover,
296
+ .button.variant_custom:focus-visible,
280
297
  .button.variant_icon-only:hover,
298
+ .button.variant_icon-only:focus-visible,
281
299
  :host([aria-expanded="true"]) .button.variant_custom,
282
300
  :host([aria-expanded="true"]) .button.variant_icon-only {
283
301
  color: var(--dx-c-button-custom-color-hover);
284
302
  background: var(--dx-c-button-custom-background-hover);
285
303
  border-color: var(--dx-c-button-custom-border-hover);
304
+
305
+ /* An inset shadow can thicken the edge without resizing the button. */
306
+ box-shadow: var(--dx-c-button-custom-border-shadow-hover, none);
307
+ }
308
+
309
+ /* Keyboard focus only; an open menu alone shows no ring. Keep last so it wins
310
+ over hover and the open state (:host lifts it above the custom and icon-only
311
+ hover rules). The outline survives Windows high-contrast mode; the white band
312
+ does not. */
313
+ :host .button:focus-visible,
314
+ :host .button:focus-visible:hover,
315
+ :host([aria-expanded="true"]) .button:focus-visible {
316
+ outline: var(--dx-c-button-focus-outline);
317
+ outline-offset: var(--dx-c-button-focus-offset);
318
+ box-shadow: var(--dx-c-button-focus-shadow);
319
+
320
+ /* The ring appears at once instead of fading in. */
321
+ transition: var(--dx-g-transition-hue-1x);
286
322
  }
@@ -1,5 +1,14 @@
1
1
  @import "dxHelpers/reset";
2
2
 
3
+ /* Options run edge to edge; the menu adds space above the first and below
4
+ the last. */
5
+ dx-popover {
6
+ --dx-c-popover-padding: var(
7
+ --dx-c-dropdown-padding,
8
+ var(--dx-g-spacing-sm) 0
9
+ );
10
+ }
11
+
3
12
  .menu-nested:not(.menu-fit-content)::part(content) {
4
13
  padding-top: var(--dx-g-spacing-sm);
5
14
  width: 354px;
@@ -14,30 +23,31 @@
14
23
  display: none;
15
24
  }
16
25
 
17
- /* Opt-in fit-content menu: hugs the labels (so it can be as narrow as the
18
- shortest one) and stops at --dx-c-dropdown-menu-max-width. Defaults still
19
- truncate; set --dx-c-dropdown-fit-white-space: normal to wrap instead. */
20
- .menu-fit-content::part(content) {
26
+ /* fit-content and fit-end: the menu is as wide as its longest label. */
27
+ .menu-fit-content {
28
+ --dx-c-popover-width: max-content;
29
+ }
30
+
31
+ /* fit-end also stops at --dx-c-dropdown-menu-max-width. Labels wrap only once
32
+ the menu reaches that width. */
33
+ .menu-fit-end::part(content) {
21
34
  box-sizing: border-box;
22
- width: max-content;
23
35
  max-width: var(
24
36
  --dx-c-dropdown-menu-max-width,
25
37
  calc(100vw - var(--dx-g-spacing-lg))
26
38
  );
27
39
  }
28
40
 
29
- .menu-fit-content {
30
- --dx-c-dropdown-option-min-width: 0;
31
- --dx-c-dropdown-option-label-display: block;
32
- --dx-c-dropdown-option-white-space: var(
33
- --dx-c-dropdown-fit-white-space,
34
- nowrap
35
- );
36
- --dx-c-dropdown-option-overflow: var(--dx-c-dropdown-fit-overflow, hidden);
37
- --dx-c-dropdown-option-text-overflow: var(
38
- --dx-c-dropdown-fit-text-overflow,
39
- ellipsis
40
- );
41
+ .menu-fit-content.menu-nested .menu_list {
42
+ width: 100%;
43
+ align-items: flex-start;
44
+ gap: var(--dx-g-spacing-sm);
45
+ }
46
+
47
+ .menu-fit-content.menu-nested .menu_option:not(:first-child) {
48
+ border-top: var(--border);
49
+ margin-top: 0;
50
+ padding-top: var(--dx-g-spacing-sm);
41
51
  }
42
52
 
43
53
  @media screen and (max-width: 1000px) {
@@ -119,7 +119,8 @@ export default class Dropdown extends LightningElement {
119
119
  "menu-nested-2-col",
120
120
  this.offset && `menu-offset-${this.offset}`,
121
121
  this.areOptionsEmpty && "menu-hidden",
122
- fitContent && "menu-fit-content"
122
+ fitContent && "menu-fit-content",
123
+ this.widthMode === "fit-end" && "menu-fit-end"
123
124
  );
124
125
  }
125
126
 
@@ -12,11 +12,16 @@
12
12
  width: var(--shape-width);
13
13
  }
14
14
 
15
+ /* The vertical stroke of the "L" runs up to the top edge of the option: the
16
+ top padding plus the space above the shape inside the line box. */
15
17
  .indented-shape::after {
16
18
  background-color: var(--background);
17
19
  bottom: 0;
18
20
  content: "";
19
- height: 15px;
21
+ height: calc(
22
+ var(--dx-g-spacing-sm) +
23
+ (var(--dx-g-spacing-lg) + var(--wide) - var(--dx-g-spacing-xs)) / 2
24
+ );
20
25
  position: absolute;
21
26
  width: var(--wide);
22
27
  }
@@ -25,14 +30,12 @@
25
30
  display: flex;
26
31
  font-family: var(--dx-g-font-sans);
27
32
  width: 100%;
28
-
29
- /* Opt-in hooks; defaults preserve today's look. */
30
- padding: var(--dx-c-dropdown-option-padding, var(--dx-g-spacing-sm));
31
- font-size: var(--dx-g-text-sm);
32
- border-radius: var(
33
- --dx-c-dropdown-option-border-radius,
34
- var(--dx-g-spacing-xs)
33
+ padding: var(
34
+ --dx-c-dropdown-option-padding,
35
+ var(--dx-g-spacing-sm) var(--dx-g-spacing-lg)
35
36
  );
37
+ font-size: var(--dx-g-text-sm);
38
+ border-radius: var(--dx-c-dropdown-option-border-radius, 0);
36
39
  transition: var(--dx-g-transition-hue-1x);
37
40
  align-items: center;
38
41
  outline: none !important;
@@ -53,8 +56,6 @@
53
56
  }
54
57
 
55
58
  .option-active {
56
- --dx-c-dropdown-option-label-color: var(--dx-g-blue-vibrant-50);
57
-
58
59
  background: var(--dx-g-cloud-blue-vibrant-95);
59
60
  }
60
61
 
@@ -62,27 +63,34 @@
62
63
  display: flex;
63
64
  flex-direction: column;
64
65
  justify-content: center;
66
+ align-items: flex-start;
67
+ gap: var(--dx-g-spacing-sm);
68
+ flex: 1;
69
+ min-width: 0;
65
70
  font-family: var(--dx-g-font-sans);
66
71
  font-size: var(--dx-g-text-sm);
67
72
  text-align: left;
68
-
69
- /* Opt-in: set to 0 to let a long label truncate instead of overflow. */
70
- min-width: var(--dx-c-dropdown-option-min-width, auto);
71
73
  }
72
74
 
73
75
  .option-indented .option_details {
74
76
  align-items: center;
75
77
  flex-direction: row;
78
+ justify-content: flex-start;
79
+ gap: 0;
76
80
  }
77
81
 
78
82
  .option_label {
79
- color: var(--dx-c-dropdown-option-label-color, var(--dx-g-blue-vibrant-50));
83
+ color: var(--dx-c-dropdown-option-label-color, var(--dx-g-text-body-color));
80
84
 
81
85
  /* Opt-in: set to block so text-overflow:ellipsis applies (ignored on flex). */
82
86
  display: var(--dx-c-dropdown-option-label-display, flex);
83
87
  align-items: center;
84
- font-weight: var(--dx-c-dropdown-option-font-weight, var(--dx-g-font-bold));
88
+ font-weight: var(
89
+ --dx-c-dropdown-option-font-weight,
90
+ var(--dx-g-font-normal)
91
+ );
85
92
  font-size: var(--dx-c-dropdown-option-font-size, var(--dx-g-text-base));
93
+ line-height: var(--dx-g-spacing-lg);
86
94
 
87
95
  /* Opt-in truncation: consumers set --dx-c-dropdown-option-white-space:
88
96
  nowrap to truncate labels with an ellipsis instead of wrapping.
@@ -107,65 +115,57 @@
107
115
 
108
116
  .option_description {
109
117
  color: var(--dx-g-gray-30);
110
- margin-top: var(--dx-g-spacing-xs);
111
118
  line-height: 18px;
112
119
  }
113
120
 
121
+ /* An option can have a start icon (iconSymbol), an end icon (endIconSymbol),
122
+ or both. */
114
123
  .option_icon {
115
- margin-right: var(--dx-g-spacing-md);
124
+ --dx-c-icon-size: var(--dx-g-icon-size-md);
125
+ --dx-c-icon-color: var(--dx-g-gray-50);
126
+
116
127
  flex-shrink: 0;
117
128
  }
118
129
 
119
- .option-indented {
120
- padding-top: var(--dx-g-spacing-xs);
121
- padding-bottom: var(--dx-g-spacing-xs);
130
+ .option_icon-start {
131
+ margin-right: var(--dx-g-spacing-md);
122
132
  }
123
133
 
124
- .option-fit-content {
125
- min-width: 0;
126
- padding: var(--dx-g-spacing-sm) var(--dx-g-spacing-lg);
134
+ .option_icon-end {
135
+ margin-left: var(--dx-g-spacing-2xl);
127
136
  }
128
137
 
129
- .option-fit-content .option_details {
130
- align-items: flex-start;
131
- gap: var(--dx-g-spacing-sm);
132
- min-width: 0;
133
- flex: 1;
138
+ /* Indented (breadcrumb hierarchy) menus keep their own selected label color. */
139
+ .option-indented.option-active {
140
+ --dx-c-dropdown-option-label-color: var(--dx-g-blue-vibrant-50);
134
141
  }
135
142
 
136
- .option-fit-content .option_description {
137
- margin-top: 0;
143
+ /* fit-content (toolbar): one line per label, truncated with an ellipsis. */
144
+ .option-fit-content {
145
+ min-width: 0;
138
146
  }
139
147
 
140
148
  .option-fit-content .option_label {
141
149
  display: block;
142
- color: var(--dx-g-gray-10);
143
- font-weight: var(--dx-g-font-normal);
144
- line-height: var(--dx-g-spacing-lg);
145
150
  white-space: nowrap;
146
151
  overflow: hidden;
147
152
  text-overflow: ellipsis;
148
153
  max-width: calc(100vw - var(--dx-g-spacing-lg) * 4);
149
154
  }
150
155
 
151
- .option-fit-content.option-active .option_label {
152
- color: var(--dx-g-blue-vibrant-50);
153
- }
154
-
155
- .option-fit-content .option_icon {
156
- --dx-c-icon-size: var(--dx-g-icon-size-md);
157
- --dx-c-icon-color: var(--dx-g-gray-50);
158
-
159
- order: 1;
160
- margin-right: 0;
161
- margin-left: var(--dx-g-spacing-2xl);
162
- }
163
-
156
+ /* Each "L" starts xs past the first letter of the label above it. A label
157
+ sits one shape plus its sm margin after its own "L", so each level steps in
158
+ by that much plus xs. */
164
159
  .option-indented:not([data-index="0"]) {
165
- --base-indentation: calc(var(--dx-g-spacing-md) + var(--shape-width));
160
+ --base-indentation: calc(
161
+ var(--shape-width) + var(--dx-g-spacing-sm) + var(--dx-g-spacing-xs)
162
+ );
166
163
  --shape-width: 8px;
167
164
 
168
- padding-left: calc(var(--indentation, 0px) + var(--dx-g-spacing-md));
165
+ padding-left: calc(
166
+ var(--indentation, 0px) + var(--dx-g-spacing-lg) +
167
+ var(--dx-g-spacing-xs)
168
+ );
169
169
  }
170
170
 
171
171
  [data-index="2"] {
@@ -11,11 +11,12 @@
11
11
  onclick={onClick}
12
12
  >
13
13
  <dx-icon
14
- class="option_icon"
14
+ class="option_icon option_icon-start"
15
15
  symbol={option.iconSymbol}
16
16
  sprite={option.iconSprite}
17
- if:true={option.iconSymbol}
18
- size={optionIconSize}
17
+ color={option.iconColor}
18
+ lwc:if={option.iconSymbol}
19
+ size="override"
19
20
  ></dx-icon>
20
21
  <div class="option_details">
21
22
  <div if:true={renderIndentedShape} class="indented-shape"></div>
@@ -30,6 +31,14 @@
30
31
  {option.description}
31
32
  </div>
32
33
  </div>
34
+ <dx-icon
35
+ class="option_icon option_icon-end"
36
+ symbol={option.endIconSymbol}
37
+ sprite={option.endIconSprite}
38
+ color={option.endIconColor}
39
+ lwc:if={option.endIconSymbol}
40
+ size="override"
41
+ ></dx-icon>
33
42
  </a>
34
43
  <button
35
44
  if:false={option.link}
@@ -40,12 +49,12 @@
40
49
  onclick={onClick}
41
50
  >
42
51
  <dx-icon
43
- class="option_icon"
52
+ class="option_icon option_icon-start"
44
53
  symbol={option.iconSymbol}
45
54
  sprite={option.iconSprite}
46
55
  color={option.iconColor}
47
- if:true={option.iconSymbol}
48
- size={optionIconSize}
56
+ lwc:if={option.iconSymbol}
57
+ size="override"
49
58
  ></dx-icon>
50
59
  <div class="option_details">
51
60
  <div if:true={renderIndentedShape} class="indented-shape"></div>
@@ -54,5 +63,13 @@
54
63
  {option.description}
55
64
  </div>
56
65
  </div>
66
+ <dx-icon
67
+ class="option_icon option_icon-end"
68
+ symbol={option.endIconSymbol}
69
+ sprite={option.endIconSprite}
70
+ color={option.endIconColor}
71
+ lwc:if={option.endIconSymbol}
72
+ size="override"
73
+ ></dx-icon>
57
74
  </button>
58
75
  </template>
@@ -4,8 +4,7 @@ import {
4
4
  OptionWithNested,
5
5
  AnalyticsPayload,
6
6
  DropdownVariant,
7
- DropdownWidthMode,
8
- IconSize
7
+ DropdownWidthMode
9
8
  } from "typings/custom";
10
9
  import { track } from "dxUtils/analytics";
11
10
 
@@ -41,10 +40,6 @@ export default class DropdownOption extends LightningElement {
41
40
  return this.variant === "indented" && this.indexPosition >= 1;
42
41
  }
43
42
 
44
- private get optionIconSize(): IconSize {
45
- return this.widthMode === "fit-content" ? "override" : "large";
46
- }
47
-
48
43
  private onClick(e: PointerEvent) {
49
44
  this.dispatchEvent(
50
45
  new CustomEvent("select", { detail: this.keyValue })
@@ -29,7 +29,6 @@
29
29
  padding: var(--popover-padding);
30
30
  overflow-y: auto;
31
31
  transition: var(--popover-transition);
32
- transition-delay: 0.02s;
33
32
  transform: translateY(var(--dx-g-spacing-xs));
34
33
  opacity: 0;
35
34
  }
@@ -40,6 +39,9 @@
40
39
  }
41
40
 
42
41
  .popover-container_open .popover {
42
+ /* Delay only on open. A closing delay keeps the menu visible for a frame
43
+ after its container hides, while it moves (a flash above the trigger). */
44
+ transition-delay: 0.02s;
43
45
  opacity: 1;
44
46
  transform: var(--popover-container-open-transform);
45
47
  }
@@ -240,6 +240,16 @@ export default class Popover extends LightningElement {
240
240
  this.dispatchEvent(new CustomEvent("controlarrowdown"));
241
241
  break;
242
242
  }
243
+ // A mouse-opened menu leaves focus on the control, so Escape lands
244
+ // here, not in the popover's own key handler.
245
+ case "Esc":
246
+ case "Escape": {
247
+ if (this.open) {
248
+ this.dispatchRequestCloseEvent("keypress-escape");
249
+ this.closePopover(true);
250
+ }
251
+ break;
252
+ }
243
253
  default:
244
254
  }
245
255
  };
@@ -5,8 +5,6 @@
5
5
  --button-primary-color-hover: var(--dx-g-cloud-blue-vibrant-95);
6
6
  --popover-container-open-transform: translateX(-4px) translateY(-8px);
7
7
  --popover-transition: none;
8
- --dx-c-dropdown-option-font-weight: normal;
9
- --dx-c-dropdown-option-label-color: var(--dx-g-gray-10);
10
8
  }
11
9
 
12
10
  .footer-item {
@@ -2,7 +2,9 @@
2
2
  @import "dxHelpers/text";
3
3
 
4
4
  :host {
5
- --dx-c-sidebar-width: 337px;
5
+ /* Width of the sidebar content (search field, version pickers) on tablet
6
+ and desktop. The sidebar adds its left padding and a 24px right inset. */
7
+ --dx-c-sidebar-content-width: 296px;
6
8
  --dx-c-sidebar-button-color: var(--dx-g-blue-vibrant-50);
7
9
  --dx-c-sidebar-button-background: white;
8
10
  --dx-c-sidebar-button-border: white;
@@ -11,7 +13,9 @@
11
13
  --dx-c-sidebar-button-border-hover: var(--dx-g-blue-vibrant-50);
12
14
  --dx-c-sidebar-left-padding: var(--dx-g-global-header-padding-horizontal);
13
15
  --dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
14
- --doc-version-picker-width: 296px;
16
+
17
+ /* Widest a small version picker menu can grow. */
18
+ --doc-version-picker-width: var(--dx-c-sidebar-content-width);
15
19
  }
16
20
 
17
21
  .header {
@@ -47,7 +51,7 @@
47
51
  color: var(--dx-g-blue-vibrant-30);
48
52
  }
49
53
 
50
- .container.collapsed {
54
+ .container.collapsed:not(.container-mobile) {
51
55
  width: var(--dx-g-spacing-xl);
52
56
  }
53
57
 
@@ -82,15 +86,19 @@
82
86
  display: flex;
83
87
  flex-direction: column;
84
88
  height: var(--dx-c-sidebar-height);
85
- width: calc(var(--dx-c-sidebar-width) + var(--left-spacing));
89
+
90
+ /* Mobile (container-mobile, set at 768px and below) fills the viewport. */
91
+ width: 100%;
86
92
  }
87
93
 
94
+ /* Tablet and desktop: left padding + content + right inset. */
88
95
  .container:not(.container-mobile) {
89
96
  --border-color: transparent;
90
- --left-spacing: calc(
91
- var(--dx-c-sidebar-left-padding) - var(--dx-g-spacing-md)
92
- );
93
97
 
98
+ width: calc(
99
+ var(--dx-c-sidebar-left-padding) + var(--dx-c-sidebar-content-width) +
100
+ var(--dx-g-spacing-lg)
101
+ );
94
102
  box-shadow: 2px 0 0 0 var(--border-color);
95
103
  min-height: var(--dx-c-sidebar-min-height);
96
104
  padding: var(--dx-c-sidebar-vertical-padding) 0 var(--dx-g-spacing-2xs) 0;
@@ -106,7 +114,9 @@
106
114
  }
107
115
 
108
116
  .container.container-mobile {
109
- width: 100%;
117
+ --doc-version-picker-width: calc(
118
+ 100vw - var(--dx-c-sidebar-left-padding) - var(--dx-g-spacing-lg)
119
+ );
110
120
  }
111
121
 
112
122
  .container.container-mobile .header {
@@ -169,11 +179,3 @@
169
179
  .sidebar-content-hasfooter {
170
180
  margin-bottom: var(--dx-g-spacing-2xl);
171
181
  }
172
-
173
- @media screen and (max-width: 767px) {
174
- :host {
175
- --doc-version-picker-width: calc(
176
- 100vw - var(--dx-c-sidebar-left-padding) - var(--dx-g-spacing-lg)
177
- );
178
- }
179
- }