@brightspace-ui/core 2.172.1 → 2.173.0

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.
@@ -66,6 +66,36 @@
66
66
  </template>
67
67
  </d2l-demo-snippet>
68
68
 
69
+ <h2>Inline help checkbox</h2>
70
+ <d2l-demo-snippet>
71
+ <template>
72
+ <d2l-input-checkbox>
73
+ Inline help checkbox
74
+ <div slot="inline-help">
75
+ Help text <b>right here</b>!
76
+ </div>
77
+ </d2l-input-checkbox>
78
+ </template>
79
+ </d2l-demo-snippet>
80
+
81
+ <h2>Inline help (multiline) checkbox</h2>
82
+ <d2l-demo-snippet>
83
+ <template>
84
+ <d2l-input-checkbox>
85
+ Inline help checkbox
86
+ <div slot="inline-help">
87
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
88
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
89
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
90
+ nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
91
+ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
92
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
93
+ qui officia deserunt mollit anim id est laborum.
94
+ </div>
95
+ </d2l-input-checkbox>
96
+ </template>
97
+ </d2l-demo-snippet>
98
+
69
99
  </d2l-demo-page>
70
100
  </body>
71
101
  </html>
@@ -46,6 +46,65 @@
46
46
  </template>
47
47
  </d2l-demo-snippet>
48
48
 
49
+ <h2>Inline Help</h2>
50
+ <d2l-demo-snippet>
51
+ <template>
52
+ <d2l-input-color type="foreground" disallow-none value="#D97B32" disabled>
53
+ <div slot="inline-help">
54
+ Inline help 1
55
+ </div>
56
+ </d2l-input-color>
57
+ <d2l-input-color type="background" disabled>
58
+ <div slot="inline-help">
59
+ <b>Inline</b> help 2
60
+ </div>
61
+ </d2l-input-color>
62
+ <d2l-input-color label="Custom Color" type="custom" value="#8ad934" disabled>
63
+ <div slot="inline-help">
64
+ Inline help 3
65
+ </div>
66
+ </d2l-input-color>
67
+ </template>
68
+ </d2l-demo-snippet>
69
+
70
+ <h2>Inline Help (multiline)</h2>
71
+ <d2l-demo-snippet>
72
+ <template>
73
+ <d2l-input-color type="foreground" disallow-none value="#D97B32" disabled>
74
+ <div slot="inline-help">
75
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
76
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
77
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
78
+ nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
79
+ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
80
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
81
+ qui officia deserunt mollit anim id est laborum.
82
+ </div>
83
+ </d2l-input-color>
84
+ <d2l-input-color type="background" disabled>
85
+ <div slot="inline-help">
86
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
87
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
88
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
89
+ nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
90
+ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
91
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
92
+ qui officia deserunt mollit anim id est laborum.
93
+ </div>
94
+ </d2l-input-color>
95
+ <d2l-input-color label="Custom Color" type="custom" value="#8ad934" disabled>
96
+ <div slot="inline-help">
97
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
98
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
99
+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
100
+ nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
101
+ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
102
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
103
+ qui officia deserunt mollit anim id est laborum.
104
+ </div>
105
+ </d2l-input-color>
106
+ </template>
107
+ </d2l-demo-snippet>
49
108
  </d2l-demo-page>
50
109
  </body>
51
110
  </html>
@@ -53,6 +53,29 @@
53
53
  <d2l-input-time label="Start Time" default-value="09:00:00"></d2l-input-time>
54
54
  </template>
55
55
  </d2l-demo-snippet>
56
+
57
+ <h2>Inline help text</h2>
58
+ <d2l-demo-snippet>
59
+ <template>
60
+ <d2l-input-time label="Start Time" default-value="09:00:00">
61
+ <div slot="inline-help">
62
+ <b>Inline</b> help text!
63
+ </div>
64
+ </d2l-input-time>
65
+ </template>
66
+ </d2l-demo-snippet>
67
+
68
+ <h2>Inline help text (multiline)</h2>
69
+ <d2l-demo-snippet>
70
+ <template>
71
+ <d2l-input-time label="Start Time" default-value="09:00:00">
72
+ <div slot="inline-help">
73
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit,
74
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
75
+ </div>
76
+ </d2l-input-time>
77
+ </template>
78
+ </d2l-demo-snippet>
56
79
  </d2l-demo-page>
