@brightspace-ui/core 3.266.1 → 3.267.1

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.
@@ -1,8 +1,10 @@
1
1
  import { css, unsafeCSS } from 'lit';
2
- import { getFocusPseudoClass } from '../../helpers/focus.js';
2
+ import { getFocusPseudoClass, getFocusVisibleStyles } from '../../helpers/focus.js';
3
+ import { _isValidCssSelector } from '../../helpers/internal/css.js';
4
+ import { getFlag } from '../../helpers/flags.js';
3
5
  import { registerSemanticVariableForSvgImageUrl } from '../colors/colors.js';
4
6
 
5
- const focusClass = unsafeCSS(getFocusPseudoClass());
7
+ const focusClass = unsafeCSS(globalThis.document !== undefined ? getFocusPseudoClass() : 'focus-visible');
6
8
 
7
9
  registerSemanticVariableForSvgImageUrl(
8
10
  '--d2l-input-invalid-image',
@@ -12,7 +14,142 @@ registerSemanticVariableForSvgImageUrl(
12
14
  </svg>`
13
15
  );
14
16
 
15
- export const inputStyles = css`
17
+ function getStyleDelegates(selector, focusSelector, textAreaSelector) {
18
+ return {
19
+ input: {
20
+ selector: focusClass => `
21
+ ${focusSelector ? `${focusSelector},` : ''}
22
+ ${selector}:${focusClass}:not(:disabled),
23
+ ${selector}:hover:not(:disabled)
24
+ `,
25
+ style: fullSelector => css`
26
+ ${fullSelector} {
27
+ border-color: var(--d2l-theme-border-color-focus);
28
+ border-width: 2px;
29
+ outline: none;
30
+ padding: var(--d2l-input-padding-focus, calc(0.4rem - 1px) calc(0.75rem - 1px));
31
+ }
32
+ `
33
+ },
34
+ textarea: {
35
+ selector: focusClass => `
36
+ ${textAreaSelector}:hover:not(:disabled),
37
+ ${textAreaSelector}:${focusClass}:not(:disabled)
38
+ `,
39
+ style: fullSelector => css`
40
+ ${fullSelector} {
41
+ padding-block: calc(0.5rem - 1px);
42
+ }
43
+ `
44
+ },
45
+ textareaInvalid: {
46
+ selector: focusClass => `
47
+ ${textAreaSelector}-focus[aria-invalid="true"],
48
+ ${textAreaSelector}[aria-invalid="true"]:hover,
49
+ ${textAreaSelector}[aria-invalid="true"]:${focusClass}
50
+ `,
51
+ style: fullSelector => css`
52
+ ${fullSelector} {
53
+ background-position: top calc(12px - 1px) var(--d2l-inline-end, right) calc(18px - 1px);
54
+ padding-inline-end: calc(18px + 0.8rem - 1px);
55
+ }
56
+ `
57
+ }
58
+ };
59
+ }
60
+
61
+ export function _generateInputStyles(selector, focusSelector) {
62
+ if (!_isValidCssSelector(selector) || (focusSelector && !_isValidCssSelector(focusSelector))) return '';
63
+ const lastSpaceIndex = selector.lastIndexOf(' ');
64
+ const textareaSelector = unsafeCSS(`${selector.substring(0, lastSpaceIndex + 1)}textarea${selector.substring(lastSpaceIndex + 1)}`);
65
+ const delegates = getStyleDelegates(selector, focusSelector, textareaSelector);
66
+
67
+ selector = unsafeCSS(selector);
68
+ return css`
69
+ ${selector} {
70
+ background-color: var(--d2l-input-background-color, var(--d2l-theme-background-color-base));
71
+ border: 1px solid var(--d2l-input-border-color, var(--d2l-theme-border-color-emphasized));
72
+ border-radius: var(--d2l-input-border-radius, 0.3rem);
73
+ box-shadow: var(--d2l-theme-shadow-inset);
74
+ box-sizing: border-box;
75
+ color: var(--d2l-theme-text-color-static-standard);
76
+ display: inline-block;
77
+ font-family: inherit;
78
+ font-size: 0.8rem;
79
+ font-weight: 400;
80
+ height: var(--d2l-input-height, auto);
81
+ letter-spacing: 0.02rem;
82
+ line-height: 1.2rem;
83
+ margin: 0;
84
+ min-width: calc(2rem + 1em);
85
+ padding: var(--d2l-input-padding, 0.4rem 0.75rem);
86
+ position: var(--d2l-input-position, relative); /* overridden by sticky headers in grades */
87
+ text-align: var(--d2l-input-text-align, start);
88
+ vertical-align: middle;
89
+ width: 100%;
90
+ }
91
+ ${getFocusVisibleStyles(delegates.input.selector, delegates.input.style)}
92
+
93
+ ${selector}::placeholder {
94
+ color: var(--d2l-theme-text-color-static-faint);
95
+ font-size: 0.8rem;
96
+ font-weight: 400;
97
+ opacity: 1; /* Firefox has non-1 default */
98
+ }
99
+ ${selector}::-ms-input-placeholder {
100
+ color: var(--d2l-theme-text-color-static-faint);
101
+ font-size: 0.8rem;
102
+ font-weight: 400;
103
+ }
104
+
105
+ [aria-invalid="true"]${selector}:not(:disabled) {
106
+ border-color: var(--d2l-theme-status-color-error);
107
+ }
108
+ ${selector}:disabled {
109
+ opacity: var(--d2l-theme-opacity-disabled-control);
110
+ }
111
+ ${selector}::-webkit-search-cancel-button,
112
+ ${selector}::-webkit-search-decoration {
113
+ display: none;
114
+ }
115
+ ${selector}::-ms-clear {
116
+ display: none;
117
+ height: 0;
118
+ width: 0;
119
+ }
120
+ ${textareaSelector} {
121
+ line-height: normal;
122
+ padding-block: 0.5rem;
123
+ }
124
+ ${getFocusVisibleStyles(delegates.textarea.selector, delegates.textarea.style)}
125
+ ${textareaSelector}[aria-invalid="true"] {
126
+ background-image: var(--d2l-input-invalid-image);
127
+ background-position: top 12px var(--d2l-inline-end, right) 18px;
128
+ background-repeat: no-repeat;
129
+ background-size: 0.8rem 0.8rem;
130
+ padding-inline-end: calc(18px + 0.8rem);
131
+ }
132
+ ${getFocusVisibleStyles(delegates.textareaInvalid.selector, delegates.textareaInvalid.style)}
133
+ ${textareaSelector}[aria-invalid="true"]:disabled {
134
+ background-image: none;
135
+ }
136
+
137
+ @media (prefers-contrast: more) {
138
+ ${selector}[aria-invalid="true"] {
139
+ background-color: Field;
140
+ border-color: var(--d2l-theme-status-color-error);
141
+ box-shadow: none;
142
+ color: FieldText;
143
+ forced-color-adjust: none;
144
+ }
145
+ ${focusSelector ? css`${unsafeCSS(focusSelector)} {
146
+ border-color: Highlight;
147
+ }` : css``}
148
+ }
149
+ `;
150
+ }
151
+
152
+ export const inputStyles = getFlag('GAUD-8852-use-input-generated-styles', true) ? _generateInputStyles('.d2l-input', '.d2l-input-focus') : css`
16
153
  .d2l-input {
17
154
  background-color: var(--d2l-input-background-color, var(--d2l-theme-background-color-base));
18
155
  border-radius: var(--d2l-input-border-radius, 0.3rem);
@@ -1,5 +1,6 @@
1
1
  import '../selection/selection-input.js';
2
2
  import { css, html, nothing } from 'lit';
3
+ import { classMap } from 'lit/directives/class-map.js';
3
4
  import { getUniqueId } from '../../helpers/uniqueId.js';
4
5
  import { isInteractiveInListItemComposedPath } from './list-item-mixin.js';
5
6
  import { SelectionInfo } from '../selection/selection-mixin.js';
@@ -57,6 +58,9 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(s
57
58
  :host([selection-disabled]) [slot="control-action"] [slot="content"] {
58
59
  pointer-events: all;
59
60
  }
61
+ :host([layout="tile"]) .bump-inline {
62
+ margin-inline-start: 2rem !important;
63
+ }
60
64
  ` ];
61
65
 
62
66
  super.styles && styles.unshift(super.styles);
@@ -164,6 +168,9 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(s
164
168
  }
165
169
 
166
170
  _renderCheckbox() {
171
+ const classes = {
172
+ 'bump-inline': this._keyboardActive
173
+ };
167
174
  return this.selectable ? html`
168
175
  <d2l-selection-input
169
176
  @d2l-selection-change="${this._onCheckboxChange}"
@@ -177,7 +184,8 @@ export const ListItemCheckboxMixin = superclass => class extends SkeletonMixin(s
177
184
  @mouseenter="${this._onMouseEnterSelection}"
178
185
  @mouseleave="${this._onMouseLeaveSelection}"
179
186
  ?selected="${this.selected}"
180
- ?skeleton="${this.skeleton}">
187
+ ?skeleton="${this.skeleton}"
188
+ class=${classMap(classes)}>
181
189
  </d2l-selection-input>
182
190
  ` : nothing;
183
191
  }
@@ -311,12 +311,32 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
311
311
  width: 100%;
312
312
  z-index: 1;
313
313
  }
