@threlte/flex 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.
- package/dist/Box/Box.svelte +24 -5
- package/dist/Box/Box.svelte.d.ts +8 -2
- package/dist/Flex/Flex.svelte +7 -1
- package/dist/Flex/Flex.svelte.d.ts +2 -0
- package/dist/Flex/InnerFlex.svelte +32 -29
- package/dist/Flex/InnerFlex.svelte.d.ts +2 -0
- package/dist/Flex/context.d.ts +1 -1
- package/dist/hooks/useDimensions.d.ts +50 -0
- package/dist/hooks/useDimensions.js +59 -0
- package/dist/hooks/useReflow.d.ts +10 -0
- package/dist/hooks/useReflow.js +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/lib/propsChanged.d.ts +8 -0
- package/dist/lib/propsChanged.js +26 -0
- package/dist/nodes/context.d.ts +3 -5
- package/dist/nodes/context.js +39 -23
- package/package.json +3 -3
package/dist/Box/Box.svelte
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
<script>import { HierarchicalObject, T } from '@threlte/core';
|
|
1
|
+
<script>import { HierarchicalObject, T, createRawEventDispatcher } from '@threlte/core';
|
|
2
2
|
import { onDestroy } from 'svelte';
|
|
3
3
|
import { Group } from 'three';
|
|
4
4
|
import { useFlex } from '../Flex/context';
|
|
5
|
+
import { createUseDimensionsContext } from '../hooks/useDimensions';
|
|
5
6
|
import { createNodeContext } from '../nodes/context';
|
|
6
7
|
export let order = undefined;
|
|
7
8
|
let _class = '';
|
|
8
9
|
export { _class as class };
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const dispatch = createRawEventDispatcher();
|
|
11
|
+
/**
|
|
12
|
+
* Create the context for `useDimensions`
|
|
13
|
+
*/
|
|
14
|
+
const dimensionsContext = createUseDimensionsContext();
|
|
15
|
+
const { scaleFactor, onEvent, addNode, removeNode, updateNodeProps, mainAxis, crossAxis, depthAxis, classParser, reflow } = useFlex();
|
|
16
|
+
const group = new Group();
|
|
12
17
|
group.userData.isNode = true;
|
|
13
|
-
|
|
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
|
+
});
|
|
14
26
|
addNode(node, group, $$restProps);
|
|
15
27
|
updateNodeProps(node, { ...classParser?.(_class, {}), ...$$restProps }, true);
|
|
16
28
|
$: updateNodeProps(node, { ...classParser?.(_class, {}), ...$$restProps });
|
|
@@ -38,6 +50,12 @@ onEvent('reflow:after', () => {
|
|
|
38
50
|
getContentGroup().position[$mainAxis] = computedWidth / 2;
|
|
39
51
|
getContentGroup().position[$crossAxis] = -computedHeight / 2;
|
|
40
52
|
getContentGroup().position[$depthAxis] = 0;
|
|
53
|
+
dimensionsContext.width.set(computedWidth);
|
|
54
|
+
dimensionsContext.height.set(computedHeight);
|
|
55
|
+
dispatch('reflow', {
|
|
56
|
+
width: computedWidth,
|
|
57
|
+
height: computedHeight
|
|
58
|
+
});
|
|
41
59
|
});
|
|
42
60
|
</script>
|
|
43
61
|
|
|
@@ -62,6 +80,7 @@ onEvent('reflow:after', () => {
|
|
|
62
80
|
}}
|
|
63
81
|
>
|
|
64
82
|
<slot
|
|
83
|
+
{reflow}
|
|
65
84
|
width={computedWidth}
|
|
66
85
|
height={computedHeight}
|
|
67
86
|
/>
|
package/dist/Box/Box.svelte.d.ts
CHANGED
|
@@ -2,14 +2,20 @@ import { SvelteComponent } from 'svelte'
|
|
|
2
2
|
import type { NodeProps } from '../lib/props'
|
|
3
3
|
|
|
4
4
|
type BoxProps = NodeProps & {
|
|
5
|
-
order?: number
|
|
5
|
+
order?: number | undefined
|
|
6
6
|
class?: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
type BoxEvents = {
|
|
9
|
+
type BoxEvents = {
|
|
10
|
+
reflow: {
|
|
11
|
+
width: number
|
|
12
|
+
height: number
|
|
13
|
+
}
|
|
14
|
+
}
|
|
10
15
|
|
|
11
16
|
type BoxSlots = {
|
|
12
17
|
default: {
|
|
18
|
+
reflow: () => void
|
|
13
19
|
width: number
|
|
14
20
|
height: number
|
|
15
21
|
}
|
package/dist/Flex/Flex.svelte
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
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
13
|
export let yoga;
|
|
@@ -20,8 +22,14 @@ export { _class as class };
|
|
|
20
22
|
const dispatch = createRawEventDispatcher();
|
|
21
23
|
const rootGroup = new Group();
|
|
22
24
|
rootGroup.userData.isNode = true;
|
|
25
|
+
const rootNode = yoga.Node.create();
|
|
26
|
+
createNodeContext(rootNode);
|
|
23
27
|
const boundingBox = new Box3();
|
|
24
28
|
const vec3 = new Vector3();
|
|
29
|
+
/**
|
|
30
|
+
* Create the context for `useDimensions`
|
|
31
|
+
*/
|
|
32
|
+
const { width: computedWidth, height: computedHeight } = createUseDimensionsContext();
|
|
25
33
|
/**
|
|
26
34
|
* Reflowing inside useFrame automatically batches reflows to 1 per frame.
|
|
27
35
|
*/
|
|
@@ -68,9 +76,11 @@ const { start: reflow, stop } = useFrame(() => {
|
|
|
68
76
|
maxY = Math.max(maxY, top + height);
|
|
69
77
|
}
|
|
70
78
|
flexContext.emit('reflow:after');
|
|
79
|
+
computedWidth.set((maxX - minX) / scaleFactor);
|
|
80
|
+
computedHeight.set((maxY - minY) / scaleFactor);
|
|
71
81
|
dispatch('reflow', {
|
|
72
|
-
width:
|
|
73
|
-
height:
|
|
82
|
+
width: computedWidth.current,
|
|
83
|
+
height: computedHeight.current
|
|
74
84
|
});
|
|
75
85
|
stop();
|
|
76
86
|
}, { autostart: false });
|
|
@@ -83,25 +93,13 @@ const flexContext = createFlexContext({
|
|
|
83
93
|
},
|
|
84
94
|
updateNodeProps(node, props, force = false) {
|
|
85
95
|
const nodeData = flexContext.nodes.get(node);
|
|
86
|
-
if (!nodeData)
|
|
87
|
-
return;
|
|
88
96
|
// Updating the props can be forced and is done so on the initial call.
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const previousKeys = Object.keys(nodeData.props);
|
|
95
|
-
const currentKeys = Object.keys(props);
|
|
96
|
-
if (previousKeys.length === currentKeys.length &&
|
|
97
|
-
currentKeys.every((key) => previousKeys.includes(key)) &&
|
|
98
|
-
previousKeys.every((key) => nodeData.props[key] === props[key])) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
97
|
+
if (force || propsChanged(node, props)) {
|
|
98
|
+
applyNodeProps(node, props, scaleFactor);
|
|
99
|
+
reflow();
|
|
100
|
+
if (nodeData)
|
|
101
|
+
nodeData.props = props;
|
|
101
102
|
}
|
|
102
|
-
applyNodeProps(node, props, scaleFactor);
|
|
103
|
-
nodeData.props = props;
|
|
104
|
-
reflow();
|
|
105
103
|
},
|
|
106
104
|
removeNode(node) {
|
|
107
105
|
flexContext.nodes.delete(node);
|
|
@@ -118,21 +116,26 @@ const flexContext = createFlexContext({
|
|
|
118
116
|
classParser
|
|
119
117
|
});
|
|
120
118
|
const { mainAxis, crossAxis, depthAxis } = flexContext;
|
|
121
|
-
const { node: rootNode } = createNodeContext();
|
|
122
119
|
$: rootNode.setWidth(width * scaleFactor), rootNode.setHeight(height * scaleFactor);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
$: flexContext.
|
|
127
|
-
$: flexContext.
|
|
128
|
-
$: flexContext.
|
|
129
|
-
$: flexContext.
|
|
130
|
-
$: flexContext.
|
|
120
|
+
// prettier-ignore
|
|
121
|
+
flexContext.updateNodeProps(rootNode, { ...classParser?.(_class, {}), ...$$restProps }, true);
|
|
122
|
+
// prettier-ignore
|
|
123
|
+
$: flexContext.updateNodeProps(rootNode, { ...classParser?.(_class, {}), ...$$restProps });
|
|
124
|
+
$: flexContext.rootWidth.set(width), flexContext.reflow();
|
|
125
|
+
$: flexContext.rootHeight.set(height), flexContext.reflow();
|
|
126
|
+
$: flexContext.mainAxis.set(plane[0]), flexContext.reflow();
|
|
127
|
+
$: flexContext.crossAxis.set(plane[1]), flexContext.reflow();
|
|
128
|
+
$: flexContext.depthAxis.set(getDepthAxis(plane)), flexContext.reflow();
|
|
129
|
+
$: flexContext.scaleFactor.set(scaleFactor), flexContext.reflow();
|
|
131
130
|
onDestroy(() => {
|
|
132
131
|
rootNode.free();
|
|
133
132
|
});
|
|
134
133
|
</script>
|
|
135
134
|
|
|
136
135
|
<T is={rootGroup}>
|
|
137
|
-
<slot
|
|
136
|
+
<slot
|
|
137
|
+
{reflow}
|
|
138
|
+
width={$computedWidth}
|
|
139
|
+
height={$computedHeight}
|
|
140
|
+
/>
|
|
138
141
|
</T>
|
package/dist/Flex/context.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type FlexContextData = {
|
|
|
25
25
|
rootGroup: Group;
|
|
26
26
|
rootWidth: CurrentWritable<number>;
|
|
27
27
|
rootHeight: CurrentWritable<number>;
|
|
28
|
-
reflow: (
|
|
28
|
+
reflow: () => void;
|
|
29
29
|
classParser?: ClassParser;
|
|
30
30
|
};
|
|
31
31
|
export type FlexContext = FlexContextData & Emitter<FlexContextEvents> & {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type CurrentWritable } from '@threlte/core';
|
|
2
|
+
type UseDimensionsContext = {
|
|
3
|
+
width: CurrentWritable<number>;
|
|
4
|
+
height: CurrentWritable<number>;
|
|
5
|
+
};
|
|
6
|
+
export declare const flexContextName = "__threlte-flex-dimensions";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a context for useDimensions.
|
|
9
|
+
*/
|
|
10
|
+
export declare const createUseDimensionsContext: () => UseDimensionsContext;
|
|
11
|
+
/**
|
|
12
|
+
* The hook `useDimensions` can be used to retrieve the computed width and
|
|
13
|
+
* height of a `<Flex>` or `<Box>` component as
|
|
14
|
+
* [CurrentWritable](https://threlte.xyz/docs/reference/core/utilities#currentwritable)
|
|
15
|
+
* stores.
|
|
16
|
+
*
|
|
17
|
+
* ## Usage
|
|
18
|
+
*
|
|
19
|
+
* ### In a `<Flex>` component
|
|
20
|
+
*
|
|
21
|
+
* Because there's no viewport to measure, the width and height of a `<Flex>`
|
|
22
|
+
* component need to be set manually. Nevertheless, the dimensions of the
|
|
23
|
+
* contents of the `<Flex>` component will be measured after a layout reflow and
|
|
24
|
+
* can be retrieved using `useDimensions` in a direct child component to
|
|
25
|
+
* `<Flex>`.
|
|
26
|
+
*
|
|
27
|
+
* ### In a `<Box>` component
|
|
28
|
+
*
|
|
29
|
+
* By default `@threlte/flex` controls elements position only. In some cases you
|
|
30
|
+
* may want to control element sizing too. Since `@threlte/flex` has no
|
|
31
|
+
* information about how the inner content size works, you need to set your
|
|
32
|
+
* content size manually. You can do this by using `useDimensions` hook in a
|
|
33
|
+
* direct child component to `<Box>`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```svelte
|
|
37
|
+
* <script>
|
|
38
|
+
* import { useDimensions } from '@threlte/flex'
|
|
39
|
+
*
|
|
40
|
+
* const { width, height } = useDimensions()
|
|
41
|
+
* </script>
|
|
42
|
+
*
|
|
43
|
+
* <T.Mesh scale.x={$width} scale.y={$height}>
|
|
44
|
+
* <T.BoxGeometry />
|
|
45
|
+
* <T.MeshBasicMaterial color="red" />
|
|
46
|
+
* </T.Mesh>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare const useDimensions: () => UseDimensionsContext;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { currentWritable } from '@threlte/core';
|
|
3
|
+
export const flexContextName = '__threlte-flex-dimensions';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a context for useDimensions.
|
|
6
|
+
*/
|
|
7
|
+
export const createUseDimensionsContext = () => {
|
|
8
|
+
const context = {
|
|
9
|
+
width: currentWritable(0),
|
|
10
|
+
height: currentWritable(0)
|
|
11
|
+
};
|
|
12
|
+
setContext(flexContextName, context);
|
|
13
|
+
return context;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The hook `useDimensions` can be used to retrieve the computed width and
|
|
17
|
+
* height of a `<Flex>` or `<Box>` component as
|
|
18
|
+
* [CurrentWritable](https://threlte.xyz/docs/reference/core/utilities#currentwritable)
|
|
19
|
+
* stores.
|
|
20
|
+
*
|
|
21
|
+
* ## Usage
|
|
22
|
+
*
|
|
23
|
+
* ### In a `<Flex>` component
|
|
24
|
+
*
|
|
25
|
+
* Because there's no viewport to measure, the width and height of a `<Flex>`
|
|
26
|
+
* component need to be set manually. Nevertheless, the dimensions of the
|
|
27
|
+
* contents of the `<Flex>` component will be measured after a layout reflow and
|
|
28
|
+
* can be retrieved using `useDimensions` in a direct child component to
|
|
29
|
+
* `<Flex>`.
|
|
30
|
+
*
|
|
31
|
+
* ### In a `<Box>` component
|
|
32
|
+
*
|
|
33
|
+
* By default `@threlte/flex` controls elements position only. In some cases you
|
|
34
|
+
* may want to control element sizing too. Since `@threlte/flex` has no
|
|
35
|
+
* information about how the inner content size works, you need to set your
|
|
36
|
+
* content size manually. You can do this by using `useDimensions` hook in a
|
|
37
|
+
* direct child component to `<Box>`.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```svelte
|
|
41
|
+
* <script>
|
|
42
|
+
* import { useDimensions } from '@threlte/flex'
|
|
43
|
+
*
|
|
44
|
+
* const { width, height } = useDimensions()
|
|
45
|
+
* </script>
|
|
46
|
+
*
|
|
47
|
+
* <T.Mesh scale.x={$width} scale.y={$height}>
|
|
48
|
+
* <T.BoxGeometry />
|
|
49
|
+
* <T.MeshBasicMaterial color="red" />
|
|
50
|
+
* </T.Mesh>
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export const useDimensions = () => {
|
|
54
|
+
const context = getContext(flexContextName);
|
|
55
|
+
if (!context) {
|
|
56
|
+
throw new Error('useDimensions must be used within a <Flex> component');
|
|
57
|
+
}
|
|
58
|
+
return context;
|
|
59
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hook useReflow allows you to manually request a [layout
|
|
3
|
+
* reflow](https://threlte.xyz/docs/reference/flex/flex#layout-reflow), for
|
|
4
|
+
* instance when a [`<Text>`](https://threlte.xyz/docs/reference/extras/text)
|
|
5
|
+
* component finished synchronizing or when a model has loaded into view and
|
|
6
|
+
* there’s no easy access to the reflow slot prop of the components `<Flex>` or
|
|
7
|
+
* `<Box>` because of component composition. Calls to`reflow` will be limited to
|
|
8
|
+
* once per frame, so it’s safe to call it from multiple components at a time.
|
|
9
|
+
*/
|
|
10
|
+
export declare const useReflow: () => () => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getContext } from 'svelte';
|
|
2
|
+
import { flexContextName } from '../Flex/context';
|
|
3
|
+
/**
|
|
4
|
+
* The hook useReflow allows you to manually request a [layout
|
|
5
|
+
* reflow](https://threlte.xyz/docs/reference/flex/flex#layout-reflow), for
|
|
6
|
+
* instance when a [`<Text>`](https://threlte.xyz/docs/reference/extras/text)
|
|
7
|
+
* component finished synchronizing or when a model has loaded into view and
|
|
8
|
+
* there’s no easy access to the reflow slot prop of the components `<Flex>` or
|
|
9
|
+
* `<Box>` because of component composition. Calls to`reflow` will be limited to
|
|
10
|
+
* once per frame, so it’s safe to call it from multiple components at a time.
|
|
11
|
+
*/
|
|
12
|
+
export const useReflow = () => {
|
|
13
|
+
const flexContext = getContext(flexContextName);
|
|
14
|
+
if (!flexContext) {
|
|
15
|
+
throw new Error('useReflow must be used within a <Flex> component');
|
|
16
|
+
}
|
|
17
|
+
return flexContext.reflow;
|
|
18
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export { default as Flex } from './Flex/Flex.svelte';
|
|
|
3
3
|
export type { NodeProps } from './lib/props';
|
|
4
4
|
export { createClassParser } from './parsers/createClassParser';
|
|
5
5
|
export { tailwindParser } from './parsers/tailwindParser';
|
|
6
|
+
export { useReflow } from './hooks/useReflow';
|
|
7
|
+
export { useDimensions } from './hooks/useDimensions';
|
package/dist/index.js
CHANGED
|
@@ -3,3 +3,6 @@ export { default as Flex } from './Flex/Flex.svelte';
|
|
|
3
3
|
// parsers
|
|
4
4
|
export { createClassParser } from './parsers/createClassParser';
|
|
5
5
|
export { tailwindParser } from './parsers/tailwindParser';
|
|
6
|
+
// hooks
|
|
7
|
+
export { useReflow } from './hooks/useReflow';
|
|
8
|
+
export { useDimensions } from './hooks/useDimensions';
|
|
@@ -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,7 @@
|
|
|
1
1
|
import type { Node } from 'yoga-layout';
|
|
2
2
|
export type NodeContext = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
removeChild: (child: Node) => void;
|
|
3
|
+
insertNode: (childNode: Node, order?: number) => void;
|
|
4
|
+
removeNode: (childNode: Node) => void;
|
|
6
5
|
};
|
|
7
6
|
export declare const nodeContextName = "__threlte-node";
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const createNodeContext: (order?: number) => NodeContext;
|
|
7
|
+
export declare const createNodeContext: (node: Node) => NodeContext | undefined;
|
package/dist/nodes/context.js
CHANGED
|
@@ -1,31 +1,47 @@
|
|
|
1
|
-
import { getContext,
|
|
2
|
-
import { useFlex } from '../Flex/context';
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
3
2
|
export const nodeContextName = '__threlte-node';
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
parentNodeContext?.removeChild(node);
|
|
14
|
-
});
|
|
15
|
-
const data = {
|
|
16
|
-
node,
|
|
17
|
-
insertChild(child, order) {
|
|
3
|
+
export const createNodeContext = (node) => {
|
|
4
|
+
const childNodes = new Set();
|
|
5
|
+
const childNodesOrderMap = new Map();
|
|
6
|
+
const parentNodeContext = getContext(nodeContextName);
|
|
7
|
+
setContext(nodeContextName, {
|
|
8
|
+
insertNode(childNode, order) {
|
|
9
|
+
// we want to keep track of all child nodes
|
|
10
|
+
childNodes.add(childNode);
|
|
11
|
+
// Additionally, we need to keep track of child nodes that need to be inserted at a specific order
|
|
18
12
|
if (order !== undefined) {
|
|
19
|
-
|
|
13
|
+
childNodesOrderMap.set(childNode, {
|
|
14
|
+
requestedOrder: order
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (childNodesOrderMap.size) {
|
|
18
|
+
// we need to sort the child nodes by their requested order. We leave the nodes that don't have a requested order untouched.
|
|
19
|
+
const sorted = Array.from(childNodes)
|
|
20
|
+
.map((node, index) => {
|
|
21
|
+
return {
|
|
22
|
+
order: childNodesOrderMap.get(node)?.requestedOrder ?? index,
|
|
23
|
+
node
|
|
24
|
+
};
|
|
25
|
+
})
|
|
26
|
+
.sort((a, b) => a.order - b.order)
|
|
27
|
+
.map(({ node }) => node);
|
|
28
|
+
// Then we need to remove all child nodes from the node and insert them in the correct order.
|
|
29
|
+
sorted.forEach((childNode) => {
|
|
30
|
+
node.removeChild(childNode);
|
|
31
|
+
});
|
|
32
|
+
sorted.forEach((childNode, index) => {
|
|
33
|
+
node.insertChild(childNode, index);
|
|
34
|
+
});
|
|
20
35
|
}
|
|
21
36
|
else {
|
|
22
|
-
|
|
37
|
+
node.insertChild(childNode, node.getChildCount());
|
|
23
38
|
}
|
|
24
39
|
},
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
removeNode(childNode) {
|
|
41
|
+
node.removeChild(childNode);
|
|
42
|
+
childNodes.delete(childNode);
|
|
43
|
+
childNodesOrderMap.delete(childNode);
|
|
27
44
|
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return data;
|
|
45
|
+
});
|
|
46
|
+
return parentNodeContext;
|
|
31
47
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threlte/flex",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"author": "Grischa Erbe <hello@legrisch.com> (https://legrisch.com)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"devDependencies": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"tslib": "^2.4.1",
|
|
28
28
|
"typescript": "^5.0.0",
|
|
29
29
|
"vite": "^4.3.6",
|
|
30
|
-
"@threlte/core": "6.0.
|
|
31
|
-
"@threlte/extras": "
|
|
30
|
+
"@threlte/core": "6.0.9",
|
|
31
|
+
"@threlte/extras": "6.0.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"mitt": "^3.0.1",
|