@atlaskit/navigation-system 5.40.0 → 6.1.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 (212) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/constellation/index/examples.mdx +5 -11
  3. package/constellation/layout/examples.mdx +3 -2
  4. package/constellation/layout/usage.mdx +3 -4
  5. package/constellation/side-nav-items/index.mdx +17 -0
  6. package/constellation/top-nav-items/examples.mdx +5 -5
  7. package/constellation/top-nav-items/usage.mdx +1 -2
  8. package/dist/cjs/components/badge-container.js +1 -1
  9. package/dist/cjs/components/list-item.js +1 -1
  10. package/dist/cjs/components/list.js +1 -1
  11. package/dist/cjs/components/skip-links/skip-link.js +3 -3
  12. package/dist/cjs/components/skip-links/skip-links-container.js +1 -1
  13. package/dist/cjs/index.js +0 -111
  14. package/dist/cjs/ui/page-layout/aside.js +1 -1
  15. package/dist/cjs/ui/page-layout/banner.js +1 -1
  16. package/dist/cjs/ui/page-layout/main/main-sticky-header.js +1 -1
  17. package/dist/cjs/ui/page-layout/main/main.js +1 -1
  18. package/dist/cjs/ui/page-layout/panel-splitter/panel-splitter.js +1 -1
  19. package/dist/cjs/ui/page-layout/panel.js +1 -1
  20. package/dist/cjs/ui/page-layout/ribbon.js +1 -1
  21. package/dist/cjs/ui/page-layout/root.js +1 -1
  22. package/dist/cjs/ui/page-layout/side-nav/side-nav-content.js +1 -1
  23. package/dist/cjs/ui/page-layout/side-nav/side-nav-footer.js +1 -1
  24. package/dist/cjs/ui/page-layout/side-nav/side-nav-header.js +1 -1
  25. package/dist/cjs/ui/page-layout/side-nav/side-nav.js +1 -1
  26. package/dist/cjs/ui/page-layout/side-nav/toggle-button.js +1 -1
  27. package/dist/cjs/ui/page-layout/top-nav/top-nav-end.js +1 -1
  28. package/dist/cjs/ui/page-layout/top-nav/top-nav-middle.js +1 -1
  29. package/dist/cjs/ui/page-layout/top-nav/top-nav-start.js +1 -1
  30. package/dist/cjs/ui/page-layout/top-nav/top-nav.js +1 -1
  31. package/dist/cjs/ui/top-nav-items/custom-title.js +1 -1
  32. package/dist/cjs/ui/top-nav-items/nav-logo/app-logo.js +1 -1
  33. package/dist/cjs/ui/top-nav-items/nav-logo/custom-logo.js +3 -3
  34. package/dist/cjs/ui/top-nav-items/nav-logo/logo-renderer.js +1 -1
  35. package/dist/cjs/ui/top-nav-items/search.js +1 -1
  36. package/dist/cjs/ui/top-nav-items/themed/button.js +1 -1
  37. package/dist/es2019/components/badge-container.js +1 -1
  38. package/dist/es2019/components/list-item.js +1 -1
  39. package/dist/es2019/components/list.js +1 -1
  40. package/dist/es2019/components/skip-links/skip-link.js +2 -2
  41. package/dist/es2019/components/skip-links/skip-links-container.js +1 -1
  42. package/dist/es2019/index.js +0 -9
  43. package/dist/es2019/ui/page-layout/aside.js +1 -1
  44. package/dist/es2019/ui/page-layout/banner.js +1 -1
  45. package/dist/es2019/ui/page-layout/main/main-sticky-header.js +1 -1
  46. package/dist/es2019/ui/page-layout/main/main.js +1 -1
  47. package/dist/es2019/ui/page-layout/panel-splitter/panel-splitter.js +1 -1
  48. package/dist/es2019/ui/page-layout/panel.js +1 -1
  49. package/dist/es2019/ui/page-layout/ribbon.js +1 -1
  50. package/dist/es2019/ui/page-layout/root.js +1 -1
  51. package/dist/es2019/ui/page-layout/side-nav/side-nav-content.js +1 -1
  52. package/dist/es2019/ui/page-layout/side-nav/side-nav-footer.js +1 -1
  53. package/dist/es2019/ui/page-layout/side-nav/side-nav-header.js +1 -1
  54. package/dist/es2019/ui/page-layout/side-nav/side-nav.js +1 -1
  55. package/dist/es2019/ui/page-layout/side-nav/toggle-button.js +1 -1
  56. package/dist/es2019/ui/page-layout/top-nav/top-nav-end.js +1 -1
  57. package/dist/es2019/ui/page-layout/top-nav/top-nav-middle.js +1 -1
  58. package/dist/es2019/ui/page-layout/top-nav/top-nav-start.js +1 -1
  59. package/dist/es2019/ui/page-layout/top-nav/top-nav.js +1 -1
  60. package/dist/es2019/ui/top-nav-items/custom-title.js +1 -1
  61. package/dist/es2019/ui/top-nav-items/nav-logo/app-logo.js +1 -1
  62. package/dist/es2019/ui/top-nav-items/nav-logo/custom-logo.js +2 -2
  63. package/dist/es2019/ui/top-nav-items/nav-logo/logo-renderer.js +1 -1
  64. package/dist/es2019/ui/top-nav-items/search.js +1 -1
  65. package/dist/es2019/ui/top-nav-items/themed/button.js +1 -1
  66. package/dist/esm/components/badge-container.js +1 -1
  67. package/dist/esm/components/list-item.js +1 -1
  68. package/dist/esm/components/list.js +1 -1
  69. package/dist/esm/components/skip-links/skip-link.js +2 -2
  70. package/dist/esm/components/skip-links/skip-links-container.js +1 -1
  71. package/dist/esm/index.js +0 -9
  72. package/dist/esm/ui/page-layout/aside.js +1 -1
  73. package/dist/esm/ui/page-layout/banner.js +1 -1
  74. package/dist/esm/ui/page-layout/main/main-sticky-header.js +1 -1
  75. package/dist/esm/ui/page-layout/main/main.js +1 -1
  76. package/dist/esm/ui/page-layout/panel-splitter/panel-splitter.js +1 -1
  77. package/dist/esm/ui/page-layout/panel.js +1 -1
  78. package/dist/esm/ui/page-layout/ribbon.js +1 -1
  79. package/dist/esm/ui/page-layout/root.js +1 -1
  80. package/dist/esm/ui/page-layout/side-nav/side-nav-content.js +1 -1
  81. package/dist/esm/ui/page-layout/side-nav/side-nav-footer.js +1 -1
  82. package/dist/esm/ui/page-layout/side-nav/side-nav-header.js +1 -1
  83. package/dist/esm/ui/page-layout/side-nav/side-nav.js +1 -1
  84. package/dist/esm/ui/page-layout/side-nav/toggle-button.js +1 -1
  85. package/dist/esm/ui/page-layout/top-nav/top-nav-end.js +1 -1
  86. package/dist/esm/ui/page-layout/top-nav/top-nav-middle.js +1 -1
  87. package/dist/esm/ui/page-layout/top-nav/top-nav-start.js +1 -1
  88. package/dist/esm/ui/page-layout/top-nav/top-nav.js +1 -1
  89. package/dist/esm/ui/top-nav-items/custom-title.js +1 -1
  90. package/dist/esm/ui/top-nav-items/nav-logo/app-logo.js +1 -1
  91. package/dist/esm/ui/top-nav-items/nav-logo/custom-logo.js +2 -2
  92. package/dist/esm/ui/top-nav-items/nav-logo/logo-renderer.js +1 -1
  93. package/dist/esm/ui/top-nav-items/search.js +1 -1
  94. package/dist/esm/ui/top-nav-items/themed/button.js +1 -1
  95. package/dist/types/index.d.ts +0 -9
  96. package/dist/types/ui/page-layout/top-nav/top-nav-start.d.ts +1 -4
  97. package/dist/types-ts4.5/index.d.ts +0 -9
  98. package/dist/types-ts4.5/ui/page-layout/top-nav/top-nav-start.d.ts +1 -4
  99. package/package.json +6 -9
  100. package/constellation/side-nav-items/code.mdx +0 -89
  101. package/constellation/side-nav-items/drag-and-drop.mdx +0 -1079
  102. package/constellation/side-nav-items/examples.mdx +0 -235
  103. package/constellation/side-nav-items/images/side-nav-anatomy-1.png +0 -0
  104. package/constellation/side-nav-items/images/side-nav-anatomy-2.png +0 -0
  105. package/constellation/side-nav-items/images/side-nav-do-1.png +0 -0
  106. package/constellation/side-nav-items/images/side-nav-do-2.png +0 -0
  107. package/constellation/side-nav-items/images/side-nav-do-3.png +0 -0
  108. package/constellation/side-nav-items/images/side-nav-do-4.png +0 -0
  109. package/constellation/side-nav-items/images/side-nav-do-5.png +0 -0
  110. package/constellation/side-nav-items/images/side-nav-do-6.png +0 -0
  111. package/constellation/side-nav-items/images/side-nav-do-7.png +0 -0
  112. package/constellation/side-nav-items/images/side-nav-dont-1.png +0 -0
  113. package/constellation/side-nav-items/images/side-nav-dont-10.png +0 -0
  114. package/constellation/side-nav-items/images/side-nav-dont-2.png +0 -0
  115. package/constellation/side-nav-items/images/side-nav-dont-3.png +0 -0
  116. package/constellation/side-nav-items/images/side-nav-dont-4.png +0 -0
  117. package/constellation/side-nav-items/images/side-nav-dont-5.png +0 -0
  118. package/constellation/side-nav-items/images/side-nav-dont-6.png +0 -0
  119. package/constellation/side-nav-items/images/side-nav-dont-7.png +0 -0
  120. package/constellation/side-nav-items/images/side-nav-dont-8.png +0 -0
  121. package/constellation/side-nav-items/images/side-nav-dont-9.png +0 -0
  122. package/constellation/side-nav-items/usage.mdx +0 -328
  123. package/dist/cjs/entry-points/side-nav-items/button-menu-item.js +0 -18
  124. package/dist/cjs/entry-points/side-nav-items/container-avatar.js +0 -12
  125. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/drag-handle.js +0 -12
  126. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/drag-preview.js +0 -12
  127. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/drop-indicator.js +0 -12
  128. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/group-drop-indicator.js +0 -12
  129. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/hitbox.js +0 -18
  130. package/dist/cjs/entry-points/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop.js +0 -12
  131. package/dist/cjs/entry-points/side-nav-items/expandable-menu-item.js +0 -30
  132. package/dist/cjs/entry-points/side-nav-items/flyout-menu-item.js +0 -48
  133. package/dist/cjs/entry-points/side-nav-items/link-menu-item.js +0 -18
  134. package/dist/cjs/entry-points/side-nav-items/menu-list-item.js +0 -12
  135. package/dist/cjs/entry-points/side-nav-items/menu-list.js +0 -12
  136. package/dist/cjs/entry-points/side-nav-items/menu-section.js +0 -24
  137. package/dist/cjs/entry-points/side-nav-items/top-level-spacer.js +0 -12
  138. package/dist/es2019/entry-points/side-nav-items/button-menu-item.js +0 -1
  139. package/dist/es2019/entry-points/side-nav-items/container-avatar.js +0 -1
  140. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/drag-handle.js +0 -1
  141. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/drag-preview.js +0 -1
  142. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/drop-indicator.js +0 -1
  143. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/group-drop-indicator.js +0 -1
  144. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/hitbox.js +0 -1
  145. package/dist/es2019/entry-points/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop.js +0 -1
  146. package/dist/es2019/entry-points/side-nav-items/expandable-menu-item.js +0 -1
  147. package/dist/es2019/entry-points/side-nav-items/flyout-menu-item.js +0 -1
  148. package/dist/es2019/entry-points/side-nav-items/link-menu-item.js +0 -1
  149. package/dist/es2019/entry-points/side-nav-items/menu-list-item.js +0 -1
  150. package/dist/es2019/entry-points/side-nav-items/menu-list.js +0 -1
  151. package/dist/es2019/entry-points/side-nav-items/menu-section.js +0 -1
  152. package/dist/es2019/entry-points/side-nav-items/top-level-spacer.js +0 -1
  153. package/dist/esm/entry-points/side-nav-items/button-menu-item.js +0 -1
  154. package/dist/esm/entry-points/side-nav-items/container-avatar.js +0 -1
  155. package/dist/esm/entry-points/side-nav-items/drag-and-drop/drag-handle.js +0 -1
  156. package/dist/esm/entry-points/side-nav-items/drag-and-drop/drag-preview.js +0 -1
  157. package/dist/esm/entry-points/side-nav-items/drag-and-drop/drop-indicator.js +0 -1
  158. package/dist/esm/entry-points/side-nav-items/drag-and-drop/group-drop-indicator.js +0 -1
  159. package/dist/esm/entry-points/side-nav-items/drag-and-drop/hitbox.js +0 -1
  160. package/dist/esm/entry-points/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop.js +0 -1
  161. package/dist/esm/entry-points/side-nav-items/expandable-menu-item.js +0 -1
  162. package/dist/esm/entry-points/side-nav-items/flyout-menu-item.js +0 -1
  163. package/dist/esm/entry-points/side-nav-items/link-menu-item.js +0 -1
  164. package/dist/esm/entry-points/side-nav-items/menu-list-item.js +0 -1
  165. package/dist/esm/entry-points/side-nav-items/menu-list.js +0 -1
  166. package/dist/esm/entry-points/side-nav-items/menu-section.js +0 -1
  167. package/dist/esm/entry-points/side-nav-items/top-level-spacer.js +0 -1
  168. package/dist/types/entry-points/side-nav-items/button-menu-item.d.ts +0 -1
  169. package/dist/types/entry-points/side-nav-items/container-avatar.d.ts +0 -1
  170. package/dist/types/entry-points/side-nav-items/drag-and-drop/drag-handle.d.ts +0 -1
  171. package/dist/types/entry-points/side-nav-items/drag-and-drop/drag-preview.d.ts +0 -1
  172. package/dist/types/entry-points/side-nav-items/drag-and-drop/drop-indicator.d.ts +0 -1
  173. package/dist/types/entry-points/side-nav-items/drag-and-drop/group-drop-indicator.d.ts +0 -1
  174. package/dist/types/entry-points/side-nav-items/drag-and-drop/hitbox.d.ts +0 -1
  175. package/dist/types/entry-points/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop.d.ts +0 -1
  176. package/dist/types/entry-points/side-nav-items/expandable-menu-item.d.ts +0 -1
  177. package/dist/types/entry-points/side-nav-items/flyout-menu-item.d.ts +0 -1
  178. package/dist/types/entry-points/side-nav-items/link-menu-item.d.ts +0 -1
  179. package/dist/types/entry-points/side-nav-items/menu-list-item.d.ts +0 -1
  180. package/dist/types/entry-points/side-nav-items/menu-list.d.ts +0 -1
  181. package/dist/types/entry-points/side-nav-items/menu-section.d.ts +0 -1
  182. package/dist/types/entry-points/side-nav-items/top-level-spacer.d.ts +0 -1
  183. package/dist/types-ts4.5/entry-points/side-nav-items/button-menu-item.d.ts +0 -1
  184. package/dist/types-ts4.5/entry-points/side-nav-items/container-avatar.d.ts +0 -1
  185. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/drag-handle.d.ts +0 -1
  186. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/drag-preview.d.ts +0 -1
  187. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/drop-indicator.d.ts +0 -1
  188. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/group-drop-indicator.d.ts +0 -1
  189. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/hitbox.d.ts +0 -1
  190. package/dist/types-ts4.5/entry-points/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop.d.ts +0 -1
  191. package/dist/types-ts4.5/entry-points/side-nav-items/expandable-menu-item.d.ts +0 -1
  192. package/dist/types-ts4.5/entry-points/side-nav-items/flyout-menu-item.d.ts +0 -1
  193. package/dist/types-ts4.5/entry-points/side-nav-items/link-menu-item.d.ts +0 -1
  194. package/dist/types-ts4.5/entry-points/side-nav-items/menu-list-item.d.ts +0 -1
  195. package/dist/types-ts4.5/entry-points/side-nav-items/menu-list.d.ts +0 -1
  196. package/dist/types-ts4.5/entry-points/side-nav-items/menu-section.d.ts +0 -1
  197. package/dist/types-ts4.5/entry-points/side-nav-items/top-level-spacer.d.ts +0 -1
  198. package/side-nav-items/button-menu-item/package.json +0 -17
  199. package/side-nav-items/container-avatar/package.json +0 -17
  200. package/side-nav-items/drag-and-drop/drag-handle/package.json +0 -17
  201. package/side-nav-items/drag-and-drop/drag-preview/package.json +0 -17
  202. package/side-nav-items/drag-and-drop/drop-indicator/package.json +0 -17
  203. package/side-nav-items/drag-and-drop/group-drop-indicator/package.json +0 -17
  204. package/side-nav-items/drag-and-drop/hitbox/package.json +0 -17
  205. package/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop/package.json +0 -17
  206. package/side-nav-items/expandable-menu-item/package.json +0 -17
  207. package/side-nav-items/flyout-menu-item/package.json +0 -17
  208. package/side-nav-items/link-menu-item/package.json +0 -17
  209. package/side-nav-items/menu-list/package.json +0 -17
  210. package/side-nav-items/menu-list-item/package.json +0 -17
  211. package/side-nav-items/menu-section/package.json +0 -17
  212. package/side-nav-items/top-level-spacer/package.json +0 -17
