@clevertask/react-sortable-tree 0.0.6 → 0.0.8

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 (36) hide show
  1. package/README.md +303 -83
  2. package/dist/e2e/index.js +51 -0
  3. package/dist/e2e/utils/drag-item.d.ts +15 -0
  4. package/dist/e2e/utils/expect-item-before.d.ts +2 -0
  5. package/dist/e2e/utils/expect-item-child-of.d.ts +3 -0
  6. package/dist/e2e/utils/get-tree-item-id.d.ts +2 -0
  7. package/dist/e2e/utils/index.d.ts +4 -0
  8. package/dist/{style.css → react-sortable-tree.css} +1 -1
  9. package/dist/react-sortable-tree.js +2404 -1381
  10. package/dist/react-sortable-tree.js.map +1 -1
  11. package/dist/src/SortableTree/SortableTree.d.ts +2 -0
  12. package/dist/src/SortableTree/components/TreeItem/TreeItem.d.ts +33 -0
  13. package/dist/{SortableTree → src/SortableTree}/components/TreeItem/index.d.ts +1 -0
  14. package/dist/src/SortableTree/components/TreeItemStructure/index.d.ts +39 -0
  15. package/dist/src/SortableTree/components/index.d.ts +4 -0
  16. package/dist/src/SortableTree/createSortableTreeGlobalStyles.d.ts +8 -0
  17. package/dist/src/SortableTree/index.d.ts +6 -0
  18. package/dist/{SortableTree → src/SortableTree}/types.d.ts +9 -11
  19. package/dist/{SortableTree → src/SortableTree}/utilities.d.ts +4 -4
  20. package/package.json +53 -29
  21. package/dist/SortableTree/SortableTree.d.ts +0 -4
  22. package/dist/SortableTree/components/TreeItem/TreeItem.d.ts +0 -23
  23. package/dist/SortableTree/components/index.d.ts +0 -1
  24. package/dist/SortableTree/index.d.ts +0 -3
  25. /package/dist/{SortableTree → src/SortableTree}/components/Action/Action.d.ts +0 -0
  26. /package/dist/{SortableTree → src/SortableTree}/components/Action/index.d.ts +0 -0
  27. /package/dist/{SortableTree → src/SortableTree}/components/Add/Add.d.ts +0 -0
  28. /package/dist/{SortableTree → src/SortableTree}/components/Add/index.d.ts +0 -0
  29. /package/dist/{SortableTree → src/SortableTree}/components/Handle/Handle.d.ts +0 -0
  30. /package/dist/{SortableTree → src/SortableTree}/components/Handle/index.d.ts +0 -0
  31. /package/dist/{SortableTree → src/SortableTree}/components/Remove/Remove.d.ts +0 -0
  32. /package/dist/{SortableTree → src/SortableTree}/components/Remove/index.d.ts +0 -0
  33. /package/dist/{SortableTree → src/SortableTree}/components/TreeItem/SortableTreeItem.d.ts +0 -0
  34. /package/dist/{SortableTree → src/SortableTree}/keyboardCoordinates.d.ts +0 -0
  35. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  36. /package/dist/{main.d.ts → src/main.d.ts} +0 -0
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @clevertask/react-sortable-tree
2
2
 