314
+
314
315
  .d2l-list-item-drag-bottom-marker {
315
316
  bottom: -6px;
316
317
  }
317
318
  .d2l-list-item-drag-top-marker {
318
319
  top: -6px;
319
320
  }
321
+
322
+ :host([layout="tile"]) .d2l-list-item-drag-bottom-marker,
323
+ :host([layout="tile"]) .d2l-list-item-drag-top-marker {
324
+ height: 100%;
325
+ width: auto;
326
+ }
327
+
328
+ :host([layout="tile"]) .d2l-list-item-drag-bottom-marker {
329
+ /* The gap between the cards plus half the width of the marker */
330
+ inset-inline-end: calc(-0.9rem + 3px);
331
+ bottom: 0;
332
+ }
333
+ :host([layout="tile"]) .d2l-list-item-drag-top-marker {
334
+ /* The gap between the cards plus half the width of the marker */
335
+ inset-inline-start: calc(-0.9rem + 3px);
336
+ top: 0;
337
+ }
338
+
339
+
320
340
  .d2l-list-item-drag-area {
321
341
  cursor: move;
322
342
  height: 100%;
@@ -326,6 +346,11 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
326
346
  grid-template-columns: 100%;
327
347
  grid-template-rows: 1rem 1fr 1fr 1rem;
328
348
  }
