@limetech/lime-elements 40.12.2 → 40.13.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/{checkbox.template-_WUgtMJy.js → checkbox.template-CNJ29zDR.js} +1 -1
  3. package/dist/cjs/drag-to-reorder-BP5YkPuu.js +3092 -0
  4. package/dist/cjs/lime-elements.cjs.js +1 -1
  5. package/dist/cjs/limel-checkbox.cjs.entry.js +1 -1
  6. package/dist/cjs/limel-chip-set.cjs.entry.js +5 -2
  7. package/dist/cjs/{limel-scroller.cjs.entry.js → limel-drag-handle_2.cjs.entry.js} +38 -0
  8. package/dist/cjs/limel-file-viewer.cjs.entry.js +64 -55
  9. package/dist/cjs/limel-form.cjs.entry.js +539 -3171
  10. package/dist/cjs/limel-list-item.cjs.entry.js +1 -1
  11. package/dist/cjs/limel-select.cjs.entry.js +2 -2
  12. package/dist/cjs/limel-slider.cjs.entry.js +4 -4
  13. package/dist/cjs/limel-switch.cjs.entry.js +1 -1
  14. package/dist/cjs/limel-tab-bar.cjs.entry.js +120 -16
  15. package/dist/cjs/limel-tab-panel.cjs.entry.js +7 -1
  16. package/dist/cjs/loader.cjs.js +1 -1
  17. package/dist/collection/components/checkbox/checkbox.template.js +1 -1
  18. package/dist/collection/components/chip-set/chip-set.js +5 -2
  19. package/dist/collection/components/form/form.css +59 -0
  20. package/dist/collection/components/form/form.js +49 -2
  21. package/dist/collection/components/form/show-field.js +116 -0
  22. package/dist/collection/components/form/templates/array-field-collapsible-item.js +1 -0
  23. package/dist/collection/components/form/templates/array-field-item.js +5 -0
  24. package/dist/collection/components/form/templates/array-field.js +20 -158
  25. package/dist/collection/components/form/templates/field.js +17 -0
  26. package/dist/collection/components/select/select.template.js +2 -2
  27. package/dist/collection/components/slider/slider.js +4 -4
  28. package/dist/collection/components/switch/switch.js +1 -1
  29. package/dist/collection/components/tab-bar/tab-bar.css +68 -22
  30. package/dist/collection/components/tab-bar/tab-bar.js +131 -4
  31. package/dist/collection/components/tab-bar/tabs.js +23 -0
  32. package/dist/collection/components/tab-panel/tab-panel.js +54 -1
  33. package/dist/collection/util/drag-to-reorder.js +116 -0
  34. package/dist/esm/{_baseForOwn-D5j7fHlv.js → _baseForOwn-vKFWmmaS.js} +1 -1
  35. package/dist/esm/{_baseIsEqual-CyF4P8uM.js → _baseIsEqual-B_JRErB0.js} +1 -1
  36. package/dist/esm/{_baseIteratee-CpbczHY1.js → _baseIteratee-CVz7aes3.js} +1 -1
  37. package/dist/esm/{_baseSet-Cw2IE6ZF.js → _baseSet-BUAq8NGm.js} +1 -1
  38. package/dist/esm/{checkbox.template-BFL4SMzl.js → checkbox.template-CAja2LKZ.js} +1 -1
  39. package/dist/esm/{cloneDeep-DAbOtbs8.js → cloneDeep-Bcll-3f8.js} +1 -1
  40. package/dist/esm/drag-to-reorder-BXmXIwCa.js +3086 -0
  41. package/dist/esm/{isEqual-CE83yS8T.js → isEqual-C-pK6AAU.js} +1 -1
  42. package/dist/esm/lime-elements.js +1 -1
  43. package/dist/esm/limel-checkbox.entry.js +1 -1
  44. package/dist/esm/limel-chip-set.entry.js +7 -4
  45. package/dist/esm/limel-dialog.entry.js +2 -2
  46. package/dist/esm/{limel-scroller.entry.js → limel-drag-handle_2.entry.js} +38 -1
  47. package/dist/esm/limel-file-dropzone_2.entry.js +3 -3
  48. package/dist/esm/limel-file-viewer.entry.js +64 -55
  49. package/dist/esm/limel-form.entry.js +536 -3168
  50. package/dist/esm/limel-list-item.entry.js +1 -1
  51. package/dist/esm/limel-prosemirror-adapter.entry.js +3 -3
  52. package/dist/esm/limel-select.entry.js +2 -2
  53. package/dist/esm/limel-slider.entry.js +4 -4
  54. package/dist/esm/limel-switch.entry.js +1 -1
  55. package/dist/esm/limel-tab-bar.entry.js +117 -13
  56. package/dist/esm/limel-tab-panel.entry.js +7 -1
  57. package/dist/esm/limel-table.entry.js +4 -4
  58. package/dist/esm/loader.js +1 -1
  59. package/dist/lime-elements/lime-elements.esm.js +1 -1
  60. package/dist/lime-elements/{p-35bc5ed2.entry.js → p-13f2afc9.entry.js} +1 -1
  61. package/dist/lime-elements/{p-43c36a02.entry.js → p-268b4da1.entry.js} +1 -1
  62. package/dist/lime-elements/p-3b6d4934.entry.js +1 -0
  63. package/dist/lime-elements/p-55b56742.entry.js +1 -0
  64. package/dist/lime-elements/p-67767276.entry.js +1 -0
  65. package/dist/lime-elements/{p-fb15f608.entry.js → p-6d65ee35.entry.js} +1 -1
  66. package/dist/lime-elements/p-714ab66d.entry.js +16 -0
  67. package/dist/lime-elements/p-7ae71c13.entry.js +1 -0
  68. package/dist/lime-elements/{p-c492af1b.entry.js → p-828558cf.entry.js} +1 -1
  69. package/dist/lime-elements/p-95322502.entry.js +1 -0
  70. package/dist/lime-elements/p-BAqAt5It.js +1 -0
  71. package/dist/lime-elements/{p-1qqvOwzC.js → p-Cadm4-WZ.js} +1 -1
  72. package/dist/lime-elements/p-Cu9Ji1iJ.js +1 -0
  73. package/dist/lime-elements/{p-BY5NjPj8.js → p-D9Ezd43A.js} +1 -1
  74. package/dist/lime-elements/{p-nVemxylR.js → p-DFu1q54T.js} +1 -1
  75. package/dist/lime-elements/p-DdnBHYb-.js +7 -0
  76. package/dist/lime-elements/{p-B6-3WXAv.js → p-DeIIlp6m.js} +1 -1
  77. package/dist/lime-elements/p-Dq0uNStc.js +1 -0
  78. package/dist/lime-elements/p-b5bb124f.entry.js +1 -0
  79. package/dist/lime-elements/{p-9168793f.entry.js → p-bd58c761.entry.js} +1 -1
  80. package/dist/lime-elements/{p-458c131f.entry.js → p-c7e34502.entry.js} +1 -1
  81. package/dist/lime-elements/p-f4c9940e.entry.js +23 -0
  82. package/dist/lime-elements/p-fb526a05.entry.js +1 -0
  83. package/dist/types/components/chip-set/chip-set.d.ts +1 -0
  84. package/dist/types/components/form/form.d.ts +15 -0
  85. package/dist/types/components/form/show-field.d.ts +9 -0
  86. package/dist/types/components/form/templates/array-context.d.ts +4 -0
  87. package/dist/types/components/form/templates/array-field-collapsible-item.d.ts +5 -0
  88. package/dist/types/components/form/templates/array-field.d.ts +3 -13
  89. package/dist/types/components/form/templates/field.d.ts +1 -0
  90. package/dist/types/components/form/templates/object-field.d.ts +2 -2
  91. package/dist/types/components/tab-bar/tab-bar.d.ts +25 -0
  92. package/dist/types/components/tab-bar/tab.types.d.ts +18 -0
  93. package/dist/types/components/tab-bar/tabs.d.ts +12 -1
  94. package/dist/types/components/tab-panel/tab-panel.d.ts +18 -1
  95. package/dist/types/components.d.ts +80 -2
  96. package/dist/types/util/drag-to-reorder.d.ts +65 -0
  97. package/package.json +4 -4
  98. package/dist/cjs/isArrayLikeObject-U2Ddbw4n.js +0 -326
  99. package/dist/cjs/limel-drag-handle.cjs.entry.js +0 -42
  100. package/dist/esm/isArrayLikeObject-CJB8HbtH.js +0 -321
  101. package/dist/esm/limel-drag-handle.entry.js +0 -40
  102. package/dist/lime-elements/p-06850418.entry.js +0 -1
  103. package/dist/lime-elements/p-262a3d66.entry.js +0 -1
  104. package/dist/lime-elements/p-49eb2f64.entry.js +0 -13
  105. package/dist/lime-elements/p-646731b6.entry.js +0 -1
  106. package/dist/lime-elements/p-89d75e9c.entry.js +0 -1
  107. package/dist/lime-elements/p-8d567e42.entry.js +0 -1
  108. package/dist/lime-elements/p-92fab922.entry.js +0 -23
  109. package/dist/lime-elements/p-BQeIv4aA.js +0 -1
  110. package/dist/lime-elements/p-COdirXg1.js +0 -1
  111. package/dist/lime-elements/p-ORUNaKm-.js +0 -1
  112. package/dist/lime-elements/p-a5246373.entry.js +0 -1
  113. package/dist/lime-elements/p-b609552e.entry.js +0 -1
  114. package/dist/lime-elements/p-bf849dc9.entry.js +0 -1
  115. package/dist/lime-elements/p-pk5KIdKH.js +0 -1