3
- A customizable React component for rendering and managing tree structures with drag-and-drop functionality. This is built on top of the [sortable tree Component from the dnd-kit library](https://github.com/clauderic/dnd-kit/blob/master/stories/3%20-%20Examples/Tree/SortableTree.tsx).
3
+ A customizable React component for rendering and managing tree structures with drag-and-drop functionality. Built on top of the [dnd-kit sortable tree example](https://github.com/clauderic/dnd-kit/blob/master/stories/3%20-%20Examples/Tree/SortableTree.tsx).
4
+
5
+ This library is currently focused on **custom item rendering** and **type-safe tree structures**. A more detailed API and feature set will be released in a future major version with support for virtualization and multi-selection.
6
+
7
+ ---
4
8
 
5
9
  ## Table of Contents
6
10
 
@@ -8,54 +12,210 @@ A customizable React component for rendering and managing tree structures with d
8
12
  - [Usage](#usage)
9
13
  - [Props](#props)
10
14
  - [Types](#types)
11
- - [TreeItem](#treeitem)
12
- - [TreeItems](#treeitems)
13
15
  - [Helper Functions](#helper-functions)
14
- - [getItemById](#getItemById)
15
- - [removeItemById](#removeitembyid)
16
- - [setTreeItemProperties](#settreeitemproperties)
17
16
  - [Roadmap](#roadmap)
18
- - [Release Process](#release-process)
19
17
  - [License](#license)
20
18
 
19
+ ---
20
+
21
21
  ## Installation
22
22
 
23
23
  ```bash
24
24
  npm install @clevertask/react-sortable-tree
25
25
  ```
26
26
 
27
+ ---
28
+
27
29
  ## Usage
28
30
 
31
+ ### 1. Define your custom tree item type if needed
32
+
33
+ ```ts
34
+ type CustomTreeItem = TreeItem<{
35
+ metadata?: Record<string, any>;
36
+ icon?: string;
37
+ }>;
38
+ ```
39
+
40
+ Otherwise, the component will use the default [tree item type](#types).
41
+
42
+ ---
43
+
44
+ ### 2. Create your custom item component
45
+
46
+ This is the basic structure you can start with:
47
+
29
48
  ```tsx
30
- import '@clevertask/react-sortable-tree/dist/style.css';
31
- import React, { useState } from 'react';
32
- import { SortableTree, TreeItems } from '@clevertask/react-sortable-tree';
49
+ import { RenderItemProps, TreeItemStructure } from '@clevertask/react-sortable-tree';
33
50
 
34
- function App() {
35
- const [items, setItems] = useState<TreeItems>([
36
- { id: '1', label: 'Item 1', children: [] },
37
- { id: '2', label: 'Item 2', children: [{ id: '3', label: 'Item 2.1', children: [] }] },
38
- ]);
51
+ export const TreeItem = (props: RenderItemProps) => {
52
+ const { treeItem, collapsed, onCollapse, dragListeners } = props;
39
53
 
40
54
  return (
41
- <SortableTree
42
- items={items}
43
- setItems={setItems}
44
- isCollapsible
45
- isRemovable
46
- allowNestedItemAddition
47
- // ... other props
48
- />
55
+ <TreeItemStructure {...props}>
56
+ {/* TreeItemStructure.DragHandler provides a default drag handle with accessible attributes and stable selectors for E2E testing.*/}
57
+ <TreeItemStructure.DragHandler>Drag me</TreeItemStructure.DragHandler>
58
+
59
+ {/* Or if you want to implement your own approach */}
60
+ <button {...dragListeners}>Drag me</button>
61
+
62
+ {onCollapse && <button onClick={onCollapse}>{collapsed ? 'Expand' : 'Collapse'}</button>}
63
+
64
+ <h5>{treeItem.label}</h5>
65
+
66
+ <button onClick={() => openItemDetailsModal(treeItem.id)}>Show treeItem info</button>
67
+ </TreeItemStructure>
49
68
  );
50
- }
69
+ };
70
+ ```
71
+
72
+ If you need to change the indicator colors when dragging an item, you can use the `createSortableTreeGlobalStyles` for that:
73
+
74
+ ```tsx
75
+ const useSortableTreeGlobalStyles = createSortableTreeGlobalStyles({
76
+ indicatorColor: 'var(--orange-7)',
77
+ indicatorBorderColor: 'var(--orange-7)',
78
+ });
79
+
80
+ useSortableTreeGlobalStyles();
81
+ ```
82
+
83
+ This is a real-world example using Radix:
84
+
85
+ ```tsx
86
+ import {
87
+ RenderItemProps,
88
+ TreeItemStructure,
89
+ createSortableTreeGlobalStyles,
90
+ TreeItem as TTreeItem,
91
+ } from '@clevertask/react-sortable-tree';
92
+ import {
93
+ DragHandleDots2Icon,
94
+ ChevronRightIcon,
95
+ ChevronDownIcon,
96
+ TrashIcon,
97
+ PlusIcon,
98
+ } from '@radix-ui/react-icons';
99
+ import { Flex, Button, Text, Box } from '@radix-ui/themes';
100
+ import { CustomTreeItem } from '.';
101
+
102
+ export const TreeItem = (
103
+ props: RenderItemProps<CustomTreeItem> & {
104
+ onClickAddNestedItemButton: (id: string) => void;
105
+ onClickItemRemoveButton: (id: string) => void;
106
+ onItemClick: (id: string) => void;
107
+ },
108
+ ) => {
109
+ const {
110
+ treeItem,
111
+ onCollapse,
112
+ collapsed,
113
+ onClickAddNestedItemButton,
114
+ onClickItemRemoveButton,
115
+ onItemClick,
116
+ } = props;
117
+
118
+ const useSortableTreeGlobalStyles = createSortableTreeGlobalStyles({
119
+ indicatorColor: 'var(--orange-7)',
120
+ indicatorBorderColor: 'var(--orange-7)',
121
+ });
122
+
123
+ useSortableTreeGlobalStyles();
124
+
125
+ return (
126
+ <TreeItemStructure
127
+ {...props}
128
+ asDropZone={Box}
129
+ asDraggableItem={Box}
130
+ draggableItemStyle={{
131
+ display: 'flex',
132
+ justifyContent: 'space-between',
133
+ padding: '1rem',
134
+ border: '1px solid var(--gray-3)',
135
+ background: 'var(--color-background)',
136
+ }}
137
+ >
138
+ <Flex align="center" gap="5" direction="row">
139
+ <TreeItemStructure.DragHandler>
140
+ <DragHandleDots2Icon />
141
+ </TreeItemStructure.DragHandler>
142
+
143
+ {onCollapse && (
144
+ <Button color="gray" variant="ghost" onClick={onCollapse}>
145
+ {collapsed ?
146
+ <ChevronRightIcon />
147
+ : <ChevronDownIcon />}
148
+ </Button>
149
+ )}
150
+
151
+ <Text style={{ cursor: 'pointer' }} onClick={() => onItemClick(treeItem.id)}>
152
+ {treeItem.label} {treeItem.metadata.foo}
153
+ </Text>
154
+ </Flex>
155
+
156
+ <Flex align="center" gap="3" direction="row">
157
+ <Button variant="ghost" color="red" onClick={() => onClickItemRemoveButton(treeItem.id)}>
158
+ <TrashIcon />
159
+ </Button>
160
+ <Button
161
+ variant="ghost"
162
+ color="gray"
163
+ onClick={() => onClickAddNestedItemButton(treeItem.id)}
164
+ >
165
+ <PlusIcon />
166
+ </Button>
167
+ </Flex>
168
+ </TreeItemStructure>
169
+ );
170
+ };
171
+ ```
172
+
173
+ The `<TreeItemStructure/>` appends the dataSlots (for CSS styles), dropzone, and drag item container listeners and refs so you don't have to do it from scratch, but it's possible making your custom tree items without that component.
174
+
175
+ ---
176
+
177
+ ### 3. Use the `SortableTree` with your custom item
178
+
179
+ ```tsx
180
+ import React, { useState } from 'react';
181
+ import { TreeItems, SortableTree } from '@clevertask/react-sortable-tree';
182
+ type CustomTreeItem = TreeItem<{ metadata?: Record<string, string> }>;
183
+
184
+ const [items, setItems] = useState<TreeItems<CustomTreeItem>>([
185
+ { id: '1', label: 'Item 1', children: [] },
186
+ {
187
+ id: '2',
188
+ label: 'Item 2',
189
+ children: [{ id: '3', label: 'Item 2.1', children: [] }],
190
+ metadata: { foo: 'foo' },
191
+ },
192
+ ]);
193
+
194
+ <SortableTree<CustomTreeItem>
195
+ isCollapsible
196
+ showDropIndicator
197
+ items={items}
198
+ setItems={setItems}
199
+ renderItem={(props: RenderItemProps<CustomTreeItem>) => (
200
+ <TreeItem
201
+ {...props}
202
+ onClickAddNestedItemButton={onClickAddNestedItemButton}
203
+ onClickItemRemoveButton={onClickItemRemoveButton}
204
+ onItemClick={onItemClick}
205
+ />
206
+ )}
207
+ />;
51
208
  ```
52
209
 
210
+ ---
211
+
53
212
  ## Props
54
213
 
55
214
  | Prop | Type | Default | Description |
56
215
  | ------------------------- | --------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------- |
57
- | `items` | `TreeItems` | Required | The array of tree items to be rendered. |
58
- | `setItems` | `React.Dispatch<React.SetStateAction<TreeItems>>` | Required | Callback function called when the tree items array changes. |
216
+ | `items` | `TreeItems<T>` | Required | The array of tree items to be rendered. |
217
+ | `setItems` | `(items: TreeItems<T>) => void` | Required | Callback function called when the tree items array changes. |
218
+ | `renderItem` | `(props: RenderItemProps<T>) => React.ReactNode` | Required | Function to render each tree item. |
59
219
  | `indentationWidth` | `number` | `undefined` | The indentation width for children elements. |
60
220
  | `isCollapsible` | `boolean` | `false` | Determines if tree items can be collapsed/expanded. |
61
221
  | `onLazyLoadChildren` | `(id: UniqueIdentifier, isExpanding: boolean) => Promise<void>` | `undefined` | Callback for lazy loading child items when a parent is expanded. Useful for getting child items from an API endpoint |
@@ -67,106 +227,166 @@ function App() {
67
227
  | `onDragEnd` | `(result: DropResult) => void` | `undefined` | Callback function called when a drag operation ends. |
68
228
  | `onItemClick` | `(id: UniqueIdentifier) => void` | `undefined` | Callback function called when an item in the tree is clicked. |
69
229
 
230
+ ---
231
+
70
232
  ## Types
71
233
 
72
234
  ### TreeItem
73
235
 
74
- ```typescript
75
- type TreeItem = {
236
+ ```ts
237
+ type TreeItem<ExtraProps = unknown> = {
76
238
  id: UniqueIdentifier;
77
239
  label: string;
78
- children: TreeItem[];
240
+ children: TreeItem<ExtraProps>[];
79
241
  collapsed?: boolean;
80
242
  canFetchChildren?: boolean;
81
243
  disableDragging?: boolean;
82
- [key: string]: any;
83
- };
244
+ } & ExtraProps;
84
245
  ```
85
246
 
86
247
  ### TreeItems
87
248
 
88
- ```typescript
89
- type TreeItems = TreeItem[];
249
+ ```ts
250
+ type TreeItems<T = TreeItem> = T[];
90
251
  ```
91
252
 
92
- ## Helper Functions
93
-
94
- ### getItemById
95
-
96
- ```typescript
97
- function getItemById(items: TreeItems, id: UniqueIdentifier): TreeItem | undefined;
253
+ ### TreeStructureProps
254
+
255
+ ```ts
256
+ export interface TreeItemStructureProps {
257
+ dropZoneRef: (element: HTMLElement | null) => void;
258
+ draggableItemRef: React.Ref<any>;
259
+ dropZoneStyle?: React.CSSProperties;
260
+ draggableItemStyle?: React.CSSProperties;
261
+ classNames?: {
262
+ dropZone?: string;
263
+ draggableItem?: string;
264
+ };
265
+ asDropZone?: React.ElementType;
266
+ asDraggableItem?: React.ElementType;
267
+ draggableItemProps?: Record<string, any>;
268
+ children?: React.ReactNode;
269
+ dataSlots: {
270
+ dropZone: Record<string, string | boolean | undefined>;
271
+ draggableItem: Record<string, string>;
272
+ };
273
+ }
98
274
  ```
99
275
 
100
- Retrieves a tree item by its unique identifier.
276
+ ### RenderItemProps
277
+
278
+ ```ts
279
+ export interface RenderItemProps<T extends TTreeItem = TTreeItem>
280
+ extends
281
+ Pick<
282
+ TreeItemStructureProps,
283
+ 'classNames' | 'dropZoneStyle' | 'dropZoneRef' | 'draggableItemRef'
284
+ >,
285
+ Pick<
286
+ Props,
287
+ | 'onCollapse'
288
+ | 'childCount'
289
+ | 'clone'
290
+ | 'ghost'
291
+ | 'indicator'
292
+ | 'disableSelection'
293
+ | 'disableInteraction'
294
+ | 'collapsed'
295
+ > {
296
+ dragListeners?: any;
297
+ treeItem: T;
298
+ dataSlots: {
299
+ dropZone: Record<string, string | boolean | undefined>;
300
+ draggableItem: Record<string, string>;
301
+ };
302
+ }
303
+ ```
101
304
 
102
- Usage example:
305
+ ---
103
306
 
104
- ```typescript
105
- const item = getItemById(items, '1');
106
- ```
307
+ ## Helper Functions
107
308
 
108
- ### removeItemById
309
+ ### getItemById
109
310
 
110
- ```typescript
111
- function removeItemById(items: TreeItems, id: UniqueIdentifier): TreeItems;
311
+ ```ts
312
+ function getItemById<T extends TreeItem>(items: TreeItems<T>, id: UniqueIdentifier): T | undefined;
112
313
  ```
113
314
 
114
- This function removes an item from the tree structure by its ID. It returns a new `TreeItems` array with the item removed. It also handles removing the item from nested children.
115
-
116
- Usage example:
315
+ ### removeItemById
117
316
 
118
- ```typescript
119
- const updatedItems = removeItemById(items, '123');
120
- setItems(updatedItems);
317
+ ```ts
318
+ function removeItemById<T extends TreeItem>(
319
+ items: TreeItems<T>,
320
+ id: UniqueIdentifier,
321
+ ): TreeItems<T>;
121
322
  ```
122
323
 
123
324
  ### setTreeItemProperties
124
325
 
125
- ```typescript
126
- function setTreeItemProperties(
127
- items: TreeItems,
326
+ ```ts
327
+ function setTreeItemProperties<T extends TreeItem>(
328
+ items: TreeItems<T>,
128
329
  id: UniqueIdentifier,
129
- setter: (value: TreeItem) => Partial<TreeItem>,
130
- ): TreeItems;
330
+ setter: (value: T) => Partial<T>,
331
+ ): TreeItems<T>;
131
332
  ```
132
333
 
133
- This function updates the properties of a specific tree item. It takes a setter function that receives the current item and returns an object with the properties to be updated. It returns a new `TreeItems` array with the updated item.
334
+ ---
335
+
336
+ ## E2E Helper Functions
337
+
338
+ While adding e2e tests for this library, we created some helper functions that makes e2e testing declarative and easy in a way the user would use the UI. Feel free to import these helpers on your e2e tests. Also feel free to see the tests added to this repo on the `e2e` folder to have an idea about using these helpers
339
+
340
+ ### dragItem
341
+
342
+ Use it whenever you want to drag an item inside, after or before another item. This already knows how to move the item based on this library contract. You need to pass the name of the item you want to drag. There will be support for targeting items by their ID, to prevent getting items with the same name, but naturally, we get items by their name.
134
343
 
135
- Usage example:
344
+ ⚠️ So, when using E2E helpers that target items by name, item labels should be unique in the rendered tree.
136
345
 
137
- ```typescript
138
- setItems((items) => {
139
- return setTreeItemProperties(items, '123', (item) => ({
140
- label: 'New Label',
141
- collapsed: !item.collapsed,
142
- }));
346
+ ```ts
347
+ await dragItem({
348
+ page,
349
+ expect,
350
+ from: { name: 'A' },
351
+ to: { name: 'C', position: 'inside' },
143
352
  });
144
353
  ```
145
354
 
146
- ## Roadmap
355
+ ### expectItemToBeChildOf/expectItemNotToBeChildOf
356
+
357
+ This helper tells you if the item is a child of a given tree item. There's its opposite helper to assert if the target element is not child of a given item.
358
+
359
+ ```ts
360
+ const taskA = page.getByRole('treeitem', { name: 'A' });
361
+ const taskC = page.getByRole('treeitem', { name: 'C' });
362
+ await expectItemToBeChildOf(expect, taskA, taskC);
363
+
364
+ // or
147
365
 
148
- We're constantly working to improve @clevertask/react-sortable-tree. Here are some features we're planning to implement:
366
+ await expectItemNotToBeChildOf(expect, taskA, taskC);
367
+ ```
368
+
369
+ ### expectItemBefore
149
370
 
150
- - **Virtualization**: Improve performance for large trees by only rendering visible nodes.
151
- - **Custom item rendering**: Allow users to provide custom components for rendering tree items.
152
- - **Selection and Multi-selection**: Add support for selecting one or multiple items in the tree.
153
- - **Drag multiple items**: Enable dragging and dropping multiple selected items at once.
154
- - **API Example**: Provide a comprehensive example illustrating real-world usage with a backend API.
155
- - **E2E tests**: It will ensure this component's working as expected.
371
+ This helper tells you if an item is before the "x" item. You don't need a function for after because it's a matter of targeting the items in their proper places.
156
372
 
157
- We're excited about these upcoming features and welcome any feedback or contributions from the community. If you have any suggestions or would like to contribute to any of these features, please open an issue or submit a pull request on our GitHub repository.
373
+ ```ts
374
+ await expectItemBefore(page, expect, 'C', 'A');
375
+ ```
158
376
 
159
- ## Release Process
377
+ ---
160
378
 
161
- This package is automatically published to npm when a new release is created on GitHub. To create a new release:
379
+ ## Roadmap
162
380
 
163
- 1. Update the version in `package.json` according to semantic versioning rules.
164
- 2. Commit the version change: `git commit -am "Bump version to x.x.x"`
165
- 3. Create a new tag: `git tag vx.x.x`
166
- 4. Push the changes and the tag: `git push && git push --tags`
167
- 5. Go to the GitHub repository and create a new release, selecting the tag you just created.
381
+ - Custom item rendering (done!)
382
+ - ✅ E2E tests: It's partially done. We have yet to add item expanding tests and future tests for the next stuff we plan to add
383
+ - 🔜 Virtualization for large trees
384
+ - 🔜 Multi-selection support
385
+ - 🔜 Drag multiple items
386
+ - 🔜 Keyboard navigation
387
+ - 🔜 API usage example
168
388
 
169
- The GitHub Action will automatically build, test, and publish the new version to npm.
389
+ ---
170
390
 
171
391
  ## License
172
392
 
@@ -0,0 +1,51 @@
1
+ async function f({ page: t, expect: e, from: o, to: a }) {
2
+ const n = t.getByLabel(`Drag ${o.name}`, { exact: !0 }), m = t.getByRole("treeitem", { name: a.name });
3
+ await e(n).toBeVisible(), await e(m).toBeVisible();
4
+ const r = await n.boundingBox(), i = await m.boundingBox();
5
+ if (!r || !i)
6
+ throw new Error("Could not determine bounding boxes for drag operation");
7
+ const c = r.x + r.width / 2, w = r.y + r.height / 2;
8
+ let u = i.x + 8, d = i.y;
9
+ const b = 4;
10
+ switch (a.position) {
11
+ case "before":
12
+ d = i.y + b;
13
+ break;
14
+ case "after":
15
+ d = i.y + i.height - b;
16
+ break;
17
+ case "inside": {
18
+ const s = await m.locator("[data-tree-draggable]").boundingBox();
19
+ if (!s)
20
+ throw new Error("Could not determine draggable item bounds");
21
+ u = s.x + s.width * 0.05, d = s.y + s.height * 0.75;
22
+ break;
23
+ }
24
+ }
25
+ await t.mouse.move(c, w), await t.mouse.down(), await t.mouse.move(c + 1, w + 1), await t.mouse.move(u, d, { steps: 10 }), await t.evaluate(() => new Promise(requestAnimationFrame)), await t.mouse.up();
26
+ }
27
+ async function l(t) {
28
+ const e = await t.getAttribute("data-tree-item-id");
29
+ if (!e)
30
+ throw new Error("Tree item does not have data-tree-item-id");
31
+ return e;
32
+ }
33
+ async function x(t, e, o, a) {
34
+ const n = await t.getByRole("treeitem").allTextContents();
35
+ e(n.indexOf(o)).toBeLessThan(n.indexOf(a));
36
+ }
37
+ async function h(t, e, o) {
38
+ const a = await l(o);
39
+ await t(e).toHaveAttribute("data-tree-item-parent-id", a);
40
+ }
41
+ async function B(t, e, o) {
42
+ const a = await l(o);
43
+ await t(e).not.toHaveAttribute("data-tree-item-parent-id", a);
44
+ }
45
+ export {
46
+ f as dragItem,
47
+ x as expectItemBefore,
48
+ B as expectItemNotToBeChildOf,
49
+ h as expectItemToBeChildOf,
50
+ l as getTreeItemId
51
+ };
@@ -0,0 +1,15 @@
1
+ import { Page, Expect } from '@playwright/test';
2
+ type DragPosition = 'before' | 'after' | 'inside';
3
+ interface DragItemOptions {
4
+ page: Page;
5
+ expect: Expect;
6
+ from: {
7
+ name: string;
8
+ };
9
+ to: {
10
+ name: string;
11
+ position: DragPosition;
12
+ };
13
+ }
14
+ export declare function dragItem({ page, expect, from, to }: DragItemOptions): Promise<void>;
15
+ export {};
@@ -0,0 +1,2 @@
1
+ import { Expect, Page } from '@playwright/test';
2
+ export declare function expectItemBefore(page: Page, expect: Expect, first: string, second: string): Promise<void>;
@@ -0,0 +1,3 @@
1
+ import { Locator, Expect } from '@playwright/test';
2
+ export declare function expectItemToBeChildOf(expect: Expect, child: Locator, parent: Locator): Promise<void>;
3
+ export declare function expectItemNotToBeChildOf(expect: Expect, child: Locator, parent: Locator): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import { Locator } from '@playwright/test';
2
+ export declare function getTreeItemId(locator: Locator): Promise<string>;
@@ -0,0 +1,4 @@
1
+ export * from './drag-item';
2
+ export * from './get-tree-item-id';
3
+ export * from './expect-item-before';
4
+ export * from './expect-item-child-of';
@@ -1 +1 @@
1
- ._Wrapper_wguit_1{list-style:none;box-sizing:border-box;padding-left:var(--spacing);margin-bottom:-1px}._Wrapper_wguit_1._clone_wguit_8{display:inline-block;pointer-events:none;padding:5px 0 0 10px}._Wrapper_wguit_1._clone_wguit_8 ._TreeItem_wguit_16{--vertical-padding: 5px;padding-right:24px;border-radius:4px;box-shadow:0 15px 15px #2221511a}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23{opacity:1;position:relative;z-index:1;margin-bottom:-1px}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16{position:relative;padding:0;height:8px;border-color:#2389ff;background-color:#56a1f8}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16:before{position:absolute;left:-8px;top:-4px;display:block;content:"";width:12px;height:12px;border-radius:50%;border:1px solid #2389ff;background-color:#fff}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16>*{opacity:0;height:0}._Wrapper_wguit_1._ghost_wguit_23:not(._indicator_wguit_23){opacity:.5}._Wrapper_wguit_1._ghost_wguit_23 ._TreeItem_wguit_16>*{box-shadow:none;background-color:transparent}._TreeItem_wguit_16{--vertical-padding: 10px;position:relative;display:flex;align-items:center;padding:var(--vertical-padding) 10px;background-color:#fff;border:1px solid #dedede;color:#222;box-sizing:border-box}._Text_wguit_78{flex-grow:1;padding-left:.5rem;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;align-self:stretch;display:flex;align-items:center;cursor:pointer}._Count_wguit_90{position:absolute;top:-10px;right:-10px;display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background-color:#2389ff;font-size:.8rem;font-weight:600;color:#fff}._disableInteraction_wguit_106{pointer-events:none}._disableSelection_wguit_110 ._Text_wguit_78,._disableSelection_wguit_110 ._Count_wguit_90,._clone_wguit_8 ._Text_wguit_78,._clone_wguit_8 ._Count_wguit_90{user-select:none;-webkit-user-select:none}._Collapse_wguit_118 svg{transition:transform .25s ease}._Collapse_wguit_118._collapsed_wguit_122 svg{transform:rotate(-90deg)}._Action_7i4a4_1{display:flex;width:12px;padding:15px;align-items:center;justify-content:center;flex:0 0 auto;touch-action:none;cursor:var(--cursor, pointer);border-radius:5px;border:none;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;-webkit-tap-highlight-color:transparent}@media (hover: hover){._Action_7i4a4_1:hover{background-color:var(--action-background, rgba(0, 0, 0, .05))}._Action_7i4a4_1:hover svg{fill:#6f7b88}}._Action_7i4a4_1 svg{flex:0 0 auto;margin:auto;height:100%;overflow:visible;fill:#919eab}._Action_7i4a4_1:active{background-color:var(--background, rgba(0, 0, 0, .05))}._Action_7i4a4_1:active svg{fill:var(--fill, #788491)}._Action_7i4a4_1:focus-visible{outline:none;box-shadow:0 0 0 2px #fff0,0 0 0 2px #4c9ffe}
1
+ ._Wrapper_wguit_1{list-style:none;box-sizing:border-box;padding-left:var(--spacing);margin-bottom:-1px}._Wrapper_wguit_1._clone_wguit_8{display:inline-block;pointer-events:none;padding:5px 0 0 10px}._Wrapper_wguit_1._clone_wguit_8 ._TreeItem_wguit_16{--vertical-padding: 5px;padding-right:24px;border-radius:4px;box-shadow:0 15px 15px #2221511a}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23{opacity:1;position:relative;z-index:1;margin-bottom:-1px}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16{position:relative;padding:0;height:8px;border-color:#2389ff;background-color:#56a1f8}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16:before{position:absolute;left:-8px;top:-4px;display:block;content:"";width:12px;height:12px;border-radius:50%;border:1px solid #2389ff;background-color:#fff}._Wrapper_wguit_1._ghost_wguit_23._indicator_wguit_23 ._TreeItem_wguit_16>*{opacity:0;height:0}._Wrapper_wguit_1._ghost_wguit_23:not(._indicator_wguit_23){opacity:.5}._Wrapper_wguit_1._ghost_wguit_23 ._TreeItem_wguit_16>*{box-shadow:none;background-color:transparent}._TreeItem_wguit_16{--vertical-padding: 10px;position:relative;display:flex;align-items:center;padding:var(--vertical-padding) 10px;background-color:#fff;border:1px solid #dedede;color:#222;box-sizing:border-box}._Text_wguit_78{flex-grow:1;padding-left:.5rem;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;align-self:stretch;display:flex;align-items:center;cursor:pointer}._Count_wguit_90{position:absolute;top:-10px;right:-10px;display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background-color:#2389ff;font-size:.8rem;font-weight:600;color:#fff}._disableInteraction_wguit_106{pointer-events:none}._disableSelection_wguit_110 ._Text_wguit_78,._disableSelection_wguit_110 ._Count_wguit_90,._clone_wguit_8 ._Text_wguit_78,._clone_wguit_8 ._Count_wguit_90{user-select:none;-webkit-user-select:none}._Collapse_wguit_118 svg{transition:transform .25s ease}._Collapse_wguit_118._collapsed_wguit_122 svg{transform:rotate(-90deg)}._Action_7i4a4_1{display:flex;width:12px;padding:15px;align-items:center;justify-content:center;flex:0 0 auto;touch-action:none;cursor:var(--cursor, pointer);border-radius:5px;border:none;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;-webkit-tap-highlight-color:transparent}@media(hover:hover){._Action_7i4a4_1:hover{background-color:var(--action-background, rgba(0, 0, 0, .05))}._Action_7i4a4_1:hover svg{fill:#6f7b88}}._Action_7i4a4_1 svg{flex:0 0 auto;margin:auto;height:100%;overflow:visible;fill:#919eab}._Action_7i4a4_1:active{background-color:var(--background, rgba(0, 0, 0, .05))}._Action_7i4a4_1:active svg{fill:var(--fill, #788491)}._Action_7i4a4_1:focus-visible{outline:none;box-shadow:0 0 0 2px #fff0,0 0 0 2px #4c9ffe}