349
+ :host([layout="tile"]) .d2l-list-item-drag-drop-grid {
350
+ display: grid;
351
+ grid-template-columns: 1rem 1fr 1fr 1rem;
352
+ grid-template-rows: 100%;
353
+ }
329
354
  :host([_drop-location="7"]) {
330
355
  z-index: 1; /* drop target border must render on top of next adjacent border */
331
356
  }
@@ -344,6 +369,10 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
344
369
  d2l-list-item-drag-handle {
345
370
  opacity: 0;
346
371
  }
372
+ :host([layout="tile"][draggable]) d2l-list-item-drag-handle {
373
+ opacity: 1;
374
+ }
375
+
347
376
  :host([selected]) d2l-list-item-drag-handle,
348
377
  :host([current]) d2l-list-item-drag-handle,
349
378
  :host([_drag-handle-show-always]) d2l-list-item-drag-handle,
@@ -858,6 +887,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
858
887
  ?disabled="${this.keyboardDragDisabled}"
859
888
  text="${ifDefined(this.dragHandleText)}"
860
889
  keyboard-text-info="${ifDefined(this._keyboardTextInfo)}"
890
+ layout="${this.layout}"
861
891
  @focusin="${this._onFocusinDragHandle}"
862
892
  @focusout="${this._onFocusoutDragHandle}"
863
893
  @d2l-list-item-drag-handle-action="${this._onDragHandleActions}">
@@ -38,6 +38,9 @@ export const dragActions = Object.freeze({
38
38
  });
39
39
 
40
40
  let hasDisplayedKeyboardTooltip = false;
41
+ export const resetDisplayedTooltip = () => {
42
+ hasDisplayedKeyboardTooltip = false;
43
+ };
41
44
 