57
80
  </body>
58
81
  </html>
@@ -4,10 +4,16 @@ import { classMap } from 'lit/directives/class-map.js';
4
4
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
5
5
  import { getUniqueId } from '../../helpers/uniqueId.js';
6
6
  import { ifDefined } from 'lit/directives/if-defined.js';
7
+ import { InputInlineHelpMixin } from './input-inline-help-mixin.js';
7
8
  import { offscreenStyles } from '../offscreen/offscreen.js';
8
9
  import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
9
10
  import { SkeletonMixin } from '../skeleton/skeleton-mixin.js';
10
11
 
12
+ export const cssSizes = {
13
+ inputBoxSize: 1.2,
14
+ checkboxMargin: 0.5,
15
+ };
16
+
11
17
  export const checkboxStyles = css`
12
18
  input[type="checkbox"].d2l-input-checkbox {
13
19
  -webkit-appearance: none;
@@ -15,17 +21,17 @@ export const checkboxStyles = css`
15
21
  appearance: none;
16
22
  background-position: center center;
17
23
  background-repeat: no-repeat;
18
- background-size: 1.2rem 1.2rem;
24
+ background-size: ${cssSizes.inputBoxSize}rem ${cssSizes.inputBoxSize}rem;
19
25
  border-radius: 0.3rem;
20
26
  border-style: solid;
21
27
  box-sizing: border-box;
22
28
  display: inline-block;
23
- height: 1.2rem;
29
+ height: ${cssSizes.inputBoxSize}rem;
24
30
  margin: 0;
25
31
  outline: none;
26
32
  padding: 0;
27
33
  vertical-align: middle;
28
- width: 1.2rem;
34
+ width: ${cssSizes.inputBoxSize}rem;
29
35
  }
30
36
  input[type="checkbox"].d2l-input-checkbox:checked {
31
37
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20fill%3D%22%23494C4E%22%20d%3D%22M8.4%2016.6c.6.6%201.5.6%202.1%200l8-8c.6-.6.6-1.5%200-2.1-.6-.6-1.5-.6-2.1%200l-6.9%207-1.9-1.9c-.6-.6-1.5-.6-2.1%200-.6.6-.6%201.5%200%202.1l2.9%202.9z%22/%3E%3C/svg%3E%0A");
@@ -57,7 +63,7 @@ export const checkboxStyles = css`
57
63
  * @slot - Checkbox information (e.g., text)
58
64
  * @fires change - Dispatched when the checkbox's state changes
59
65
  */
60
- class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
66
+ class InputCheckbox extends InputInlineHelpMixin(FocusMixin(SkeletonMixin(RtlMixin(LitElement)))) {
61
67
 
62
68
  static get properties() {
63
69
  return {
@@ -109,7 +115,7 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
109
115
  css`
110
116
  :host {
111
117
  display: block;
112
- line-height: 1.2rem;
118
+ line-height: ${cssSizes.inputBoxSize}rem;
113
119
  margin-bottom: 0.9rem;
114
120
  }
115
121
  :host([hidden]) {
@@ -131,13 +137,13 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
131
137
  display: inline-block;
132
138
  font-size: 0.8rem;
133
139
  font-weight: 400;
134
- margin-left: 0.5rem;
140
+ margin-left: ${cssSizes.checkboxMargin}rem;
135
141
  vertical-align: top;
136
142
  white-space: normal;
137
143
  }
138
144
  :host([dir="rtl"]) .d2l-input-checkbox-text {
139
145
  margin-left: 0;
140
- margin-right: 0.5rem;
146
+ margin-right: ${cssSizes.checkboxMargin}rem;
141
147
  }
142
148
  :host([aria-label]) .d2l-input-checkbox-text {
143
149
  margin-left: 0;
@@ -151,6 +157,9 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
151
157
  bottom: 0.3rem;
152
158
  top: 0.3rem;
153
159
  }
160
+ .d2l-input-inline-help {
161
+ margin-inline-start: ${cssSizes.inputBoxSize + cssSizes.checkboxMargin}rem;
162
+ }
154
163
  .d2l-input-checkbox-text-disabled {
155
164
  opacity: 0.5;
156
165
  }
@@ -173,6 +182,7 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
173
182
  this.notTabbable = false;
174
183
  this.value = 'on';
175
184
  this._descriptionId = getUniqueId();
185
+ this._inlineHelpId = getUniqueId();
176
186
  }
