@getflip/swirl-components 0.67.0 → 0.68.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.
Files changed (58) hide show
  1. package/components.json +175 -9
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/sortable.esm-73cf219b.js +3023 -0
  4. package/dist/cjs/swirl-app-layout_7.cjs.entry.js +168 -11
  5. package/dist/cjs/swirl-avatar.cjs.entry.js +1 -1
  6. package/dist/cjs/swirl-card.cjs.entry.js +1 -1
  7. package/dist/cjs/swirl-components.cjs.js +1 -1
  8. package/dist/cjs/swirl-modal.cjs.entry.js +1 -1
  9. package/dist/cjs/swirl-option-list.cjs.entry.js +8 -3027
  10. package/dist/cjs/swirl-resource-list-file-item.cjs.entry.js +1 -1
  11. package/dist/collection/components/swirl-avatar/swirl-avatar.css +1 -1
  12. package/dist/collection/components/swirl-card/swirl-card.css +3 -0
  13. package/dist/collection/components/swirl-modal/swirl-modal.css +9 -0
  14. package/dist/collection/components/swirl-resource-list/swirl-resource-list.js +231 -10
  15. package/dist/collection/components/swirl-resource-list/swirl-resource-list.spec.js +52 -9
  16. package/dist/collection/components/swirl-resource-list/swirl-resource-list.stories.js +3 -31
  17. package/dist/collection/components/swirl-resource-list-file-item/swirl-resource-list-file-item.js +1 -1
  18. package/dist/collection/components/swirl-resource-list-file-item/swirl-resource-list-file-item.spec.js +16 -18
  19. package/dist/collection/components/swirl-resource-list-item/swirl-resource-list-item.css +61 -3
  20. package/dist/collection/components/swirl-resource-list-item/swirl-resource-list-item.js +129 -3
  21. package/dist/collection/components/swirl-resource-list-item/swirl-resource-list-item.spec.js +31 -20
  22. package/dist/components/sortable.esm.js +3021 -0
  23. package/dist/components/swirl-avatar.js +1 -1
  24. package/dist/components/swirl-card.js +1 -1
  25. package/dist/components/swirl-modal.js +1 -1
  26. package/dist/components/swirl-option-list2.js +1 -3020
  27. package/dist/components/swirl-resource-list-file-item.js +2 -3
  28. package/dist/components/swirl-resource-list-item2.js +56 -9
  29. package/dist/components/swirl-resource-list2.js +146 -15
  30. package/dist/esm/loader.js +1 -1
  31. package/dist/esm/sortable.esm-8c3d5856.js +3021 -0
  32. package/dist/esm/swirl-app-layout_7.entry.js +169 -12
  33. package/dist/esm/swirl-avatar.entry.js +1 -1
  34. package/dist/esm/swirl-card.entry.js +1 -1
  35. package/dist/esm/swirl-components.js +1 -1
  36. package/dist/esm/swirl-modal.entry.js +1 -1
  37. package/dist/esm/swirl-option-list.entry.js +1 -3020
  38. package/dist/esm/swirl-resource-list-file-item.entry.js +1 -1
  39. package/dist/swirl-components/p-1486d7ea.js +7 -0
  40. package/dist/swirl-components/p-192d2465.entry.js +1 -0
  41. package/dist/swirl-components/p-687f534e.entry.js +1 -0
  42. package/dist/swirl-components/p-8c62e1d4.entry.js +1 -0
  43. package/dist/swirl-components/p-8d01c725.entry.js +10 -0
  44. package/dist/swirl-components/p-b0131a2e.entry.js +1 -0
  45. package/dist/swirl-components/p-fbc7f835.entry.js +1 -0
  46. package/dist/swirl-components/swirl-components.css +1 -1
  47. package/dist/swirl-components/swirl-components.esm.js +1 -1
  48. package/dist/types/components/swirl-resource-list/swirl-resource-list.d.ts +25 -0
  49. package/dist/types/components/swirl-resource-list-item/swirl-resource-list-item.d.ts +15 -1
  50. package/dist/types/components.d.ts +26 -0
  51. package/package.json +1 -1
  52. package/vscode-data.json +32 -0
  53. package/dist/swirl-components/p-49a2e41e.entry.js +0 -10
  54. package/dist/swirl-components/p-66abd436.entry.js +0 -1
  55. package/dist/swirl-components/p-78c61caf.entry.js +0 -1
  56. package/dist/swirl-components/p-85052283.entry.js +0 -1
  57. package/dist/swirl-components/p-bbf0621a.entry.js +0 -1
  58. package/dist/swirl-components/p-be12400c.entry.js +0 -7
@@ -6,7 +6,7 @@ const index = require('./index-506fe4ea.js');
6
6
  const index$1 = require('./index-2ddd0598.js');
7
7
  const utils = require('./utils-c00c09b9.js');
8
8
 