42
45
  /**
43
46
  * @fires d2l-list-item-drag-handle-action - Dispatched when an action performed on the drag handle
@@ -61,6 +64,10 @@ class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(LitElement)) {
61
64
  * @type {string}
62
65
  */
63
66
  text: { type: String },
67
+ /**
68
+ * When layout = tile, the drag handle become horizontal
69
+ */
70
+ layout: { type: String },
64
71
  _displayKeyboardTooltip: { type: Boolean },
65
72
  _keyboardActive: { type: Boolean }
66
73
  };
@@ -117,6 +124,12 @@ class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(LitElement)) {
117
124
  d2l-button-move {
118
125
  pointer-events: auto; /* required since ancestors may set point-events: none; (see generic layout) */
119
126
  }
127
+
128
+ :host([layout="tile"]) {
129
+ align-items: center;
130
+ display: flex;
131
+ height: 39px;
132
+ }
120
133
  `];
121
134
  }
122
135
 
@@ -152,7 +165,9 @@ class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(LitElement)) {
152
165
  get _defaultLabel() {
153
166
  const namespace = 'components.list-item-drag-handle';
154
167
  const defaultLabel = this.localize(`${namespace}.${'default'}`, 'name', this.text);
155
- const keyboardTextLabel = this.localize(`${namespace}.${'keyboard'}`, 'currentPosition', this.keyboardTextInfo && this.keyboardTextInfo.currentPosition, 'size', this.keyboardTextInfo && this.keyboardTextInfo.count);
168
+ const keyboardTextLabel = this.layout !== 'tile'
169
+ ? this.localize(`${namespace}.${'keyboard'}`, 'currentPosition', this.keyboardTextInfo && this.keyboardTextInfo.currentPosition, 'size', this.keyboardTextInfo && this.keyboardTextInfo.count)
170
+ : this.localize(`${namespace}.${'side-to-side.keyboard'}`, 'currentPosition', this.keyboardTextInfo && this.keyboardTextInfo.currentPosition, 'size', this.keyboardTextInfo && this.keyboardTextInfo.count);
156
171
  return this._keyboardActive ? keyboardTextLabel : defaultLabel;
157
172
  }
158
173
 
@@ -182,6 +197,20 @@ class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(LitElement)) {
182
197
 
183
198
  const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
184
199
 
200
+ if (this.layout === 'tile') {
201
+ if (!isRtl) {
202
+ if (e.detail.action === moveActions.right)
203
+ e.detail.action = moveActions.down;
204
+ if (e.detail.action === moveActions.left)
205
+ e.detail.action = moveActions.up;
206
+ } else {
207
+ if (e.detail.action === moveActions.right)
208
+ e.detail.action = moveActions.up;
209
+ if (e.detail.action === moveActions.left)
210
+ e.detail.action = moveActions.down;
211
+ }
212
+ }
213
+
185
214
  let action = null;
186
215
  switch (e.detail.action) {
187
216
  case moveActions.up:
@@ -299,19 +328,25 @@ class ListItemDragHandle extends LocalizeCoreElement(FocusMixin(LitElement)) {
299
328
  id="${this._buttonId}"
300
329
  @keydown="${this._onMoveButtonKeydown}"
301
330
  @mousedown="${this._onMoveButtonMouseDown}"
302
- text="${this._defaultLabel}">
331
+ text="${this._defaultLabel}"
332
+ ?side-to-side="${this.layout === 'tile'}">
303
333
  </d2l-button-move>
304
334
  ${this._displayKeyboardTooltip ? html`<d2l-tooltip class="vdiff-target" align="start" announced for="${this._buttonId}" for-type="descriptor">${this._renderTooltipContent()}</d2l-tooltip>` : ''}
305
335
  `;
306
336
  }
307
337
 
