@brightspace-ui/core 2.135.0 → 2.137.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.
@@ -49,6 +49,7 @@ class CollapsiblePanelSummaryItem extends SkeletonMixin(LitElement) {
49
49
  constructor() {
50
50
  super();
51
51
  this.text = '';
52
+ this.lines = 0;
52
53
  }
53
54
 
54
55
  render() {
@@ -329,17 +329,21 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
329
329
  if (this.hasAttribute('aria-label')) {
330
330
  this.labelRequired = false;
331
331
  }
332
+ this.addEventListener('mouseover', this._handleMouseEnter);
333
+ this.addEventListener('mouseout', this._handleMouseLeave);
334
+ this.addEventListener('click', this._handleClick);
332
335
  }
333
336
 
334
337
  disconnectedCallback() {
335
338
  super.disconnectedCallback();
336
339
  if (this._intersectionObserver) this._intersectionObserver.disconnect();
337
340
  const container = this.shadowRoot && this.shadowRoot.querySelector('.d2l-input-text-container');
341
+ this.removeEventListener('mouseover', this._handleMouseEnter);
342
+ this.removeEventListener('mouseout', this._handleMouseLeave);
343
+ this.removeEventListener('click', this._handleClick);
338
344
  if (!container) return;
339
345
  container.removeEventListener('blur', this._handleBlur, true);
340
346
  container.removeEventListener('focus', this._handleFocus, true);
341
- container.removeEventListener('mouseover', this._handleMouseEnter);
342
- container.removeEventListener('mouseout', this._handleMouseLeave);
343
347
  }
344
348
 
345
349
  firstUpdated(changedProperties) {
@@ -352,8 +356,6 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
352
356
  if (!container) return;
353
357
  container.addEventListener('blur', this._handleBlur, true);
354
358
  container.addEventListener('focus', this._handleFocus, true);
355
- container.addEventListener('mouseover', this._handleMouseEnter);
356
- container.addEventListener('mouseout', this._handleMouseLeave);
357
359
 
358
360
  // if initially hidden then update layout when it becomes visible
359
361
  if (typeof(IntersectionObserver) === 'function') {
@@ -542,6 +544,12 @@ class InputText extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMixin(
542
544
  ));
543
545
  }
544
546
 
547
+ _handleClick(e) {
548
+ const input = this.shadowRoot?.querySelector('.d2l-input');
549
+ if (!input || e.composedPath()[0] !== this) return;
550
+ input.focus();
551
+ }
552
+
545
553
  _handleFocus() {
546
554
  this._focused = true;
547
555
  }
@@ -1,5 +1,6 @@
1
1
  import '../tooltip/tooltip.js';
2
2
  import { css, html, LitElement } from 'lit';
3
+ import { classMap } from 'lit-html/directives/class-map.js';
3
4
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
4
5
  import { formatNumber } from '@brightspace-ui/intl/lib/number.js';
5
6
  import { FormElementMixin } from '../form/form-element-mixin.js';
@@ -86,7 +87,8 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
86
87
  * Value of the input
87
88
  * @type {string}
88
89
  */
89
- value: { type: String }
90
+ value: { type: String },
91
+ _hovered: { state: true }
90
92
  };
91
93
  }
92
94
 
@@ -157,6 +159,7 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
157
159
  this.value = '';
158
160
 
159
161
  this._descriptionId = getUniqueId();
162
+ this._hovered = false;
160
163
  this._textareaId = getUniqueId();
161
164
  }
162
165
 
@@ -192,6 +195,16 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
192
195
  if (this.hasAttribute('aria-label')) {
193
196
  this.labelRequired = false;
194
197
  }
198
+ this.addEventListener('mouseover', this._handleMouseEnter);
199
+ this.addEventListener('mouseout', this._handleMouseLeave);
200
+ this.addEventListener('click', this._handleClick);
201
+ }
202
+
203
+ disconnectedCallback() {
204
+ super.disconnectedCallback();
205
+ this.removeEventListener('mouseover', this._handleMouseEnter);
206
+ this.removeEventListener('mouseout', this._handleMouseLeave);
207
+ this.removeEventListener('click', this._handleClick);
195
208
  }
196
209
 