177
187
 
178
188
  static get focusElementSelector() {
@@ -189,11 +199,12 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
189
199
  const ariaChecked = this.indeterminate ? 'mixed' : undefined;
190
200
  const disabled = this.disabled || this.skeleton;
191
201
  const offscreenContainer = this.description ? html`<div class="d2l-offscreen" id="${this._descriptionId}">${this.description}</div>` : null;
202
+ const ariaDescribedByIds = `${this.description ? this._descriptionId : ''} ${this._hasInlineHelp ? this._inlineHelpId : ''}`.trim();
192
203
  return html`
193
204
  <label>
194
205
  <span class="d2l-input-checkbox-wrapper d2l-skeletize"><input
195
206
  aria-checked="${ifDefined(ariaChecked)}"
196
- aria-describedby="${ifDefined(this.description ? this._descriptionId : undefined)}"
207
+ aria-describedby="${ifDefined(ariaDescribedByIds.length > 0 ? ariaDescribedByIds : undefined)}"
197
208
  aria-label="${ifDefined(this.ariaLabel)}"
198
209
  @change="${this._handleChange}"
199
210
  class="d2l-input-checkbox"
@@ -206,7 +217,8 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
206
217
  type="checkbox"
207
218
  .value="${this.value}"></span><span class="${classMap(textClasses)}"><slot></slot></span>
208
219
  </label>
209
- ${offscreenContainer}
220
+ ${this._renderInlineHelp(this._inlineHelpId)}
221
+ ${offscreenContainer}
210
222
  `;
211
223
  }
212
224
 
@@ -239,6 +251,5 @@ class InputCheckbox extends FocusMixin(SkeletonMixin(RtlMixin(LitElement))) {
239
251
  this.simulateClick();
240
252
  }
241
253
  }
242
-
243
254
  }
244
255
  customElements.define('d2l-input-checkbox', InputCheckbox);
@@ -7,8 +7,10 @@ import { classMap } from 'lit/directives/class-map.js';
7
7
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
8
8
  import { FormElementMixin } from '../form/form-element-mixin.js';
9
9
  import { getFocusPseudoClass } from '../../helpers/focus.js';
10
+ import { getUniqueId } from '../../helpers/uniqueId.js';
10
11
  import { getValidHexColor } from '../../helpers/color.js';
11
12
  import { ifDefined } from 'lit/directives/if-defined.js';
13
+ import { InputInlineHelpMixin } from './input-inline-help-mixin.js';
12
14
  import { inputLabelStyles } from './input-label-styles.js';
13
15
  import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
14
16
  import { PropertyRequiredMixin } from '../../mixins/property-required/property-required-mixin.js';
@@ -81,7 +83,7 @@ const SWATCH_TRANSPARENT = `<svg xmlns="http://www.w3.org/2000/svg" width="24" h
81
83
  * This component allows for inputting a HEX color value.
82
84
  * @fires change - Dispatched when an alteration to the value is committed by the user.
83
85
  */
84
- class InputColor extends PropertyRequiredMixin(FocusMixin(FormElementMixin(LocalizeCoreElement(LitElement)))) {
86
+ class InputColor extends InputInlineHelpMixin(PropertyRequiredMixin(FocusMixin(FormElementMixin(LocalizeCoreElement(LitElement))))) {
85
87
 
86
88
  static get properties() {
87
89
  return {
@@ -141,7 +143,7 @@ class InputColor extends PropertyRequiredMixin(FocusMixin(FormElementMixin(Local
141
143
  }
142
144
 
143
145
  static get styles() {
144
- return [ buttonStyles, inputLabelStyles,
146
+ return [ super.styles, buttonStyles, inputLabelStyles,
145
147
  css`