308
338
  _renderTooltipContent() {
339
+ const namespace = 'components.list-item-drag-handle-tooltip';
340
+ const controlNamespace = this.layout === 'tile'
341
+ ? `${namespace}.side-to-side`
342
+ : namespace;
343
+
309
344
  return html`
310
- <div>${this.localize('components.list-item-drag-handle-tooltip.title')}</div>
345
+ <div>${this.localize(`${namespace}.title`)}</div>
311
346
  <ul>
312
- <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.enter-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.enter-desc')}</li>
313
- <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.up-down-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.up-down-desc')}</li>
314
- <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize('components.list-item-drag-handle-tooltip.left-right-key')}</span> - ${this.localize('components.list-item-drag-handle-tooltip.left-right-desc')}</li>
347
+ <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize(`${namespace}.enter-key`)}</span> - ${this.localize(`${namespace}.enter-desc`)}</li>
348
+ <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize(`${namespace}.up-down-key`)}</span> - ${this.localize(`${controlNamespace}.up-down-desc`)}</li>
349
+ <li><span class="d2l-list-item-drag-handle-tooltip-key">${this.localize(`${namespace}.left-right-key`)}</span> - ${this.localize(`${controlNamespace}.left-right-desc`)}</li>
315
350
  </ul>
316
351
  `;
317
352
  }
@@ -65,8 +65,7 @@ class ListItemGenericLayout extends LitElement {
65
65
  /**
66
66
  * @ignore
67
67
  */
68
- layout: { type: String, reflect: true }
69
-
68
+ layout: { type: String, reflect: true },
70
69
  };
71
70
  }
72
71
 
