@nanoporetech-digital/components 4.9.4 → 5.0.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 (240) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/cjs/drag-777bd8dd.js +74 -0
  3. package/dist/cjs/drag-777bd8dd.js.map +1 -0
  4. package/dist/cjs/{form-control-2e900f54.js → form-control-443e90bf.js} +2 -3
  5. package/dist/cjs/form-control-443e90bf.js.map +1 -0
  6. package/dist/cjs/index-71f899a7.js +10 -2
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/cjs/nano-components.cjs.js +1 -1
  9. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js +6 -6
  10. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js.map +1 -1
  11. package/dist/cjs/nano-grid-item.cjs.entry.js +29 -0
  12. package/dist/cjs/nano-grid-item.cjs.entry.js.map +1 -0
  13. package/dist/cjs/nano-grid_2.cjs.entry.js +436 -0
  14. package/dist/cjs/nano-grid_2.cjs.entry.js.map +1 -0
  15. package/dist/cjs/nano-hero.cjs.entry.js +4 -10
  16. package/dist/cjs/nano-hero.cjs.entry.js.map +1 -1
  17. package/dist/cjs/nano-icon-button_2.cjs.entry.js +40 -3
  18. package/dist/cjs/nano-icon-button_2.cjs.entry.js.map +1 -1
  19. package/dist/cjs/nano-input.cjs.entry.js +2 -2
  20. package/dist/cjs/nano-input.cjs.entry.js.map +1 -1
  21. package/dist/cjs/nano-range.cjs.entry.js +1 -1
  22. package/dist/cjs/nano-range.cjs.entry.js.map +1 -1
  23. package/dist/cjs/nano-sortable.cjs.entry.js +654 -0
  24. package/dist/cjs/nano-sortable.cjs.entry.js.map +1 -0
  25. package/dist/cjs/nano-split-pane.cjs.entry.js +30 -45
  26. package/dist/cjs/nano-split-pane.cjs.entry.js.map +1 -1
  27. package/dist/cjs/nano-tab-group.cjs.entry.js +39 -43
  28. package/dist/cjs/nano-tab-group.cjs.entry.js.map +1 -1
  29. package/dist/cjs/nano-tab.cjs.entry.js +3 -3
  30. package/dist/cjs/nano-tab.cjs.entry.js.map +1 -1
  31. package/dist/cjs/{nano-table-54a4ba34.js → nano-table-11052a34.js} +52 -172
  32. package/dist/cjs/nano-table-11052a34.js.map +1 -0
  33. package/dist/cjs/nano-table.cjs.entry.js +1 -1
  34. package/dist/cjs/{table.worker-20ed37a5.js → table.worker-83433a8b.js} +3 -3
  35. package/dist/cjs/table.worker-83433a8b.js.map +1 -0
  36. package/dist/cjs/{table.worker-f820b411.js → table.worker-bd51e29f.js} +1 -1
  37. package/dist/collection/collection-manifest.json +1 -0
  38. package/dist/collection/components/form-control/form-control.js +1 -2
  39. package/dist/collection/components/form-control/form-control.js.map +1 -1
  40. package/dist/collection/components/grid/grid-item.js +11 -136
  41. package/dist/collection/components/grid/grid-item.js.map +1 -1
  42. package/dist/collection/components/grid/grid.css +9 -242
  43. package/dist/collection/components/grid/grid.js +248 -240
  44. package/dist/collection/components/grid/grid.js.map +1 -1
  45. package/dist/collection/components/hero/hero.css +42 -89
  46. package/dist/collection/components/hero/hero.js +4 -11
  47. package/dist/collection/components/hero/hero.js.map +1 -1
  48. package/dist/collection/components/icon-button/icon-button.css +18 -4
  49. package/dist/collection/components/icon-button/icon-button.js +83 -4
  50. package/dist/collection/components/icon-button/icon-button.js.map +1 -1
  51. package/dist/collection/components/input/input.css +8 -9
  52. package/dist/collection/components/nav-item/nav-item.js +4 -4
  53. package/dist/collection/components/nav-item/nav-item.js.map +1 -1
  54. package/dist/collection/components/range/range.css +0 -3
  55. package/dist/collection/components/select/select.css +8 -9
  56. package/dist/collection/components/sortable/sortable.css +28 -0
  57. package/dist/collection/components/sortable/sortable.js +1181 -0
  58. package/dist/collection/components/sortable/sortable.js.map +1 -0
  59. package/dist/collection/components/split-pane/split-pane.js +29 -27
  60. package/dist/collection/components/split-pane/split-pane.js.map +1 -1
  61. package/dist/collection/components/table/table-interface.js.map +1 -1
  62. package/dist/collection/components/table/table.css +18 -38
  63. package/dist/collection/components/table/table.header.js +3 -86
  64. package/dist/collection/components/table/table.header.js.map +1 -1
  65. package/dist/collection/components/table/table.js +27 -108
  66. package/dist/collection/components/table/table.js.map +1 -1
  67. package/dist/collection/components/table/table.row.js +7 -7
  68. package/dist/collection/components/table/table.row.js.map +1 -1
  69. package/dist/collection/components/table/table.store.js +1 -1
  70. package/dist/collection/components/table/table.store.js.map +1 -1
  71. package/dist/collection/components/table/table.worker.js +3 -3
  72. package/dist/collection/components/table/table.worker.js.map +1 -1
  73. package/dist/collection/components/tabs/tab-group.css +9 -13
  74. package/dist/collection/components/tabs/tab-group.js +39 -43
  75. package/dist/collection/components/tabs/tab-group.js.map +1 -1
  76. package/dist/collection/components/tabs/tab.css +53 -14
  77. package/dist/collection/components/tabs/tab.js +8 -2
  78. package/dist/collection/components/tabs/tab.js.map +1 -1
  79. package/dist/collection/utils/constructible-style.js +129 -0
  80. package/dist/collection/utils/constructible-style.js.map +1 -0
  81. package/dist/collection/utils/drag.js +52 -4
  82. package/dist/collection/utils/drag.js.map +1 -1
  83. package/dist/components/drag.js +72 -0
  84. package/dist/components/drag.js.map +1 -0
  85. package/dist/components/form-control.js +1 -2
  86. package/dist/components/form-control.js.map +1 -1
  87. package/dist/components/grid.js +268 -183
  88. package/dist/components/grid.js.map +1 -1
  89. package/dist/components/icon-button.js +45 -5
  90. package/dist/components/icon-button.js.map +1 -1
  91. package/dist/components/index.d.ts +1 -0
  92. package/dist/components/index.js +1 -0
  93. package/dist/components/index.js.map +1 -1
  94. package/dist/components/input.js +1 -1
  95. package/dist/components/input.js.map +1 -1
  96. package/dist/components/nano-grid-item.js +33 -1
  97. package/dist/components/nano-grid-item.js.map +1 -1
  98. package/dist/components/nano-hero.js +6 -19
  99. package/dist/components/nano-hero.js.map +1 -1
  100. package/dist/components/nano-range.js +1 -1
  101. package/dist/components/nano-range.js.map +1 -1
  102. package/dist/components/nano-sortable.d.ts +11 -0
  103. package/dist/components/nano-sortable.js +692 -0
  104. package/dist/components/nano-sortable.js.map +1 -0
  105. package/dist/components/nano-split-pane.js +30 -45
  106. package/dist/components/nano-split-pane.js.map +1 -1
  107. package/dist/components/nano-tab-group.js +40 -44
  108. package/dist/components/nano-tab-group.js.map +1 -1
  109. package/dist/components/nano-tab.js +3 -3
  110. package/dist/components/nano-tab.js.map +1 -1
  111. package/dist/components/nav-item.js +4 -4
  112. package/dist/components/nav-item.js.map +1 -1
  113. package/dist/components/select.js +1 -1
  114. package/dist/components/select.js.map +1 -1
  115. package/dist/components/table.js +52 -173
  116. package/dist/components/table.js.map +1 -1
  117. package/dist/components/table.worker.js +1 -1
  118. package/dist/esm/drag-1723a4cc.js +72 -0
  119. package/dist/esm/drag-1723a4cc.js.map +1 -0
  120. package/dist/esm/{form-control-269ba84f.js → form-control-e8739b2e.js} +2 -3
  121. package/dist/esm/form-control-e8739b2e.js.map +1 -0
  122. package/dist/esm/index-dad5627b.js +10 -2
  123. package/dist/esm/loader.js +1 -1
  124. package/dist/esm/nano-components.js +1 -1
  125. package/dist/esm/nano-global-nav-user-profile_3.entry.js +6 -6
  126. package/dist/esm/nano-global-nav-user-profile_3.entry.js.map +1 -1
  127. package/dist/esm/nano-grid-item.entry.js +25 -0
  128. package/dist/esm/nano-grid-item.entry.js.map +1 -0
  129. package/dist/esm/nano-grid_2.entry.js +431 -0
  130. package/dist/esm/nano-grid_2.entry.js.map +1 -0
  131. package/dist/esm/nano-hero.entry.js +4 -10
  132. package/dist/esm/nano-hero.entry.js.map +1 -1
  133. package/dist/esm/nano-icon-button_2.entry.js +41 -4
  134. package/dist/esm/nano-icon-button_2.entry.js.map +1 -1
  135. package/dist/esm/nano-input.entry.js +2 -2
  136. package/dist/esm/nano-input.entry.js.map +1 -1
  137. package/dist/esm/nano-range.entry.js +1 -1
  138. package/dist/esm/nano-range.entry.js.map +1 -1
  139. package/dist/esm/nano-sortable.entry.js +650 -0
  140. package/dist/esm/nano-sortable.entry.js.map +1 -0
  141. package/dist/esm/nano-split-pane.entry.js +30 -45
  142. package/dist/esm/nano-split-pane.entry.js.map +1 -1
  143. package/dist/esm/nano-tab-group.entry.js +39 -43
  144. package/dist/esm/nano-tab-group.entry.js.map +1 -1
  145. package/dist/esm/nano-tab.entry.js +3 -3
  146. package/dist/esm/nano-tab.entry.js.map +1 -1
  147. package/dist/esm/{nano-table-929ac4d9.js → nano-table-ba637f26.js} +53 -173
  148. package/dist/esm/nano-table-ba637f26.js.map +1 -0
  149. package/dist/esm/nano-table.entry.js +1 -1
  150. package/dist/esm/{table.worker-2425382a.js → table.worker-1cae39c9.js} +3 -3
  151. package/dist/esm/table.worker-1cae39c9.js.map +1 -0
  152. package/dist/{nano-components/p-f820b411.js → esm/table.worker-bd51e29f.js} +1 -1
  153. package/dist/nano-components/nano-components.css +1 -1
  154. package/dist/nano-components/nano-components.esm.js +1 -1
  155. package/dist/nano-components/nano-components.esm.js.map +1 -1
  156. package/dist/nano-components/p-00cf8021.entry.js +5 -0
  157. package/dist/nano-components/p-00cf8021.entry.js.map +1 -0
  158. package/dist/nano-components/{p-906de5a2.entry.js → p-158c73b0.entry.js} +2 -2
  159. package/dist/nano-components/p-365c997a.js +5 -0
  160. package/dist/nano-components/p-553acf24.entry.js +5 -0
  161. package/dist/nano-components/p-553acf24.entry.js.map +1 -0
  162. package/dist/nano-components/p-6975f110.entry.js +5 -0
  163. package/dist/nano-components/p-6975f110.entry.js.map +1 -0
  164. package/dist/nano-components/p-71057181.js +5 -0
  165. package/dist/nano-components/p-71057181.js.map +1 -0
  166. package/dist/nano-components/p-842cf127.js +5 -0
  167. package/dist/nano-components/p-842cf127.js.map +1 -0
  168. package/dist/nano-components/p-ad6209ec.entry.js +5 -0
  169. package/dist/nano-components/p-ad6209ec.entry.js.map +1 -0
  170. package/dist/nano-components/p-b8e76fdf.entry.js +5 -0
  171. package/dist/nano-components/p-b8e76fdf.entry.js.map +1 -0
  172. package/dist/{esm/table.worker-f820b411.js → nano-components/p-bd51e29f.js} +1 -1
  173. package/dist/nano-components/p-bdef618c.entry.js +5 -0
  174. package/dist/nano-components/p-bdef618c.entry.js.map +1 -0
  175. package/dist/nano-components/p-d79c6862.entry.js +5 -0
  176. package/dist/nano-components/p-d79c6862.entry.js.map +1 -0
  177. package/dist/nano-components/p-deb0799c.entry.js +5 -0
  178. package/dist/nano-components/{p-6a3a29c6.entry.js.map → p-deb0799c.entry.js.map} +1 -1
  179. package/dist/nano-components/p-ebb98a9e.entry.js +5 -0
  180. package/dist/nano-components/p-ebb98a9e.entry.js.map +1 -0
  181. package/dist/nano-components/p-f60fe933.entry.js +5 -0
  182. package/dist/nano-components/p-f60fe933.entry.js.map +1 -0
  183. package/dist/nano-components/p-f7535f45.entry.js +5 -0
  184. package/dist/nano-components/p-f7535f45.entry.js.map +1 -0
  185. package/dist/nano-components/p-fc585ea2.js +5 -0
  186. package/dist/nano-components/p-fc585ea2.js.map +1 -0
  187. package/dist/types/components/grid/grid-item.d.ts +3 -11
  188. package/dist/types/components/grid/grid.d.ts +44 -68
  189. package/dist/types/components/hero/hero.d.ts +1 -3
  190. package/dist/types/components/icon-button/icon-button.d.ts +14 -0
  191. package/dist/types/components/sortable/sortable.d.ts +204 -0
  192. package/dist/types/components/table/table-interface.d.ts +2 -4
  193. package/dist/types/components/table/table.d.ts +5 -30
  194. package/dist/types/components/table/table.header.d.ts +0 -3
  195. package/dist/types/components/tabs/tab-group.d.ts +0 -1
  196. package/dist/types/components/tabs/tab.d.ts +6 -0
  197. package/dist/types/components.d.ts +333 -89
  198. package/dist/types/utils/constructible-style.d.ts +31 -0
  199. package/dist/types/utils/drag.d.ts +21 -1
  200. package/docs-json.json +743 -168
  201. package/docs-vscode.json +102 -26
  202. package/hydrate/index.js +1210 -552
  203. package/package.json +2 -2
  204. package/dist/cjs/form-control-2e900f54.js.map +0 -1
  205. package/dist/cjs/nano-grid_3.cjs.entry.js +0 -431
  206. package/dist/cjs/nano-grid_3.cjs.entry.js.map +0 -1
  207. package/dist/cjs/nano-table-54a4ba34.js.map +0 -1
  208. package/dist/cjs/table.worker-20ed37a5.js.map +0 -1
  209. package/dist/collection/components/grid/grid-item.css +0 -15
  210. package/dist/components/grid-item.js +0 -107
  211. package/dist/components/grid-item.js.map +0 -1
  212. package/dist/esm/form-control-269ba84f.js.map +0 -1
  213. package/dist/esm/nano-grid_3.entry.js +0 -425
  214. package/dist/esm/nano-grid_3.entry.js.map +0 -1
  215. package/dist/esm/nano-table-929ac4d9.js.map +0 -1
  216. package/dist/esm/table.worker-2425382a.js.map +0 -1
  217. package/dist/nano-components/p-068bdd89.entry.js +0 -5
  218. package/dist/nano-components/p-068bdd89.entry.js.map +0 -1
  219. package/dist/nano-components/p-107d4549.entry.js +0 -5
  220. package/dist/nano-components/p-107d4549.entry.js.map +0 -1
  221. package/dist/nano-components/p-239d343a.entry.js +0 -5
  222. package/dist/nano-components/p-239d343a.entry.js.map +0 -1
  223. package/dist/nano-components/p-4f260028.js +0 -5
  224. package/dist/nano-components/p-4f260028.js.map +0 -1
  225. package/dist/nano-components/p-5381c118.js +0 -5
  226. package/dist/nano-components/p-58b53239.entry.js +0 -5
  227. package/dist/nano-components/p-58b53239.entry.js.map +0 -1
  228. package/dist/nano-components/p-5ac74848.js +0 -5
  229. package/dist/nano-components/p-5ac74848.js.map +0 -1
  230. package/dist/nano-components/p-64b56ee6.entry.js +0 -5
  231. package/dist/nano-components/p-64b56ee6.entry.js.map +0 -1
  232. package/dist/nano-components/p-6a3a29c6.entry.js +0 -5
  233. package/dist/nano-components/p-a5a560e7.entry.js +0 -5
  234. package/dist/nano-components/p-a5a560e7.entry.js.map +0 -1
  235. package/dist/nano-components/p-a761ac89.entry.js +0 -5
  236. package/dist/nano-components/p-a761ac89.entry.js.map +0 -1
  237. package/dist/nano-components/p-d792f692.entry.js +0 -5
  238. package/dist/nano-components/p-d792f692.entry.js.map +0 -1
  239. /package/dist/nano-components/{p-5381c118.js.map → p-158c73b0.entry.js.map} +0 -0
  240. /package/dist/nano-components/{p-906de5a2.entry.js.map → p-365c997a.js.map} +0 -0