9
- const swirlResourceListFileItemCss = ":host{display:block;width:100%}:host *{box-sizing:border-box}.resource-list-file-item{position:relative;display:flex;width:100%;padding:var(--s-space-12) var(--s-space-16);align-items:center;background-color:var(--s-background-default);line-height:var(--s-line-height-base);gap:var(--s-space-12)}.resource-list-file-item:focus{outline:none}.resource-list-file-item:focus-visible{background-color:var(--s-background-hovered)}@media (min-width: 992px) and (max-width: 1439px) and (hover: hover),(min-width: 1440px){.resource-list-file-item{padding:var(--s-space-12);font-size:var(--s-font-size-sm);line-height:var(--s-line-height-sm)}}.resource-list-file-item--has-control .resource-list-file-item__label-container{padding-right:calc(var(--s-space-12) + 2.5rem)}.resource-list-file-item__icon{color:var(--s-icon-highlight)}.resource-list-file-item__label-container{position:relative;display:flex;min-width:0;min-height:2.875rem;flex-grow:1;justify-content:center;flex-direction:column}.resource-list-file-item__label-container:after{position:absolute;right:0;bottom:calc(-1 * var(--s-space-12));left:0;height:0.0625rem;background-color:var(--s-border-default);content:\"\"}.resource-list-file-item__label{overflow:hidden;font-weight:var(--s-font-weight-medium);white-space:nowrap;text-overflow:ellipsis}.resource-list-file-item__description{overflow:hidden;margin-top:var(--s-space-2);color:var(--s-text-subdued);font-size:var(--s-font-size-sm);line-height:var(--s-line-height-sm);white-space:nowrap;text-overflow:ellipsis}.resource-list-file-item__error-message{margin-top:var(--s-space-2)}.resource-list-file-item__remove-button{position:absolute;top:50%;right:var(--s-space-16);display:inline-flex;transform:translateY(-50%)}.resource-list-file-item__spinner{position:absolute;top:50%;right:var(--s-space-24);display:inline-flex;transform:translateY(-50%)}";
9
+ const swirlResourceListFileItemCss = ".sc-swirl-resource-list-file-item-h{display:block;width:100%}.sc-swirl-resource-list-file-item-h *.sc-swirl-resource-list-file-item{box-sizing:border-box}.resource-list-file-item.sc-swirl-resource-list-file-item{position:relative;display:flex;width:100%;padding:var(--s-space-12) var(--s-space-16);align-items:center;background-color:var(--s-background-default);line-height:var(--s-line-height-base);gap:var(--s-space-12)}.resource-list-file-item.sc-swirl-resource-list-file-item:focus{outline:none}.resource-list-file-item.sc-swirl-resource-list-file-item:focus-visible{background-color:var(--s-background-hovered)}@media (min-width: 992px) and (max-width: 1439px) and (hover: hover),(min-width: 1440px){.resource-list-file-item.sc-swirl-resource-list-file-item{padding:var(--s-space-12);font-size:var(--s-font-size-sm);line-height:var(--s-line-height-sm)}}.resource-list-file-item--has-control.sc-swirl-resource-list-file-item .resource-list-file-item__label-container.sc-swirl-resource-list-file-item{padding-right:calc(var(--s-space-12) + 2.5rem)}.resource-list-file-item__icon.sc-swirl-resource-list-file-item{color:var(--s-icon-highlight)}.resource-list-file-item__label-container.sc-swirl-resource-list-file-item{position:relative;display:flex;min-width:0;min-height:2.875rem;flex-grow:1;justify-content:center;flex-direction:column}.resource-list-file-item__label-container.sc-swirl-resource-list-file-item:after{position:absolute;right:0;bottom:calc(-1 * var(--s-space-12));left:0;height:0.0625rem;background-color:var(--s-border-default);content:\"\"}.resource-list-file-item__label.sc-swirl-resource-list-file-item{overflow:hidden;font-weight:var(--s-font-weight-medium);white-space:nowrap;text-overflow:ellipsis}.resource-list-file-item__description.sc-swirl-resource-list-file-item{overflow:hidden;margin-top:var(--s-space-2);color:var(--s-text-subdued);font-size:var(--s-font-size-sm);line-height:var(--s-line-height-sm);white-space:nowrap;text-overflow:ellipsis}.resource-list-file-item__error-message.sc-swirl-resource-list-file-item{margin-top:var(--s-space-2)}.resource-list-file-item__remove-button.sc-swirl-resource-list-file-item{position:absolute;top:50%;right:var(--s-space-16);display:inline-flex;transform:translateY(-50%)}.resource-list-file-item__spinner.sc-swirl-resource-list-file-item{position:absolute;top:50%;right:var(--s-space-24);display:inline-flex;transform:translateY(-50%)}";
10
10
 