146
148
  :host {
147
149
  display: inline-block;
@@ -239,6 +241,7 @@ class InputColor extends PropertyRequiredMixin(FocusMixin(FormElementMixin(Local
239
241
  this._missingLabelErrorHasBeenThrown = false;
240
242
  this._opened = false;
241
243
  this._value = undefined;
244
+ this._inlineHelpId = getUniqueId();
242
245
  }
243
246
 
244
247
  get associatedValue() { return this._associatedValue; }
@@ -270,7 +273,10 @@ class InputColor extends PropertyRequiredMixin(FocusMixin(FormElementMixin(Local
270
273
  const tooltip = !this._opened ? html`<d2l-tooltip for="opener" for-type="label" class="vdiff-target">${this._getTooltipLabel()}</d2l-tooltip>` : nothing;
271
274
  const opener = this._getOpener();
272
275
 
273
- return html`${label}${opener}${tooltip}`;
276
+ return html`
277
+ ${label}${opener}${tooltip}
278
+ ${this._renderInlineHelp(this._inlineHelpId)}
279
+ `;
274
280
 
275
281
  }
276
282
 
@@ -302,7 +308,14 @@ class InputColor extends PropertyRequiredMixin(FocusMixin(FormElementMixin(Local
302
308
  };
303
309
  const ariaLabel = this._opened ? this._getTooltipLabel() : undefined;
304
310
  const button = html`
305
- <button id="opener" class="${classMap(buttonClass)}" aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}" aria-label="${ifDefined(ariaLabel)}" @click="${this._handleOpenDialog}">
311
+ <button
312
+ id="opener"
313
+ class="${classMap(buttonClass)}"
314
+ aria-describedby="${ifDefined(this._hasInlineHelp ? this._inlineHelpId : undefined)}"
315
+ aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}"
316
+ aria-label="${ifDefined(ariaLabel)}"
317
+ @click="${this._handleOpenDialog}"
318
+ >
306
319
  ${this._getSwatch()}
307
320
  <svg xmlns="http://www.w3.org/2000/svg" width="10" height="6" fill="none" viewBox="0 0 10 6">
308
321
  <path fill="#202122" d="M4.792 5.528a.733.733 0 0 1-.537-.223L.224 1.282a.745.745 0 0 1 0-1.065.751.751 0 0 1 1.057 0l3.51 3.511L8.303.218A.751.751 0 0 1 9.36 1.281L5.337 5.305a.753.753 0 0 1-.535.223h-.01Z"/>
@@ -0,0 +1,45 @@
1
+ import { css, html } from 'lit';
2
+ import { bodySmallStyles } from '../typography/styles.js';
3
+
4
+ export const InputInlineHelpMixin = superclass => class extends superclass {
5
+
6
+ static get properties() {
7
+ return {
8
+ _hasInlineHelp: { type: Boolean, reflect: true, attribute: '_has-inline-help' }
9
+ };
10
+ }
11
+
12
+ static get styles() {
13
+ const styles = [ bodySmallStyles, css`
14
+ :host([_has-inline-help]) .d2l-input-inline-help {
15
+ display: block;
16
+ }
17
+ .d2l-input-inline-help {
18
+ display: none;
19
+ margin-top: 0.5rem !important;
20
+ overflow-wrap: anywhere;
21
+ }
22
+ `];
23
+
24
+ super.styles && styles.unshift(super.styles);
25
+ return styles;
26
+ }
27
+
28
+ constructor() {
29
+ super();
30
+ this._hasInlineHelp = false;
31
+ }
32
+
33
+ _handleInlineHelpSlotChange(e) {
34
+ const content = e.target.assignedNodes({ flatten: true });
35
+ this._hasInlineHelp = content?.length > 0;
36
+ }
37
+
38
+ _renderInlineHelp(id) {
39
+ return html`
40
+ <div id="${id}" class="d2l-body-small d2l-input-inline-help">
41
+ <slot name="inline-help" @slotchange="${this._handleInlineHelpSlotChange}"></slot>
42
+ </div>
43
+ `;
44
+ }
45
+ };
@@ -11,6 +11,7 @@ import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
11
11
  import { FormElementMixin } from '../form/form-element-mixin.js';
12
12
  import { getUniqueId } from '../../helpers/uniqueId.js';
13
13
  import { ifDefined } from 'lit/directives/if-defined.js';
14
+ import { InputInlineHelpMixin } from './input-inline-help-mixin.js';
14
15
  import { inputLabelStyles } from './input-label-styles.js';
15
16
  import { inputStyles } from './input-styles.js';
16
17
  import { LabelledMixin } from '../../mixins/labelled/labelled-mixin.js';
@@ -118,7 +119,7 @@ function initIntervals(size, enforceTimeIntervals) {
118
119
  * A component that consists of a text input field for typing a time and an attached dropdown for time selection. It displays the "value" if one is specified, or a placeholder if not, and reflects the selected value when one is selected in the dropdown or entered in the text input.
119
120
  * @fires change - Dispatched when there is a change to selected time. `value` corresponds to the selected value and is formatted in ISO 8601 time format (`hh:mm:ss`).
120
121
  */
121
- class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(RtlMixin(LitElement))))) {
122
+ class InputTime extends InputInlineHelpMixin(FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(RtlMixin(LitElement)))))) {
122
123
 
123
124
  static get properties() {
124
125
  return {
@@ -228,6 +229,7 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
228
229
  this._dropdownId = getUniqueId();
229
230
  this._hiddenContentWidth = '6rem';
230
231
  this._timezone = formatTime(new Date(), { format: 'ZZZ' });
232
+ this._inlineHelpId = getUniqueId();
231
233
  }
232
234
 
233
235
  get value() { return this._value; }
@@ -323,6 +325,8 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
323
325
  const formattedWideTimePM = formatTime(new Date(2020, 0, 1, 23, 23, 0));
324
326
  const inputTextWidth = `calc(${this._hiddenContentWidth} + 1.5rem + 3px)`; // text and icon width + left & right padding + border width + 1
325
327
  const opened = this.opened && !this.disabled && !this.skeleton;
328
+ const dropdownIdTimezone = `${this._dropdownId}-timezone`;
329
+ const ariaDescribedByIds = `${this._dropdownId ? dropdownIdTimezone : ''} ${this._hasInlineHelp ? this._inlineHelpId : ''}`.trim();
326
330
  this.style.maxWidth = inputTextWidth;
327
331
 
328
332
  return html`
@@ -338,7 +342,7 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
338
342
  <input
339
343
  aria-invalid="${this.invalid ? 'true' : 'false'}"
340
344
  aria-controls="${this._dropdownId}"
341
- aria-describedby="${this._dropdownId}-timezone"
345
+ aria-describedby="${ifDefined(ariaDescribedByIds.length > 0 ? ariaDescribedByIds : undefined)}"
342
346
  aria-expanded="false"
343
347
  aria-haspopup="true"
344
348
  aria-required="${ifDefined(ariaRequired)}"
@@ -367,9 +371,10 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
367
371
  role="listbox">
368
372
  ${menuItems}
369
373
  </d2l-menu>
370
- <div class="d2l-input-time-timezone d2l-body-small" id="${this._dropdownId}-timezone" slot="footer">${this._timezone}</div>
374
+ <div class="d2l-input-time-timezone d2l-body-small" id="${dropdownIdTimezone}" slot="footer">${this._timezone}</div>
371
375
  </d2l-dropdown-menu>
372
376
  </d2l-dropdown>
377
+ ${this._renderInlineHelp(this._inlineHelpId)}
373
378
  `;
374
379
  }
375
380
 
@@ -449,6 +454,5 @@ class InputTime extends FocusMixin(LabelledMixin(SkeletonMixin(FormElementMixin(
449
454
  e.preventDefault();
450
455
  }
451
456
  }
452
-
453
457
  }
454
458
  customElements.define('d2l-input-time', InputTime);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.172.1",
3
+ "version": "2.173.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",