@@ -216,7 +215,21 @@ class ListItemGenericLayout extends LitElement {
216
215
 
217
216
  :host([layout="tile"]) {
218
217
  grid-template-columns:
219
- [start control-start] minmax(0, min-content)
218
+ [start outside-control-start] minmax(0, 26px)
219
+ [outside-control-end control-start] minmax(0, min-content)
220
+ [control-end actions-start] minmax(0, auto)
221
+ [actions-end end];
222
+ grid-template-rows:
223
+ [start header-start] minmax(0, min-content)
224
+ [header-end content-start] auto
225
+ [content-end end];
226
+ height: 100%;
227
+ }
228
+
229
+ :host([layout="tile"]:not([is-draggable])) {
230
+ grid-template-columns:
231
+ [start outside-control-start] 0
232
+ [outside-control-end control-start] minmax(0, min-content)
220
233
  [control-end actions-start] minmax(0, auto)
221
234
  [actions-end end];
222
235
  grid-template-rows:
@@ -258,14 +271,22 @@ class ListItemGenericLayout extends LitElement {
258
271
  grid-row: content-start / content-end;
259
272
  }
260
273
 
274
+ :host([layout="tile"]) ::slotted([slot="outside-control"]) {
275
+ grid-column: outside-control-start / outside-control-end;
276
+ grid-row: start / start;
277
+ width: min-content;
278
+ }
279
+
280
+ :host([layout="tile"]) ::slotted([slot="outside-control-action"]) {
281
+ grid-column: start / end;
282
+ grid-row: start / start;
283
+ }
284
+
261
285
  :host(:not([layout="tile"])) slot[name="header"],
262
286
  :host([layout="tile"]) slot[name="add-top"],
263
287
  :host([layout="tile"]) slot[name="control-container"],
264
288
  :host([layout="tile"]) slot[name="before-content"],
265
- :host([layout="tile"]) slot[name="outside-control"],
266
- :host([layout="tile"]) slot[name="outside-control-action"],
267
289
  :host([layout="tile"]) slot[name="expand-collapse"],
268
- :host([layout="tile"]) slot[name="drop-target"],
269
290
  :host([layout="tile"]) slot[name="nested"],
270
291
  :host([layout="tile"]) slot[name="add"] {
271
292
  display: none;
@@ -35,6 +35,10 @@ export const ListItemLinkMixin = superclass => class extends ListItemMixin(super
35
35
  :host([action-href]:not([action-href=""])) [slot="outside-control-action"] {
36
36
  grid-column-end: control-end;
37
37
  }
38
+
39
+ :host([action-href]:not([action-href=""])[layout="tile"]) [slot="outside-control-action"] {
40
+ grid-column-end: end;
41
+ }
38
42
  ` ];
39
43
 
40
44
  super.styles && styles.unshift(super.styles);
@@ -163,6 +163,11 @@ export const ListItemMixin = superclass => class extends composeMixins(
163
163
  background: white;
164
164
  }
165
165
 
166
+ :host([dragging][layout="tile"]) d2l-list-item-generic-layout {
167
+ filter: grayscale(75%);
168
+ opacity: 0.4;
169
+ }
170
+
166
171
  [slot="control-container"] {
167
172
  pointer-events: none;
168
173
  position: relative;
@@ -333,6 +338,11 @@ export const ListItemMixin = superclass => class extends composeMixins(
333
338
  margin: 0.25rem 0.3rem;
334
339
  }
335
340
 
341
+ :host([layout="tile"]) d2l-list-item-drag-handle {
342
+ margin-block: 0;
343
+ margin-inline: 0.3rem 0;
344
+ }
345
+
336
346
  [slot="outside-control-container"] {
337
347
  border: 1px solid transparent;
338
348
  border-radius: 6px;
@@ -474,6 +484,7 @@ export const ListItemMixin = superclass => class extends composeMixins(
474
484
  transform: translateY(-10px);
475
485
  transition: opacity 200ms ease-out, transform 0ms ease-out 300ms;
476
486
  }
487
+
477
488
  :host([layout="tile"][_selection-when-interacted]) [slot="control"]:hover,
478
489
  :host([layout="tile"][_selection-when-interacted][_focusing]) [slot="control"],
479
490
  :host([layout="tile"][_selection-when-interacted][_force-show-selection]) [slot="control"],
@@ -484,6 +495,10 @@ export const ListItemMixin = superclass => class extends composeMixins(
484
495
  transition: opacity 200ms ease-out, transform 200ms ease-out;
485
496
  }
486
497
 
498
+ :host([layout="tile"][draggable][tile-header]) [slot="control"] {
499
+ margin: 0.25rem 0;
500
+ }
501
+
487
502
  @media (prefers-reduced-motion: reduce) {
488
503
  :host([layout="tile"][_selection-when-interacted]) [slot="control"] {
489
504
  transform: none;
@@ -587,6 +602,11 @@ export const ListItemMixin = superclass => class extends composeMixins(
587
602
  :host([layout="tile"]) d2l-selection-input {
588
603
  margin: 0;
589
604
  }
605
+
606
+ :host([layout="tile"][draggable]) d2l-selection-input {
607
+ margin: auto;
608
+ margin-inline-start: 0.3rem;
609
+ }
590
610
  :host([layout="tile"]:not([tile-header])) d2l-selection-input {
591
611
  --d2l-input-checkbox-border-color-hover-focus: var(--d2l-color-celestine-minus-1);
592
612
  --d2l-input-radio-border-color-hover-focus: var(--d2l-color-celestine-minus-1);
@@ -724,6 +744,9 @@ export const ListItemMixin = superclass => class extends composeMixins(
724
744
  this._hasListItemContent = !!this.shadowRoot.querySelector('slot:not([name])').assignedElements({ flatten: true })
725
745
  .find(elem => elem.tagName === 'D2L-LIST-ITEM-CONTENT');
726
746
  }
747
+ if (this.draggable) {
748
+ this.tileHeader = true;
749
+ }
727
750
  }
728
751
 
729
752
  focus() {
@@ -975,6 +998,8 @@ export const ListItemMixin = superclass => class extends composeMixins(
975
998
  data-separators="${ifDefined(this._separators)}"
976
999
  indentation="${ifDefined(this.indentation)}"
977
1000
  ?grid-active="${this.role === 'row'}"
1001
+ ?selectable="${this.selectable}"
1002
+ ?is-draggable="${this.draggable}"
978
1003
  layout="${this.layout}"
979
1004
  ?no-primary-action="${this.noPrimaryAction}">
980
1005
  ${this._showAddButton && this.first ? html`
@@ -1038,10 +1063,12 @@ export const ListItemMixin = superclass => class extends composeMixins(
1038
1063
  </d2l-list-item-generic-layout>
1039
1064
  `;
1040
1065
 
1066
+ const isDraggableTile = this.draggable && this.layout === 'tile';
1067
+
1041
1068
  return html`
1042
- ${this._renderTopPlacementMarker(html`<d2l-list-item-placement-marker></d2l-list-item-placement-marker>`)}
1069
+ ${this._renderTopPlacementMarker(html`<d2l-list-item-placement-marker ?vertical="${isDraggableTile}"></d2l-list-item-placement-marker>`)}
1043
1070
  ${this.draggable ? html`<div class="d2l-list-item-drag-image">${innerView}</div>` : innerView}
1044
- ${this._renderBottomPlacementMarker(html`<d2l-list-item-placement-marker></d2l-list-item-placement-marker>`)}
1071
+ ${this._renderBottomPlacementMarker(html`<d2l-list-item-placement-marker ?vertical="${isDraggableTile}"></d2l-list-item-placement-marker>`)}
1045
1072
  ${this._displayKeyboardTooltip && tooltipForId ? html`<d2l-tooltip align="start" announced for="${tooltipForId}" for-type="descriptor">${this.localizeHTML('components.list.keyboard')}</d2l-tooltip>` : ''}
1046
1073
  ${this.draggable ? this._renderDragMultipleImage() : nothing}
1047
1074
  `;
@@ -3,25 +3,44 @@ import { css, html, LitElement } from 'lit';
3
3
 
4
4
  class ListItemPlacementMarker extends LitElement {
5
5
 
6
+ static properties = {
7
+ vertical: { type: Boolean, reflect: true }
8
+ };
9
+
6
10
  static get styles() {
7
11
  return css`
8
12
  :host {
9
13
  display: block;
10
14
  }
11
15
 
16
+ :host([vertical]) {
17
+ height: 100%;
18
+ }
19
+
12
20
  :host([hidden]) {
13
21
  display: none;
14
22
  }
15
23
 
24
+ :host([vertical]) .d2l-list-drag-marker-line {
25
+ height: 100%;
26
+ margin: -1px 0;
27
+ width: 12px;
28
+ }
29
+
16
30
  .d2l-list-drag-marker-line {
17
31
  height: 12px;
18
- margin-left: -1px;
19
- margin-right: -1px;
32
+ margin-inline: -1px;
20
33
  stroke: var(--d2l-color-celestine);
21
34
  stroke-width: 3px;
22
35
  width: 100%;
23
36
  }
24
37
 
38
+ :host([vertical]) .d2l-list-drag-marker-linecap {
39
+ height: 4px;
40
+ margin-inline: 0 -2px;
41
+ width: 12px;
42
+ }
43
+
25
44
  .d2l-list-drag-marker-linecap {
26
45
  fill: var(--d2l-color-celestine);
27
46
  height: 12px;
@@ -30,6 +49,11 @@ class ListItemPlacementMarker extends LitElement {
30
49
  width: 4px;
31
50
  }
32
51
 
52
+ :host([vertical]) .d2l-list-drag-marker-circle {
53
+ margin-inline: 0 0;
54
+ }
55
+
56
+
33
57
  .d2l-list-drag-marker-circle {
34
58
  fill: none;
35
59
  height: 12px;
@@ -43,10 +67,37 @@ class ListItemPlacementMarker extends LitElement {
43
67
  display: flex;
44
68
  flex-wrap: nowrap;
45
69
  }
70
+
71
+ :host([vertical]) .d2l-list-drag-marker {
72
+ flex-direction: column;
73
+ height: 100%;
74
+ }
46
75
  `;
47
76
  }
48
77
 
78
+ constructor() {
79
+ super();
80
+ this.vertical = false;
81
+ }
82
+
49
83
  render() {
84
+
85
+ if (this.vertical) {
86
+ return html`
87
+ <div class="d2l-list-drag-marker">
88
+ <svg class="d2l-list-drag-marker-circle">
89
+ <circle cx="50%" cy="50%" r="3.8px"/>
90
+ </svg>
91
+ <svg class="d2l-list-drag-marker-line">
92
+ <line x1="50%" y1="0" x2="50%" y2="100%" />
93
+ </svg>
94
+ <svg class="d2l-list-drag-marker-linecap">
95
+ <circle cx="50%" cy="50%" r="1.5px"/>
96
+ </svg>
97
+ </div>
98
+ `;
99
+ }
100
+
50
101
  return html`
51
102
  <div class="d2l-list-drag-marker">
52
103
  <svg class="d2l-list-drag-marker-circle">