11
11
  const SwirlResourceListFileItem = class {
12
12
  constructor(hostRef) {
@@ -19,7 +19,7 @@
19
19
 
20
20
  .avatar--has-icon {
21
21
  color: var(--s-icon-default);
22
- background-color: var(--s-surface-raised-default);
22
+ background-color: var(--swirl-avatar-background-color);
23
23
  }
24
24
 
25
25
  .avatar--has-initials {
@@ -23,6 +23,9 @@
23
23
  --swirl-ghost-button-background-default: var(--s-surface-default);
24
24
  --swirl-ghost-button-background-hovered: var(--s-surface-hovered);
25
25
  --swirl-ghost-button-background-pressed: var(--s-surface-pressed);
26
+ --swirl-resource-list-item-background-default: var(--s-surface-default);
27
+ --swirl-resource-list-item-background-hovered: var(--s-surface-hovered);
28
+ --swirl-resource-list-item-background-pressed: var(--s-surface-pressed);
26
29
  }
27
30
 
28
31
  a.card,
@@ -10,6 +10,15 @@
10
10
  --swirl-ghost-button-background-default: var(--s-surface-overlay-default);
11
11
  --swirl-ghost-button-background-hovered: var(--s-surface-overlay-hovered);
12
12
  --swirl-ghost-button-background-pressed: var(--s-surface-overlay-pressed);
13
+ --swirl-resource-list-item-background-default: var(
14
+ --s-surface-overlay-default
15
+ );
16
+ --swirl-resource-list-item-background-hovered: var(
17
+ --s-surface-overlay-hovered
18
+ );
19
+ --swirl-resource-list-item-background-pressed: var(
20
+ --s-surface-overlay-pressed
21
+ );
13
22
 
14
23
  position: fixed;
15
24
  z-index: var(--s-z-40);
@@ -1,16 +1,62 @@
1
- import { h, Host } from "@stencil/core";
1
+ import { h, Host, } from "@stencil/core";
2
+ import Sortable from "sortablejs";
2
3
  export class SwirlResourceList {
3
4
  constructor() {
4
5
  this.focusedIndex = 0;
6
+ this.toggleDrag = (event) => {
7
+ const item = event.detail;
8
+ if (Boolean(this.dragging)) {
9
+ this.stopDrag(item);
10
+ }
11
+ else {
12
+ this.startDrag(item);
13
+ }
14
+ };
15
+ this.startDrag = (item) => {
16
+ this.dragging = item;
17
+ this.draggingStartIndex = this.getItemIndex(this.dragging);
18
+ item.setAttribute("dragging", "true");
19
+ const index = this.getItemIndex(this.dragging);
20
+ this.focusItemAtIndex(index);
21
+ this.assistiveText = this.assistiveTextItemGrabbed;
22
+ };
23
+ this.stopDrag = (item) => {
24
+ const newIndex = this.getItemIndex(this.dragging);
25
+ this.dragging = undefined;
26
+ item.removeAttribute("dragging");
27
+ this.assistiveText = `${this.assistiveTextItemMoved} ${newIndex + 1}`;
28
+ this.itemDrop.emit({ item, oldIndex: this.draggingStartIndex, newIndex });
29
+ this.draggingStartIndex = undefined;
30
+ };
5
31
  this.onKeyDown = (event) => {
6
32
  if (event.key === "ArrowDown") {
7
33
  event.preventDefault();
8
- this.focusItemAtIndex((this.focusedIndex + 1) % this.items.length);
34
+ if (!Boolean(this.dragging)) {
35
+ this.focusItemAtIndex((this.focusedIndex + 1) % this.items.length);
36
+ }
37
+ else {
38
+ this.moveDraggedItemDown();
39
+ }
9
40
  }
10
41
  else if (event.key === "ArrowUp") {
11
42
  event.preventDefault();
12
- const prevIndex = this.focusedIndex === 0 ? this.items.length - 1 : this.focusedIndex - 1;
13
- this.focusItemAtIndex(prevIndex);
43
+ if (!Boolean(this.dragging)) {
44
+ const prevIndex = this.focusedIndex === 0
45
+ ? this.items.length - 1
46
+ : this.focusedIndex - 1;
47
+ this.focusItemAtIndex(prevIndex);
48
+ }
49
+ else {
50
+ this.moveDraggedItemUp();
51
+ }
52
+ }
53
+ else if (event.key === "Space" || event.key === "Enter") {
54
+ const target = event.composedPath()[0];
55
+ if (Boolean(this.dragging) &&
56
+ !(target === null || target === void 0 ? void 0 : target.classList.contains("resource-list-item__drag-handle"))) {
57
+ event.preventDefault();
58
+ this.stopDrag(this.dragging);
59
+ }
14
60
  }
15
61
  else if (event.key === "Home") {
16
62
  event.preventDefault();
@@ -24,28 +70,79 @@ export class SwirlResourceList {
24
70
  this.onSlotChange = () => {
25
71
  this.collectItems();
26
72
  };
73
+ this.allowDrag = undefined;
74
+ this.assistiveTextItemGrabbed = "Item grabbed. Use arrow keys to move item up or down. Use spacebar to save position.";
75
+ this.assistiveTextItemMoving = "Current position:";
76
+ this.assistiveTextItemMoved = "Item moved. New position:";
27
77
  this.label = undefined;
78
+ this.assistiveText = undefined;
28
79
  }
29
80
  componentDidLoad() {
30
81
  this.collectItems();
82
+ this.setItemAllowDragState();
83
+ this.setupDragDrop();
84
+ }
85
+ disconnectedCallback() {
86
+ var _a;
87
+ (_a = this.sortable) === null || _a === void 0 ? void 0 : _a.destroy();
88
+ }
89
+ watchAllowDrag() {
90
+ this.setItemAllowDragState();
91
+ this.setupDragDrop();
31
92
  }
32
93
  collectItems() {
33
94
  this.items = Array.from(this.el.querySelectorAll("swirl-resource-list-item, swirl-resource-list-file-item")).filter((el) => el.isConnected);
34
95
  this.removeItemsFromTabOrder();
35
96
  this.enableItemFocus(this.items[this.focusedIndex]);
36
97
  }
98
+ getItemIndex(item) {
99
+ return this.items.map((i) => i).findIndex((i) => i === item);
100
+ }
37
101
  removeItemsFromTabOrder() {
38
102
  this.items.forEach((item) => {
39
- var _a, _b;
40
- return (_b = (_a = item.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".resource-list-item__content, .resource-list-file-item")) === null || _b === void 0 ? void 0 : _b.setAttribute("tabIndex", "-1");
103
+ var _a;
104
+ return (_a = item === null || item === void 0 ? void 0 : item.querySelector(".resource-list-item__content, .resource-list-file-item")) === null || _a === void 0 ? void 0 : _a.setAttribute("tabIndex", "-1");
105
+ });
106
+ }
107
+ setItemAllowDragState() {
108
+ if (this.allowDrag) {
109
+ this.items.forEach((item) => {
110
+ item.setAttribute("allow-drag", "true");
111
+ item.addEventListener("toggleDrag", this.toggleDrag);
112
+ });
113
+ }
114
+ else {
115
+ this.items.forEach((item) => {
116
+ item.removeAttribute("allow-drag");
117
+ item.removeEventListener("toggleDrag", this.toggleDrag);
118
+ });
119
+ }
120
+ }
121
+ setupDragDrop() {
122
+ if (Boolean(this.sortable)) {
123
+ this.sortable.destroy();
124
+ }
125
+ if (!this.allowDrag) {
126
+ return;
127
+ }
128
+ this.sortable = Sortable.create(this.gridEl, {
129
+ animation: 150,
130
+ draggable: "swirl-resource-list-item",
131
+ handle: ".resource-list-item__drag-handle",
132
+ onEnd: (event) => {
133
+ this.itemDrop.emit({
134
+ item: event.item,
135
+ oldIndex: event.oldIndex,
136
+ newIndex: event.newIndex,
137
+ });
138
+ },
41
139
  });
42
140
  }
43
141
  enableItemFocus(item, focus) {
44
- var _a;
45
142
  if (!Boolean(item)) {
46
143
  return;
47
144
  }
48
- const interactiveElement = (_a = item.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".resource-list-item__content, .resource-list-file-item");
145
+ const interactiveElement = item.querySelector(".resource-list-item__content, .resource-list-file-item");
49
146
  if (!Boolean(interactiveElement)) {
50
147
  return;
51
148
  }
@@ -63,11 +160,31 @@ export class SwirlResourceList {
63
160
  this.enableItemFocus(item, true);
64
161
  this.focusedIndex = index;
65
162
  }
163
+ moveDraggedItemDown() {
164
+ const nextSibling = this.dragging.nextElementSibling;
165
+ if (!Boolean(nextSibling)) {
166
+ return;
167
+ }
168
+ nextSibling.after(this.dragging);
169
+ this.collectItems();
170
+ this.focusItemAtIndex(this.getItemIndex(this.dragging));
171
+ this.assistiveText = `${this.assistiveTextItemMoving} ${this.getItemIndex(this.dragging) + 1}`;
172
+ }
173
+ moveDraggedItemUp() {
174
+ const prevSibling = this.dragging.previousElementSibling;
175
+ if (!Boolean(prevSibling)) {
176
+ return;
177
+ }
178
+ prevSibling.before(this.dragging);
179
+ this.collectItems();
180
+ this.focusItemAtIndex(this.getItemIndex(this.dragging));
181
+ this.assistiveText = `${this.assistiveTextItemMoving} ${this.getItemIndex(this.dragging) + 1}`;
182
+ }
66
183
  render() {
67
- return (h(Host, { onKeyDown: this.onKeyDown }, h("swirl-stack", { "aria-label": this.label, role: "grid" }, h("slot", { onSlotchange: this.onSlotChange }))));
184
+ return (h(Host, { onKeyDown: this.onKeyDown }, h("swirl-visually-hidden", { role: "alert" }, this.assistiveText), h("swirl-stack", { "aria-label": this.label, class: "resource-list", ref: (el) => (this.gridEl = el), role: "grid" }, h("slot", { onSlotchange: this.onSlotChange }))));
68
185
  }
69
186
  static get is() { return "swirl-resource-list"; }
70
- static get encapsulation() { return "shadow"; }
187
+ static get encapsulation() { return "scoped"; }
71
188
  static get originalStyleUrls() {
72
189
  return {
73
190
  "$": ["swirl-resource-list.css"]
@@ -80,6 +197,77 @@ export class SwirlResourceList {
80
197
  }
81
198
  static get properties() {
82
199
  return {
200
+ "allowDrag": {
201
+ "type": "boolean",
202
+ "mutable": false,
203
+ "complexType": {
204
+ "original": "boolean",
205
+ "resolved": "boolean",
206
+ "references": {}
207
+ },
208
+ "required": false,
209
+ "optional": true,
210
+ "docs": {
211
+ "tags": [],
212
+ "text": ""
213
+ },
214
+ "attribute": "allow-drag",
215
+ "reflect": false
216
+ },
217
+ "assistiveTextItemGrabbed": {
218
+ "type": "string",
219
+ "mutable": false,
220
+ "complexType": {
221
+ "original": "string",
222
+ "resolved": "string",
223
+ "references": {}
224
+ },
225
+ "required": false,
226
+ "optional": true,
227
+ "docs": {
228
+ "tags": [],
229
+ "text": ""
230
+ },
231
+ "attribute": "assistive-text-item-grabbed",
232
+ "reflect": false,
233
+ "defaultValue": "\"Item grabbed. Use arrow keys to move item up or down. Use spacebar to save position.\""
234
+ },
235
+ "assistiveTextItemMoving": {
236
+ "type": "string",
237
+ "mutable": false,
238
+ "complexType": {
239
+ "original": "string",
240
+ "resolved": "string",
241
+ "references": {}
242
+ },
243
+ "required": false,
244
+ "optional": true,
245
+ "docs": {
246
+ "tags": [],
247
+ "text": ""
248
+ },
249
+ "attribute": "assistive-text-item-moving",
250
+ "reflect": false,
251
+ "defaultValue": "\"Current position:\""
252
+ },
253
+ "assistiveTextItemMoved": {
254
+ "type": "string",
255
+ "mutable": false,
256
+ "complexType": {
257
+ "original": "string",
258
+ "resolved": "string",
259
+ "references": {}
260
+ },
261
+ "required": false,
262
+ "optional": true,
263
+ "docs": {
264
+ "tags": [],
265
+ "text": ""
266
+ },
267
+ "attribute": "assistive-text-item-moved",
268
+ "reflect": false,
269
+ "defaultValue": "\"Item moved. New position:\""
270
+ },
83
271
  "label": {
84
272
  "type": "string",
85
273
  "mutable": false,
@@ -99,5 +287,38 @@ export class SwirlResourceList {
99
287
  }
100
288
  };
101
289
  }
290
+ static get states() {
291
+ return {
292
+ "assistiveText": {}
293
+ };
294
+ }
295
+ static get events() {
296
+ return [{
297
+ "method": "itemDrop",
298
+ "name": "itemDrop",
299
+ "bubbles": true,
300
+ "cancelable": true,
301
+ "composed": true,
302
+ "docs": {
303
+ "tags": [],
304
+ "text": ""
305
+ },
306
+ "complexType": {
307
+ "original": "{\n item: HTMLSwirlResourceListItemElement;\n oldIndex: number;\n newIndex: number;\n }",
308
+ "resolved": "{ item: HTMLSwirlResourceListItemElement; oldIndex: number; newIndex: number; }",
309
+ "references": {
310
+ "HTMLSwirlResourceListItemElement": {
311
+ "location": "global"
312
+ }
313
+ }
314
+ }
315
+ }];
316
+ }
102
317
  static get elementRef() { return "el"; }
318
+ static get watchers() {
319
+ return [{
320
+ "propName": "allowDrag",
321
+ "methodName": "watchAllowDrag"
322
+ }];
323
+ }
103
324
  }
@@ -1,6 +1,23 @@
1
1
  import { newSpecPage } from "@stencil/core/testing";
2
2
  import { SwirlResourceListItem } from "../swirl-resource-list-item/swirl-resource-list-item";
3
3
  import { SwirlResourceList } from "./swirl-resource-list";
4
+ import { MockElement } from "@stencil/core/mock-doc";
5
+ MockElement.prototype.after = function () {
6
+ var argArr = Array.prototype.slice.call(arguments);
7
+ var docFrag = document.createDocumentFragment();
8
+ for (var n = 0; n < argArr.length; n++) {
9
+ docFrag.appendChild(argArr[n]);
10
+ }
11
+ this.parentNode.insertBefore(docFrag, this.nextSibling);
12
+ };
13
+ MockElement.prototype.before = function () {
14
+ var argArr = Array.prototype.slice.call(arguments);
15
+ var docFrag = document.createDocumentFragment();
16
+ for (var n = 0; n < argArr.length; n++) {
17
+ docFrag.appendChild(argArr[n]);
18
+ }
19
+ this.parentNode.insertBefore(docFrag, this.previousSibling);
20
+ };
4
21
  describe("swirl-resource-list", () => {
5
22
  const template = `
6
23
  <swirl-resource-list label="Label">
@@ -23,13 +40,11 @@ describe("swirl-resource-list", () => {
23
40
  });
24
41
  expect(page.root).toEqualHtml(`
25
42
  <swirl-resource-list label="Label">
26
- <mock:shadow-root>
27
- <swirl-stack aria-label="Label" role="grid">
28
- <slot></slot>
29
- </swirl-stack>
30
- </mock:shadow-root>
31
- <swirl-resource-list-item description="With a description" label="This is a resource item" media="<swirl-avatar label=&quot;John Doe&quot; src=&quot;https://picsum.photos/id/433/144/144&quot;></swirl-avatar>"></swirl-resource-list-item>
32
- <swirl-resource-list-item description="With a description" label="This is a resource item" media="<swirl-avatar label=&quot;John Doe&quot; src=&quot;https://picsum.photos/id/103/144/144&quot;></swirl-avatar>"></swirl-resource-list-item>
43
+ <swirl-visually-hidden role="alert"></swirl-visually-hidden>
44
+ <swirl-stack aria-label="Label" class="resource-list" role="grid">
45
+ <swirl-resource-list-item description="With a description" label="This is a resource item" media="<swirl-avatar label=&quot;John Doe&quot; src=&quot;https://picsum.photos/id/433/144/144&quot;></swirl-avatar>"></swirl-resource-list-item>
46
+ <swirl-resource-list-item description="With a description" label="This is a resource item" media="<swirl-avatar label=&quot;John Doe&quot; src=&quot;https://picsum.photos/id/103/144/144&quot;></swirl-avatar>"></swirl-resource-list-item>
47
+ </swirl-stack>
33
48
  </swirl-resource-list>
34
49
  `);
35
50
  });
@@ -39,9 +54,9 @@ describe("swirl-resource-list", () => {
39
54
  html: template,
40
55
  });
41
56
  const items = Array.from(page.root.querySelectorAll("swirl-resource-list-item"));
42
- const interactiveElements = items.map((item) => item.shadowRoot.querySelector(".resource-list-item__content"));
57
+ const interactiveElements = items.map((item) => item.querySelector(".resource-list-item__content"));
43
58
  // focuses the first element if list is focused
44
- page.root.shadowRoot.children[0].focus();
59
+ page.root.children[0].focus();
45
60
  expect(interactiveElements[0].getAttribute("tabIndex")).toBe("0");
46
61
  // Down arrow focues the next element
47
62
  page.root.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" }));
@@ -60,4 +75,32 @@ describe("swirl-resource-list", () => {
60
75
  expect(interactiveElements[0].getAttribute("tabIndex")).toBe("0");
61
76
  expect(interactiveElements[1].getAttribute("tabIndex")).toBe("-1");
62
77
  });
78
+ it("makes items draggable", async () => {
79
+ const page = await newSpecPage({
80
+ components: [SwirlResourceList, SwirlResourceListItem],
81
+ html: template,
82
+ });
83
+ const items = Array.from(page.root.querySelectorAll("swirl-resource-list-item"));
84
+ const assistiveText = page.root.querySelector('[role="alert"]');
85
+ const resourceList = page.root.querySelector(".resource-list").parentElement;
86
+ for (const item of items) {
87
+ expect(item.getAttribute("allow-drag")).toBeNull();
88
+ }
89
+ page.root.setAttribute("allow-drag", "true");
90
+ await page.waitForChanges();
91
+ for (const item of items) {
92
+ expect(item.getAttribute("allow-drag")).toBe("true");
93
+ }
94
+ items[0]
95
+ .querySelector(".resource-list-item__drag-handle")
96
+ .dispatchEvent(new KeyboardEvent("keydown", { code: "Space" }));
97
+ await page.waitForChanges();
98
+ expect(assistiveText.innerHTML).toBe("Item grabbed. Use arrow keys to move item up or down. Use spacebar to save position.");
99
+ resourceList.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" }));
100
+ await page.waitForChanges();
101
+ expect(assistiveText.innerHTML).toBe("Current position: 2");
102
+ resourceList.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowUp" }));
103
+ await page.waitForChanges();
104
+ expect(assistiveText.innerHTML).toBe("Current position: 1");
105
+ });
63
106
  });
@@ -15,51 +15,23 @@ const Template = (args) => {
15
15
  element.innerHTML = `
16
16
  <swirl-resource-list-item
17
17
  description="With a description"
18
- label="This is a resource item"
18
+ label="This is a resource item 1"
19
19
  >
20
20
  <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
21
21
  </swirl-resource-list-item>
22
22
  <swirl-resource-list-item
23
23
  description="With a description"
24
- label="This is a resource item"
24
+ label="This is a resource item 2"
25
25
  >
26
26
  <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
27
27
  </swirl-resource-list-item>
28
28
  <swirl-resource-list-item
29
29
  description="With a description"
30
- label="This is a resource item"
30
+ label="This is a resource item 3"
31
31
  >
32
32
  <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
33
33
  </swirl-resource-list-item>
34
34
  `;
35
- setTimeout(() => {
36
- element.innerHTML = `
37
- <swirl-resource-list-item
38
- description="With a description"
39
- label="This is a resource item"
40
- >
41
- <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
42
- </swirl-resource-list-item>
43
- <swirl-resource-list-item
44
- description="With a description"
45
- label="This is a resource item"
46
- >
47
- <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
48
- </swirl-resource-list-item>
49
- <swirl-resource-list-item
50
- description="With a description"
51
- label="This is a resource item"
52
- >
53
- <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
54
- </swirl-resource-list-item>
55
- <swirl-resource-list-item
56
- description="With a description"
57
- label="New"
58
- >
59
- <swirl-avatar label="John Doe" src="https://picsum.photos/id/1027/144/144" slot="media"></swirl-avatar>
60
- </swirl-resource-list-item>
61
- `;
62
- }, 4000);
63
35
  return element;
64
36
  };
65
37
  export const SwirlResourceList = Template.bind({});
@@ -41,7 +41,7 @@ export class SwirlResourceListFileItem {
41
41
  return (h(Host, { role: "row" }, h("div", { class: className, part: "resource-list-file-item", role: "gridcell" }, h("span", { class: "resource-list-file-item__icon", innerHTML: this.icon, ref: (el) => (this.iconEl = el) }), h("span", { class: "resource-list-file-item__label-container" }, h("span", { class: "resource-list-file-item__label", id: "label" }, this.label), showDescription && (h("span", { class: "resource-list-file-item__description" }, this.description)), showError && (h("span", { "aria-live": "polite", class: "resource-list-file-item__error-message" }, h("swirl-inline-error", { message: this.errorMessage, size: "s" })))), showSpinner && (h("span", { class: "resource-list-file-item__spinner" }, h("swirl-spinner", { size: "s" }))), showRemoveButton && (h("span", { class: "resource-list-file-item__remove-button" }, h("swirl-button", { hideLabel: true, icon: "<swirl-icon-close></swirl-icon-close>", label: this.removeButtonLabel, onClick: this.remove.emit }))))));
42
42
  }
43
43
  static get is() { return "swirl-resource-list-file-item"; }
44
- static get encapsulation() { return "shadow"; }
44
+ static get encapsulation() { return "scoped"; }
45
45
  static get originalStyleUrls() {
46
46
  return {
47
47
  "$": ["swirl-resource-list-file-item.css"]
@@ -14,24 +14,22 @@ describe("swirl-resource-list-file-item", () => {
14
14
  });
15
15
  expect(page.root).toEqualHtml(`
16
16
  <swirl-resource-list-file-item description="Description" label="Label" loading="true" role="row">
17
- <mock:shadow-root>
18
- <div class="resource-list-file-item resource-list-file-item--has-control" part="resource-list-file-item" role="gridcell">
19
- <span class="resource-list-file-item__icon">
20
- <swirl-icon-file size="24"></swirl-icon-file>
17
+ <div class="resource-list-file-item resource-list-file-item--has-control" part="resource-list-file-item" role="gridcell">
18
+ <span class="resource-list-file-item__icon">
19
+ <swirl-icon-file size="24"></swirl-icon-file>
20
+ </span>
21
+ <span class="resource-list-file-item__label-container">
22
+ <span class="resource-list-file-item__label" id="label">
23
+ Label
21
24
  </span>
22
- <span class="resource-list-file-item__label-container">
23
- <span class="resource-list-file-item__label" id="label">
24
- Label
25
- </span>
26
- <span class="resource-list-file-item__description">
27
- Description
28
- </span>
25
+ <span class="resource-list-file-item__description">
26
+ Description
29
27
  </span>
30
- <span class="resource-list-file-item__spinner">
31
- <swirl-spinner size="s"></swirl-spinner>
32
- </span>
33
- </div>
34
- </mock:shadow-root>
28
+ </span>
29
+ <span class="resource-list-file-item__spinner">
30
+ <swirl-spinner size="s"></swirl-spinner>
31
+ </span>
32
+ </div>
35
33
  </swirl-resource-list-file-item>
36
34
  `);
37
35
  });
@@ -40,7 +38,7 @@ describe("swirl-resource-list-file-item", () => {
40
38
  components: [SwirlResourceListFileItem],
41
39
  html: `<swirl-resource-list-file-item label="Label" error-message="Error"></swirl-resource-list-file-item>`,
42
40
  });
43
- expect(page.root.shadowRoot
41
+ expect(page.root
44
42
  .querySelector('[aria-live="polite"] > swirl-inline-error')
45
43
  .getAttribute("message")).toBe("Error");
46
44
  });
@@ -51,7 +49,7 @@ describe("swirl-resource-list-file-item", () => {
51
49
  });
52
50
  const spy = jest.fn();
53
51
  page.root.addEventListener("remove", spy);
54
- page.root.shadowRoot
52
+ page.root
55
53
  .querySelector(".resource-list-file-item__remove-button > swirl-button")
56
54
  .click();
57
55
  expect(spy).toHaveBeenCalled();
@@ -1,4 +1,5 @@
1
1
  :host {
2
+ position: relative;
2
3
  display: block;
3
4
  width: 100%;
4
5
  }
@@ -12,6 +13,10 @@
12
13
  width: 100%;
13
14
  }
14
15
 
16
+ .resource-list-item:hover {
17
+ --swirl-ghost-button-background-default: var(--s-background-hovered);
18
+ }
19
+
15
20
  .resource-list-item--checked .resource-list-item__checkbox {
16
21
  border-color: var(--s-icon-highlight);
17
22
  color: var(--s-text-on-status);
@@ -48,6 +53,29 @@
48
53
  font-weight: var(--s-font-weight-medium);
49
54
  }
50
55
 
56
+ .resource-list-item--draggable .resource-list-item__content {
57
+ padding-left: calc(var(--s-space-16) * 2 + 1.5rem);
58
+ }
59
+
60
+ @media (min-width: 992px) and (max-width: 1439px) and (hover: hover),(min-width: 1440px) {
61
+
62
+ .resource-list-item--draggable .resource-list-item__content {
63
+ padding-left: calc(var(--s-space-16) * 2 + 1rem)
64
+ }
65
+ }
66
+
67
+ .resource-list-item--dragging {
68
+ z-index: 1;
69
+ border-radius: var(--s-border-radius-s);
70
+ background-color: var(--s-surface-overlay-pressed);
71
+ box-shadow: 0 0.0625rem 0.125rem rgba(25, 26, 28, 0.08),
72
+ 0 0.25rem 2rem rgba(25, 26, 28, 0.16);
73
+ }
74
+
75
+ .resource-list-item--dragging:hover:not(.resource-list-item--disabled) {
76
+ background-color: var(--s-surface-overlay-pressed);
77
+ }
78
+
51
79
  .resource-list-item__content {
52
80
  --swirl-avatar-group-border-color: var(--s-background-default);
53
81
  --swirl-badge-border-color: var(--s-background-default);
@@ -62,7 +90,7 @@
62
90
  align-items: center;
63
91
  border: none;
64
92
  color: var(--s-text-default);
65
- background-color: var(--s-background-default);
93
+ background-color: var(--swirl-resource-list-item-background-default);
66
94
  font: inherit;
67
95
  line-height: var(--s-line-height-base);
68
96
  text-align: left;
@@ -72,16 +100,17 @@
72
100
  }
73
101
 
74
102
  .resource-list-item__content:hover:not(:disabled) {
75
- background-color: var(--s-background-hovered);
103
+ background-color: var(--swirl-resource-list-item-background-hovered);
76
104
  }
77
105
 
78
106
  .resource-list-item__content:hover:not(:disabled) .resource-list-item__media {
107
+ --swirl-avatar-background-color: var(--s-surface-raised-hovered);
79
108
  --swirl-avatar-group-border-color: var(--s-background-hovered);
80
109
  --swirl-badge-border-color: var(--s-background-hovered);
81
110
  }
82
111
 
83
112
  .resource-list-item__content:active:not(:disabled) {
84
- background-color: var(--s-background-pressed);
113
+ background-color: var(--swirl-resource-list-item-background-pressed);
85
114
  }
86
115
 
87
116
  .resource-list-item__content:active:not(:disabled) .resource-list-item__media {
@@ -215,3 +244,32 @@
215
244
  color: var(--s-text-subdued);
216
245
  font-size: var(--s-font-size-sm);
217
246
  }
247
+
248
+ .resource-list-item__drag-handle {
249
+ position: absolute;
250
+ z-index: 1;
251
+ top: 50%;
252
+ left: var(--s-space-4);
253
+ display: inline-flex;
254
+ margin: 0;
255
+ padding: 0;
256
+ padding: var(--s-space-8);
257
+ flex-shrink: 0;
258
+ border: none;
259
+ color: var(--s-icon-default);
260
+ background-color: transparent;
261
+ cursor: grab;
262
+ transform: translateY(-50%);
263
+ }
264
+
265
+ .resource-list-item__drag-handle:active {
266
+ cursor: grabbing;
267
+ }
268
+
269
+ .resource-list-item__drag-handle:focus:not(:focus-visible) {
270
+ outline: none;
271
+ }
272
+
273
+ .resource-list-item__drag-handle:focus-visible {
274
+ outline-color: var(--s-focus-default);
275
+ }