@@ -1,1079 +0,0 @@
1
- ---
2
- title: Side nav items
3
- description: Menu items and elements for the side nav area.
4
- order: 2
5
- ---
6
-
7
- import SectionMessage, { SectionMessageAction } from '@atlaskit/section-message';
8
- import Lozenge from '@atlaskit/lozenge';
9
- import { IconButton } from '@atlaskit/button/new';
10
- import ShowMoreHorizontalIcon from '@atlaskit/icon/core/show-more-horizontal';
11
- import { AllMenuItems } from '../../examples/constellation/drag-and-drop/simple';
12
- import { StandaloneJiraSidebar } from '../../examples/constellation/drag-and-drop/standalone-jira-sidebar';
13
-
14
- This guide will show you how to setup drag and drop for menu items in the side navigation. These
15
- guidelines correspond to our wider drag and drop
16
- [design guidelines](/components/pragmatic-drag-and-drop/design-guidelines) and
17
- [accessibility guidelines](/components/pragmatic-drag-and-drop/accessibility-guidelines/), adding
18
- some specific affordances and decisions specifically for our side navigation.
19
-
20
- <Example Component={StandaloneJiraSidebar} appearance="showcase-only" />
21
-
22
- <details>
23
- <summary>Thinking about our approach</summary>
24
-
25
- Our approach to drag and drop in the sidebar has been guided by three concerns:
26
-
27
- 1. **Performance**: we only want consumers who need drag and drop to include code for it.
28
- 2. **Flexibility**: we have created a system that lets you achieve any drag and drop operation you
29
- could think of, and puts you in control of all of the business logic
30
- 3. **Consistency**: we want drag and drop operations in the sidebar to all feel the same to our
31
- users
32
-
33
- These desired outcomes have pushed us towards a solution were we provide a lot of the small pieces,
34
- and it is up to you to put them together.
35
-
36
- </details>
37
-
38
- <SectionMessage title="Required" appearance="warning">
39
-
40
- It is so important that you stay within these guidelines for your experiences as it will promote
41
- user experience consistency as well as enable us to more easily evolve all experiences.
42
-
43
- </SectionMessage>
44
-
45
- <SectionMessage title="Pre reading" appearance="discovery" actions={<SectionMessageAction href="/components/pragmatic-drag-and-drop">Learn about Pragmatic drag and drop</SectionMessageAction>}>
46
-
47
- This guide assumes you already have a working knowledge of Pragmatic drag and drop.
48
-
49
- </SectionMessage>
50
-
51
- ## Before a drag
52
-
53
- **<Lozenge appearance="success" isBold>Goal</Lozenge> let a user know that a menu item can be
54
- dragged**
55
-
56
- All types of sidebar menu items can be dragged (`ButtonMenuItem`, `LinkMenuItem`,
57
- `FlyoutMenuItemTrigger`, `ExpandableMenuItemTrigger`).
58
-
59
- By default, menu items are _not draggable_ and you need to opt into making them draggable. To make a
60
- menu item draggable there are two things you need to do:
61
-
62
- 1. Set `hasDragIndicator` to `true` on the menu item
63
- 2. Make the menu item `draggable()`
64
-
65
- ### hasDragIndicator
66
-
67
- Setting `hasDragIndicator` to true on a menu item will enable visual affordances on the menu item to
68
- make it clear that the item is draggable:
69
-
70
- - Showing a drag handle icon before the start of the menu item on `:hover`
71
- - **Changing** the cursor to `grab` after `800ms`. We have a delayed cursor change as
72
- [dragging is a non-primary action](/components/pragmatic-drag-and-drop/design-guidelines#cursor-changes)
73
-
74
- `hasDragIndicator` will not automatically make the menu item a `draggable` (which is why we avoided
75
- the prop name `isDraggable` or `draggable`) - you need to make the item a `draggable` element in
76
- step 2.
77
-
78
- ```tsx
79
- function Item({ item }) {
80
- return <ButtonMenuItem hasDragIndicator>{item.content}</ButtonMenuItem>;
81
- }
82
- ```
83
-
84
- ### Make the menu item `draggable()`
85
-
86
- You make a menu item _actually_ draggable by users with `draggable({element})` from Pragmatic drag
87
- and drop.
88
-
89
- Be sure to use the forwarded `ref` from the menu item as the `draggable` element, and not another
90
- `ref` such as `visualContentRef`. We want users to be able to drag from the main interactive element
91
- of a menu item (the `ref`), but not from buttons (eg `actions` or `actionsOnHover`) that appear on
92
- top of menu items.
93
-
94
- With `useMenuItemDragAndDrop()` _(recommended)_
95
-
96
- ```tsx
97
- function Item({ item }) {
98
- const { draggableButtonRef } = useMenuItemDragAndDrop({
99
- draggable: {
100
- /*...*/
101
- },
102
- });
103
-
104
- return (
105
- <ButtonMenuItem ref={draggableButtonRef} hasDragIndicator>
106
- {item.content}
107
- </ButtonMenuItem>
108
- );
109
- }
110
- ```
111
-
112
- Without `useMenuItemDragAndDrop()`
113
-
114
- ```tsx
115
- function Item({ item }) {
116
- const ref = useRef<HTMLDivElement | null>(null);
117
-
118
- useEffect(() => {
119
- const element = ref.current;
120
- invariant(element && dropTarget);
121
-
122
- return draggable({
123
- element,
124
- });
125
- }, []);
126
-
127
- return (
128
- <ButtonMenuItem ref={ref} hasDragIndicator>
129
- {item.content}
130
- </ButtonMenuItem>
131
- );
132
- }
133
- ```
134
-
135
- ## Start of a drag
136
-
137
- **<Lozenge appearance="success" isBold>Goal</Lozenge> make it clear what is dragging**
138
-
139
- When a drag is starting, there are two things you need to do:
140
-
141
- 1. Setup the drag preview
142
-
143
- We have a `<DragPreview />` component that embodies the visual language we want for menu item drag
144
- previews:
145
-
146
- - Only displays essential information - `elemBefore` and content (the `children`)
147
- - Is limited in width
148
- ([due to web platform design constraints](/components/pragmatic-drag-and-drop/web-platform-design-constraints))
149
-
150
- ```tsx
151
- import { DragPreview } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/drag-preview';
152
- import ProjectIcon from '@atlaskit/icon/core/project';
153
-
154
- function ProjectsDragPreview() {
155
- return <DragPreview elemBefore={<ProjectIcon label="" />} content="Projects" />;
156
- }
157
- ```
158
-
159
- If no `elemBefore` is provided, then the `elemBefore` will automatically collapse. There is no need
160
- to pass in `COLLAPSE_ELEM_BEFORE`. We do this as there is no need to maintain vertical side
161
- navigation vertical alignment in the drag preview.
162
-
163
- ```tsx
164
- import { DragPreview } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/drag-preview';
165
-
166
- function ProjectsDragPreview() {
167
- return <DragPreview content="Projects" />;
168
- }
169
- ```
170
-
171
- <SectionMessage>
172
-
173
- `useMenuItemDragAndDrop()` does a lot of the wiring talked about below. Please try to use the hook
174
- first before reaching for the lower level pieces.
175
-
176
- </SectionMessage>
177
-
178
- Please ensure the drag preview is pushed away from the users pointer (with `pointerOutsideOfPreview`
179
- from Pragmatic drag and drop) by our
180
- [standard amount](/components/pragmatic-drag-and-drop/design-guidelines)
181
- (`{x: token('space.200'), y: token('space.100')`).
182
-
183
- See our
184
- [drag preview guidelines](/components/pragmatic-drag-and-drop/core-package/adapters/element/drag-previews)
185
- for more information about mounting native drag previews.
186
-
187
- 2. Pass `isDragging={true}` to the menu item
188
-
189
- This will lower the opacity on the item being dragged as our
190
- [standard visual cue](/components/pragmatic-drag-and-drop/design-guidelines) that something is being
191
- dragged.
192
-
193
- ## While dragging
194
-
195
- **<Lozenge appearance="success" isBold>Goal</Lozenge> make it clear what the result of the drag will
196
- be**
197
-
198
- There are four things you need to do in order to make it possible for a menu item to be dropped on:
199
-
200
- 1. Make the menu item a _drop target_
201
- 2. Add hitbox information to the menu item
202
- 3. Display drop indicators as needed on menu item
203
- 4. Display a group drop indicator around the current group of menu items
204
-
205
- 1, 2 and 3 can more easily be achieved with `useMenuItemDragAndDrop()`; and 4 requires some light
206
- wiring by consumers.
207
-
208
- ### Making a menu item a drop target
209
-
210
- #### Use `visualContentRef`
211
-
212
- To make a menu item a drop target you call `dropTargetForElements` with the `visualContentRef`
213
- provided by all menu items.
214
-
215
- _Rationale:_
216
-
217
- - It is the full width of the element. We want to enable users to be able to drag only vertically to
218
- be able to drag into nested menu items
219
- - It wraps all elements in the menu item and so will be triggered even when dragging over `actions`
220
- and other elements on top of the main interactive element.
221
-
222
- With `useMenuItemDragAndDrop()` _(recommended)_
223
-
224
- ```tsx
225
- function Item({ item }) {
226
- const { draggableButtonRef, dropTargetRef } = useMenuItemDragAndDrop({});
227
-
228
- return (
229
- <ButtonMenuItem visualContentRef={dropTargetRef} ref={draggableButtonRef}>
230
- {item.content}
231
- </ButtonMenuItem>
232
- );
233
- }
234
- ```
235
-
236
- Custom implementation
237
-
238
- ```tsx
239
- function Item({ item }) {
240
- const dropTargetRef = useRef<HTMLDivElement | null>(null);
241
- const ref = useRef<HTMLDivElement | null>(null);
242
-
243
- useEffect(() => {
244
- const element = ref.current;
245
- const dropTarget = dropTargetRef.current;
246
- invariant(element && dropTarget);
247
-
248
- return combine(
249
- // make the menu item a drop target
250
- dropTargetForElements({
251
- element: dropTarget,
252
- // make the drop target sticky
253
- getIsSticky: () => true,
254
- // prevent dropping on self
255
- canDrop: ({ source }) => source.element !== element && source.data.type === 'menu-item',
256
- }),
257
- // make the menu item draggable
258
- draggable({
259
- element,
260
- }),
261
- );
262
- }, []);
263
-
264
- return (
265
- <ButtonMenuItem ref={ref} visualContentRef={dropTargetRef}>
266
- {item.content}
267
- </ButtonMenuItem>
268
- );
269
- }
270
- ```
271
-
272
- #### Stickiness
273
-
274
- <SectionMessage>
275
-
276
- [Background information about stickiness](/components/pragmatic-drag-and-drop/core-package/drop-targets#getissticky)
277
-
278
- </SectionMessage>
279
-
280
- If you are setting up drop targets without `useMenuItemDragAndDrop()` it is important that you make
281
- the menu item drop target sticky `getIsSticky: () => true`. The `<GroupDropIndicator>` should _not_
282
- be sticky, and it will clear stickiness when you leave the group. Stickiness on the menu items helps
283
- to have a nicer experience when dragging over a group that contains gaps in drop targets, for
284
- example when there are titles in the sidebar.
285
-
286
- #### Don't allow menu items to drop on themselves
287
-
288
- If you are setting up drop targets without `useMenuItemDragAndDrop()`, you need to manually ensure
289
- that a menu item cannot drop on itself with `canDrop()`
290
-
291
- ```ts
292
- dropTargetForElements({
293
- element: dropTarget,
294
- // Don't allow dropping on itself
295
- canDrop: ({ source }) => source.element !== element && source.data.type === 'menu-item',
296
- });
297
- ```
298
-
299
- ### Add hitbox information to a menu item
300
-
301
- The hitbox is responsible for examining the user input when over a drop target and outputting the
302
- appropriate operation for that input. For a menu item, you can specify which of the following
303
- operations are permitted:
304
-
305
- - `"reorder-before"`
306
- - `"reorder-after"`
307
- - `"combine"`
308
-
309
- A result of a hitbox function call, will result in an `Instruction` which you can use to determine
310
- what operation should be completed when the drag finishes, as well as for displaying the drop
311
- indicator during a drag operation.
312
-
313
- Each operation has three possible values:
314
-
315
- - `"not-available"` (default)
316
- - `"available"`
317
- - `"blocked"` (similar to `"available"`, but will show warning colors. See below for more
318
- information)
319
-
320
- The hitbox for an drop target will automatically adjust to accommodate each additional available
321
- operation.
322
-
323
- ```ts
324
- type Operation = 'reorder-before' | 'reorder-after' | 'combine';
325
-
326
- type Instruction = {
327
- // What the operation is
328
- operation: Operation;
329
-
330
- // whether or not the operation was "blocked"
331
- blocked: boolean;
332
- };
333
- ```
334
-
335
- With `useMenuItemDragAndDrop()` _(recommended)_
336
-
337
- ```tsx
338
- import { useMenuItemDragAndDrop } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop';
339
-
340
- function OurButtonItem() {
341
- const { state, draggableButtonRef, dragPreview, dropTargetRef, dropIndicator } =
342
- useMenuItemDragAndDrop({
343
- dropTarget: {
344
- getOperations: () => ({
345
- 'reorder-before': 'available',
346
- combine: 'available',
347
- 'reorder-after': 'available',
348
- }),
349
- },
350
- });
351
-
352
- return (
353
- <>
354
- <ButtonMenuItem
355
- elemBefore={<BasketballIcon label="" />}
356
- ref={draggableButtonRef}
357
- isDragging={state.type === 'dragging'}
358
- hasDragIndicator
359
- dropIndicator={dropIndicator}
360
- visualContentRef={dropTargetRef}
361
- >
362
- Button menu item
363
- </ButtonMenuItem>
364
- {dragPreview}
365
- </>
366
- );
367
- }
368
- ```
369
-
370
- Manually adding operations
371
-
372
- ```tsx
373
- import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
374
- import {
375
- attachInstruction,
376
- extractInstruction,
377
- type Instruction,
378
- } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/hitbox';
379
-
380
- function Item({ item }) {
381
- const dropTargetRef = useRef<HTMLDivElement | null>(null);
382
- const ref = useRef<HTMLDivElement | null>(null);
383
-
384
- useEffect(() => {
385
- const element = ref.current;
386
- const dropTarget = dropTargetRef.current;
387
- invariant(element && dropTarget);
388
-
389
- return combine(
390
- // make the menu item a drop target
391
- dropTargetForElements({
392
- element: dropTarget,
393
- getData: ({ input, element }) => {
394
- // your base data you want to attach to the drop target
395
- const data = {
396
- type: 'menu-item',
397
- itemId: 'A',
398
- };
399
- // this will 'attach' an `Instruction` to your data object
400
- return attachInstruction(data, {
401
- input,
402
- element,
403
- operations: {
404
- 'reorder-before': 'available',
405
- 'reorder-after': 'available',
406
- combine: 'available',
407
- },
408
- });
409
- },
410
- onDrop: (args) => {
411
- const instruction: Instruction | null = extractInstruction(args.self.data);
412
- },
413
- }),
414
- // make the menu item draggable
415
- draggable({
416
- element,
417
- }),
418
- );
419
- }, []);
420
-
421
- return (
422
- <ButtonMenuItem ref={ref} visualContentRef={dropTargetRef}>
423
- {item.content}
424
- </ButtonMenuItem>
425
- );
426
- }
427
- ```
428
-
429
- #### Preventing operations
430
-
431
- If you don't want an operation to be available, you have a few options.
432
-
433
- 1. Set `canDrop: () => false`
434
- 2. Set an operation to `"not-available"`
435
-
436
- With `useMenuItemDragAndDrop()` _(recommended)_
437
-
438
- ```ts
439
- useMenuItemDragAndDrop({
440
- dropTarget: {
441
- getOperations: () => ({
442
- 'reorder-before': 'available',
443
- 'reorder-after': 'not-available', // reordering after no longer available
444
- }),
445
- },
446
- });
447
- ```
448
-
449
- Without `useMenuItemDragAndDrop()`
450
-
451
- ```ts
452
- return attachInstruction(data, {
453
- input,
454
- element,
455
- operations: {
456
- 'reorder-before': 'available',
457
- 'reorder-after': 'not-available', // reordering after no longer available
458
- },
459
- });
460
- ```
461
-
462
- 3. Don't include an operation in `operations`
463
-
464
- With `useMenuItemDragAndDrop()` _(recommended)_
465
-
466
- ```ts
467
- useMenuItemDragAndDrop({
468
- dropTarget: {
469
- getOperations: () => ({
470
- 'reorder-before': 'available',
471
- // 'reorder-after' and 'combine' are "not-available" by default
472
- }),
473
- },
474
- });
475
- ```
476
-
477
- Without `useMenuItemDragAndDrop()`
478
-
479
- ```ts
480
- return attachInstruction(data, {
481
- input,
482
- element,
483
- operations: {
484
- 'reorder-before': 'available',
485
- // 'reorder-after' and 'combine' are "not-available" by default
486
- },
487
- });
488
- ```
489
-
490
- #### Blocking operations
491
-
492
- Sometimes you want to explicitly call out that an operation is not permitted _right now_. An example
493
- of this is draft pages in Confluence which cannot be the target of a drag operation, but once page
494
- is no longer a draft it could be the target of a drag operation. In these cases, it can be helpful
495
- to make it explicit to the user that a particular drag operation can not permitted. You can use
496
- `blocked` for this use case. When an operation is blocked, it will be used by our _drop indicator_
497
- to show a drop indicator with a warning color.
498
-
499
- ```ts
500
- useMenuItemDragAndDrop({
501
- dropTarget: {
502
- getOperations: () => ({
503
- combine: 'blocked',
504
- }),
505
- },
506
- });
507
- ```
508
-
509
- ### Drop indicators
510
-
511
- Drop indicators are used to make it clear what the result of a drag operation will be. There are two
512
- types of drop indicators that are **required** for you to setup:
513
-
514
- 1. Drop indicators that appear on menu items
515
- 2. Drop indicators that appear around groups of menu items (`<GroupDropIndicator/>`)
516
-
517
- #### Menu item drop indicator
518
-
519
- A menu item `<DropIndicator>` component is responsible for the visual representation of an
520
- `Instruction` from the `hitbox`. In order for the `<DropIndicator>` to be rendered correctly, it is
521
- important that you provide the component to the `dropIndicator` prop on a menu item.
522
-
523
- The `<DropIndicator />` is handled for you when leveraging `useMenuItemDragAndDrop()`
524
-
525
- ```tsx
526
- import { useMenuItemDragAndDrop } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/use-menu-item-drag-and-drop';
527
-
528
- function OurButtonItem() {
529
- const { state, draggableButtonRef, dragPreview, dropTargetRef, dropIndicator } =
530
- useMenuItemDragAndDrop({
531
- dropTarget: {
532
- getOperations: () => ({
533
- 'reorder-before': 'available',
534
- 'reorder-after': 'available',
535
- }),
536
- },
537
- });
538
-
539
- return (
540
- <>
541
- <ButtonMenuItem
542
- elemBefore={<BasketballIcon label="" />}
543
- ref={draggableButtonRef}
544
- isDragging={state.type === 'dragging'}
545
- hasDragIndicator
546
- // 👇 pass the drop indicator ReactNode into the dropIndicator prop
547
- dropIndicator={dropIndicator}
548
- visualContentRef={dropTargetRef}
549
- >
550
- Button menu item
551
- </ButtonMenuItem>
552
- {dragPreview}
553
- </>
554
- );
555
- }
556
- ```
557
-
558
- Rough idea when not using `useMenuItemDragAndDrop()`
559
-
560
- ```tsx
561
- import { DropIndicator } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/drop-indicator';
562
-
563
- function Item({ item }) {
564
- const [state, setState] = useState<TItemState>({ type: 'idle' });
565
- const dropIndicator = state.type === 'is-over' && state.instruction && (
566
- <DropIndicator instruction={state.instruction} />
567
- );
568
-
569
- return (
570
- <ButtonMenuItem
571
- ref={ref}
572
- elemBefore={item.elemBefore}
573
- isDragging={state.type === 'dragging'}
574
- // 👇 pass the drop indicator to the dropIndicator prop
575
- dropIndicator={dropIndicator}
576
- visualContentRef={dropTargetRef}
577
- hasDragIndicator
578
- >
579
- {item.content}
580
- </ButtonMenuItem>
581
- );
582
- }
583
- ```
584
-
585
- #### Group drop indicator
586
-
587
- As a part of the design language for drag and drop in the sidebar, we also add a visual affordance
588
- around the section that the user is dragging over. This is to help make it even clearer where
589
- something will end up after a drop.
590
-
591
- To achieve this, you need to wrap any groups of draggable menu items in our `<GroupDropIndicator>`.
592
- A group is any logical list of menu items at the same level in the side navigation. A group could be
593
- all items on a particular level, or a logical subset of items at a particular level (eg a "recent
594
- projects" section).
595
-
596
- - You need to setup the `<GroupDropIndicator>` as a drop target
597
- - The drop target should _not_ have stickiness. This is important as it is the mechanism for
598
- clearing stickiness on menu item drop targets.
599
- - Set `isActive={true}` on the `<GroupDropIndicator>` when it is the innermost available
600
- `<GroupDropIndicator>`
601
-
602
- <Example Component={AllMenuItems} appearance="showcase-only" />
603
-
604
- ```tsx
605
- import { GroupDropIndicator } from '@atlaskit/navigation-system/side-nav-items/drag-and-drop/group-drop-indicator';
606
-
607
- function isInnerMostGroup({ location, self }: ElementDropTargetEventBasePayload): boolean {
608
- const [innerMost] = location.current.dropTargets.filter(
609
- (dropTarget) => dropTarget.data.type === 'menu-item-group',
610
- );
611
- return innerMost?.element === self.element;
612
- }
613
-
614
- export function MyMenuItemGroup() {
615
- const [isInnerMostOver, setIsInnerMostOver] = useState<boolean>(false);
616
- const ref = useRef<HTMLDivElement | null>(null);
617
-
618
- useEffect(() => {
619
- const element = ref.current;
620
- invariant(element);
621
- return dropTargetForElements({
622
- element,
623
- canDrop: ({ source }) => source.data.type === 'menu-item',
624
- getData: () => ({ type: 'menu-item-group' }),
625
- onDragStart: (args) => setIsInnerMostOver(isInnerMostGroup(args)),
626
- onDropTargetChange: (args) => setIsInnerMostOver(isInnerMostGroup(args)),
627
- onDrop: () => setIsInnerMostOver(false),
628
- });
629
- }, []);
630
-
631
- return (
632
- <GroupDropIndicator isActive={isInnerMostOver} ref={ref}>
633
- <OurLinkMenuItem />
634
- <OurButtonItem />
635
- <OurFlyoutItem />
636
- <OurExpandableItem />
637
- </GroupDropIndicator>
638
- );
639
- }
640
- ```
641
-
642
- ### Automatic scrolling
643
-
644
- During a drag operation, it is important that a user be able to effortlessly scroll the sidebar in
645
- order to easily place a dragging item in any position.
646
- [Please wire up `autoScrollForElements`](/components/pragmatic-drag-and-drop/optional-packages/auto-scroll/about)
647
- on the `ref` that the `<SideNavContent>` returns to ensure the scrollable portion of the sidebar
648
- automatically scrolls during a drag operation.
649
-
650
- ```tsx
651
- import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
652
-
653
- function Sidebar() {
654
- const scrollableRef = useRef<HTMLDivElement | null>(null);
655
-
656
- // setup auto scrolling for sidenav scroll container
657
- useEffect(() => {
658
- const scrollable = scrollableRef.current;
659
- invariant(scrollable);
660
- return autoScrollForElements({
661
- element: scrollable,
662
- canScroll: ({ source }) => source.data.type === 'menu-item',
663
- });
664
- }, []);
665
-
666
- return <SideNavContent ref={scrollableRef}>{/* ... */}</SideNavContent>;
667
- }
668
- ```
669
-
670
- ## On drop
671
-
672
- **<Lozenge appearance="success" isBold>Goal</Lozenge> immediately update the interface**
673
-
674
- 1. Figure out what `Operation` to do
675
-
676
- Using `extractInstruction` you can extract the `Instruction` to be performed.
677
-
678
- ```ts
679
- type Operation = 'reorder-before' | 'reorder-after' | 'combine';
680
-
681
- type Instruction = {
682
- // What the operation is
683
- operation: Operation;
684
-
685
- // whether or not the operation was "blocked"
686
- blocked: boolean;
687
- };
688
- ```
689
-
690
- ```tsx
691
- useEffect(() => {
692
- return monitorForElements({
693
- canMonitor: ({ source }) => source.data.type === 'menu-item',
694
- onDrop({ source, location }) {
695
- const dragging = source.data;
696
- const [innerMost] = location.current.dropTargets;
697
-
698
- if (!innerMost) {
699
- return;
700
- }
701
- const dropTargetData = innerMost.data;
702
-
703
- const instruction: Instruction | null = extractInstruction(dropTargetData);
704
- if (!instruction) {
705
- return;
706
- }
707
-
708
- // Do something based on the instruction
709
- });
710
- }, []);
711
-
712
- ```
713
-
714
- 2. Optimistically update the interface
715
-
716
- When a drag operation is finished, you need to optimistically update the interface (don't wait for
717
- the update to persist on the server). Don't lock the interface while the update is persisting, allow
718
- them to continue to engage with the interface (including performing more drag and drop operations).
719
-
720
- If an update fails, please let the user know in the interface through a flag; and synchronize the
721
- interface with the server state. The interface can become locked during this synchronization if
722
- needed.
723
-
724
- 3. Flash the moved menu item
725
-
726
- Leverage
727
- [`triggerPostMoveFlash`](/components/pragmatic-drag-and-drop/optional-packages/flourish/trigger-post-move-flash/examples)
728
- to trigger a flash on the interactive element (it's `ref`) of the moved menu item. This gives
729
- helpful clarity to users about what has changed.
730
-
731
- See our complete example above to see how you can achieve this.
732
-
733
- Some possible options:
734
-
735
- - Keep a registry of `HTMLElement`s for all menu items, so you can look up the menu item element
736
- after it has been moved
737
- - Lookup elements with data attributes after the drop. Not ideal, but can get the job done.
738
-
739
- ## useMenuItemDragAndDrop
740
-
741
- We have created a `react` hook `useMenuItemDragAndDrop()` which takes care of a lot of plumbing when
742
- setting up drag and drop for menu items in the sidebar. We strongly recommend that you start with
743
- this hook, and if it doesn't work for you, then you can build up everything using the pieces we
744
- expose.
745
-
746
- ```tsx
747
- import { getProjectData, isProjectData } from './helpers';
748
-
749
- function Project({ project }: { project: TProject }) {
750
- const { state, draggableAnchorRef, dragPreview, dropTargetRef, dropIndicator } =
751
- useMenuItemDragAndDrop({
752
- draggable: {
753
- getInitialData: () => getProjectData(project),
754
- getDragPreviewPieces: () => ({
755
- elemBefore: <ProjectIcon label="" color="currentColor" />,
756
- content: project.name,
757
- }),
758
- },
759
- dropTarget: {
760
- getData: () => getProjectData(project),
761
- getOperations: () => ({
762
- 'reorder-after': 'available',
763
- 'reorder-before': 'available',
764
- }),
765
- canDrop: ({ source }) => isProjectData(source.data),
766
- },
767
- });
768
-
769
- return (
770
- <>
771
- <LinkMenuItem
772
- href={project.href}
773
- elemBefore={project.icon}
774
- ref={draggableAnchorRef}
775
- isDragging={state.type === 'dragging'}
776
- hasDragIndicator
777
- dropIndicator={dropIndicator}
778
- visualContentRef={dropTargetRef}
779
- >
780
- {project.name}
781
- </LinkMenuItem>
782
- {dragPreview}
783
- </>
784
- );
785
- }
786
- ```
787
-
788
- What `useMenuItemDragAndDrop` does for you:
789
-
790
- - Sets up a `draggable()` (with conditional dragging)
791
- - Sets up a `dropTargetForElements()` (with conditional dropping)
792
- - Prevents dropping on self
793
- - Sets up the `<DragPreview>`, pushes it away from the users pointer by the desired amount, and
794
- mounts it to a `react` portal
795
- - Attaches `Operation`s to the drop target
796
- - Returns the correct drop indicator for the current `Operation`.
797
- - Manages it's own state in a performant way and let's you respond to state changes
798
- - Automatically makes the drop target sticky (stickiness will be cleared by `GroupDropIndicator`)
799
-
800
- Arguments:
801
-
802
- - `draggable`: object containing arguments relevant for setting up the `draggable()`. Don't include
803
- the `draggable` property if you don't ever want the menu item it be a draggable.
804
- - `draggable.canDrag`: Whether or not the element should be `draggable` (useful for conditional
805
- dragging)
806
- - `draggable.getInitialData()`: data to attach to the `draggable` (see
807
- [draggable | getInitialData](TODO))
808
- - `draggable.getDragPreviewPieces()`: provide the `ReactNode`s to be used when rendering the
809
- `<DragPreview />`
810
-
811
- - `dropTarget`: object containg arguments relevant for setting up a menu item as a drop target.
812
- Don't include the `dropTarget` property if you don't ever want the menu item it be a draggable.
813
- - `dropTarget.canDrop()`: whether or not the menu item can be dropped on (see
814
- [dropTargetForElements | canDrop](TODO))
815
- - `dropTarget.getData()`: data to attach to the drop target (see [dropTarget | getData](TODO))
816
- - `dropTarget.getOperations()`: which drop `Operation`s
817
- (`"reorder-before" | "reorder-after" | "combine`") are permitted on the menu item
818
-
819
- Return value:
820
-
821
- - `state`: an object containing what the drag and drop state of the menu item is
822
- (`"idle" | "preview" | "dragging" | "is-over"`)
823
- - `draggableAnchorRef`: used to mark an anchor element as the draggable element. Use this if the
824
- menu item is an anchor.
825
- - `draggableButtonRef`: used to mark an button element as the draggable element. Use this if the
826
- menu item is an button.
827
- - `dropTargetRef`: must be used to mark the `HTMLDivElement` as the `dropTargetForElements`
828
- - `dragPreview`: a `ReactNode` to be included in your `react` tree which will be used to render the
829
- `<DragPreview />`
830
- - `dropIndicator`: a `ReactNode` containing the drop indicator if it's needed
831
-
832
- ## Accessible actions
833
-
834
- **<Lozenge appearance="success" isBold>Goal</Lozenge> provide a delightful way for folks leveraging
835
- assistive technologies to achieve the same outcomes as a drag and drop operation**
836
-
837
- All menu items that have drag and drop enabled must also include an alternative mechanism to achieve
838
- the same outcomes as drag and drop operations.
839
-
840
- <Example Component={StandaloneJiraSidebar} appearance="showcase-only" />
841
-
842
- What you need to do (for all menu items _except_ `FlyoutMenuItemTrigger`)
843
-
844
- - All menu items with drag and drop enabled must have a "more" button as `actionsOnHover`
845
- - The more menu should be a trigger for a `DropdownMenu`
846
- - The `DropdownMenu` menu should contain an entry called `"Reorder ${entityName}"` or `"Move"`. The
847
- `DropdownMenu` can also contain other actions for the entity (eg "Archive").
848
-
849
- For `FlyoutMenuItemTrigger`:
850
-
851
- - `FlyoutMenuItemTrigger` does not support `actionsOnHover`, so you need to put a
852
- `"Reorder ${entityName}"` menu item in the `FlyoutMenuItemContent` of the `FlyoutMenuItem`.
853
- - It is known that this is a minor inconsistency with other menu items; however, this was decided to
854
- be the best available option based on how our menu items work today.
855
-
856
- ### Move operations
857
-
858
- There are two categories of movement actions:
859
-
860
- 1. Only reordering is available
861
-
862
- Show a further submenu with available operations. The possible operations are:
863
-
864
- 1. "Move to top"
865
- 2. "Move up"
866
- 3. "Move down"
867
- 4. "Move to bottom"
868
-
869
- - When an item is in the last position: "Move down" and "Move to bottom" should be disabled
870
- - When an item is in the first position: "Move to top" and "Move up" should be disabled
871
- - When there is only one item in the group, the `"Reorder ${entityName}"` dropdown menu should be
872
- disabled.
873
-
874
- _See "project" menu items in the above example for what this looks like_
875
-
876
- 2. More complex operations are available
877
-
878
- When operations other than just reordering are possible (eg combining, moving to different levels in
879
- the navigation and so on), then show a modal containing a form with a way for a user to input any
880
- available action.
881
-
882
- _See "filter" menu items in the above example for what this looks like_
883
-
884
- ### Focus restoration
885
-
886
- After an item has been moved with an action menu, and the control triggering the action had focus,
887
- then the **menu item** `ref` should be given focus in it's new location. At this stage we have
888
- decided not to give focus to the more menu dropdown button as that is not universally available on
889
- the menu item (eg for flyout menu items, we are putting the move action in the flyout).
890
-
891
- See
892
- ["Let the user easily continue to trigger more outcomes"](/components/pragmatic-drag-and-drop/accessibility-guidelines#3-let-the-user-easily-continue-to-trigger-more-outcomes)
893
- in our drag and drop accessibility guide.
894
-
895
- When working with complex movement actions (eg move into child) this will require expanding all
896
- parent expandable menu items when the drag finishes.
897
-
898
- ## Special guidance
899
-
900
- ### ExpandableMenuItem
901
-
902
- Sometimes you want the `ExpandableMenuItemTrigger` to be your drop target, and sometimes you want
903
- the `ExpandableMenuItemTrigger` and the `ExpandableMenuItemContent` to be a single drop target.
904
-
905
- _In our provided example, when dragging a top level menu item, the whole `ExpandableMenuItem` is a
906
- drop target, whereas when dragging a filter, the `ExpandableMenuItemTrigger` is the drop target._
907
-
908
- When the `ExpandableMenuItemTrigger` is the drop target, you should attach the `dropTargetRef` and
909
- provide the `dropIndicator` to the `ExpandableMenuItemTrigger`.
910
-
911
- ```tsx
912
- function Project({ project }: { project: TProject }) {
913
- const { state, draggableAnchorRef, dragPreview, dropTargetRef, dropIndicator } =
914
- useMenuItemDragAndDrop({
915
- draggable: {
916
- getInitialData: () => getProjectData(project),
917
- getDragPreviewPieces: () => ({
918
- elemBefore: project.icon,
919
- content: project.name,
920
- }),
921
- },
922
- dropTarget: {
923
- getData: () => getProjectData(project),
924
- getOperations: () => ({
925
- 'reorder-after': 'available',
926
- 'reorder-before': 'available',
927
- }),
928
- canDrop: ({ source }) => isProjectData(source.data),
929
- },
930
- });
931
-
932
- return (
933
- <>
934
- <LinkMenuItem
935
- href={project.href}
936
- elemBefore={project.icon}
937
- ref={draggableAnchorRef}
938
- isDragging={state.type === 'dragging'}
939
- hasDragIndicator
940
- // 👇 drop target is the the trigger
941
- visualContentRef={dropTargetRef}
942
- dropIndicator={dropIndicator}
943
- >
944
- {project.name}
945
- </LinkMenuItem>
946
- {dragPreview}
947
- </>
948
- );
949
- }
950
- ```
951
-
952
- When the whole `ExpandableMenuItem` is the drop target, you should attach the `dropTargetRef` and
953
- provide the `dropIndicator` to the `ExpandableMenuItem`.
954
-
955
- ```tsx
956
- export function ProjectsMenuItem() {
957
- const { state, draggableButtonRef, dragPreview, dropTargetRef, dropIndicator } =
958
- useMenuItemDragAndDrop({
959
- draggable: {
960
- getInitialData: () => getTopLevelItemData('projects'),
961
- getDragPreviewPieces: () => ({
962
- elemBefore: <ProjectIcon label="" color="currentColor" />,
963
- content: 'Projects',
964
- }),
965
- },
966
- dropTarget: {
967
- getData: () => getTopLevelItemData('projects'),
968
- getOperations: () => ({
969
- 'reorder-after': 'available',
970
- 'reorder-before': 'available',
971
- }),
972
- canDrop: ({ source }) => isTopLevelItemData(source.data),
973
- },
974
- });
975
-
976
- return (
977
- <>
978
- <ExpandableMenuItem
979
- // 👇 drop target is the whole expandable item
980
- ref={dropTargetRef}
981
- // 👇 pass the drop indicator to the whole expandable item
982
- dropIndicator={dropIndicator}
983
- >
984
- <ExpandableMenuItemTrigger
985
- // 👇 trigger is still the draggable
986
- ref={draggableButtonRef}
987
- isDragging={state.type === 'dragging'}
988
- hasDragIndicator
989
- elemBefore={<ProjectIcon label="" color="currentColor" />}
990
- >
991
- Projects
992
- </ExpandableMenuItemTrigger>
993
- <ExpandableMenuItemContent>{/* ... */}</ExpandableMenuItemContent>
994
- </ExpandableMenuItem>
995
- {dragPreview}
996
- </>
997
- );
998
- }
999
- ```
1000
-
1001
- ### ExpandableMenuItemTrigger
1002
-
1003
- #### Drag start
1004
-
1005
- When dragging any menu item, all expandable menu items that are valid drop targets, or contain valid
1006
- drop targets, should have their `<ExpandableMenuItemTrigger>` should no longer show any custom
1007
- `elemBefore` and use the default icons. Expandable menu items can be expanded during a drag, and
1008
- showing their chevrons is a helpful way for users to see at a glance which parts of the side
1009
- navigation can potentially be nested into
1010
-
1011
- ```tsx
1012
- <ExpandableMenuItemTrigger elemBefore={isFilterDragging ? null : item.elemBefore}>
1013
- {filter.name}
1014
- </ExpandableMenuItemTrigger>
1015
- ```
1016
-
1017
- When dragging a `<ExpandableMenuItemTrigger>` you should collapse the expandable menu when the drag
1018
- is starting. This prevents the strange case of a parent dragging into itself.
1019
-
1020
- #### While dragging
1021
-
1022
- If a user drags over of `<ExpandableMenuItemTrigger>` for `500ms` with the `"combine"` operation,
1023
- and the menu item is not expanded, then it should be expanded. This allows users to drag into
1024
- collapsed menu items.
1025
-
1026
- #### On drop
1027
-
1028
- Once the drag is completed, you should restore the collapsed state of the
1029
- `ExpandableMenuItemTrigger`
1030
-
1031
- - If it was collapsed before the drag started: keep it collapsed
1032
- - If it was expanded before the drag started: expand it again after the drag as completed
1033
-
1034
- The dragged `ExpandableMenuItemTrigger` must be visible after the drag has finished. This will
1035
- involve expanding any parent `ExpandableMenuItemTrigger` needed.
1036
-
1037
- An example: Dragging Filter A and the drop operation is a `"combine"` on a collapsed Filter B
1038
- `ExpandableMenuItemTrigger`. Outcome: Filter B should be expanded to make Filter A visible after the
1039
- drop.
1040
-
1041
- ### FlyoutMenuItemTrigger
1042
-
1043
- #### Drag start
1044
-
1045
- All `<FlyoutMenuItemTrigger>`s should be closed when dragging _any_ menu item.
1046
-
1047
- #### While dragging
1048
-
1049
- <SectionMessage title="Not supported (yet)" appearance="warning">
1050
-
1051
- It is currently _not supported_ to drop an item onto a `FlyoutMenuItemTrigger` or into
1052
- `FlyoutMenuItemContent`. There are some experience questions to be worked through to support this.
1053
- We thought we would wait and see if anybody needed this before spending too much time on it. If you
1054
- have need of this use case, please reach out and we can prioritize working through the design
1055
- challenges.
1056
-
1057
- </SectionMessage>
1058
-
1059
- #### Accessible actions for flyouts
1060
-
1061
- See our [accessible actions](#accessible-actions) section for `FlyoutMenuItemTrigger` specific
1062
- guidance.
1063
-
1064
- ### anchors
1065
-
1066
- By default, menu items that are **anchor elements (`<a>`)** are _not_ draggable (unlike standard
1067
- anchor elements that are **draggable** by default).
1068
-
1069
- Menu items that are anchors:
1070
-
1071
- - `LinkMenuItem`
1072
- - `ExpandableMenuItemTrigger` with a `href`
1073
- - `FlyoutMenuItemTrigger` with a `href`
1074
-
1075
- If you want one of these menu items to be draggable, then you need to wire them up for drag and drop
1076
- according to this guide. For anchor elements, the URL information is _automatically_ attached to the
1077
- native drag data, so the anchor can be dragged into the browser menu bar, other external application
1078
- and so on. You are welcome to attach additional information using
1079
- [`getInitialData()` and `getInitialDataForExternal()` from Pragmatic drag and drop](/components/pragmatic-drag-and-drop/core-package/adapters/element/about#draggable).