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

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,4 @@
1
- import { SvelteComponent } from 'svelte'
2
- import type { NodeProps } from '../lib/props'
3
-
4
- type BoxProps = NodeProps & {
5
- order?: number | undefined
6
- class?: string
7
- }
8
-
9
- type BoxEvents = {
10
- reflow: {
11
- width: number
12
- height: number
13
- }
14
- }
15
-
16
- type BoxSlots = {
17
- default: {
18
- reflow: () => void
19
- width: number
20
- height: number
21
- }
22
- }
23
-
24
- export default class Box extends SvelteComponent<BoxProps, BoxEvents, BoxSlots> {}
1
+ /// <reference types="svelte" />
2
+ import type { BoxProps } from './types';
3
+ declare const Box: import("svelte").Component<BoxProps, {}, "">;
4
+ export default Box;
@@ -0,0 +1,17 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { NodeProps } from '../lib/props';
3
+ export type BoxProps = NodeProps & {
4
+ order?: number | undefined;
5
+ class?: string;
6
+ children?: Snippet<[
7
+ {
8
+ reflow: () => void;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ ]>;
13
+ onreflow?: (event: {
14
+ width: number;
15
+ height: number;
16
+ }) => void;
17
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -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, ref = $bindable(), ...props } = $props();
4
4
  let yoga = $state(undefined);
5
5
  const initialize = async () => {
6
6
  yoga = await loadYoga();
@@ -11,15 +11,11 @@ initialize();
11
11
  {#if yoga}
12
12
  <InnerFlex
13
13
  {yoga}
14
+ bind:ref
14
15
  {...props}
15
- let:reflow
16
- let:width
17
- let:height
18
16
  >
19
- <slot
20
- {reflow}
21
- {width}
22
- {height}
23
- />
17
+ {#snippet children({ reflow, width, height })}
18
+ {@render innerChildren?.({ reflow, width, height })}
19
+ {/snippet}
24
20
  </InnerFlex>
25
21
  {/if}
@@ -1,18 +1,4 @@
1
- import { SvelteComponent } from 'svelte'
2
- import type { ComponentEvents, ComponentProps } from 'svelte'
3
- import type InnerFlex from './InnerFlex.svelte'
4
-
5
- type FlexProps = Omit<ComponentProps<InnerFlex>, 'yoga'>
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> {}
1
+ /// <reference types="svelte" />
2
+ import type { FlexProps } from './types';
3
+ declare const Flex: import("svelte").Component<FlexProps, {}, "ref">;
4
+ export default Flex;
@@ -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,37 +1,4 @@
1
- import type { Stage } from '@threlte/core'
2
- import { SvelteComponent } from 'svelte'
3
- import type { Direction, Yoga } from 'yoga-layout'
4
- import type { ClassParser, FlexPlane, NodeProps } from '../lib/props'
5
-
6
- type InnerFlexProps = NodeProps & {
7
- yoga: Yoga
8
- width?: number
9
- height?: number
10
- plane?: FlexPlane
11
- direction?: keyof typeof Direction
12
- scaleFactor?: number
13
- class?: string
14
- classParser?: ClassParser
15
- reflowStage?: Stage
16
- }
17
-
18
- type InnerFlexEvents = {
19
- reflow: {
20
- width: number
21
- height: number
22
- }
23
- }
24
-
25
- type InnerFlexSlots = {
26
- default: {
27
- reflow: () => void
28
- width: number
29
- height: number
30
- }
31
- }
32
-
33
- export default class InnerFlex extends SvelteComponent<
34
- InnerFlexProps,
35
- InnerFlexEvents,
36
- InnerFlexSlots
37
- > {}
1
+ /// <reference types="svelte" />
2
+ import type { InnerFlexProps } from './types';
3
+ declare const InnerFlex: import("svelte").Component<InnerFlexProps, {}, "ref">;
4
+ export default InnerFlex;
@@ -0,0 +1,40 @@
1
+ import type { CurrentWritable } from '@threlte/core';
2
+ import { type Emitter } from 'mitt';
3
+ import type { Group } from 'three';
4
+ import type { Node } from 'yoga-layout';
5
+ import type Yoga from 'yoga-layout';
6
+ import type { Axis, ClassParser, NodeProps } from '../lib/props';
7
+ type FlexContextEvents = {
8
+ 'reflow:before': void;
9
+ 'reflow:after': void;
10
+ };
11
+ type FlexContextNode = {
12
+ node: Node;
13
+ group: Group;
14
+ props: NodeProps;
15
+ };
16
+ export type FlexContextData = {
17
+ yoga: typeof Yoga;
18
+ nodes: Map<Node, FlexContextNode>;
19
+ addNode: (node: Node, group: Group, props: NodeProps) => void;
20
+ updateNodeProps: (node: Node, props: NodeProps, force?: boolean) => void;
21
+ removeNode: (node: Node) => void;
22
+ scaleFactor: CurrentWritable<number>;
23
+ mainAxis: CurrentWritable<Axis>;
24
+ crossAxis: CurrentWritable<Axis>;
25
+ depthAxis: CurrentWritable<Axis>;
26
+ rootGroup: Group;
27
+ rootWidth: CurrentWritable<number>;
28
+ rootHeight: CurrentWritable<number>;
29
+ reflow: () => void;
30
+ classParser?: ClassParser;
31
+ };
32
+ export type FlexContext = FlexContextData & Emitter<FlexContextEvents> & {
33
+ onEvent: <Type extends keyof FlexContextEvents>(type: Type, callback: (payload: FlexContextEvents[Type]) => void) => void;
34
+ };
35
+ export declare const flexContextName = "__threlte-flex";
36
+ export declare const createFlexContext: (data: FlexContextData) => FlexContextData & Emitter<FlexContextEvents> & {
37
+ onEvent: <Type extends keyof FlexContextEvents>(type: Type, callback: (payload: FlexContextEvents[Type]) => void) => void;
38
+ };
39
+ export declare const useFlex: () => FlexContext;
40
+ export {};
@@ -0,0 +1,30 @@
1
+ import type { Stage } from '@threlte/core';
2
+ import type { Snippet } from 'svelte';
3
+ import type { Group } from 'three';
4
+ import type Yoga from 'yoga-layout';
5
+ import type { Direction } from 'yoga-layout';
6
+ import type { ClassParser, FlexPlane, NodeProps } from '../lib/props';
7
+ export type InnerFlexProps = NodeProps & {
8
+ yoga: typeof Yoga;
9
+ width?: number;
10
+ height?: number;
11
+ plane?: FlexPlane;
12
+ direction?: keyof typeof Direction;
13
+ scaleFactor?: number;
14
+ class?: string;
15
+ classParser?: ClassParser;
16
+ reflowStage?: Stage;
17
+ ref?: Group;
18
+ children?: Snippet<[
19
+ {
20
+ reflow: () => void;
21
+ width: number;
22
+ height: number;
23
+ }
24
+ ]>;
25
+ onreflow?: (event: {
26
+ width: number;
27
+ height: number;
28
+ }) => void;
29
+ };
30
+ export type FlexProps = Omit<InnerFlexProps, 'yoga'>;
@@ -0,0 +1 @@
1
+ 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.11",
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.33"
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
  }