@@ -0,0 +1,692 @@
1
+ /*!
2
+ * Web Components for Nanopore digital Web Apps
3
+ */
4
+ import { proxyCustomElement, HTMLElement, writeTask, Build, createEvent, readTask, h, Host } from '@stencil/core/internal/client';
5
+ import { d as drag } from './drag.js';
6
+ import { d as debounce } from './throttle.js';
7
+
8
+ const sortableCss = ":host{box-sizing:border-box}*,*::before,*::after{box-sizing:border-box}[hidden]{display:none !important}:host{position:relative;display:block}.sortable__live-region{clip:rect(1px, 1px, 1px, 1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute}";
9
+
10
+ // Orientation map to limit dragging to horizontal or vertical.
11
+ const orientationMap = {
12
+ horizontal: { x: 1, y: 0 },
13
+ vertical: { x: 0, y: 1 },
14
+ };
15
+ let sortableIds = 0;
16
+ const Sortable = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
17
+ handleItemSelectorChange() {
18
+ this.refreshKeyboardHandles();
19
+ }
20
+ handleHandleSelectorChange() {
21
+ this.refreshKeyboardHandles();
22
+ this.attachMutationObserver();
23
+ }
24
+ handleCreateKeyboardHandleChange() {
25
+ this.refreshKeyboardHandles();
26
+ }
27
+ handleSortableHostElement(_newVal, oldVal) {
28
+ if (oldVal)
29
+ this.removeEventHandlers(oldVal);
30
+ this.addEventHandlers();
31
+ this.refreshKeyboardHandles();
32
+ this.attachMutationObserver();
33
+ if (this.sortableHostElement) {
34
+ // sortable host must have position relative
35
+ this.sortableHostElement.style.position = 'relative';
36
+ }
37
+ }
38
+ /** If sortable elements change dynamically, use this method to add handle controls to new elements */
39
+ async refreshKeyboardHandles() {
40
+ var _a, _b, _c;
41
+ if (this.handleSelector) {
42
+ if ((_a = this.keyboardHandleMap) === null || _a === void 0 ? void 0 : _a.size) {
43
+ this.keyboardHandleMap.clear();
44
+ }
45
+ this.sortableHost
46
+ .querySelectorAll(this.handleSelector)
47
+ .forEach((handle) => {
48
+ if (!handle.getAttribute('aria-describedby'))
49
+ handle.setAttribute('aria-describedby', this.sortableId);
50
+ const sortEle = handle.closest(this.itemSelector);
51
+ if (sortEle)
52
+ this.keyboardHandleMap.set(handle, sortEle);
53
+ });
54
+ return;
55
+ }
56
+ if ((_b = this.keyboardHandleMap) === null || _b === void 0 ? void 0 : _b.size) {
57
+ (_c = this.keyboardHandleMap) === null || _c === void 0 ? void 0 : _c.forEach((_ele, handle) => handle.remove());
58
+ this.keyboardHandleMap.clear();
59
+ }
60
+ this.sortableHost
61
+ .querySelectorAll(this.itemSelector)
62
+ .forEach((ele, i) => {
63
+ const handle = this.createKeyboardHandle(i, ele);
64
+ if (!handle) {
65
+ console.error('`createKeyboardHandle` *must* return the handle element it creates');
66
+ return;
67
+ }
68
+ this.keyboardHandleMap.set(handle, ele);
69
+ handle.setAttribute('aria-describedby', this.sortableId);
70
+ });
71
+ }
72
+ /**
73
+ * Get instance of sortable host.
74
+ * By default it is `nano-sortable` which can be overridden by property `sortableHostElement`
75
+ */
76
+ get sortableHost() {
77
+ if (this.sortableHostElement)
78
+ return this.sortableHostElement;
79
+ return this.host;
80
+ }
81
+ /**
82
+ * Queues aria messages which are then displayed in a 'live' region.
83
+ * Messages are cleared after 10s
84
+ * @param msg aria message to announce
85
+ */
86
+ addAriaMsg(msg) {
87
+ this.ariaTextList = [...this.ariaTextList, msg];
88
+ setTimeout(() => {
89
+ const mIdx = this.ariaTextList.indexOf(msg);
90
+ this.ariaTextList.splice(mIdx, 1);
91
+ this.ariaTextList = [...this.ariaTextList];
92
+ }, 10000);
93
+ }
94
+ /**
95
+ * Try to stop text highlight whilst dragging
96
+ * @param userSelect
97
+ */
98
+ updateUserSelectStyle(userSelect) {
99
+ this.host.style.userSelect = userSelect;
100
+ // @ts-ignore
101
+ this.host.style.MozUserSelect = userSelect;
102
+ // @ts-ignore
103
+ this.host.style.msUserSelect = userSelect;
104
+ this.host.style.webkitUserSelect = userSelect;
105
+ }
106
+ /**
107
+ * Fast and simple hit test to check whether the center of a node intersects with the rectangle of any of the
108
+ * given targets. Returns an array of matches.
109
+ * @param node
110
+ * @param targets
111
+ * @returns all the items that currently intersect with the target node
112
+ */
113
+ hitTest(node, targets) {
114
+ const { left: l, top: t, width: w, height: h, } = node.getBoundingClientRect();
115
+ const x = l + w / 2;
116
+ const y = t + h / 2;
117
+ return targets.filter((item) => {
118
+ const { left, right, top, bottom } = item.getBoundingClientRect();
119
+ return !(x < left || x > right || y < top || y > bottom);
120
+ });
121
+ }
122
+ /**
123
+ * Returns a boolean indicating whether the node is currently in an animation.
124
+ * @param node
125
+ * @returns whether a node is currently animating or not
126
+ */
127
+ isAnimating(node) {
128
+ return this.animatedElements.indexOf(node) !== -1;
129
+ }
130
+ /**
131
+ * Triggers a CSS animation on a node with the given dx and dy. Used following dom updates to make it appear as
132
+ * if nodes animate from their old to their new position in the dom. */
133
+ animateNode(node, dx = 0, dy = 0) {
134
+ if (!node.animate) {
135
+ return;
136
+ }
137
+ // keep a stack of currently animating nodes to exclude as drag & drop targets.
138
+ this.animatedElements.push(node);
139
+ node.style.willChange = 'transform';
140
+ // animate from dx/dy (old node position) to none (new node position)
141
+ writeTask(() => {
142
+ this.animationPromise = new Promise((resolve) => {
143
+ node
144
+ .animate([
145
+ { transform: `translate3d(${dx}px, ${dy}px, 0)` },
146
+ { transform: 'none' },
147
+ ], this.animationTiming)
148
+ .addEventListener('finish', () => {
149
+ const index = this.animatedElements.indexOf(node);
150
+ node.style.willChange = '';
151
+ if (index !== -1) {
152
+ // splice out when done to unlock as a valid target
153
+ this.animatedElements.splice(index, 1);
154
+ }
155
+ resolve();
156
+ delete this.animationPromise;
157
+ }, { once: true });
158
+ });
159
+ });
160
+ }
161
+ /**
162
+ * Inserts node at target to update sibling sorting. If the node precedes the target, it is inserted after it;
163
+ * If it follows the target, it is inserted before it. This ensures any node can be dragged from the very
164
+ * beginning to the very end and vice versa. The animateNode function is called for all nodes that moved because
165
+ * of this dom update */
166
+ insertAtTarget(node, target) {
167
+ if (!node || !target)
168
+ return;
169
+ let offsets = [];
170
+ if (this.animationEnabled) {
171
+ offsets = this.sortableNodes.map((item) => ({
172
+ x: item.offsetLeft,
173
+ y: item.offsetTop,
174
+ }));
175
+ }
176
+ if (!node.isConnected || !target.isConnected)
177
+ return;
178
+ if (this.dropzoneNodes.indexOf(target) > -1) {
179
+ target.append(node);
180
+ }
181
+ else {
182
+ const nodeComparison = node.compareDocumentPosition(target);
183
+ let position;
184
+ if (nodeComparison & this.host.DOCUMENT_POSITION_FOLLOWING) {
185
+ position =
186
+ target.parentNode === node.parentNode ? 'afterend' : 'beforebegin';
187
+ }
188
+ if (nodeComparison & this.host.DOCUMENT_POSITION_PRECEDING) {
189
+ position =
190
+ target.parentNode === node.parentNode ? 'beforebegin' : 'afterend';
191
+ }
192
+ if (position)
193
+ target.insertAdjacentElement(position, node);
194
+ }
195
+ if (this.animationEnabled) {
196
+ this.sortableNodes.forEach((sortableNode, i) => {
197
+ const { x, y } = offsets[i];
198
+ const dx = x - sortableNode.offsetLeft;
199
+ const dy = y - sortableNode.offsetTop;
200
+ if (dx !== 0 || dy !== 0) {
201
+ this.animateNode(sortableNode, dx, dy);
202
+ }
203
+ });
204
+ }
205
+ }
206
+ reset() {
207
+ if (this.draggedElementClone !== undefined &&
208
+ this.draggedElementClone.parentNode !== null) {
209
+ this.draggedElementClone.parentNode.removeChild(this.draggedElementClone);
210
+ }
211
+ if (this.draggedElement &&
212
+ this.draggedElement.parentNode &&
213
+ this.draggedElementOrigin) {
214
+ this.draggedElement.classList.remove(this.placeholderClass);
215
+ }
216
+ if (this.dropzoneActiveClass && this.dropzoneNodes.length) {
217
+ this.dropzoneNodes.forEach((dze) => dze.classList.remove(this.dropzoneActiveClass));
218
+ }
219
+ delete this.draggedElementClone;
220
+ delete this.draggedElement;
221
+ this.dropzoneNodes = [];
222
+ this.sortableNodes = [];
223
+ this.animatedElements = [];
224
+ this.dragRequestPending = false;
225
+ this.updateUserSelectStyle('');
226
+ }
227
+ /**
228
+ * Clones a given node to visually drag around. The original node is left in the same flow as its siblings.
229
+ * Clone styles are added onto the style object directly, since the ::slotted()
230
+ * selector can't universally target nodes that may be nested an unknown amount of shadow dom levels deep
231
+ * @param node html node to clone
232
+ * @returns the cloned html node
233
+ */
234
+ createClone(node) {
235
+ const clone = node.cloneNode(true);
236
+ if (node.id)
237
+ clone.id = 'clone__' + clone.id;
238
+ /**
239
+ * Bugfix for table row sorting.
240
+ * During dragging table rows shrink, so we manually set them width of original node.
241
+ */
242
+ Array.from(clone.children).forEach((nodeChild, index) => {
243
+ const clonedNodeChild = nodeChild;
244
+ const originalNodeChild = node.children.item(index);
245
+ if (originalNodeChild) {
246
+ clonedNodeChild.style.width = `${originalNodeChild.offsetWidth}px`;
247
+ }
248
+ });
249
+ const { offsetLeft: x, offsetTop: y, offsetWidth: w, offsetHeight: h, } = node;
250
+ Object.assign(clone.style, {
251
+ position: 'absolute',
252
+ left: `calc(${x}px - var(--grab-offset-x, 0px))`,
253
+ top: `calc(${y}px - var(--grab-offset-y, 0px))`,
254
+ height: this.dragResize ? `${h}px` : undefined,
255
+ width: this.dragResize ? `${w}px` : undefined,
256
+ willChange: 'transform,opacity',
257
+ });
258
+ clone.classList.add(this.draggedClass);
259
+ return node.parentNode.appendChild(clone);
260
+ }
261
+ /// Event handlers ///
262
+ removeEventHandlers(ele) {
263
+ ele = ele || this.sortableHost;
264
+ ele.removeEventListener('mousedown', this.handleTrack);
265
+ ele.removeEventListener('touchstart', this.handleTrack);
266
+ ele.removeEventListener('keydown', this.handleKeydown);
267
+ }
268
+ addEventHandlers(ele) {
269
+ ele = ele || this.sortableHost;
270
+ ele.addEventListener('mousedown', this.handleTrack);
271
+ ele.addEventListener('touchstart', this.handleTrack);
272
+ ele.addEventListener('keydown', this.handleKeydown);
273
+ }
274
+ /**
275
+ * Watch for any changes in grab-able handle elements.
276
+ */
277
+ attachMutationObserver() {
278
+ if (!Build.isBrowser)
279
+ return;
280
+ if (this.mutationObserver) {
281
+ this.mutationObserver.disconnect();
282
+ this.mutationObserver = undefined;
283
+ }
284
+ this.mutationObserver = new MutationObserver(() => {
285
+ const currHandles = Array.from(this.keyboardHandleMap.values());
286
+ const newHandles = Array.from(this.sortableHost.querySelectorAll(this.itemSelector));
287
+ // simple test for equality
288
+ if (currHandles.length !== newHandles.length ||
289
+ !!newHandles.find((h) => !currHandles.includes(h))) {
290
+ this.refreshKeyboardHandles();
291
+ }
292
+ });
293
+ this.mutationObserver.observe(this.sortableHost, {
294
+ subtree: true,
295
+ childList: true,
296
+ });
297
+ }
298
+ handleKeydown(e) {
299
+ const targetElement = e.target;
300
+ let foundHandle;
301
+ let sortEle;
302
+ if (this.handleSelector) {
303
+ foundHandle = targetElement.closest(this.handleSelector);
304
+ sortEle = targetElement.closest(this.itemSelector);
305
+ }
306
+ else {
307
+ sortEle = this.keyboardHandleMap.get(targetElement);
308
+ foundHandle = targetElement;
309
+ }
310
+ // have we found a handle and matching sort element from the keydown element
311
+ if (!foundHandle || !sortEle)
312
+ return;
313
+ const activateSort = (isActive) => {
314
+ this.keyboardSortActive = isActive;
315
+ this.draggedElement = isActive ? sortEle : undefined;
316
+ sortEle.classList.toggle(this.draggedClass, isActive);
317
+ foundHandle.classList.toggle(this.handleDraggedClass, isActive);
318
+ if (isActive) {
319
+ this.addAriaMsg(this.grabbedHelperText(sortEle));
320
+ document.addEventListener('mousedown', () => activateSort(false), {
321
+ once: true,
322
+ });
323
+ }
324
+ else {
325
+ this.addAriaMsg(this.droppedHelperText(sortEle));
326
+ }
327
+ };
328
+ // start editing this element's order?
329
+ if ([' ', 'Space', 'Enter'].includes(e.key)) {
330
+ e.preventDefault();
331
+ if (!this.keyboardSortActive) {
332
+ // grabbed the element
333
+ activateSort(true);
334
+ this.sortableNodes =
335
+ Array.from(this.sortableHost.querySelectorAll(this.itemSelector)) ||
336
+ [];
337
+ const nanoGrabbedEv = this.nanoGrabbed.emit({
338
+ element: sortEle,
339
+ index: this.sortableNodes.indexOf(sortEle),
340
+ });
341
+ if (nanoGrabbedEv.defaultPrevented) {
342
+ activateSort(false);
343
+ return;
344
+ }
345
+ }
346
+ else {
347
+ // dropped the element
348
+ activateSort(false);
349
+ this.nanoDropped.emit({ element: sortEle });
350
+ }
351
+ return;
352
+ }
353
+ if (!this.keyboardSortActive)
354
+ return;
355
+ // Tabbing away from this handle - deactivate
356
+ if (['Escape', 'Tab'].includes(e.key))
357
+ activateSort(false);
358
+ let moveKeys = ['Home', 'End'];
359
+ if (!this.orientation || this.orientation === 'horizontal')
360
+ moveKeys = [...moveKeys, 'ArrowRight', 'ArrowLeft'];
361
+ if (!this.orientation || this.orientation === 'vertical')
362
+ moveKeys = [...moveKeys, 'ArrowUp', 'ArrowDown'];
363
+ if (!moveKeys.includes(e.key))
364
+ return;
365
+ // move the element with the keyboard
366
+ e.preventDefault();
367
+ /** Collect all elements that have drag positions.
368
+ * Both sortable elements and 'dropzones' (placeholders where items can always be placed) */
369
+ this.sortableNodes =
370
+ Array.from(this.sortableHost.querySelectorAll(this.itemSelector)) || [];
371
+ this.dropzoneNodes =
372
+ Array.from(this.sortableHost.querySelectorAll(this.dropzoneSelector)) ||
373
+ [];
374
+ const currIdx = this.sortableNodes.indexOf(this.draggedElement);
375
+ let curDzIdx = -1;
376
+ if (this.dropzoneNodes.length) {
377
+ const curDropzone = this.draggedElement.closest(this.dropzoneSelector);
378
+ curDzIdx = this.dropzoneNodes.indexOf(curDropzone);
379
+ curDzIdx = curDzIdx > -1 ? curDzIdx : -1;
380
+ }
381
+ /** If we don't have a next / prev sortable element in our list, test to see if there's a dropzone instead */
382
+ const prevEle = currIdx - 1 < 0 && curDzIdx > -1
383
+ ? this.dropzoneNodes[curDzIdx - 1]
384
+ : this.sortableNodes[currIdx - 1];
385
+ const nextEle = currIdx + 1 === this.sortableNodes.length && curDzIdx > -1
386
+ ? this.dropzoneNodes[curDzIdx + 1]
387
+ : this.sortableNodes[currIdx + 1];
388
+ if (e.key === 'Home') {
389
+ this.insertAtTarget(this.draggedElement, this.sortableNodes[0]);
390
+ }
391
+ if (e.key === 'End') {
392
+ this.insertAtTarget(this.draggedElement, this.sortableNodes[this.sortableNodes.length - 1]);
393
+ }
394
+ if (['ArrowRight', 'ArrowDown'].includes(e.key)) {
395
+ this.insertAtTarget(this.draggedElement, nextEle);
396
+ }
397
+ if (['ArrowLeft', 'ArrowUp'].includes(e.key)) {
398
+ this.insertAtTarget(this.draggedElement, prevEle);
399
+ }
400
+ this.finishOrder();
401
+ this.draggedElement = sortEle;
402
+ const focus = () => {
403
+ requestAnimationFrame(() => {
404
+ typeof foundHandle['setFocus'] === 'function'
405
+ ? foundHandle.setFocus()
406
+ : foundHandle.focus();
407
+ });
408
+ };
409
+ // replace focus to handle so we don't 'drop' the element
410
+ if (this.animationPromise)
411
+ this.animationPromise.then(() => focus());
412
+ else
413
+ focus();
414
+ }
415
+ /**
416
+ * Tracks a pointer from touchstart/mousedown to touchend/mouseup. Note that the start state is fired following
417
+ * the first actual move event following a touchstart/mousedown */
418
+ handleTrack(e) {
419
+ if (this.dragRequestPending || (e.button && e.button !== 1))
420
+ return;
421
+ clearTimeout(this.mouseDownTimer);
422
+ this.mouseDownTimer = window === null || window === void 0 ? void 0 : window.setTimeout(() => {
423
+ if (!this.trackStart(e))
424
+ return;
425
+ this.addAriaMsg(this.grabbedHelperText(this.draggedElement));
426
+ drag(this.sortableHost, {
427
+ initialEvent: e,
428
+ relative: true,
429
+ onMove: (x, y) => {
430
+ this.trackMove(x, y);
431
+ },
432
+ onStop: () => {
433
+ this.nanoDropped.emit({ element: this.draggedElement });
434
+ const didStop = () => {
435
+ this.addAriaMsg(this.droppedHelperText(this.draggedElement));
436
+ requestAnimationFrame(() => this.finishOrder());
437
+ };
438
+ if (this.animationPromise) {
439
+ this.animationPromise.then(() => didStop());
440
+ }
441
+ else
442
+ didStop();
443
+ },
444
+ });
445
+ }, 100);
446
+ document.addEventListener('mouseup', () => clearTimeout(this.mouseDownTimer), { once: true });
447
+ }
448
+ /**
449
+ * Initialized a drag and drop sequence if a child node was clicked that matches the itemSelector property.
450
+ * OR If a handleSelector is defined, a node matching this selector must be clicked instead
451
+ * @returns boolean - whether tracking for this event should continue or not
452
+ */
453
+ trackStart(e) {
454
+ const targetElement = e.target;
455
+ let targetHandle;
456
+ // If we have a handle set, return now if not being pressed
457
+ if (this.handleSelector) {
458
+ targetHandle = targetElement.closest(this.handleSelector);
459
+ if (!targetHandle)
460
+ return;
461
+ targetHandle.classList.add(this.handleDraggedClass);
462
+ }
463
+ // Check that we've found the target element via itemSelector
464
+ const node = targetElement.closest(this.itemSelector);
465
+ if (!node)
466
+ return false;
467
+ this.sortableNodes =
468
+ Array.from(this.sortableHost.querySelectorAll(this.itemSelector)) || [];
469
+ const nanoGrabbedEv = this.nanoGrabbed.emit({
470
+ element: node,
471
+ index: this.sortableNodes.indexOf(node),
472
+ });
473
+ if (nanoGrabbedEv.defaultPrevented)
474
+ return false;
475
+ // Element found... start everything
476
+ e.preventDefault();
477
+ this.updateUserSelectStyle('none');
478
+ this.dragRequestPending = true;
479
+ this.draggedElement = node;
480
+ this.dropzoneNodes =
481
+ Array.from(this.sortableHost.querySelectorAll(this.dropzoneSelector)) ||
482
+ [];
483
+ this.draggedElementClone = this.createClone(node);
484
+ this.draggedElementOrigin = node.nextSibling;
485
+ this.animatedElements = [];
486
+ this.draggedElement.classList.add(this.placeholderClass);
487
+ return true;
488
+ }
489
+ /** Ends re-ordering */
490
+ finishOrder() {
491
+ if (!this.draggedElement)
492
+ return;
493
+ const updated = Array.from(this.sortableHost.querySelectorAll(this.itemSelector)).filter((ele) => ele !== this.draggedElementClone);
494
+ const originalIndex = this.sortableNodes.indexOf(this.draggedElement);
495
+ const targetIndex = updated.indexOf(this.draggedElement);
496
+ if (this.handleSelector) {
497
+ const targetHandle = this.draggedElement.querySelector(this.handleSelector);
498
+ targetHandle.classList.remove(this.handleDraggedClass);
499
+ }
500
+ if (originalIndex !== targetIndex) {
501
+ const orderChangeEv = this.nanoOrderChange.emit({
502
+ element: this.draggedElement,
503
+ originalIndex,
504
+ targetIndex,
505
+ });
506
+ if (orderChangeEv.defaultPrevented) {
507
+ /** Event was prevented, wait a moment to send element back to whence it came - gives a nicer visual queue */
508
+ this.animationPromise = new Promise((resolve) => {
509
+ setTimeout(() => {
510
+ this.insertAtTarget(this.draggedElement, updated[originalIndex]);
511
+ this.reset();
512
+ this.dragRequestPending = false;
513
+ resolve();
514
+ }, 200);
515
+ });
516
+ return;
517
+ }
518
+ this.addAriaMsg(this.reorderHelperText(this.draggedElement, updated, targetIndex + 1));
519
+ }
520
+ this.reset();
521
+ this.dragRequestPending = false;
522
+ }
523
+ /// Component lifecycle ///
524
+ constructor() {
525
+ super();
526
+ this.__registerHost();
527
+ this.__attachShadow();
528
+ this.nanoOrderChange = createEvent(this, "nanoOrderChange", 7);
529
+ this.nanoGrabbed = createEvent(this, "nanoGrabbed", 7);
530
+ this.nanoDropped = createEvent(this, "nanoDropped", 7);
531
+ this.dragRequestPending = false;
532
+ this.sortableNodes = [];
533
+ this.dropzoneNodes = [];
534
+ this.animatedElements = [];
535
+ this.keyboardHandleMap = new Map();
536
+ this.sortableId = `nano-sortable-${sortableIds++}`;
537
+ /**
538
+ * Moves the active node's clone to follow the pointer. The node that the clone intersects with (via hitTest) is
539
+ * the insert point for updated sorting */
540
+ this.trackMove = (x, y) => {
541
+ if (!this.draggedElementClone) {
542
+ return;
543
+ }
544
+ if (this.orientation) {
545
+ x = x * orientationMap[this.orientation].x;
546
+ y = y * orientationMap[this.orientation].y;
547
+ }
548
+ writeTask(() => {
549
+ Object.assign(this.draggedElementClone.style, {
550
+ transform: `translate3d(${x}px, ${y}px, 0)`,
551
+ });
552
+ });
553
+ let target = this.hitTest(this.draggedElementClone, this.sortableNodes)[0];
554
+ let activeDropzone;
555
+ if (this.dropzoneSelector && this.dropzoneActiveClass) {
556
+ readTask(() => {
557
+ activeDropzone = this.draggedElement.closest(this.dropzoneSelector);
558
+ writeTask(() => {
559
+ this.dropzoneNodes
560
+ .filter((dze) => dze !== activeDropzone)
561
+ .forEach((dze) => dze.classList.remove(this.dropzoneActiveClass));
562
+ activeDropzone.classList.add(this.dropzoneActiveClass);
563
+ });
564
+ });
565
+ }
566
+ // didn't find a target - let's test to see if we can use a drop-zone instead
567
+ if (!target && this.dropzoneNodes.length) {
568
+ target = this.hitTest(this.draggedElementClone, this.dropzoneNodes)[0];
569
+ if (this.draggedElement.closest(this.dropzoneSelector) === target)
570
+ return;
571
+ }
572
+ if (
573
+ // if clone intersects with a valid target,
574
+ target &&
575
+ // other than its own origin,
576
+ target !== this.draggedElement &&
577
+ // and the target isn't currently animating, which causes false hit tests,
578
+ !this.isAnimating(target)) {
579
+ this.insertAtTarget(this.draggedElement, target);
580
+ }
581
+ };
582
+ this.itemSelector = 'li';
583
+ this.handleSelector = undefined;
584
+ this.dropzoneSelector = undefined;
585
+ this.helperText = 'Press "Space" or "Enter" to enable element reordering and use the arrow keys to reorder items.' +
586
+ 'Press "Escape" to cancel reordering. Alternatively, use your mouse to drag / reorder.';
587
+ this.itemDescriptor = (el) => `"${el.textContent.trim()}"`;
588
+ this.grabbedHelperText = (el) => `${this.itemDescriptor(el)} grabbed`;
589
+ this.droppedHelperText = (el) => `${this.itemDescriptor(el)} dropped`;
590
+ this.reorderHelperText = (el, elements, position) => `The list has been reordered, ${this.itemDescriptor(el)} is now item ${position} of ${elements.length}`;
591
+ this.createKeyboardHandle = (_number, _element) => {
592
+ const handleTpl = /* html */ `
593
+ <nano-icon-button
594
+ slot="end"
595
+ icon-name="light/arrows"
596
+ class="nano-sortable__keyboard-handle visually-hidden"
597
+ label="Re-order this item"
598
+ ></nano-icon-button>`;
599
+ const div = globalThis.document.createElement('div');
600
+ div.innerHTML = handleTpl;
601
+ const handle = div.children[0];
602
+ _element.append(handle);
603
+ return handle;
604
+ };
605
+ this.sortableHostElement = undefined;
606
+ this.animationEnabled = true;
607
+ this.draggedClass = 'nano-sortable__dragged';
608
+ this.handleDraggedClass = 'nano-sortable__handle-dragged';
609
+ this.placeholderClass = 'nano-sortable__placeholder';
610
+ this.dropzoneActiveClass = '';
611
+ this.animationTiming = { duration: 200, easing: 'ease-out' };
612
+ this.orientation = undefined;
613
+ this.dragResize = false;
614
+ this.keyboardSortActive = false;
615
+ this.ariaTextList = [];
616
+ this.handleTrack = this.handleTrack.bind(this);
617
+ this.handleKeydown = this.handleKeydown.bind(this);
618
+ this.refreshKeyboardHandles = this.refreshKeyboardHandles.bind(this);
619
+ this.refreshKeyboardHandles = debounce(this.refreshKeyboardHandles, 500);
620
+ }
621
+ connectedCallback() {
622
+ this.addEventHandlers();
623
+ this.refreshKeyboardHandles();
624
+ this.attachMutationObserver();
625
+ if (Build.isBrowser && !this.host.querySelector(`#${this.sortableId}`)) {
626
+ // inject a light-dom / a11y description that we can connect sortable items to
627
+ this.host.insertAdjacentHTML('beforeend', `<div class="visually-hidden" id="${this.sortableId}">${this.helperText}</div>`);
628
+ }
629
+ }
630
+ disconnectedCallback() {
631
+ var _a;
632
+ this.removeEventHandlers();
633
+ (_a = this.host.querySelector(`#${this.sortableId}`)) === null || _a === void 0 ? void 0 : _a.remove();
634
+ if (this.mutationObserver) {
635
+ this.mutationObserver.disconnect();
636
+ this.mutationObserver = undefined;
637
+ }
638
+ }
639
+ render() {
640
+ return (h(Host, null, h("div", { class: "sortable__live-region", "aria-live": "polite", "aria-relevant": "additions", "aria-atomic": "true", role: "log", part: "announcements" }, this.ariaTextList.map((str) => (h("div", null, str)))), h("slot", null)));
641
+ }
642
+ get host() { return this; }
643
+ static get watchers() { return {
644
+ "itemSelector": ["handleItemSelectorChange"],
645
+ "handleSelector": ["handleHandleSelectorChange"],
646
+ "createKeyboardHandle": ["handleCreateKeyboardHandleChange"],
647
+ "sortableHostElement": ["handleSortableHostElement"]
648
+ }; }
649
+ static get style() { return sortableCss; }
650
+ }, [1, "nano-sortable", {
651
+ "itemSelector": [1, "item-selector"],
652
+ "handleSelector": [1, "handle-selector"],
653
+ "dropzoneSelector": [1, "dropzone-selector"],
654
+ "helperText": [1, "helper-text"],
655
+ "itemDescriptor": [16],
656
+ "grabbedHelperText": [16],
657
+ "droppedHelperText": [16],
658
+ "reorderHelperText": [16],
659
+ "createKeyboardHandle": [16],
660
+ "sortableHostElement": [16],
661
+ "animationEnabled": [4, "animation-enabled"],
662
+ "draggedClass": [1, "dragged-class"],
663
+ "handleDraggedClass": [1, "handle-dragged-class"],
664
+ "placeholderClass": [1, "placeholder-class"],
665
+ "dropzoneActiveClass": [1, "dropzone-active-class"],
666
+ "animationTiming": [8, "animation-timing"],
667
+ "orientation": [1],
668
+ "dragResize": [4, "drag-resize"],
669
+ "keyboardSortActive": [32],
670
+ "ariaTextList": [32],
671
+ "refreshKeyboardHandles": [64]
672
+ }]);
673
+ function defineCustomElement$1() {
674
+ if (typeof customElements === "undefined") {
675
+ return;
676
+ }
677
+ const components = ["nano-sortable"];
678
+ components.forEach(tagName => { switch (tagName) {
679
+ case "nano-sortable":
680
+ if (!customElements.get(tagName)) {
681
+ customElements.define(tagName, Sortable);
682
+ }
683
+ break;
684
+ } });
685
+ }
686
+
687
+ const NanoSortable = Sortable;
688
+ const defineCustomElement = defineCustomElement$1;
689
+
690
+ export { NanoSortable, defineCustomElement };
691
+
692
+ //# sourceMappingURL=nano-sortable.js.map