197
210
  render() {
@@ -211,6 +224,11 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
211
224
  if (this.rows > 0) mirrorStyles.minHeight = `calc(${this.rows + 1}rem + 2px)`;
212
225
  if (this.maxRows > 0) mirrorStyles.maxHeight = `calc(${this.maxRows + 1}rem + 2px)`;
213
226
 
227
+ const inputClasses = {
228
+ 'd2l-input': true,
229
+ 'd2l-input-focus': !this.disabled && this._hovered
230
+ };
231
+
214
232
  const textarea = html`
215
233
  <div class="d2l-input-textarea-container d2l-skeletize">
216
234
  <div class="d2l-input d2l-input-textarea-mirror" style="${styleMap(mirrorStyles)}" aria-invalid="${ifDefined(ariaInvalid)}">
@@ -222,7 +240,7 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
222
240
  aria-required="${ifDefined(ariaRequired)}"
223
241
  @blur="${this._handleBlur}"
224
242
  @change="${this._handleChange}"
225
- class="d2l-input"
243
+ class=${classMap(inputClasses)}
226
244
  ?disabled="${disabled}"
227
245
  id="${this._textareaId}"
228
246
  @input="${this._handleInput}"
@@ -307,6 +325,12 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
307
325
  ));
308
326
  }
309
327
 
328
+ _handleClick(e) {
329
+ const input = this.shadowRoot && this.shadowRoot.querySelector('textarea');
330
+ if (!input || e.composedPath()[0] !== this) return;
331
+ input.focus();
332
+ }
333
+
310
334
  _handleInput(e) {
311
335
  this.value = e.target.value;
312
336
  return true;
@@ -316,6 +340,14 @@ class InputTextArea extends FocusMixin(LabelledMixin(FormElementMixin(SkeletonMi
316
340
  e.preventDefault();
317
341
  }
318
342
 
343
+ _handleMouseEnter() {
344
+ this._hovered = true;
345
+ }
346
+
347
+ _handleMouseLeave() {
348
+ this._hovered = false;
349
+ }
350
+
319
351
  }
320
352
 
321
353
  customElements.define('d2l-input-textarea', InputTextArea);
@@ -51,6 +51,7 @@ Import and use the `<d2l-link>` web component instead of the native `<a>` elemen
51
51
  | `aria-label` | String | Sets an accessible label |
52
52
  | `download` | Boolean | Download a URL instead of navigating to it |
53
53
  | `main` | Boolean | Whether to apply the "main" link style |
54
+ | `lines` | Number | The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified. |
54
55
  | `small` | Boolean | Whether to apply the "small" link style |
55
56
  | `target` | String | Where to display the linked URL |
56
57
  <!-- docs: end hidden content -->
@@ -15,6 +15,9 @@
15
15
  max-width: 400px;
16
16
  padding: 0.6rem;
17
17
  }
18
+ .block {
19
+ display: block;
20
+ }
18
21
  </style>
19
22
  </head>
20
23
  <body unresolved>
@@ -48,11 +51,29 @@
48
51
  </template>
49
52
  </d2l-demo-snippet>
50
53
 
51
- <h2>Overflow-Ellipsis</h2>
54
+ <h2>Block Wrap</h2>
55
+ <d2l-demo-snippet>
56
+ <template>
57
+ <div class="truncate-container">
58
+ <d2l-link class="block" href="https://www.d2l.com">A really long link that will wrap in its container to the next line.</d2l-link>
59
+ </div>
60
+ </template>
61
+ </d2l-demo-snippet>
62
+
63
+ <h2>Clamp - One Line</h2>
64
+ <d2l-demo-snippet>
65
+ <template>
66
+ <div class="truncate-container">
67
+ <d2l-link href="https://www.d2l.com" lines="1">A really long link that will overflow its container and display an ellipsis.</d2l-link>
68
+ </div>
69
+ </template>
70
+ </d2l-demo-snippet>
71
+
72
+ <h2>Clamp - Two Lines</h2>
52
73
  <d2l-demo-snippet>
53
74
  <template>
54
75
  <div class="truncate-container">
55
- <d2l-link href="https://www.d2l.com" overflow-ellipsis>A really long link that will overflow its container.</d2l-link>
76
+ <d2l-link href="https://www.d2l.com" lines="2">A really really long link that wraps in its container and then truncates after two lines of text like this.</d2l-link>
56
77
  </div>
57
78
  </template>
58
79
  </d2l-demo-snippet>
@@ -4,6 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
4
4
  import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
5
5
  import { getFocusPseudoClass } from '../../helpers/focus.js';
6
6
  import { ifDefined } from 'lit/directives/if-defined.js';
7
+ import { styleMap } from 'lit/directives/style-map.js';
7
8
 
8
9
  export const linkStyles = css`
9
10
  .d2l-link, .d2l-link:visited, .d2l-link:active, .d2l-link:link {
@@ -74,10 +75,10 @@ class Link extends FocusMixin(LitElement) {
74
75
  */
75
76
  main: { type: Boolean, reflect: true },
76
77
  /**
77
- * Whether to truncate the link with ellipsis
78
- * @type {boolean}
78
+ * The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.
79
+ * @type {number}
79
80
  */
80
- overflowEllipsis: { type: Boolean, attribute: 'overflow-ellipsis', reflect: true },
81
+ lines: { type: Number },
81
82
  /**
82
83
  * Whether to apply the "small" link style
83
84
  * @type {boolean}
@@ -105,16 +106,14 @@ class Link extends FocusMixin(LitElement) {
105
106
  font-size: 0.7rem;
106
107
  line-height: 1.05rem;
107
108
  }
108
- :host([overflow-ellipsis]) {
109
- display: inline-block;
110
- max-width: 100%;
109
+ a {
110
+ display: inherit;
111
111
  }
112
- :host([overflow-ellipsis]) .d2l-link {
113
- display: inline-block;
114
- max-width: 100%;
112
+ a.truncate {
113
+ -webkit-box-orient: vertical;
114
+ display: -webkit-box;
115
115
  overflow: hidden;
116
- text-overflow: ellipsis;
117
- white-space: nowrap;
116
+ overflow-wrap: anywhere;
118
117
  }
119
118
  `
120
119
  ];
@@ -125,6 +124,7 @@ class Link extends FocusMixin(LitElement) {
125
124
  this.download = false;
126
125
  this.main = false;
127
126
  this.small = false;
127
+ this.lines = 0;
128
128
  }
129
129
 
130
130
  static get focusElementSelector() {
@@ -135,11 +135,14 @@ class Link extends FocusMixin(LitElement) {
135
135
  const linkClasses = {
136
136
  'd2l-link': true,
137
137
  'd2l-link-main': this.main,
138
- 'd2l-link-small': this.small
138
+ 'd2l-link-small': this.small,
139
+ 'truncate': this.lines > 0
139
140
  };
141
+ const styles = (this.lines > 0) ? { '-webkit-line-clamp': this.lines } : {};
140
142
  return html`<a
141
143
  aria-label="${ifDefined(this.ariaLabel)}"
142
144
  class="${classMap(linkClasses)}"
145
+ style="${styleMap(styles)}"
143
146
  ?download="${this.download}"
144
147
  href="${ifDefined(this.href)}"
145
148
  target="${ifDefined(this.target)}"><slot></slot></a>`;
@@ -56,6 +56,10 @@
56
56
  white-space: nowrap;
57
57
  }
58
58
 
59
+ .truncated d2l-link {
60
+ display: flex;
61
+ }
62
+
59
63
  .dark-background {
60
64
  background-color: black;
61
65
  padding: 20px;
@@ -159,11 +163,11 @@
159
163
  <d2l-tooltip for="tooltip-long" show-truncated-only>
160
164
  Very Very Very Very Long Tooltip - this tooltip will show because the text is truncating.
161
165
  </d2l-tooltip>
162
- <d2l-link id="link-short" href="https://www.d2l.com" overflow-ellipsis>Short Text</d2l-link>
166
+ <d2l-link id="link-short" href="https://www.d2l.com" lines="1">Short Text</d2l-link>
163
167
  <d2l-tooltip for="link-short" show-truncated-only>
164
168
  This tooltip will not show.
165
169
  </d2l-tooltip>
166
- <d2l-link id="link-long" href="https://www.d2l.com" overflow-ellipsis>Very Very Very Very Long Text</d2l-link>
170
+ <d2l-link id="link-long" href="https://www.d2l.com" lines="1">Very Very Very Very Long Text</d2l-link>
167
171
  <d2l-tooltip for="link-long" show-truncated-only>
168
172
  Very Very Very Very Long Text - this tooltip will show because the text is truncating.
169
173
  </d2l-tooltip>
@@ -976,6 +976,7 @@ class Tooltip extends RtlMixin(LitElement) {
976
976
  const clone = target.cloneNode(true);
977
977
  clone.removeAttribute('id');
978
978
  clone.style.maxWidth = 'none';
979
+ clone.style.display = 'inline-block';
979
980
 
980
981
  cloneContainer.appendChild(clone);
981
982
  target.appendChild(cloneContainer);
@@ -1162,17 +1162,18 @@
1162
1162
  "path": "./components/collapsible-panel/collapsible-panel-summary-item.js",
1163
1163
  "description": "A component for a \"summary item\" child component that describes the content in a collapsible panel.",
1164
1164
  "attributes": [
1165
- {
1166
- "name": "lines",
1167
- "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
1168
- "type": "number"
1169
- },
1170
1165
  {
1171
1166
  "name": "text",
1172
1167
  "description": "REQUIRED: Text that is displayed",
1173
1168
  "type": "string",
1174
1169
  "default": "\"\""
1175
1170
  },
1171
+ {
1172
+ "name": "lines",
1173
+ "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
1174
+ "type": "number",
1175
+ "default": "0"
1176
+ },
1176
1177
  {
1177
1178
  "name": "skeleton",
1178
1179
  "description": "Renders the input as a [skeleton loader](https://github.com/BrightspaceUI/core/tree/main/components/skeleton)",
@@ -1181,12 +1182,6 @@
1181
1182
  }
1182
1183
  ],
1183
1184
  "properties": [
1184
- {
1185
- "name": "lines",
1186
- "attribute": "lines",
1187
- "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
1188
- "type": "number"
1189
- },
1190
1185
  {
1191
1186
  "name": "text",
1192
1187
  "attribute": "text",
@@ -1194,6 +1189,13 @@
1194
1189
  "type": "string",
1195
1190
  "default": "\"\""
1196
1191
  },
1192
+ {
1193
+ "name": "lines",
1194
+ "attribute": "lines",
1195
+ "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
1196
+ "type": "number",
1197
+ "default": "0"
1198
+ },
1197
1199
  {
1198
1200
  "name": "skeleton",
1199
1201
  "attribute": "skeleton",
@@ -7591,11 +7593,6 @@
7591
7593
  "description": "REQUIRED: URL or URL fragment of the link",
7592
7594
  "type": "string"
7593
7595
  },
7594
- {
7595
- "name": "overflow-ellipsis",
7596
- "description": "Whether to truncate the link with ellipsis",
7597
- "type": "boolean"
7598
- },
7599
7596
  {
7600
7597
  "name": "target",
7601
7598
  "description": "Where to display the linked URL",
@@ -7618,6 +7615,12 @@
7618
7615
  "description": "Whether to apply the \"small\" link style",
7619
7616
  "type": "boolean",
7620
7617
  "default": "false"
7618
+ },
7619
+ {
7620
+ "name": "lines",
7621
+ "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
7622
+ "type": "number",
7623
+ "default": "0"
7621
7624
  }
7622
7625
  ],
7623
7626
  "properties": [
@@ -7633,12 +7636,6 @@
7633
7636
  "description": "REQUIRED: URL or URL fragment of the link",
7634
7637
  "type": "string"
7635
7638
  },
7636
- {
7637
- "name": "overflowEllipsis",
7638
- "attribute": "overflow-ellipsis",
7639
- "description": "Whether to truncate the link with ellipsis",
7640
- "type": "boolean"
7641
- },
7642
7639
  {
7643
7640
  "name": "target",
7644
7641
  "attribute": "target",
@@ -7665,6 +7662,13 @@
7665
7662
  "description": "Whether to apply the \"small\" link style",
7666
7663
  "type": "boolean",
7667
7664
  "default": "false"
7665
+ },
7666
+ {
7667
+ "name": "lines",
7668
+ "attribute": "lines",
7669
+ "description": "The number of lines to display before truncating text with an ellipsis. The text will not be truncated unless a value is specified.",
7670
+ "type": "number",
7671
+ "default": "0"
7668
7672
  }
7669
7673
  ],
7670
7674
  "slots": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "2.135.0",
3
+ "version": "2.137.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",
@@ -19,9 +19,9 @@
19
19
  "lint:style": "stylelint \"**/*.{js,html}\" --ignore-path .gitignore",
20
20
  "start": "web-dev-server --node-resolve --watch --open",
21
21
  "test": "npm run lint && npm run test:translations && npm run test:headless && npm run test:axe",
22
- "test:axe": "web-test-runner --group aXe",
23
- "test:headless": "web-test-runner --group unit",
24
- "test:headless:watch": "web-test-runner --group unit --watch",
22
+ "test:axe": "d2l-test-runner aXe",
23
+ "test:headless": "d2l-test-runner",
24
+ "test:headless:watch": "d2l-test-runner --watch",
25
25
  "test:translations": "mfv -e -s en -p ./lang/ -i untranslated"
26
26
  },
27
27
  "files": [
@@ -45,7 +45,7 @@
45
45
  "devDependencies": {
46
46
  "@babel/eslint-parser": "^7",
47
47
  "@brightspace-ui/stylelint-config": "^0.8",
48
- "@brightspace-ui/testing": "^0.15",
48
+ "@brightspace-ui/testing": "^0.18",
49
49
  "@open-wc/semantic-dom-diff": "^0.20",
50
50
  "@rollup/plugin-dynamic-import-vars": "^2",
51
51
  "@rollup/plugin-node-resolve": "^15",