@dxos/react-ui-mosaic 0.3.3-main.6b9536c → 0.3.3-main.6bede4d
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.
- package/dist/lib/browser/index.mjs +51 -30
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/mosaic/Container.d.ts +10 -7
- package/dist/types/src/mosaic/Container.d.ts.map +1 -1
- package/dist/types/src/mosaic/Mosaic.d.ts +1 -2
- package/dist/types/src/mosaic/Mosaic.d.ts.map +1 -1
- package/dist/types/src/mosaic/Root.d.ts.map +1 -1
- package/dist/types/src/mosaic/hooks/index.d.ts +1 -1
- package/dist/types/src/mosaic/hooks/index.d.ts.map +1 -1
- package/dist/types/src/mosaic/hooks/useItemsWithOrigin.d.ts +3 -0
- package/dist/types/src/mosaic/hooks/useItemsWithOrigin.d.ts.map +1 -0
- package/dist/types/src/mosaic/hooks/useItemsWithPreview.d.ts.map +1 -1
- package/dist/types/src/stories/Home.stories.d.ts +11 -0
- package/dist/types/src/stories/Home.stories.d.ts.map +1 -0
- package/dist/types/src/testing/decorators.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +3 -10
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -1
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/views/Grid/Grid.d.ts +1 -1
- package/dist/types/src/views/Grid/Grid.d.ts.map +1 -1
- package/dist/types/src/views/Grid/Grid.stories.d.ts +1 -1
- package/dist/types/src/views/Stack/Columns.stories.d.ts +1 -1
- package/dist/types/src/views/Stack/Columns.stories.d.ts.map +1 -1
- package/dist/types/src/views/Tree/Graph.stories.d.ts +1 -1
- package/dist/types/src/views/Tree/Tree.d.ts +2 -3
- package/dist/types/src/views/Tree/Tree.d.ts.map +1 -1
- package/dist/types/src/views/Tree/Tree.stories.d.ts +1 -1
- package/dist/types/src/views/Tree/testing.d.ts +1 -1
- package/dist/types/src/views/Tree/testing.d.ts.map +1 -1
- package/package.json +14 -15
- package/src/mosaic/Container.tsx +10 -11
- package/src/mosaic/Mosaic.ts +0 -3
- package/src/mosaic/Root.tsx +1 -2
- package/src/mosaic/hooks/index.ts +1 -1
- package/src/mosaic/hooks/useItemsWithOrigin.ts +33 -0
- package/src/mosaic/hooks/useItemsWithPreview.ts +8 -3
- package/src/stories/Home.stories.tsx +87 -0
- package/src/testing/decorators.tsx +1 -0
- package/src/testing/generator.ts +11 -14
- package/src/testing/index.ts +0 -1
- package/src/views/Grid/Grid.tsx +4 -2
- package/src/views/Kanban/Kanban.tsx +1 -1
- package/src/views/Stack/Columns.stories.tsx +1 -1
- package/src/views/Stack/testing.tsx +1 -1
- package/src/views/Tree/Tree.tsx +9 -12
- package/src/views/Tree/testing.tsx +13 -31
- package/dist/types/src/mosaic/hooks/useSortedItems.d.ts +0 -6
- package/dist/types/src/mosaic/hooks/useSortedItems.d.ts.map +0 -1
- package/dist/types/src/testing/next-fractional-index.d.ts +0 -5
- package/dist/types/src/testing/next-fractional-index.d.ts.map +0 -1
- package/src/mosaic/hooks/useSortedItems.ts +0 -14
- package/src/testing/next-fractional-index.ts +0 -36
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useMosaic } from './useMosaic';
|
|
6
|
+
import { type MosaicDataItem } from '../types';
|
|
7
|
+
import { Path } from '../util';
|
|
8
|
+
|
|
9
|
+
// TODO(thure): Harmonize this hook signature with its sibling’s.
|
|
10
|
+
export const useItemsWithOrigin = <T extends MosaicDataItem>(path: string, items: T[]) => {
|
|
11
|
+
const { operation, activeItem, overItem } = useMosaic();
|
|
12
|
+
|
|
13
|
+
if (!activeItem || !overItem) {
|
|
14
|
+
return items;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const activeIsChild = Path.hasChild(path, activeItem.path);
|
|
18
|
+
const overIsChild = Path.hasChild(path, overItem.path);
|
|
19
|
+
|
|
20
|
+
if (activeIsChild && !overIsChild && operation !== 'rearrange') {
|
|
21
|
+
// Change the dnd-id of the origin item that may move to a foreign destination
|
|
22
|
+
return items.map((item) => {
|
|
23
|
+
if (item.id === activeItem.item.id) {
|
|
24
|
+
return { ...item, id: `${item.id}--origin` };
|
|
25
|
+
} else {
|
|
26
|
+
return item;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
// Reset items.
|
|
31
|
+
return items;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -24,7 +24,7 @@ export const useItemsWithPreview = <T extends MosaicDataItem>({ path, items }: {
|
|
|
24
24
|
const [lastOverParent, setLastOverParent] = useState(overParent);
|
|
25
25
|
|
|
26
26
|
useEffect(() => {
|
|
27
|
-
if (
|
|
27
|
+
if (!activeItem || !overItem) {
|
|
28
28
|
setLastOverParent(undefined);
|
|
29
29
|
setItemsWithPreview(items);
|
|
30
30
|
return;
|
|
@@ -34,12 +34,17 @@ export const useItemsWithPreview = <T extends MosaicDataItem>({ path, items }: {
|
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
setLastOverParent(overParent);
|
|
38
|
-
|
|
39
37
|
const activeIsChild = Path.hasChild(path, activeItem.path);
|
|
40
38
|
const overIsChild = Path.hasChild(path, overItem.path);
|
|
41
39
|
const overSelf = overItem.path === path;
|
|
42
40
|
|
|
41
|
+
if (operation === 'reject' || operation === 'rearrange') {
|
|
42
|
+
setLastOverParent(undefined);
|
|
43
|
+
setItemsWithPreview(items);
|
|
44
|
+
return;
|
|
45
|
+
} else {
|
|
46
|
+
setLastOverParent(overParent);
|
|
47
|
+
}
|
|
43
48
|
if (!activeIsChild && overIsChild) {
|
|
44
49
|
// Insert item into sortable.
|
|
45
50
|
setItemsWithPreview((items) => {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
import { FullscreenDecorator } from '../testing';
|
|
10
|
+
|
|
11
|
+
const org = '@dxos-mosaic';
|
|
12
|
+
|
|
13
|
+
const data = {
|
|
14
|
+
quote: `"I've written a few thousand words on why traditional “semantic class names” are the reason CSS is hard to ' +
|
|
15
|
+
'maintain, but the truth is you’re never going to believe me until you actually try it. If you can suppress the ' +
|
|
16
|
+
'urge to retch long enough to give it a chance, I really think you’ll wonder how you ever worked with CSS any other ' +
|
|
17
|
+
'way." [User]`,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const packages = [
|
|
21
|
+
{
|
|
22
|
+
name: `${org}/ui`,
|
|
23
|
+
description: 'Component primitives.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: `${org}/dnd`,
|
|
27
|
+
description: 'Drag-and-drop containers and tiles.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: `${org}/echo`,
|
|
31
|
+
description: 'DXOS ECHO bindings.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: `${org}/editor`,
|
|
35
|
+
description: 'Rich text editor.',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: `${org}/table`,
|
|
39
|
+
description: 'Blazingly fast virtualized tables.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: `${org}/stack`,
|
|
43
|
+
description: 'Flexible block editor.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: `${org}/grid`,
|
|
47
|
+
description: 'Hierarchical and zoomable grid.',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const Home = () => {
|
|
52
|
+
return (
|
|
53
|
+
<div className='flex flex-col w-[800px] bg-white px-16 py-20 gap-4 text-lg font-light'>
|
|
54
|
+
<b className='text-4xl font-medium text-black'>Mosaic</b>
|
|
55
|
+
<p>
|
|
56
|
+
Mosaic is an extensible user interface framework and component library built using{' '}
|
|
57
|
+
<span className='font-mono text-purple-700'>radix</span> and{' '}
|
|
58
|
+
<span className='font-mono text-purple-700'>tailwindcss</span>. It enables the rapid development of beautiful
|
|
59
|
+
data-driven applications.
|
|
60
|
+
</p>
|
|
61
|
+
<p>Mosaic is an extensible family of packages, which include:</p>
|
|
62
|
+
<table>
|
|
63
|
+
<tbody>
|
|
64
|
+
{packages.map(({ name, description }) => (
|
|
65
|
+
<tr key={name}>
|
|
66
|
+
<td className='font-mono text-purple-700 w-[260px]'>{name}</td>
|
|
67
|
+
<td>{description}</td>
|
|
68
|
+
</tr>
|
|
69
|
+
))}
|
|
70
|
+
</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
<br />
|
|
73
|
+
<h1 className='text-lg flex justify-center font-medium text-blue-700'>Data-drive components, done right.</h1>
|
|
74
|
+
<p className='px-8'>{data.quote}</p>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default {
|
|
80
|
+
component: Home,
|
|
81
|
+
decorators: [FullscreenDecorator('flex justify-center bg-[url(/images/bg-mosaic.png)]')],
|
|
82
|
+
parameters: {
|
|
83
|
+
layout: 'fullscreen',
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const Default = {};
|
|
@@ -12,6 +12,7 @@ import { mx } from '@dxos/react-ui-theme';
|
|
|
12
12
|
export const FullscreenDecorator = (className?: string): DecoratorFunction<ReactRenderer> => {
|
|
13
13
|
return (Story) => (
|
|
14
14
|
<div className={mx('flex fixed inset-0 overflow-hidden', className)}>
|
|
15
|
+
{/* TODO(burdon): Remove DensityProvider from generic decorator. */}
|
|
15
16
|
<DensityProvider density='fine'>
|
|
16
17
|
<Story />
|
|
17
18
|
</DensityProvider>
|
package/src/testing/generator.ts
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
// TODO(burdon): Reconcile with @dxos/
|
|
6
|
-
|
|
7
|
-
// TODO(burdon): Bug when adding stale objects to space (e.g., static objects already added in previous story invocation).
|
|
5
|
+
// TODO(burdon): Reconcile with @dxos/echo-generator.
|
|
8
6
|
|
|
9
7
|
import { faker } from '@faker-js/faker';
|
|
10
8
|
|
|
11
|
-
import { Schema
|
|
9
|
+
import { Schema } from '@dxos/client/echo';
|
|
12
10
|
import { Expando, type TypedObject } from '@dxos/echo-schema';
|
|
13
11
|
|
|
14
12
|
// TODO(burdon): Util.
|
|
@@ -17,16 +15,15 @@ export const range = <T>(fn: (i: number) => T | undefined, length: number): T[]
|
|
|
17
15
|
.map((_, i) => fn(i))
|
|
18
16
|
.filter(Boolean) as T[];
|
|
19
17
|
|
|
20
|
-
// TODO(burdon): Commit to using ECHO to generate all test data? Or convert from raw data?
|
|
21
18
|
export type TestItem = { id: string; type: string } & Record<string, any>;
|
|
22
19
|
|
|
23
20
|
type ObjectDataGenerator = {
|
|
24
|
-
createSchema?: () =>
|
|
21
|
+
createSchema?: () => Schema;
|
|
25
22
|
createData: () => any;
|
|
26
23
|
};
|
|
27
24
|
|
|
28
25
|
type ObjectFactory<T extends TypedObject> = {
|
|
29
|
-
schema?:
|
|
26
|
+
schema?: Schema; // TODO(burdon): Support both typed and expando schema.
|
|
30
27
|
createObject: () => T;
|
|
31
28
|
};
|
|
32
29
|
|
|
@@ -44,7 +41,7 @@ const createFactory = ({ createSchema, createData }: ObjectDataGenerator) => {
|
|
|
44
41
|
export const Status = ['pending', 'active', 'done'];
|
|
45
42
|
export const Priority = [1, 2, 3, 4, 5];
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
const defaultGenerators: { [type: string]: ObjectDataGenerator } = {
|
|
48
45
|
document: {
|
|
49
46
|
createData: () => ({
|
|
50
47
|
title: faker.lorem.sentence(3),
|
|
@@ -62,23 +59,23 @@ export const defaultGenerators: { [type: string]: ObjectDataGenerator } = {
|
|
|
62
59
|
|
|
63
60
|
project: {
|
|
64
61
|
createSchema: () =>
|
|
65
|
-
new
|
|
62
|
+
new Schema({
|
|
66
63
|
props: [
|
|
67
64
|
{
|
|
68
65
|
id: 'title',
|
|
69
|
-
type:
|
|
66
|
+
type: Schema.PropType.STRING,
|
|
70
67
|
},
|
|
71
68
|
{
|
|
72
69
|
id: 'repo',
|
|
73
|
-
type:
|
|
70
|
+
type: Schema.PropType.STRING,
|
|
74
71
|
},
|
|
75
72
|
{
|
|
76
73
|
id: 'status',
|
|
77
|
-
type:
|
|
74
|
+
type: Schema.PropType.STRING,
|
|
78
75
|
},
|
|
79
76
|
{
|
|
80
77
|
id: 'priority',
|
|
81
|
-
type:
|
|
78
|
+
type: Schema.PropType.NUMBER,
|
|
82
79
|
},
|
|
83
80
|
],
|
|
84
81
|
}),
|
|
@@ -106,7 +103,7 @@ export class TestObjectGenerator {
|
|
|
106
103
|
}, {});
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
get schema():
|
|
106
|
+
get schema(): Schema[] {
|
|
110
107
|
return Object.values(this.factories).map((f) => f.schema!);
|
|
111
108
|
}
|
|
112
109
|
|
package/src/testing/index.ts
CHANGED
package/src/views/Grid/Grid.tsx
CHANGED
|
@@ -52,8 +52,8 @@ type GridOptions = {
|
|
|
52
52
|
|
|
53
53
|
const defaultGridOptions: GridOptions = {
|
|
54
54
|
size: { x: 8, y: 8 },
|
|
55
|
-
cellBounds: { width:
|
|
56
|
-
spacing:
|
|
55
|
+
cellBounds: { width: 272, height: 272 },
|
|
56
|
+
spacing: 6,
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
//
|
|
@@ -90,6 +90,7 @@ export const Grid = ({
|
|
|
90
90
|
Component = Mosaic.DefaultComponent,
|
|
91
91
|
className,
|
|
92
92
|
onDrop,
|
|
93
|
+
onOver,
|
|
93
94
|
onSelect,
|
|
94
95
|
onCreate,
|
|
95
96
|
onAction,
|
|
@@ -155,6 +156,7 @@ export const Grid = ({
|
|
|
155
156
|
getOverlayProps: () => ({ grow: true }),
|
|
156
157
|
getOverlayStyle: () => getDimension(cellBounds, options.spacing),
|
|
157
158
|
onDrop,
|
|
159
|
+
onOver,
|
|
158
160
|
}}
|
|
159
161
|
>
|
|
160
162
|
<div className={mx('flex grow overflow-auto', className)}>
|
|
@@ -51,7 +51,7 @@ export const Kanban = ({
|
|
|
51
51
|
// Restrict to objects from other columns.
|
|
52
52
|
// TODO(burdon): Consider objects from other containers.
|
|
53
53
|
// TODO(wittjosiah): Allow override.
|
|
54
|
-
onOver: ({ active, over }) => (Path.length(active.path) >= Path.length(over.path) ? '
|
|
54
|
+
onOver: ({ active, over }) => (Path.length(active.path) >= Path.length(over.path) ? 'transfer' : 'reject'),
|
|
55
55
|
onDrop,
|
|
56
56
|
}}
|
|
57
57
|
>
|
package/src/views/Tree/Tree.tsx
CHANGED
|
@@ -15,8 +15,7 @@ import {
|
|
|
15
15
|
useContainer,
|
|
16
16
|
useMosaic,
|
|
17
17
|
Path,
|
|
18
|
-
|
|
19
|
-
type MosaicCompareDataItem,
|
|
18
|
+
useItemsWithOrigin,
|
|
20
19
|
} from '../../mosaic';
|
|
21
20
|
|
|
22
21
|
// TODO(burdon): Tree data model that provides a pure abstraction of the plugin Graph.
|
|
@@ -27,7 +26,6 @@ import {
|
|
|
27
26
|
export type TreeProps<TData extends MosaicDataItem = TreeData> = MosaicContainerProps<TData, number> & {
|
|
28
27
|
items?: TData[];
|
|
29
28
|
debug?: boolean;
|
|
30
|
-
compare?: MosaicCompareDataItem;
|
|
31
29
|
};
|
|
32
30
|
|
|
33
31
|
export type TreeData = {
|
|
@@ -37,7 +35,7 @@ export type TreeData = {
|
|
|
37
35
|
};
|
|
38
36
|
|
|
39
37
|
// TODO(burdon): Make generic (and forwardRef).
|
|
40
|
-
export const Tree = ({ id, Component = TreeItem, onOver, onDrop, items = [], debug
|
|
38
|
+
export const Tree = ({ id, Component = TreeItem, onOver, onDrop, items = [], debug }: TreeProps) => {
|
|
41
39
|
return (
|
|
42
40
|
<Mosaic.Container
|
|
43
41
|
{...{
|
|
@@ -46,7 +44,6 @@ export const Tree = ({ id, Component = TreeItem, onOver, onDrop, items = [], deb
|
|
|
46
44
|
Component,
|
|
47
45
|
onOver,
|
|
48
46
|
onDrop,
|
|
49
|
-
compare,
|
|
50
47
|
}}
|
|
51
48
|
>
|
|
52
49
|
<TreeRoot items={items} />
|
|
@@ -56,12 +53,12 @@ export const Tree = ({ id, Component = TreeItem, onOver, onDrop, items = [], deb
|
|
|
56
53
|
|
|
57
54
|
const TreeRoot = ({ items }: { items: TreeData[] }) => {
|
|
58
55
|
const { id, Component } = useContainer();
|
|
59
|
-
const
|
|
56
|
+
const itemsWithOrigin = useItemsWithOrigin(id, items);
|
|
60
57
|
|
|
61
58
|
return (
|
|
62
59
|
<TreeComponent.Root classNames='flex flex-col'>
|
|
63
|
-
<Mosaic.SortableContext id={id} items={
|
|
64
|
-
{
|
|
60
|
+
<Mosaic.SortableContext id={id} items={itemsWithOrigin} direction='vertical'>
|
|
61
|
+
{itemsWithOrigin.map((item, index) => (
|
|
65
62
|
<TreeItemComponent.Root key={item.id} collapsible defaultOpen>
|
|
66
63
|
<Mosaic.SortableTile item={item} path={id} position={index} Component={Component!} />
|
|
67
64
|
</TreeItemComponent.Root>
|
|
@@ -102,12 +99,12 @@ const TreeItem: MosaicTileComponent<TreeData> = forwardRef(
|
|
|
102
99
|
const TreeBranch = ({ path, items }: { path: string; items: TreeData[] }) => {
|
|
103
100
|
const { operation, overItem } = useMosaic();
|
|
104
101
|
const { Component } = useContainer();
|
|
105
|
-
const
|
|
102
|
+
const itemsWithOrigin = useItemsWithOrigin(path, items);
|
|
106
103
|
|
|
107
104
|
return (
|
|
108
105
|
<TreeItemComponent.Body className='pis-4'>
|
|
109
|
-
<Mosaic.SortableContext id={path} items={
|
|
110
|
-
{
|
|
106
|
+
<Mosaic.SortableContext id={path} items={itemsWithOrigin} direction='vertical'>
|
|
107
|
+
{itemsWithOrigin.map((child, index) => (
|
|
111
108
|
<TreeComponent.Branch key={child.id}>
|
|
112
109
|
<TreeItemComponent.Root collapsible defaultOpen>
|
|
113
110
|
<Mosaic.SortableTile
|
|
@@ -116,7 +113,7 @@ const TreeBranch = ({ path, items }: { path: string; items: TreeData[] }) => {
|
|
|
116
113
|
position={index}
|
|
117
114
|
Component={Component!}
|
|
118
115
|
isOver={
|
|
119
|
-
overItem?.path === Path.create(path, child.id) && (operation === '
|
|
116
|
+
overItem?.path === Path.create(path, child.id) && (operation === 'transfer' || operation === 'copy')
|
|
120
117
|
}
|
|
121
118
|
/>
|
|
122
119
|
</TreeItemComponent.Root>
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
import { faker } from '@faker-js/faker';
|
|
6
6
|
import React, { useCallback, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type Graph, GraphBuilder
|
|
9
|
-
import { buildGraph } from '@
|
|
8
|
+
import { type Graph, GraphBuilder } from '@dxos/app-graph';
|
|
9
|
+
import { buildGraph } from '@dxos/app-graph/testing';
|
|
10
10
|
import { arrayMove } from '@dxos/util';
|
|
11
11
|
|
|
12
12
|
import { Tree, type TreeData, type TreeProps } from './Tree';
|
|
13
|
-
import { type MosaicDropEvent, type MosaicMoveEvent, Path } from '../../mosaic';
|
|
14
|
-
import { TestObjectGenerator
|
|
13
|
+
import { type MosaicDropEvent, type MosaicMoveEvent, Path, type MosaicOperation } from '../../mosaic';
|
|
14
|
+
import { TestObjectGenerator } from '../../testing';
|
|
15
15
|
|
|
16
16
|
const fake = faker.helpers.fake;
|
|
17
17
|
|
|
@@ -47,8 +47,8 @@ export const DemoTree = ({ id = 'tree', initialItems, types, debug }: DemoTreePr
|
|
|
47
47
|
}),
|
|
48
48
|
);
|
|
49
49
|
|
|
50
|
-
const handleOver = useCallback(({
|
|
51
|
-
return
|
|
50
|
+
const handleOver = useCallback(({ over }: MosaicMoveEvent<number>) => {
|
|
51
|
+
return over && Path.hasChild(id, over.path) ? 'transfer' : 'reject';
|
|
52
52
|
}, []);
|
|
53
53
|
|
|
54
54
|
// NOTE: Does not handle deep operations.
|
|
@@ -67,8 +67,8 @@ export const DemoTree = ({ id = 'tree', initialItems, types, debug }: DemoTreePr
|
|
|
67
67
|
if (Path.last(Path.parent(active.path)) === item.id) {
|
|
68
68
|
children.splice(active.position!, 1);
|
|
69
69
|
}
|
|
70
|
-
if (Path.last(
|
|
71
|
-
children.
|
|
70
|
+
if (Path.last(over.path) === item.id) {
|
|
71
|
+
children.push(active.item as TreeData);
|
|
72
72
|
}
|
|
73
73
|
return { ...item, children };
|
|
74
74
|
}),
|
|
@@ -104,20 +104,7 @@ export const createGraph = () => {
|
|
|
104
104
|
return buildGraph(new GraphBuilder().build(), 'tree', content);
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
const graphNodeCompare = (a: Node, b: Node) => {
|
|
108
|
-
if (a.properties.index && b.properties.index) {
|
|
109
|
-
if (a.properties.index < b.properties.index) {
|
|
110
|
-
return -1;
|
|
111
|
-
} else if (a.properties.index > b.properties.index) {
|
|
112
|
-
return 1;
|
|
113
|
-
}
|
|
114
|
-
return 0;
|
|
115
|
-
}
|
|
116
|
-
return 0;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
107
|
export const GraphTree = ({ id, graph = createGraph(), debug }: { id: string; graph?: Graph; debug: boolean }) => {
|
|
120
|
-
// TODO(wittjosiah): This graph does not handle order currently.
|
|
121
108
|
const handleDrop = ({ operation, active, over }: MosaicDropEvent<number>) => {
|
|
122
109
|
// Moving within the tree.
|
|
123
110
|
if (Path.hasDescendent(id, active.path) && Path.hasDescendent(id, over.path)) {
|
|
@@ -135,22 +122,17 @@ export const GraphTree = ({ id, graph = createGraph(), debug }: { id: string; gr
|
|
|
135
122
|
operation === 'rearrange'
|
|
136
123
|
) {
|
|
137
124
|
// This is a rearrange operation
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
} else if (activeNode && activeParent && overParent && operation === 'adopt') {
|
|
125
|
+
console.warn('[react-ui-mosaic]', 'Tree', 'rearrange', 'needs implementation');
|
|
126
|
+
} else if (activeNode && activeParent && overParent && operation === 'transfer') {
|
|
141
127
|
activeParent.removeNode(active.item.id);
|
|
142
128
|
overNode.addNode('tree', { ...activeNode });
|
|
143
129
|
}
|
|
144
130
|
}
|
|
145
131
|
};
|
|
146
132
|
|
|
133
|
+
const handleOver = (): MosaicOperation => 'transfer';
|
|
134
|
+
|
|
147
135
|
return (
|
|
148
|
-
<Tree
|
|
149
|
-
id={id}
|
|
150
|
-
items={graph.root.children as TreeData[]}
|
|
151
|
-
onDrop={handleDrop}
|
|
152
|
-
debug={debug}
|
|
153
|
-
compare={graphNodeCompare}
|
|
154
|
-
/>
|
|
136
|
+
<Tree id={id} items={graph.root.children as TreeData[]} onDrop={handleDrop} onOver={handleOver} debug={debug} />
|
|
155
137
|
);
|
|
156
138
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useSortedItems.d.ts","sourceRoot":"","sources":["../../../../../src/mosaic/hooks/useSortedItems.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,cAAc,+CAG1B,CAAC"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type UniqueIdentifier } from '@dnd-kit/core';
|
|
2
|
-
import { type Node } from '@braneframe/plugin-graph';
|
|
3
|
-
export declare const nextRearrangeIndex: (nodes: Node[], activeId: UniqueIdentifier, overId?: UniqueIdentifier) => string | null;
|
|
4
|
-
export declare const nextCopyIndex: (nodes: Node[], overId?: UniqueIdentifier) => string;
|
|
5
|
-
//# sourceMappingURL=next-fractional-index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"next-fractional-index.d.ts","sourceRoot":"","sources":["../../../../src/testing/next-fractional-index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,eAAO,MAAM,kBAAkB,UAAW,IAAI,EAAE,YAAY,gBAAgB,WAAW,gBAAgB,kBAYtG,CAAC;AAEF,eAAO,MAAM,aAAa,UAAW,IAAI,EAAE,WAAW,gBAAgB,WAYrE,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { useContainer } from './useContainer';
|
|
6
|
-
import { type MosaicDataItem } from '../types';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Returns a sorted collection of items if a compare function is provided.
|
|
10
|
-
*/
|
|
11
|
-
export const useSortedItems = <T extends MosaicDataItem>(items: T[]): T[] => {
|
|
12
|
-
const { compare } = useContainer();
|
|
13
|
-
return compare ? [...items].sort(compare) : items;
|
|
14
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2023 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type UniqueIdentifier } from '@dnd-kit/core';
|
|
6
|
-
import { getIndexAbove, getIndexBelow, getIndexBetween } from '@tldraw/indices';
|
|
7
|
-
|
|
8
|
-
import { type Node } from '@braneframe/plugin-graph';
|
|
9
|
-
|
|
10
|
-
export const nextRearrangeIndex = (nodes: Node[], activeId: UniqueIdentifier, overId?: UniqueIdentifier) => {
|
|
11
|
-
const overOrderIndex = nodes.length > 0 ? nodes.findIndex(({ id }) => id === overId) : -1;
|
|
12
|
-
if (overOrderIndex >= 0) {
|
|
13
|
-
const activeOrderIndex = nodes.findIndex(({ id }) => id === activeId);
|
|
14
|
-
return overOrderIndex < 1
|
|
15
|
-
? getIndexBelow(nodes[overOrderIndex].properties.index)
|
|
16
|
-
: activeOrderIndex < overOrderIndex
|
|
17
|
-
? getIndexBetween(nodes[overOrderIndex].properties.index, nodes[overOrderIndex + 1]?.properties.index)
|
|
18
|
-
: getIndexBetween(nodes[overOrderIndex - 1].properties.index, nodes[overOrderIndex].properties.index);
|
|
19
|
-
} else {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const nextCopyIndex = (nodes: Node[], overId?: UniqueIdentifier) => {
|
|
25
|
-
const overOrderIndex = nodes.length > 0 ? nodes.findIndex(({ id }) => id === overId) : -1;
|
|
26
|
-
const previewOrderIndex = nodes.findIndex(({ id }) => id.startsWith('preview--'));
|
|
27
|
-
if (overOrderIndex >= 0) {
|
|
28
|
-
return overOrderIndex < 1
|
|
29
|
-
? getIndexBelow(nodes[overOrderIndex].properties.index)
|
|
30
|
-
: previewOrderIndex < overOrderIndex && previewOrderIndex >= 0
|
|
31
|
-
? getIndexBetween(nodes[overOrderIndex].properties.index, nodes[overOrderIndex + 1]?.properties.index)
|
|
32
|
-
: getIndexBetween(nodes[overOrderIndex - 1].properties.index, nodes[overOrderIndex]?.properties.index);
|
|
33
|
-
} else {
|
|
34
|
-
return nodes.length ? getIndexAbove(nodes[nodes.length - 1].properties.index) : 'a0';
|
|
35
|
-
}
|
|
36
|
-
};
|