@threlte/flex 2.0.0-next.1 → 2.0.0-next.10

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.
@@ -1,10 +1,10 @@
1
- <script lang="ts">import { HierarchicalObject, T } from '@threlte/core';
1
+ <script lang="ts">import { T } from '@threlte/core';
2
2
  import { onDestroy } from 'svelte';
3
- import { Group } from 'three';
3
+ import { Group, Object3D } from 'three';
4
4
  import { useFlex } from '../Flex/context';
5
5
  import { createUseDimensionsContext } from '../hooks/useDimensions';
6
6
  import { createNodeContext } from '../nodes/context';
7
- let { order, class: _class = '', ...props } = $props();
7
+ let { order, class: _class = '', onreflow, children, ...props } = $props();
8
8
  /**
9
9
  * Create the context for `useDimensions`
10
10
  */
@@ -41,36 +41,39 @@ onEvent('reflow:after', () => {
41
41
  contentGroup.position[$depthAxis] = 0;
42
42
  dimensionsContext.width.set(computedWidth);
43
43
  dimensionsContext.height.set(computedHeight);
44
- props.$$events?.reflow?.({
44
+ onreflow?.({
45
45
  width: computedWidth,
46
46
  height: computedHeight
47
47
  });
48
48
  });
49
+ const proxy = new Object3D();
50
+ proxy.add = (child) => {
51
+ if (child.userData.isNode) {
52
+ group.add(child);
53
+ }
54
+ else {
55
+ contentGroup.add(child);
56
+ }
57
+ return child;
58
+ };
59
+ proxy.remove = (child) => {
60
+ if (child.userData.isNode) {
61
+ group.remove(child);
62
+ }
63
+ else {
64
+ contentGroup.remove(child);
65
+ }
66
+ return child;
67
+ };
49
68
  </script>
50
69
 
51
70
  <T is={group}>
52
71
  <T is={contentGroup} />
53
72
  </T>
54
73
 
55
- <HierarchicalObject
56
- onChildMount={(child) => {
57
- if (child.userData.isNode) {
58
- group.add(child)
59
- } else {
60
- contentGroup.add(child)
61
- }
62
- }}
63
- onChildDestroy={(child) => {
64
- if (child.userData.isNode) {
65
- group.remove(child)
66
- } else {
67
- contentGroup.remove(child)
68
- }
69
- }}
74
+ <T
75
+ is={proxy}
76
+ attach={false}
70
77
  >
71
- <slot
72
- {reflow}
73
- width={computedWidth}
74
- height={computedHeight}
75
- />
76
- </HierarchicalObject>
78
+ {@render children?.({ reflow, width: computedWidth, height: computedHeight })}
79
+ </T>
@@ -1,24 +1,21 @@
1
- import { SvelteComponent } from 'svelte'
1
+ import { SvelteComponent, type Snippet } from 'svelte'
2
2
  import type { NodeProps } from '../lib/props'
3
3
 
4
4
  type BoxProps = NodeProps & {
5
5
  order?: number | undefined
6
6
  class?: string
7
- }
8
7
 
9
- type BoxEvents = {
10
- reflow: {
11
- width: number
12
- height: number
13
- }
14
- }
8
+ children?: Snippet<
9
+ [
10
+ {
11
+ reflow: () => void
12
+ width: number
13
+ height: number
14
+ }
15
+ ]
16
+ >
15
17
 
16
- type BoxSlots = {
17
- default: {
18
- reflow: () => void
19
- width: number
20
- height: number
21
- }
18
+ onreflow?: (event: { width: number; height: number }) => void
22
19
  }
23
20
 
24
- export default class Box extends SvelteComponent<BoxProps, BoxEvents, BoxSlots> {}
21
+ export default class Box extends SvelteComponent<BoxProps> {}
@@ -1,6 +1,6 @@
1
- <script lang="ts">import { loadYoga } from 'yoga-layout';
1
+ <script lang="ts">import { loadYoga } from 'yoga-layout/load';
2
2
  import InnerFlex from './InnerFlex.svelte';
3
- let { ...props } = $props();
3
+ let { children: innerChildren, ...props } = $props();
4
4
  let yoga = $state(undefined);
5
5
  const initialize = async () => {
6
6
  yoga = await loadYoga();
@@ -12,14 +12,9 @@ initialize();
12
12
  <InnerFlex
13
13
  {yoga}
14
14
  {...props}
15
- let:reflow
16
- let:width
17
- let:height
18
15
  >
19
- <slot
20
- {reflow}
21
- {width}
22
- {height}
23
- />
16
+ {#snippet children({ reflow, width, height })}
17
+ {@render innerChildren?.({ reflow, width, height })}
18
+ {/snippet}
24
19
  </InnerFlex>
25
20
  {/if}
@@ -1,18 +1,7 @@
1
1
  import { SvelteComponent } from 'svelte'
2
- import type { ComponentEvents, ComponentProps } from 'svelte'
2
+ import type { ComponentProps } from 'svelte'
3
3
  import type InnerFlex from './InnerFlex.svelte'
4
4
 
5
5
  type FlexProps = Omit<ComponentProps<InnerFlex>, 'yoga'>
6
6
 
7
- type FlexEvents = ComponentEvents<InnerFlex>
8
-
9
- // Currently, there's no svelte helper to get the slots of a component.
10
- type FlexSlots = {
11
- default: {
12
- reflow: () => void
13
- width: number
14
- height: number
15
- }
16
- }
17
-
18
- export default class Flex extends SvelteComponent<FlexProps, FlexEvents, FlexSlots> {}
7
+ export default class Flex extends SvelteComponent<FlexProps> {}
@@ -10,7 +10,7 @@ import { applyNodeProps } from '../lib/props';
10
10
  import { propsChanged } from '../lib/propsChanged';
11
11
  import { createNodeContext } from '../nodes/context';
12
12
  import { createFlexContext } from './context';
13
- let { yoga, width = 1, height = 1, plane = 'xy', direction = 'LTR', scaleFactor = 1000, classParser, class: _class = '', reflowStage, ref = $bindable(), ...props } = $props();
13
+ let { yoga, width = 1, height = 1, plane = 'xy', direction = 'LTR', scaleFactor = 1000, classParser, class: _class = '', reflowStage, ref = $bindable(), onreflow, children, ...props } = $props();
14
14
  $inspect(yoga);
15
15
  ref = new Group();
16
16
  ref.userData.isNode = true;
@@ -21,7 +21,7 @@ const vec3 = new Vector3();
21
21
  */
22
22
  const { width: computedWidth, height: computedHeight } = createUseDimensionsContext();
23
23
  /**
24
- * Reflowing inside useFrame automatically batches reflows to 1 per frame.
24
+ * Reflowing inside useTask automatically batches reflows to 1 per frame.
25
25
  */
26
26
  const { start: reflow, stop } = useTask(Symbol('threlte-flex-reflow'), () => {
27
27
  flexContext.emit('reflow:before');
@@ -68,7 +68,7 @@ const { start: reflow, stop } = useTask(Symbol('threlte-flex-reflow'), () => {
68
68
  flexContext.emit('reflow:after');
69
69
  computedWidth.set((maxX - minX) / scaleFactor);
70
70
  computedHeight.set((maxY - minY) / scaleFactor);
71
- props.$$events?.reflow?.({
71
+ onreflow?.({
72
72
  width: computedWidth.current,
73
73
  height: computedHeight.current
74
74
  });
@@ -151,9 +151,9 @@ onDestroy(() => {
151
151
  </script>
152
152
 
153
153
  <T is={ref}>
154
- <slot
155
- {reflow}
156
- width={$computedWidth}
157
- height={$computedHeight}
158
- />
154
+ {@render children?.({
155
+ reflow,
156
+ width: $computedWidth,
157
+ height: $computedHeight
158
+ })}
159
159
  </T>
@@ -1,7 +1,8 @@
1
1
  import type { Stage } from '@threlte/core'
2
- import { SvelteComponent } from 'svelte'
2
+ import { SvelteComponent, type Snippet } from 'svelte'
3
3
  import type { Direction, Yoga } from 'yoga-layout'
4
4
  import type { ClassParser, FlexPlane, NodeProps } from '../lib/props'
5
+ import type { Group } from 'three'
5
6
 
6
7
  type InnerFlexProps = NodeProps & {
7
8
  yoga: Yoga
@@ -13,25 +14,19 @@ type InnerFlexProps = NodeProps & {
13
14
  class?: string
14
15
  classParser?: ClassParser
15
16
  reflowStage?: Stage
16
- }
17
+ ref?: Group
17
18
 
18
- type InnerFlexEvents = {
19
- reflow: {
20
- width: number
21
- height: number
22
- }
23
- }
19
+ children?: Snippet<
20
+ [
21
+ {
22
+ reflow: () => void
23
+ width: number
24
+ height: number
25
+ }
26
+ ]
27
+ >
24
28
 
25
- type InnerFlexSlots = {
26
- default: {
27
- reflow: () => void
28
- width: number
29
- height: number
30
- }
29
+ onreflow?: (event: { width: number; height: number }) => void
31
30
  }
32
31
 
33
- export default class InnerFlex extends SvelteComponent<
34
- InnerFlexProps,
35
- InnerFlexEvents,
36
- InnerFlexSlots
37
- > {}
32
+ export default class InnerFlex extends SvelteComponent<InnerFlexProps> {}
@@ -0,0 +1,39 @@
1
+ import type { CurrentWritable } from '@threlte/core';
2
+ import { type Emitter } from 'mitt';
3
+ import type { Group } from 'three';
4
+ import type { Node, Yoga } from 'yoga-layout';
5
+ import type { Axis, ClassParser, NodeProps } from '../lib/props';
6
+ type FlexContextEvents = {
7
+ 'reflow:before': void;
8
+ 'reflow:after': void;
9
+ };
10
+ type FlexContextNode = {
11
+ node: Node;
12
+ group: Group;
13
+ props: NodeProps;
14
+ };
15
+ export type FlexContextData = {
16
+ yoga: Yoga;
17
+ nodes: Map<Node, FlexContextNode>;
18
+ addNode: (node: Node, group: Group, props: NodeProps) => void;
19
+ updateNodeProps: (node: Node, props: NodeProps, force?: boolean) => void;
20
+ removeNode: (node: Node) => void;
21
+ scaleFactor: CurrentWritable<number>;
22
+ mainAxis: CurrentWritable<Axis>;
23
+ crossAxis: CurrentWritable<Axis>;
24
+ depthAxis: CurrentWritable<Axis>;
25
+ rootGroup: Group;
26
+ rootWidth: CurrentWritable<number>;
27
+ rootHeight: CurrentWritable<number>;
28
+ reflow: () => void;
29
+ classParser?: ClassParser;
30
+ };
31
+ export type FlexContext = FlexContextData & Emitter<FlexContextEvents> & {
32
+ onEvent: <Type extends keyof FlexContextEvents>(type: Type, callback: (payload: FlexContextEvents[Type]) => void) => void;
33
+ };
34
+ export declare const flexContextName = "__threlte-flex";
35
+ export declare const createFlexContext: (data: FlexContextData) => FlexContextData & Emitter<FlexContextEvents> & {
36
+ onEvent: <Type extends keyof FlexContextEvents>(type: Type, callback: (payload: FlexContextEvents[Type]) => void) => void;
37
+ };
38
+ export declare const useFlex: () => FlexContext;
39
+ export {};
@@ -1,2 +1,3 @@
1
+ import type { Node } from 'yoga-layout';
1
2
  /** @returns [mainAxisShift, crossAxisShift] */
2
3
  export declare const getRootShift: (rootWidth: number, rootHeight: number, node: Node) => number[] | readonly [number, number];
@@ -1 +1,2 @@
1
+ import type { Node } from 'yoga-layout';
1
2
  export declare const isTopLevelChildNode: (node: Node) => boolean;
@@ -1,4 +1,5 @@
1
1
  import type { Align, FlexDirection, Justify, Node, Wrap } from 'yoga-layout';
2
+ import * as Yoga from 'yoga-layout';
2
3
  export type FlexPlane = 'xy' | 'yz' | 'xz';
3
4
  export type ClassParser = (className: string, props: NodeProps) => NodeProps;
4
5
  export type Axis = 'x' | 'y' | 'z';
@@ -10,41 +11,50 @@ export type Axis = 'x' | 'y' | 'z';
10
11
  * prevent unnecessary reflows.
11
12
  */
12
13
  export declare const propSetter: {
13
- alignItems: (align: keyof typeof Align, node: Node) => any;
14
- alignSelf: (align: keyof typeof Align, node: Node) => any;
15
- alignContent: (align: keyof typeof Align, node: Node) => any;
16
- justifyContent: (justify: keyof typeof Justify, node: Node) => any;
17
- flexDirection: (dir: keyof typeof FlexDirection, node: Node) => any;
18
- flexWrap: (wrap: keyof typeof Wrap, node: Node) => any;
19
- flex: (flex: Parameters<Node['setFlex']>[0], node: Node) => any;
20
- flexBasis: (basis: Parameters<Node['setFlexBasis']>[0], node: Node) => any;
21
- flexGrow: (grow: Parameters<Node['setFlexGrow']>[0], node: Node) => any;
22
- flexShrink: (shrink: Parameters<Node['setFlexShrink']>[0], node: Node) => any;
23
- height: (height: Parameters<Node['setHeight']>[0], node: Node) => any;
24
- width: (width: Parameters<Node['setWidth']>[0], node: Node) => any;
25
- maxHeight: (maxHeight: Parameters<Node['setMaxHeight']>[0], node: Node) => any;
26
- maxWidth: (maxWidth: Parameters<Node['setMaxWidth']>[0], node: Node) => any;
27
- minHeight: (minHeight: Parameters<Node['setMinHeight']>[0], node: Node) => any;
28
- minWidth: (minWidth: Parameters<Node['setMinWidth']>[0], node: Node) => any;
14
+ alignItems: (align: keyof typeof Align, node: Node) => void;
15
+ alignSelf: (align: keyof typeof Align, node: Node) => void;
16
+ alignContent: (align: keyof typeof Align, node: Node) => void;
17
+ justifyContent: (justify: keyof typeof Justify, node: Node) => void;
18
+ flexDirection: (dir: keyof typeof FlexDirection, node: Node) => void;
19
+ flexWrap: (wrap: keyof typeof Wrap, node: Node) => void;
20
+ flex: (flex: Parameters<Node['setFlex']>[0], node: Node) => void;
21
+ flexBasis: (basis: Parameters<Node['setFlexBasis']>[0], node: Node) => void;
22
+ flexGrow: (grow: Parameters<Node['setFlexGrow']>[0], node: Node) => void;
23
+ flexShrink: (shrink: Parameters<Node['setFlexShrink']>[0], node: Node) => void;
24
+ height: (height: Parameters<Node['setHeight']>[0], node: Node) => void;
25
+ width: (width: Parameters<Node['setWidth']>[0], node: Node) => void;
26
+ maxHeight: (maxHeight: Parameters<Node['setMaxHeight']>[0], node: Node) => void;
27
+ maxWidth: (maxWidth: Parameters<Node['setMaxWidth']>[0], node: Node) => void;
28
+ minHeight: (minHeight: Parameters<Node['setMinHeight']>[0], node: Node) => void;
29
+ minWidth: (minWidth: Parameters<Node['setMinWidth']>[0], node: Node) => void;
29
30
  /** As of now, this won't work since the bounding box is still computed by nodes marked as absolutely positioned */
30
- top: (top: Parameters<Node['setPosition']>[1], node: Node) => any;
31
- right: (right: Parameters<Node['setPosition']>[1], node: Node) => any;
32
- bottom: (bottom: Parameters<Node['setPosition']>[1], node: Node) => any;
33
- left: (left: Parameters<Node['setPosition']>[1], node: Node) => any;
34
- padding: (padding: Parameters<Node['setPadding']>[1], node: Node) => any;
35
- paddingTop: (paddingTop: Parameters<Node['setPadding']>[1], node: Node) => any;
36
- paddingRight: (paddingRight: Parameters<Node['setPadding']>[1], node: Node) => any;
37
- paddingBottom: (paddingBottom: Parameters<Node['setPadding']>[1], node: Node) => any;
38
- paddingLeft: (paddingLeft: Parameters<Node['setPadding']>[1], node: Node) => any;
39
- margin: (margin: Parameters<Node['setMargin']>[1], node: Node) => any;
40
- marginTop: (marginTop: Parameters<Node['setMargin']>[1], node: Node) => any;
41
- marginRight: (marginRight: Parameters<Node['setMargin']>[1], node: Node) => any;
42
- marginBottom: (marginBottom: Parameters<Node['setMargin']>[1], node: Node) => any;
43
- marginLeft: (marginLeft: Parameters<Node['setMargin']>[1], node: Node) => any;
44
- gap: (gap: Parameters<Node['setGap']>[1], node: Node) => any;
45
- gapColumn: (gapColumn: Parameters<Node['setGap']>[1], node: Node) => any;
46
- gapRow: (gapRow: Parameters<Node['setGap']>[1], node: Node) => any;
47
- aspectRatio: (aspectRatio: Parameters<Node['setAspectRatio']>[0], node: Node) => any;
31
+ top: (top: Parameters<Node['setPosition']>[1], node: Node) => void;
32
+ right: (right: Parameters<Node['setPosition']>[1], node: Node) => void;
33
+ bottom: (bottom: Parameters<Node['setPosition']>[1], node: Node) => void;
34
+ left: (left: Parameters<Node['setPosition']>[1], node: Node) => void;
35
+ padding: (padding: Parameters<Node['setPadding']>[1], node: Node) => void;
36
+ paddingTop: (paddingTop: Parameters<Node['setPadding']>[1], node: Node) => void;
37
+ paddingRight: (paddingRight: Parameters<Node['setPadding']>[1], node: Node) => void;
38
+ paddingBottom: (paddingBottom: Parameters<Node['setPadding']>[1], node: Node) => void;
39
+ paddingLeft: (paddingLeft: Parameters<Node['setPadding']>[1], node: Node) => void;
40
+ margin: (margin: Parameters<Node['setMargin']>[1], node: Node) => void;
41
+ marginTop: (marginTop: Parameters<Node['setMargin']>[1], node: Node) => void;
42
+ marginRight: (marginRight: Parameters<Node['setMargin']>[1], node: Node) => void;
43
+ marginBottom: (marginBottom: Parameters<Node['setMargin']>[1], node: Node) => void;
44
+ marginLeft: (marginLeft: Parameters<Node['setMargin']>[1], node: Node) => void;
45
+ gap: (gap: Parameters<Node['setGap']>[1], node: Node) => {
46
+ unit: Yoga.Unit;
47
+ value: number;
48
+ };
49
+ gapColumn: (gapColumn: Parameters<Node['setGap']>[1], node: Node) => {
50
+ unit: Yoga.Unit;
51
+ value: number;
52
+ };
53
+ gapRow: (gapRow: Parameters<Node['setGap']>[1], node: Node) => {
54
+ unit: Yoga.Unit;
55
+ value: number;
56
+ };
57
+ aspectRatio: (aspectRatio: Parameters<Node['setAspectRatio']>[0], node: Node) => void;
48
58
  };
49
59
  export type NodeProps = {
50
60
  [Key in keyof typeof propSetter]?: Parameters<(typeof propSetter)[Key]>[0];
@@ -1,3 +1,4 @@
1
+ import type { Node } from 'yoga-layout';
1
2
  import type { NodeProps } from './props';
2
3
  /**
3
4
  * Because all NodeProps are primitive types, we can make a simple comparison
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@threlte/flex",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.10",
4
4
  "author": "Grischa Erbe <hello@legrisch.com> (https://legrisch.com)",
5
5
  "license": "MIT",
6
+ "description": "Components to easily use the flexbox spec with Threlte",
6
7
  "devDependencies": {
7
8
  "@sveltejs/adapter-auto": "^3.2.0",
8
- "@sveltejs/kit": "^2.5.5",
9
- "@sveltejs/package": "^2.3.1",
9
+ "@sveltejs/kit": "^2.7.2",
10
+ "@sveltejs/package": "^2.3.7",
10
11
  "@sveltejs/vite-plugin-svelte": "^3.1.0",
11
12
  "@types/node": "^20.12.7",
12
- "@types/three": "^0.163.0",
13
+ "@types/three": "^0.169.0",
13
14
  "@typescript-eslint/eslint-plugin": "^7.6.0",
14
15
  "@typescript-eslint/parser": "^7.6.0",
15
16
  "@yushijinhun/three-minifier-rollup": "^0.4.0",
@@ -20,26 +21,43 @@
20
21
  "prettier-plugin-svelte": "^3.2.2",
21
22
  "publint": "^0.2.7",
22
23
  "rimraf": "^5.0.5",
23
- "svelte": "^5.0.0-next.95",
24
+ "svelte": "^5.1.6",
24
25
  "svelte-check": "^3.6.9",
25
26
  "svelte-preprocess": "^5.1.3",
26
27
  "svelte2tsx": "^0.7.6",
27
- "three": "^0.163.0",
28
+ "three": "^0.169.0",
28
29
  "tslib": "^2.6.2",
29
30
  "typescript": "^5.4.5",
30
31
  "vite": "^5.2.8",
31
- "@threlte/core": "8.0.0-next.2",
32
- "@threlte/extras": "9.0.0-next.2"
32
+ "@threlte/core": "8.0.0-next.23",
33
+ "@threlte/extras": "9.0.0-next.32"
33
34
  },
34
35
  "dependencies": {
35
36
  "mitt": "^3.0.1",
36
- "yoga-layout": "^2.0.1"
37
+ "yoga-layout": "^3.1.0"
37
38
  },
38
39
  "peerDependencies": {
39
40
  "svelte": ">=5",
40
- "three": ">=0.152"
41
+ "three": ">=0.155"
41
42
  },
42
43
  "type": "module",
44
+ "keywords": [
45
+ "flex",
46
+ "threlte",
47
+ "svelte",
48
+ "three",
49
+ "three.js",
50
+ "3d"
51
+ ],
52
+ "homepage": "https://threlte.xyz",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/threlte/threlte.git",
56
+ "directory": "packages/flex"
57
+ },
58
+ "bugs": {
59
+ "url": "https://github.com/threlte/threlte/issues"
60
+ },
43
61
  "exports": {
44
62
  ".": {
45
63
  "types": "./dist/index.d.ts",
@@ -56,8 +74,8 @@
56
74
  "package": "svelte-kit sync && svelte-package && node ./scripts/cleanupPackage.js && publint",
57
75
  "check": "svelte-check --tsconfig ./tsconfig.json",
58
76
  "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
59
- "lint": "prettier --check --plugin-search-dir=. . && eslint .",
60
- "format": "prettier --write --plugin-search-dir=. .",
77
+ "lint": "prettier --check .",
78
+ "format": "prettier --write .",
61
79
  "cleanup": "rimraf node_modules .svelte-kit dist"
62
80
  }
63
81
  }