@threlte/flex 0.0.7 → 0.0.9
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/Box/Box.svelte +12 -4
- package/dist/Box/Box.svelte.d.ts +1 -1
- package/dist/Flex/InnerFlex.svelte +13 -23
- package/dist/lib/propsChanged.d.ts +8 -0
- package/dist/lib/propsChanged.js +26 -0
- package/dist/nodes/context.d.ts +4 -5
- package/dist/nodes/context.js +95 -23
- package/package.json +1 -1
package/dist/Box/Box.svelte
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { onDestroy } from 'svelte';
|
|
3
3
|
import { Group } from 'three';
|
|
4
4
|
import { useFlex } from '../Flex/context';
|
|
5
|
-
import { createNodeContext } from '../nodes/context';
|
|
6
5
|
import { createUseDimensionsContext } from '../hooks/useDimensions';
|
|
6
|
+
import { createNodeContext } from '../nodes/context';
|
|
7
7
|
export let order = undefined;
|
|
8
8
|
let _class = '';
|
|
9
9
|
export { _class as class };
|
|
@@ -13,10 +13,18 @@ const dispatch = createRawEventDispatcher();
|
|
|
13
13
|
*/
|
|
14
14
|
const dimensionsContext = createUseDimensionsContext();
|
|
15
15
|
const { scaleFactor, onEvent, addNode, removeNode, updateNodeProps, mainAxis, crossAxis, depthAxis, classParser, reflow } = useFlex();
|
|
16
|
-
|
|
17
|
-
export const contentGroup = new Group();
|
|
16
|
+
const group = new Group();
|
|
18
17
|
group.userData.isNode = true;
|
|
19
|
-
|
|
18
|
+
const contentGroup = new Group();
|
|
19
|
+
const { yoga } = useFlex();
|
|
20
|
+
const node = yoga.Node.create();
|
|
21
|
+
const parentNodeContext = createNodeContext(node);
|
|
22
|
+
parentNodeContext?.insertNode(node, order);
|
|
23
|
+
onDestroy(() => {
|
|
24
|
+
parentNodeContext?.removeNode(node);
|
|
25
|
+
});
|
|
26
|
+
// update the order of the node
|
|
27
|
+
$: parentNodeContext?.updateNodeOrder(node, order);
|
|
20
28
|
addNode(node, group, $$restProps);
|
|
21
29
|
updateNodeProps(node, { ...classParser?.(_class, {}), ...$$restProps }, true);
|
|
22
30
|
$: updateNodeProps(node, { ...classParser?.(_class, {}), ...$$restProps });
|
package/dist/Box/Box.svelte.d.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import { onDestroy } from 'svelte';
|
|
3
3
|
import { Box3, Group, Vector3 } from 'three';
|
|
4
4
|
import { Direction } from 'yoga-layout';
|
|
5
|
+
import { createUseDimensionsContext } from '../hooks/useDimensions';
|
|
5
6
|
import { getDepthAxis } from '../lib/getDepthAxis';
|
|
6
7
|
import { getOrientedBoundingBoxSize } from '../lib/getOrientedBoundingBoxSize';
|
|
7
8
|
import { getRootShift } from '../lib/getRootShift';
|
|
8
9
|
import { applyNodeProps } from '../lib/props';
|
|
10
|
+
import { propsChanged } from '../lib/propsChanged';
|
|
9
11
|
import { createNodeContext } from '../nodes/context';
|
|
10
12
|
import { createFlexContext } from './context';
|
|
11
|
-
import { createUseDimensionsContext } from '../hooks/useDimensions';
|
|
12
13
|
export let yoga;
|
|
13
14
|
export let width = 1;
|
|
14
15
|
export let height = 1;
|
|
@@ -90,25 +91,13 @@ const flexContext = createFlexContext({
|
|
|
90
91
|
},
|
|
91
92
|
updateNodeProps(node, props, force = false) {
|
|
92
93
|
const nodeData = flexContext.nodes.get(node);
|
|
93
|
-
if (!nodeData)
|
|
94
|
-
return;
|
|
95
94
|
// Updating the props can be forced and is done so on the initial call.
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const previousKeys = Object.keys(nodeData.props);
|
|
102
|
-
const currentKeys = Object.keys(props);
|
|
103
|
-
if (previousKeys.length === currentKeys.length &&
|
|
104
|
-
currentKeys.every((key) => previousKeys.includes(key)) &&
|
|
105
|
-
previousKeys.every((key) => nodeData.props[key] === props[key])) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
95
|
+
if (force || propsChanged(node, props)) {
|
|
96
|
+
applyNodeProps(node, props, scaleFactor);
|
|
97
|
+
reflow();
|
|
98
|
+
if (nodeData)
|
|
99
|
+
nodeData.props = props;
|
|
108
100
|
}
|
|
109
|
-
applyNodeProps(node, props, scaleFactor);
|
|
110
|
-
nodeData.props = props;
|
|
111
|
-
reflow();
|
|
112
101
|
},
|
|
113
102
|
removeNode(node) {
|
|
114
103
|
flexContext.nodes.delete(node);
|
|
@@ -124,13 +113,14 @@ const flexContext = createFlexContext({
|
|
|
124
113
|
reflow,
|
|
125
114
|
classParser
|
|
126
115
|
});
|
|
116
|
+
const rootNode = yoga.Node.create();
|
|
117
|
+
createNodeContext(rootNode);
|
|
127
118
|
const { mainAxis, crossAxis, depthAxis } = flexContext;
|
|
128
|
-
const { node: rootNode } = createNodeContext();
|
|
129
119
|
$: rootNode.setWidth(width * scaleFactor), rootNode.setHeight(height * scaleFactor);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
120
|
+
// prettier-ignore
|
|
121
|
+
flexContext.updateNodeProps(rootNode, { ...classParser?.(_class, {}), ...$$restProps }, true);
|
|
122
|
+
// prettier-ignore
|
|
123
|
+
$: flexContext.updateNodeProps(rootNode, { ...classParser?.(_class, {}), ...$$restProps });
|
|
134
124
|
$: flexContext.rootWidth.set(width), flexContext.reflow();
|
|
135
125
|
$: flexContext.rootHeight.set(height), flexContext.reflow();
|
|
136
126
|
$: flexContext.mainAxis.set(plane[0]), flexContext.reflow();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NodeProps } from './props';
|
|
2
|
+
/**
|
|
3
|
+
* Because all NodeProps are primitive types, we can make a simple comparison
|
|
4
|
+
* and only request a reflow when necessary. We do that by checking the length
|
|
5
|
+
* of the props object and then checking if all keys are the same and all values
|
|
6
|
+
* are the same.
|
|
7
|
+
*/
|
|
8
|
+
export declare const propsChanged: (node: Node, props: NodeProps) => boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const nodePropsMap = new WeakMap();
|
|
2
|
+
/**
|
|
3
|
+
* Because all NodeProps are primitive types, we can make a simple comparison
|
|
4
|
+
* and only request a reflow when necessary. We do that by checking the length
|
|
5
|
+
* of the props object and then checking if all keys are the same and all values
|
|
6
|
+
* are the same.
|
|
7
|
+
*/
|
|
8
|
+
export const propsChanged = (node, props) => {
|
|
9
|
+
// get a reference to the props data for this node
|
|
10
|
+
const propsData = nodePropsMap.get(node);
|
|
11
|
+
// assume that the props have changed
|
|
12
|
+
let changed = true;
|
|
13
|
+
if (propsData) {
|
|
14
|
+
// compare the keys and values of the previous and current props
|
|
15
|
+
const previousKeys = Object.keys(propsData);
|
|
16
|
+
const currentKeys = Object.keys(props);
|
|
17
|
+
if (previousKeys.length === currentKeys.length &&
|
|
18
|
+
currentKeys.every((key) => previousKeys.includes(key)) &&
|
|
19
|
+
previousKeys.every((key) => propsData[key] === props[key])) {
|
|
20
|
+
changed = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// update the props data for this node
|
|
24
|
+
nodePropsMap.set(node, props);
|
|
25
|
+
return changed;
|
|
26
|
+
};
|
package/dist/nodes/context.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Node } from 'yoga-layout';
|
|
2
2
|
export type NodeContext = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
insertNode: (childNode: Node, order?: number) => void;
|
|
4
|
+
removeNode: (childNode: Node) => void;
|
|
5
|
+
updateNodeOrder: (childNode: Node, order?: number) => void;
|
|
6
6
|
};
|
|
7
7
|
export declare const nodeContextName = "__threlte-node";
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const createNodeContext: (order?: number) => NodeContext;
|
|
8
|
+
export declare const createNodeContext: (node: Node) => NodeContext | undefined;
|
package/dist/nodes/context.js
CHANGED
|
@@ -1,31 +1,103 @@
|
|
|
1
|
-
import { getContext,
|
|
2
|
-
import {
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { useReflow } from '..';
|
|
3
3
|
export const nodeContextName = '__threlte-node';
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const parentNodeContext =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
export const createNodeContext = (node) => {
|
|
5
|
+
const reflow = useReflow();
|
|
6
|
+
/** Set to keep track of all child nodes */
|
|
7
|
+
const childNodes = new Set();
|
|
8
|
+
/** Map to keep track of the requested order of nodes */
|
|
9
|
+
const childNodesOrderMap = new Map();
|
|
10
|
+
const parentNodeContext = getContext(nodeContextName);
|
|
11
|
+
const removeAllChildNodes = () => {
|
|
12
|
+
childNodes.forEach((childNode) => {
|
|
13
|
+
node.removeChild(childNode);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
setContext(nodeContextName, {
|
|
17
|
+
insertNode(childNode, order) {
|
|
18
|
+
// we want to keep track of all child nodes
|
|
19
|
+
childNodes.add(childNode);
|
|
20
|
+
// Additionally, we need to keep track of child nodes that need to be
|
|
21
|
+
// inserted at a specific order
|
|
18
22
|
if (order !== undefined) {
|
|
19
|
-
|
|
23
|
+
childNodesOrderMap.set(childNode, {
|
|
24
|
+
requestedOrder: order
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (childNodesOrderMap.size) {
|
|
28
|
+
// we need to sort the child nodes by their requested order. We leave
|
|
29
|
+
// the nodes that don't have a requested order untouched.
|
|
30
|
+
const sorted = Array.from(childNodes)
|
|
31
|
+
.map((node, index) => {
|
|
32
|
+
return {
|
|
33
|
+
order: childNodesOrderMap.get(node)?.requestedOrder ?? index,
|
|
34
|
+
node
|
|
35
|
+
};
|
|
36
|
+
})
|
|
37
|
+
.sort((a, b) => a.order - b.order)
|
|
38
|
+
.map(({ node }) => node);
|
|
39
|
+
// Then we need to remove all child nodes from the node and insert them
|
|
40
|
+
// in the correct order.
|
|
41
|
+
removeAllChildNodes();
|
|
42
|
+
sorted.forEach((childNode, index) => {
|
|
43
|
+
node.insertChild(childNode, index);
|
|
44
|
+
});
|
|
20
45
|
}
|
|
21
46
|
else {
|
|
22
|
-
|
|
47
|
+
node.insertChild(childNode, node.getChildCount());
|
|
23
48
|
}
|
|
49
|
+
reflow();
|
|
50
|
+
},
|
|
51
|
+
removeNode(childNode) {
|
|
52
|
+
node.removeChild(childNode);
|
|
53
|
+
childNodes.delete(childNode);
|
|
54
|
+
childNodesOrderMap.delete(childNode);
|
|
55
|
+
reflow();
|
|
24
56
|
},
|
|
25
|
-
|
|
26
|
-
|
|
57
|
+
updateNodeOrder(childNode, order) {
|
|
58
|
+
let update = false;
|
|
59
|
+
const oldOrder = childNodesOrderMap.get(childNode)?.requestedOrder;
|
|
60
|
+
if (order === undefined) {
|
|
61
|
+
// if the order is undefined, we remove the node from the map
|
|
62
|
+
if (oldOrder !== undefined) {
|
|
63
|
+
childNodesOrderMap.delete(childNode);
|
|
64
|
+
update = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// if the order is defined, we update the node in the map
|
|
69
|
+
const oldOrder = childNodesOrderMap.get(childNode)?.requestedOrder;
|
|
70
|
+
if (oldOrder !== order) {
|
|
71
|
+
childNodesOrderMap.set(childNode, {
|
|
72
|
+
requestedOrder: order
|
|
73
|
+
});
|
|
74
|
+
update = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// if there's no update, return early
|
|
78
|
+
if (!update)
|
|
79
|
+
return;
|
|
80
|
+
// remove all child nodes from the node
|
|
81
|
+
removeAllChildNodes();
|
|
82
|
+
// we need to sort the child nodes by their requested order. We leave the
|
|
83
|
+
// nodes that don't have a requested order untouched.
|
|
84
|
+
const sorted = Array.from(childNodes)
|
|
85
|
+
.map((node, index) => {
|
|
86
|
+
return {
|
|
87
|
+
order: childNodesOrderMap.get(node)?.requestedOrder ?? index,
|
|
88
|
+
node
|
|
89
|
+
};
|
|
90
|
+
})
|
|
91
|
+
.sort((a, b) => a.order - b.order)
|
|
92
|
+
.map(({ node }) => node);
|
|
93
|
+
// Then we need to remove all child nodes from the node and insert them in
|
|
94
|
+
// the correct order.
|
|
95
|
+
removeAllChildNodes();
|
|
96
|
+
sorted.forEach((childNode, index) => {
|
|
97
|
+
node.insertChild(childNode, index);
|
|
98
|
+
});
|
|
99
|
+
reflow();
|
|
27
100
|
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return data;
|
|
101
|
+
});
|
|
102
|
+
return parentNodeContext;
|
|
31
103
|
};
|