@@ -128,12 +128,57 @@ limel-scroller {
128
128
  background-color: rgb(var(--limel-tab-background-color));
129
129
  }
130
130
 
131
- :host(.has-tabs-with-equal-width:not([orientation=vertical])) button {
131
+ :host(.has-tabs-with-equal-width:not([orientation=vertical])) button[role=tab],
132
+ :host(.has-tabs-with-equal-width:not([orientation=vertical])) limel-scroller > div {
132
133
  flex: 1 0 auto;
133
134
  max-width: var(--tab-bar-horizontal-tab-max-width, none);
134
135
  }
135
136
 
136
- button {
137
+ limel-scroller > div:has(limel-drag-handle:hover), limel-scroller > div:has(limel-drag-handle:focus-within), limel-scroller > div.is-elevated, limel-scroller > div.sortable-chosen {
138
+ will-change: transform, box-shadow, border-radius, background-color;
139
+ }
140
+ limel-scroller > div.sortable-ghost {
141
+ border-radius: 0.5rem;
142
+ box-shadow: var(--shadow-depth-64), 0 0.65rem 0.75rem -0.425rem rgb(var(--color-black), 0.3);
143
+ }
144
+ limel-scroller > div.sortable-chosen {
145
+ border-radius: 0.5rem;
146
+ background-color: var(--lime-elevated-surface-background-color);
147
+ }
148
+ limel-scroller > div.is-elevated[draggable=false] {
149
+ animation: sit-here 0.8s forwards;
150
+ }
151
+ @keyframes sit-here {
152
+ 0% {
153
+ border-radius: 0.5rem;
154
+ background-color: var(--lime-elevated-surface-background-color);
155
+ box-shadow: var(--shadow-depth-64), 0 0.65rem 0.75rem -0.425rem rgb(var(--color-black), 0.3);
156
+ }
157
+ 100% {
158
+ box-shadow: none;
159
+ }
160
+ }
161
+ limel-scroller > div {
162
+ position: relative;
163
+ display: flex;
164
+ flex: 0 0 auto;
165
+ }
166
+ limel-scroller > div button[role=tab] {
167
+ flex: 1 1 auto;
168
+ min-width: 0;
169
+ }
170
+ limel-scroller > div span.content {
171
+ padding-right: 2rem;
172
+ }
173
+ limel-scroller > div limel-drag-handle {
174
+ position: absolute;
175
+ z-index: 3;
176
+ top: 0;
177
+ bottom: 0;
178
+ right: 0.25rem;
179
+ }
180
+
181
+ button[role=tab] {
137
182
  appearance: none;
138
183
  background: none;
139
184
  border: none;
@@ -156,34 +201,34 @@ button {
156
201
  white-space: nowrap;
157
202
  font-size: var(--limel-theme-default-font-size);
158
203
  }
159
- button limel-icon {
204
+ button[role=tab] limel-icon {
160
205
  transition: color 0.2s ease;
161
206
  color: rgb(var(--contrast-800));
162
207
  margin-left: -0.25rem;
163
208
  flex-shrink: 0;
164
209
  }
165
- button span.text {
210
+ button[role=tab] span.text {
166
211
  transition: color 0.2s ease;
167
212
  line-height: 1.25;
168
213
  overflow: hidden;
169
214
  text-overflow: ellipsis;
170
215
  color: var(--limel-theme-on-surface-color);
171
216
  }
172
- button:hover span.text {
217
+ button[role=tab]:hover span.text {
173
218
  color: var(--limel-theme-text-primary-on-background-color);
174
219
  }
175
- button limel-badge {
220
+ button[role=tab] limel-badge {
176
221
  margin-right: -0.25rem;
177
222
  box-shadow: 0 0 0 1px rgb(var(--contrast-600));
178
223
  pointer-events: none;
179
224
  flex-shrink: 0;
180
225
  }
181
226
 
182
- button[aria-selected=true] {
227
+ button[role=tab][aria-selected=true] {
183
228
  background-color: var(--limel-active-tab-background-color);
184
229
  z-index: 2;
185
230
  }
186
- button[aria-selected=true]:before, button[aria-selected=true]:after {
231
+ button[role=tab][aria-selected=true]:before, button[role=tab][aria-selected=true]:after {
187
232
  content: "";
188
233
  display: block;
189
234
  width: var(--limel-tab-active-outer-edge-curve-size);
@@ -193,10 +238,10 @@ button[aria-selected=true]:before, button[aria-selected=true]:after {
193
238
  -webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E");
194
239
  mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E");
195
240
  }
196
- button[aria-selected=true] limel-icon {
241
+ button[role=tab][aria-selected=true] limel-icon {
197
242
  color: var(--limel-active-tab-color);
198
243
  }
199
- button[aria-selected=true] span.text {
244
+ button[role=tab][aria-selected=true] span.text {
200
245
  color: var(--limel-active-tab-color);
201
246
  }
202
247
 
@@ -211,15 +256,15 @@ span.content {
211
256
  padding: 0 0.75rem;
212
257
  border-radius: calc(var(--limel-tab-border-radius) - var(--limel-tab-content-inset));
213
258
  }
214
- button:focus-visible span.content {
259
+ button[role=tab]:focus-visible span.content {
215
260
  transition-duration: 0.3s;
216
261
  box-shadow: var(--shadow-depth-8-focused);
217
262
  }
218
263
 
219
- :host(limel-tab-bar:not([orientation=vertical])) button {
264
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab] {
220
265
  max-width: var(--tab-bar-horizontal-tab-max-width, 16rem);
221
266
  }
222
- :host(limel-tab-bar:not([orientation=vertical])) button:not([aria-selected=true]):after {
267
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab]:not([aria-selected=true]):after {
223
268
  content: "";
224
269
  display: block;
225
270
  background-color: var(--limel-tab-separator-background-color);
@@ -232,20 +277,21 @@ button:focus-visible span.content {
232
277
  border-radius: 1rem;
233
278
  right: calc(-1 * var(--limel-tab-separator-width));
234
279
  }
235
- :host(limel-tab-bar:not([orientation=vertical])) button:not([aria-selected=true]):last-of-type:after {
280
+ :host(limel-tab-bar:not([orientation=vertical])) limel-scroller > :last-child:not([aria-selected=true]):after,
281
+ :host(limel-tab-bar:not([orientation=vertical])) limel-scroller > :last-child > button[role=tab]:not([aria-selected=true]):after {
236
282
  display: none;
237
283
  }
238
- :host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true] {
284
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab][aria-selected=true] {
239
285
  border-radius: var(--limel-tab-border-radius) var(--limel-tab-border-radius) 0 0;
240
286
  }
241
- :host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:before, :host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:after {
287
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab][aria-selected=true]:before, :host(limel-tab-bar:not([orientation=vertical])) button[role=tab][aria-selected=true]:after {
242
288
  bottom: 0;
243
289
  }
244
- :host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:before {
290
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab][aria-selected=true]:before {
245
291
  left: calc(-1 * var(--limel-tab-active-outer-edge-curve-size));
246
292
  transform: rotateY(180deg);
247
293
  }
248
- :host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:after {
294
+ :host(limel-tab-bar:not([orientation=vertical])) button[role=tab][aria-selected=true]:after {
249
295
  right: calc(-1 * var(--limel-tab-active-outer-edge-curve-size));
250
296
  }
251
297
 
@@ -262,17 +308,17 @@ button:focus-visible span.content {
262
308
  0 var(--limel-tab-active-outer-edge-curve-size) 0.25rem;
263
309
  height: 100%;
264
310
  }
265
- :host(limel-tab-bar[orientation=vertical]) button[aria-selected=true] {
311
+ :host(limel-tab-bar[orientation=vertical]) button[role=tab][aria-selected=true] {
266
312
  border-radius: var(--limel-tab-border-radius) 0 0 var(--limel-tab-border-radius);
267
313
  }
268
- :host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:before, :host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:after {
314
+ :host(limel-tab-bar[orientation=vertical]) button[role=tab][aria-selected=true]:before, :host(limel-tab-bar[orientation=vertical]) button[role=tab][aria-selected=true]:after {
269
315
  right: 0;
270
316
  }
271
- :host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:before {
317
+ :host(limel-tab-bar[orientation=vertical]) button[role=tab][aria-selected=true]:before {
272
318
  bottom: 100%;
273
319
  transform: rotateY(180deg);
274
320
  }
275
- :host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:after {
321
+ :host(limel-tab-bar[orientation=vertical]) button[role=tab][aria-selected=true]:after {
276
322
  top: 100%;
277
323
  transform: rotate(180deg);
278
324
  }
@@ -1,8 +1,9 @@
1
1
  import { h, } from "@stencil/core";
2
2
  import { isEqual, difference } from "lodash-es";
3
- import { setActiveTab } from "./tabs";
3
+ import { getTabReorder, setActiveTab } from "./tabs";
4
4
  import { getIconColor, getIconName } from "../icon/get-icon-props";
5
5
  import { findNavigationTarget, findTabStop, isNavigationKey, NO_NAVIGATION_TARGET, } from "../../util/keyboard-navigation";
6
+ import { DragToReorder } from "../../util/drag-to-reorder";
6
7
  /**
7
8
  * Tabs are great to organize information hierarchically in the interface and divide it into distinct categories. Using tabs, you can create groups of content that are related and at the same level in the hierarchy.
8
9
  * :::warning
@@ -13,6 +14,7 @@ import { findNavigationTarget, findTabStop, isNavigationKey, NO_NAVIGATION_TARGE
13
14
  * A tab bar can contain an unlimited number of tabs. However, depending on the device width and width of the tabs, the number of tabs that are visible at the same time will vary. When there is limited horizontal space, the component shows a left-arrow and/or right-arrow button, which scrolls and reveals the additional tabs. The tab bar can also be swiped left and right on a touch-device. A vertical tab bar does the same, upwards and downwards.
14
15
  * The arrows are only a shortcut for people who use a mouse or a touch screen. Screen readers do not announce them, and the Tab key skips them. People who use a keyboard or a screen reader move between the tabs, and the tab bar keeps the selected tab in view.
15
16
  * The left and right arrow keys move to the previous and the next tab, and select it. In a vertical tab bar, the up and down arrow keys do that instead. Home and End move to the first and the last tab. Moving past the last tab continues at the first one, and the other way around. The Tab key moves on to what comes after the tab bar, and moving back with Shift and Tab lands on the selected tab, or on the first tab when none is selected.
17
+ * Set `allowTabReorder` to let the user drag the tabs into the order they want. Every tab then gets a drag handle, and the tab bar emits `reorderTab` when the user drops a tab in a new place. The tab bar does not change `tabs` itself, so the component that uses it decides the new order, and can save it for the user. A tab that the component does not move, stays where it was. The tabs can be reordered with a mouse and a touch screen, but not yet with the keyboard.
16
18
  * :::tip Other things to consider
17
19
  * Never divide the content of a tab using a nested tab bar.
18
20
  * Never place two tab bars within the same screen.
@@ -26,6 +28,8 @@ import { findNavigationTarget, findTabStop, isNavigationKey, NO_NAVIGATION_TARGE
26
28
  * @exampleComponent limel-example-tab-bar-with-equal-tab-width
27
29
  * @exampleComponent limel-example-tab-bar-vertical
28
30
  * @exampleComponent limel-example-tab-bar-tab-width
31
+ * @exampleComponent limel-example-tab-bar-reorder
32
+ * @exampleComponent limel-example-tab-bar-reorder-vertical
29
33
  */
30
34
  export class TabBar {
31
35
  constructor() {
@@ -38,8 +42,24 @@ export class TabBar {
38
42
  * to, or in a column, next to it.
39
43
  */
40
44
  this.orientation = 'horizontal';
45
+ /**
46
+ * Set to `true` to let the user reorder the tabs by dragging them. Listen
47
+ * for `reorderTab` and give the tab bar the tabs in their new order.
48
+ */
49
+ this.allowTabReorder = false;
41
50
  this.hasLoaded = false;
42
51
  this.isLaidOutAgain = false;
52
+ this.renderedTabs = [];
53
+ this.handleReorder = (event) => {
54
+ const reorder = getTabReorder(this.tabs, event);
55
+ if (!reorder) {
56
+ return;
57
+ }
58
+ const ids = this.tabs.map(({ id }) => id);
59
+ ids.splice(reorder.toIndex, 0, ...ids.splice(reorder.fromIndex, 1));
60
+ this.tabIdsAfterReorder = ids;
61
+ this.reorderTab.emit(reorder);
62
+ };
43
63
  this.handleKeyDown = this.handleKeyDown.bind(this);
44
64
  }
45
65
  async connectedCallback() {
@@ -49,20 +69,39 @@ export class TabBar {
49
69
  return;
50
70
  }
51
71
  this.revealedTabId = undefined;
72
+ this.setUpReordering();
52
73
  await this.revealActiveTab('auto');
53
74
  }
75
+ disconnectedCallback() {
76
+ var _a;
77
+ (_a = this.dragToReorder) === null || _a === void 0 ? void 0 : _a.teardown();
78
+ }
54
79
  componentDidLoad() {
55
80
  this.hasLoaded = true;
56
81
  this.triggerIconColorWarning();
57
82
  }
83
+ componentWillRender() {
84
+ var _a;
85
+ const index = this.getTabElements().indexOf(this.host.shadowRoot.activeElement);
86
+ this.tabWithFocus =
87
+ index === -1
88
+ ? undefined
89
+ : {
90
+ id: (_a = this.renderedTabs[index]) === null || _a === void 0 ? void 0 : _a.id,
91
+ button: this.getTabElements()[index],
92
+ };
93
+ }
58
94
  async componentDidRender() {
95
+ this.restoreFocus();
96
+ this.renderedTabs = this.tabs;
97
+ this.setUpReordering();
59
98
  const isLaidOutAgain = this.isLaidOutAgain;
60
99
  this.isLaidOutAgain = false;
61
100
  await this.revealActiveTab(!this.hasLoaded || isLaidOutAgain ? 'auto' : undefined, isLaidOutAgain);
62
101
  }
63
102
  render() {
64
103
  const tabStop = findTabStop(this.tabs, this.tabs.findIndex((tab) => tab.active), this.getNavigationOptions());
65
- return (h("div", { key: 'f4a760e69615d4d4d87ad3e176d109dbcdf2ea34', role: "tablist", "aria-orientation": this.getOrientation(), onKeyDown: this.handleKeyDown }, h("limel-scroller", { key: 'f3ff8810cf0a248c13aa2d9840c80c6f6270df68', orientation: this.getOrientation() }, this.tabs.map((tab, index) => this.renderTab(tab, index, index === tabStop)))));
104
+ return (h("div", { key: 'a6fea42551095401324faac28bad996dd4137428', role: "tablist", "aria-orientation": this.getOrientation(), onKeyDown: this.handleKeyDown }, h("limel-scroller", { key: '956d8b890785071eacb66478e4f6af8bbc467a93', orientation: this.getOrientation() }, this.tabs.map((tab, index) => this.renderTabOrMovableTab(tab, index, index === tabStop)))));
66
105
  }
67
106
  tabsChanged(newTabs = [], oldTabs = []) {
68
107
  const newIds = newTabs.map((tab) => tab.id);
@@ -70,6 +109,11 @@ export class TabBar {
70
109
  if (isEqual(newIds, oldIds)) {
71
110
  return;
72
111
  }
112
+ const idsAfterReorder = this.tabIdsAfterReorder;
113
+ this.tabIdsAfterReorder = undefined;
114
+ if (isEqual(newIds, idsAfterReorder)) {
115
+ return;
116
+ }
73
117
  this.revealedTabId = undefined;
74
118
  }
75
119
  orientationChanged() {
@@ -82,11 +126,41 @@ export class TabBar {
82
126
  getNavigationOptions() {
83
127
  return { orientation: this.getOrientation(), wrap: true };
84
128
  }
129
+ restoreFocus() {
130
+ var _a;
131
+ const tabWithFocus = this.tabWithFocus;
132
+ this.tabWithFocus = undefined;
133
+ if (!tabWithFocus || tabWithFocus.button.isConnected) {
134
+ return;
135
+ }
136
+ const index = this.tabs.findIndex((tab) => tab.id === tabWithFocus.id);
137
+ (_a = this.getTabElements()[index]) === null || _a === void 0 ? void 0 : _a.focus();
138
+ }
85
139
  getTabElements() {
86
140
  return [
87
141
  ...this.host.shadowRoot.querySelectorAll('button[role="tab"]'),
88
142
  ];
89
143
  }
144
+ canReorderTabs() {
145
+ return this.allowTabReorder && this.tabs.length > 1;
146
+ }
147
+ setUpReordering() {
148
+ var _a, _b;
149
+ if (!this.canReorderTabs()) {
150
+ (_a = this.dragToReorder) === null || _a === void 0 ? void 0 : _a.teardown();
151
+ return;
152
+ }
153
+ const scroller = this.host.shadowRoot.querySelector('limel-scroller');
154
+ if (!scroller) {
155
+ return;
156
+ }
157
+ (_b = this.dragToReorder) !== null && _b !== void 0 ? _b : (this.dragToReorder = new DragToReorder({
158
+ draggable: '[data-reorder-id]',
159
+ revertDrop: true,
160
+ onReorder: this.handleReorder,
161
+ }));
162
+ this.dragToReorder.setup(scroller, this.getOrientation());
163
+ }
90
164
  /**
91
165
  * A tab that is activated by the user receives focus, and the scroller
92
166
  * reveals what receives focus. This is for a tab that becomes active
@@ -122,8 +196,11 @@ export class TabBar {
122
196
  if (!isNavigationKey(event, options)) {
123
197
  return;
124
198
  }
125
- event.preventDefault();
126
199
  const current = this.getTabElements().indexOf(event.target);
200
+ if (current === -1) {
201
+ return;
202
+ }
203
+ event.preventDefault();
127
204
  this.activateTab(findNavigationTarget(this.tabs, event.key, current, options));
128
205
  }
129
206
  activateTab(index) {
@@ -158,8 +235,16 @@ export class TabBar {
158
235
  }
159
236
  return (h("limel-icon", { name: name, style: style, size: "small", "aria-hidden": "true" }));
160
237
  }
238
+ renderTabOrMovableTab(tab, index, isTabStop) {
239
+ if (!this.canReorderTabs()) {
240
+ return this.renderTab(tab, index, isTabStop);
241
+ }
242
+ return (h("div", { key: tab.id, role: "presentation", "data-reorder-id": tab.id }, this.renderTab(tab, index, isTabStop), h("limel-drag-handle", { "aria-hidden": "true", dragDirection: this.getOrientation(), tooltipOpenDirection: this.getOrientation() === 'vertical'
243
+ ? 'right'
244
+ : 'bottom' })));
245
+ }
161
246
  renderTab(tab, index, isTabStop) {
162
- return (h("button", { role: "tab", "aria-selected": tab.active ? 'true' : 'false', tabindex: isTabStop ? 0 : -1, onClick: () => this.activateTab(index) }, h("span", { class: "content" }, this.renderIcon(tab), h("span", { class: "text" }, tab.text), tab.badge ? h("limel-badge", { label: tab.badge }) : '')));
247
+ return (h("button", { key: tab.id, role: "tab", "aria-selected": tab.active ? 'true' : 'false', tabindex: isTabStop ? 0 : -1, onClick: () => this.activateTab(index) }, h("span", { class: "content" }, this.renderIcon(tab), h("span", { class: "text" }, tab.text), tab.badge ? h("limel-badge", { label: tab.badge }) : '')));
163
248
  }
164
249
  triggerIconColorWarning() {
165
250
  if (this.tabs.some((tab) => tab.iconColor)) {
@@ -224,6 +309,26 @@ export class TabBar {
224
309
  "reflect": true,
225
310
  "attribute": "orientation",
226
311
  "defaultValue": "'horizontal'"
312
+ },
313
+ "allowTabReorder": {
314
+ "type": "boolean",
315
+ "mutable": false,
316
+ "complexType": {
317
+ "original": "boolean",
318
+ "resolved": "boolean",
319
+ "references": {}
320
+ },
321
+ "required": false,
322
+ "optional": false,
323
+ "docs": {
324
+ "tags": [],
325
+ "text": "Set to `true` to let the user reorder the tabs by dragging them. Listen\nfor `reorderTab` and give the tab bar the tabs in their new order."
326
+ },
327
+ "getter": false,
328
+ "setter": false,
329
+ "reflect": true,
330
+ "attribute": "allow-tab-reorder",
331
+ "defaultValue": "false"
227
332
  }
228
333
  };
229
334
  }
@@ -250,6 +355,28 @@ export class TabBar {
250
355
  }
251
356
  }
252
357
  }
358
+ }, {
359
+ "method": "reorderTab",
360
+ "name": "reorderTab",
361
+ "bubbles": true,
362
+ "cancelable": true,
363
+ "composed": true,
364
+ "docs": {
365
+ "tags": [],
366
+ "text": "Emitted when the user has dragged a tab to a new place. The tab bar does\nnot change `tabs` itself. The tab stays where it was until `tabs` is set\nto the tabs in their new order."
367
+ },
368
+ "complexType": {
369
+ "original": "TabReorderEvent",
370
+ "resolved": "TabReorderEvent",
371
+ "references": {
372
+ "TabReorderEvent": {
373
+ "location": "import",
374
+ "path": "./tab.types",
375
+ "id": "src/components/tab-bar/tab.types.ts::TabReorderEvent",
376
+ "referenceLocation": "TabReorderEvent"
377
+ }
378
+ }
379
+ }
253
380
  }];
254
381
  }
255
382
  static get elementRef() { return "host"; }
@@ -1,3 +1,4 @@
1
+ import { isEqual } from "lodash-es";
1
2
  /**
2
3
  * Set a tabs `active` state to true in a list of tabs. The previous tab with
3
4
  * `active` set to true will have it set to `false` instead.
@@ -15,3 +16,25 @@ export function setActiveTab(tabs, index) {
15
16
  result[index] = Object.assign(Object.assign({}, tabs[index]), { active: true });
16
17
  return result;
17
18
  }
19
+ /**
20
+ * Describe a move that the user has made, in the tabs that the user made it in.
21
+ *
22
+ * @param tabs - the tabs of the tab bar now
23
+ * @param reorder - the move, as the list of tabs that the user dragged reported
24
+ * it
25
+ * @returns the move, or `undefined` when `tabs` are not the tabs that the user
26
+ * began to drag, since the move would point to another tab then
27
+ */
28
+ export function getTabReorder(tabs, reorder) {
29
+ const { order, fromIndex, toIndex } = reorder;
30
+ const isATab = (index) => index >= 0 && index < tabs.length;
31
+ if (!isATab(fromIndex) || !isATab(toIndex)) {
32
+ return undefined;
33
+ }
34
+ const orderBeforeTheMove = [...order];
35
+ orderBeforeTheMove.splice(fromIndex, 0, ...orderBeforeTheMove.splice(toIndex, 1));
36
+ if (!isEqual(orderBeforeTheMove, tabs.map(({ id }) => String(id)))) {
37
+ return undefined;
38
+ }
39
+ return { tab: tabs[fromIndex], fromIndex, toIndex };
40
+ }
@@ -15,10 +15,16 @@ import { dispatchResizeEvent } from "../../util/dispatch-resize-event";
15
15
  * The slotted components can also emit the `changeTab` event to update anything
16
16
  * inside the actual tab, e.g. to change the icon, color or badge.
17
17
  *
18
+ * Set `allowTabReorder` to let the user reorder the tabs by dragging them. The
19
+ * panel does not change `tabs` itself. Listen for `reorderTab`, and give the
20
+ * panel the tabs in their new order. The tabs can be reordered with a mouse
21
+ * and a touch screen, but not yet with the keyboard.
22
+ *
18
23
  * @slot - Content to put inside the `limel-tab-panel`. Each slotted element
19
24
  * must have the `id` attribute equal to the id of the tab it belongs to.
20
25
  * @exampleComponent limel-example-tab-panel-basic
21
26
  * @exampleComponent limel-example-tab-panel-vertical
27
+ * @exampleComponent limel-example-tab-panel-reorder
22
28
  */
23
29
  export class TabPanel {
24
30
  constructor() {
@@ -31,6 +37,11 @@ export class TabPanel {
31
37
  * column, to the left of it.
32
38
  */
33
39
  this.orientation = 'horizontal';
40
+ /**
41
+ * Set to `true` to let the user reorder the tabs by dragging them. Listen
42
+ * for `reorderTab` and give the panel the tabs in their new order.
43
+ */
44
+ this.allowTabReorder = false;
34
45
  this.slotElements = [];
35
46
  this.handleChangeTabs = this.handleChangeTabs.bind(this);
36
47
  this.setSlotElements = this.setSlotElements.bind(this);
@@ -64,7 +75,7 @@ export class TabPanel {
64
75
  }
65
76
  }
66
77
  render() {
67
- return (h(Host, { key: '69b4a7ee8bbe366dd3a001e2d63a96c1680660c1', onChangeTab: this.handleChangeTabs }, h("div", { key: '5844651fd25248b2767127f6ca6ab5f02f03c347', class: "tab-panel" }, h("limel-tab-bar", { key: '0ef45e1bead572d950148b0e4f8b53c8d9f567ce', tabs: this.tabs, orientation: this.orientation }), h("div", { key: 'a8b336877c2bc9b1ebda32fd726d76be3957bbf3', class: "tab-content" }, h("slot", { key: '97e10533292738d2b4d0914eb9922cac0b396bb6' })))));
78
+ return (h(Host, { key: '3f70176f334708cbe3c0629ed5b00ea26676b187', onChangeTab: this.handleChangeTabs }, h("div", { key: '49d629465a2df872df90a8534aba05db1d1eab6d', class: "tab-panel" }, h("limel-tab-bar", { key: 'c6c7392edaaf36de925bee5851ff24c64cf639a3', tabs: this.tabs, orientation: this.orientation, allowTabReorder: this.allowTabReorder }), h("div", { key: '2f1e5eb59c3ae94fa0dc92a6fe3ba4dec50dd5be', class: "tab-content" }, h("slot", { key: '7441131f62ff758351e44c33c50b4a499e05351c' })))));
68
79
  }
69
80
  setSlotElements() {
70
81
  const slot = this.getSlot();
@@ -165,6 +176,26 @@ export class TabPanel {
165
176
  "reflect": true,
166
177
  "attribute": "orientation",
167
178
  "defaultValue": "'horizontal'"
179
+ },
180
+ "allowTabReorder": {
181
+ "type": "boolean",
182
+ "mutable": false,
183
+ "complexType": {
184
+ "original": "boolean",
185
+ "resolved": "boolean",
186
+ "references": {}
187
+ },
188
+ "required": false,
189
+ "optional": false,
190
+ "docs": {
191
+ "tags": [],
192
+ "text": "Set to `true` to let the user reorder the tabs by dragging them. Listen\nfor `reorderTab` and give the panel the tabs in their new order."
193
+ },
194
+ "getter": false,
195
+ "setter": false,
196
+ "reflect": true,
197
+ "attribute": "allow-tab-reorder",
198
+ "defaultValue": "false"
168
199
  }
169
200
  };
170
201
  }
@@ -191,6 +222,28 @@ export class TabPanel {
191
222
  }
192
223
  }
193
224
  }
225
+ }, {
226
+ "method": "reorderTab",
227
+ "name": "reorderTab",
228
+ "bubbles": true,
229
+ "cancelable": true,
230
+ "composed": true,
231
+ "docs": {
232
+ "tags": [],
233
+ "text": "Emitted when the user has dragged a tab to a new place. The panel does\nnot change `tabs` itself. The tab stays where it was until `tabs` is set\nto the tabs in their new order."
234
+ },
235
+ "complexType": {
236
+ "original": "TabReorderEvent",
237
+ "resolved": "TabReorderEvent",
238
+ "references": {
239
+ "TabReorderEvent": {
240
+ "location": "import",
241
+ "path": "../tab-bar/tab.types",
242
+ "id": "src/components/tab-bar/tab.types.ts::TabReorderEvent",
243
+ "referenceLocation": "TabReorderEvent"
244
+ }
245
+ }
246
+ }
194
247
  }];
195
248
  }
196
249
  static get elementRef() { return "host"; }
@@ -0,0 +1,116 @@
1
+ import Sortable from "sortablejs";
2
+ const DRAG_HANDLE_SELECTOR = '[data-drag-handle]';
3
+ const DRAGGING_CONTAINER_CLASS = 'has-an-item-which-is-being-dragged';
4
+ const ELEVATED_ITEM_CLASS = 'is-elevated';
5
+ const ELEVATION_DURATION_MS = 1000;
6
+ const TOUCH_DRAG_DELAY_MS = 200;
7
+ const ANIMATION_DURATION_MS = 150;
8
+ /**
9
+ * Lets the user reorder the children of a list with a drag handle.
10
+ *
11
+ * Every child of the list has a `data-reorder-id`, and the drag starts from
12
+ * an element with the `data-drag-handle` attribute inside a child.
13
+ */
14
+ export class DragToReorder {
15
+ constructor(options) {
16
+ this.options = options;
17
+ this.orderBeforeDrag = [];
18
+ this.handleStart = (event) => {
19
+ var _a, _b;
20
+ this.orderBeforeDrag = this.readOrder();
21
+ this.nextSiblingBeforeDrag = (_a = event.item.nextElementSibling) !== null && _a !== void 0 ? _a : undefined;
22
+ (_b = this.container) === null || _b === void 0 ? void 0 : _b.classList.add(DRAGGING_CONTAINER_CLASS);
23
+ this.elevate(event.item);
24
+ };
25
+ this.handleEnd = (event) => {
26
+ var _a;
27
+ (_a = this.container) === null || _a === void 0 ? void 0 : _a.classList.remove(DRAGGING_CONTAINER_CLASS);
28
+ this.keepElevatedBriefly(event.item);
29
+ const order = this.readOrder();
30
+ const id = event.item.dataset.reorderId;
31
+ const fromIndex = this.orderBeforeDrag.indexOf(id);
32
+ const toIndex = order.indexOf(id);
33
+ const nextSibling = this.nextSiblingBeforeDrag;
34
+ this.orderBeforeDrag = [];
35
+ this.nextSiblingBeforeDrag = undefined;
36
+ if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
37
+ return;
38
+ }
39
+ if (this.options.revertDrop) {
40
+ this.putBack(event.item, nextSibling);
41
+ }
42
+ this.options.onReorder({ order, fromIndex, toIndex });
43
+ };
44
+ }
45
+ /**
46
+ * @param container - the list
47
+ * @param direction - the way the children are laid out. Leave it out to
48
+ * let SortableJS find out. Setting up the same list again without it keeps
49
+ * the direction that the list has.
50
+ */
51
+ setup(container, direction) {
52
+ if (this.getDraggableItems(container).length < 2) {
53
+ this.teardown();
54
+ return;
55
+ }
56
+ if (this.sortable && this.container === container) {
57
+ this.changeDirection(direction);
58
+ return;
59
+ }
60
+ this.teardown();
61
+ this.container = container;
62
+ this.direction = direction;
63
+ this.sortable = Sortable.create(container, Object.assign(Object.assign({ animation: ANIMATION_DURATION_MS, handle: DRAG_HANDLE_SELECTOR, draggable: this.options.draggable, delay: TOUCH_DRAG_DELAY_MS, delayOnTouchOnly: true }, (direction && { direction: direction })), { onStart: this.handleStart, onEnd: this.handleEnd }));
64
+ }
65
+ teardown() {
66
+ var _a, _b;
67
+ (_a = this.sortable) === null || _a === void 0 ? void 0 : _a.destroy();
68
+ this.sortable = undefined;
69
+ this.removeElevation();
70
+ (_b = this.container) === null || _b === void 0 ? void 0 : _b.classList.remove(DRAGGING_CONTAINER_CLASS);
71
+ this.container = undefined;
72
+ this.direction = undefined;
73
+ this.orderBeforeDrag = [];
74
+ this.nextSiblingBeforeDrag = undefined;
75
+ }
76
+ putBack(item, nextSibling) {
77
+ const isStillInList = (nextSibling === null || nextSibling === void 0 ? void 0 : nextSibling.parentNode) === this.container;
78
+ this.container.insertBefore(item, isStillInList ? nextSibling : null);
79
+ }
80
+ changeDirection(direction) {
81
+ if (!direction || direction === this.direction) {
82
+ return;
83
+ }
84
+ this.direction = direction;
85
+ this.sortable.option('direction', direction);
86
+ }
87
+ getDraggableItems(container) {
88
+ return [...container.children].filter((child) => child.matches(this.options.draggable));
89
+ }
90
+ readOrder() {
91
+ var _a, _b;
92
+ const children = [...((_b = (_a = this.container) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [])];
93
+ return children
94
+ .filter((child) => {
95
+ return (child instanceof HTMLElement &&
96
+ child.dataset.reorderId !== undefined);
97
+ })
98
+ .map((child) => child.dataset.reorderId);
99
+ }
100
+ elevate(item) {
101
+ this.removeElevation();
102
+ item.classList.add(ELEVATED_ITEM_CLASS);
103
+ this.elevatedItem = item;
104
+ }
105
+ keepElevatedBriefly(item) {
106
+ this.elevate(item);
107
+ this.elevationTimeout = setTimeout(() => this.removeElevation(), ELEVATION_DURATION_MS);
108
+ }
109
+ removeElevation() {
110
+ var _a;
111
+ clearTimeout(this.elevationTimeout);
112
+ this.elevationTimeout = undefined;
113
+ (_a = this.elevatedItem) === null || _a === void 0 ? void 0 : _a.classList.remove(ELEVATED_ITEM_CLASS);
114
+ this.elevatedItem = undefined;
115
+ }
116
+ }
@@ -1,4 +1,4 @@
1
- import { k as keys } from './_baseIsEqual-CyF4P8uM.js';
1
+ import { k as keys } from './_baseIsEqual-B_JRErB0.js';
2
2
 
3
3
  /**
4
4
  * Creates a base function for methods like `_.forIn` and `_.forOwn`.
@@ -1203,4 +1203,4 @@ function baseIsEqual(value, other, bitmask, customizer, stack) {
1203
1203
  return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
1204
1204
  }
1205
1205
 
1206
- export { MapCache as M, SetCache as S, Uint8Array as U, Stack as a, baseIsEqual as b, cacheHas as c, arrayPush as d, arrayLikeKeys as e, stubArray as f, getAllKeys as g, getSymbols as h, baseGetAllKeys as i, keys as k, setToArray as s };
1206
+ export { MapCache as M, SetCache as S, Uint8Array as U, arrayPush as a, baseIsEqual as b, cacheHas as c, Stack as d, arrayLikeKeys as e, stubArray as f, getAllKeys as g, getSymbols as h, baseGetAllKeys as i, keys as k, setToArray as s };