Skip to content

Commit 936485d

Browse files
committed
feat: refactor done
1 parent b40ce13 commit 936485d

31 files changed

+1182
-840
lines changed

README.md

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,39 @@ https://codesandbox.io/s/react-three-fiber-gui-62pvp
1313
Basic example
1414

1515
```tsx
16-
import { Controls, useControl } from 'react-three-gui';
16+
import { ControlsProvider, Controls, useControl } from 'react-three-gui';
1717

1818
export const App = () => {
1919
const rotationX = useControl('Rotation X', { type: 'number' });
2020
return (
21-
<>
22-
<Canvas>
23-
<mesh rotation-x={rotationX} />
24-
</Canvas>
25-
<Controls />
26-
</>
27-
);
21+
<ControlsProvider>
22+
<Canvas>
23+
<mesh rotation-x={rotationX} />
24+
</Canvas>
25+
<Controls />
26+
</ControlsProvider>
27+
);
2828
};
2929
```
3030

3131
Use the spring option to return a react-spring value:
32+
3233
```tsx
3334
useControl('My ctrl', {
3435
type: 'number',
3536
spring: true,
36-
})
37+
});
3738

3839
// or pass a react-spring configuration value
3940

4041
useControl('My ctrl', {
4142
type: 'number',
4243
spring: { mass: 5, tension: 280, friction: 50 },
43-
})
44+
});
4445
```
4546

4647
Also possible to pass in your own state:
48+
4749
```tsx
4850
const [value, set] = useState(0);
4951

@@ -54,11 +56,12 @@ useControl('Adjust value', {
5456
```
5557

5658
Also you can pass your own control component:
59+
5760
```tsx
58-
const MyControl = ({ control, value }) => (
61+
const MyControl = ({ value, setValue }) => (
5962
<input
6063
type="number"
61-
onChange={e => control.set(e.currentTarget.value)}
64+
onChange={e => setValue(e.currentTarget.value)}
6265
value={value}
6366
/>
6467
);
@@ -71,13 +74,14 @@ useControl('Test', {
7174
```
7275

7376
## API
77+
7478
```tsx
7579
import { useControl, Controls } from 'react-three-gui';
7680

7781
// All the possible options
7882
useControl(name: string, {
7983
// General
80-
type: 'number' | 'xypad' | 'boolean' | 'button' | 'color' | 'select' | 'string' | 'custom';
84+
type: 'number' | 'xypad' | 'boolean' | 'button' | 'color' | 'select' | 'string' | 'file' | 'custom';
8185
value: any; // Initial value
8286
spring: boolean | SpringConfig; // Use spring
8387
group: string; // Group name
@@ -96,12 +100,19 @@ useControl(name: string, {
96100
// button
97101
onClick(): void;
98102

103+
// file
104+
loader?: THREE.TextureLoader | THREE.FileLoader | etc;
105+
99106
// custom
100107
component?: React.Component;
101108
});
102109

103-
// Currently does not have any props
104-
<Controls />
110+
// Controls component
111+
<Controls
112+
title="Custom title"
113+
collapsed={true}
114+
defaultClosedGroups={['Other', 'Stuff']}
115+
/>
105116
```
106117

107118
## Supported controls
@@ -118,14 +129,17 @@ useControl(name: string, {
118129
- Returns `string` (as hex: #ffffff)
119130
- select
120131
- Returns `string`
132+
- file
133+
- Returns `new THREE.FileLoader`
121134
- string
122135
- Returns `string`
123136

124137
### Future plans
125138

126139
- [x] Support custom control components
127-
- [ ] Support passing refs and directly manipulate THREE objects
140+
- [x] File upload loader control
128141
- [x] Groups
129142
- [x] Draggable Widget
130-
- [ ] Collapsable widget
143+
- [x] Collapsable widget
144+
- [x] Persist state localstorage
131145
- [ ] Multi platform?

example/index.tsx

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,70 @@ import * as React from 'react';
22
import 'react-app-polyfill/ie11';
33
import * as ReactDOM from 'react-dom';
44
import { animated } from 'react-spring';
5-
import { a } from 'react-spring/three';
6-
import { Canvas } from 'react-three-fiber';
5+
import { a } from '@react-spring/three';
6+
import { Canvas, useLoader } from 'react-three-fiber';
77
import * as THREE from 'three';
8-
import { Controls, useControl } from '../src';
8+
import { Controls, ControlsProvider, useControl, BaseControl } from '../src';
99
import fontFile from './resources/unknown';
10+
import { useEffect } from 'react';
1011

1112
function Text({ children, size = 1, letterSpacing = 0.01, color = '#000000' }) {
12-
const [font] = React.useState(() => new THREE.FontLoader().parse(fontFile))
13+
const [font] = React.useState(() => new THREE.FontLoader().parse(fontFile));
1314
const [shapes, [x, y]] = React.useMemo(() => {
1415
let x = 0,
15-
y = 0
16-
let letters = [...children]
17-
let mat = new THREE.MeshBasicMaterial({ color, opacity: 1, transparent: true })
16+
y = 0;
17+
let letters = [...children];
18+
let mat = new THREE.MeshBasicMaterial({
19+
color,
20+
opacity: 1,
21+
transparent: true,
22+
});
1823
return [
1924
letters.map(letter => {
20-
const geom = new THREE.ShapeGeometry(font.generateShapes(letter, size, 1))
21-
geom.computeBoundingBox()
22-
const mesh = new THREE.Mesh(geom, mat)
23-
mesh.position.x = x
24-
x += geom.boundingBox.max.x + letterSpacing
25-
y = Math.max(y, geom.boundingBox.max.y)
26-
return mesh
25+
const geom = new THREE.ShapeGeometry(font.generateShapes(letter, size));
26+
geom.computeBoundingBox();
27+
const mesh = new THREE.Mesh(geom, mat);
28+
mesh.position.x = x;
29+
x += geom.boundingBox?.max?.x! + letterSpacing;
30+
y = Math.max(y, geom.boundingBox?.max?.y!);
31+
return mesh;
2732
}),
2833
[x, y],
29-
]
30-
}, [children])
34+
];
35+
}, [children]);
3136

3237
return (
3338
<group position={[-x / 2, -y / 2, 0]}>
3439
{shapes.map((shape, index) => (
3540
<primitive key={index} object={shape} />
3641
))}
3742
</group>
38-
)
43+
);
3944
}
4045

4146
const Next = () => {
42-
const rotationX = useControl('Mega', { group: 'Test', type: 'number', spring: true });
47+
const rotationX = useControl('Mega', {
48+
group: 'Test',
49+
type: 'number',
50+
spring: true,
51+
});
4352
return (
4453
<a.mesh position={[1.5, 0, 0]} rotation-x={rotationX}>
4554
<boxGeometry attach="geometry" args={[1, 1, 1]} />
4655
<meshStandardMaterial attach="material" />
4756
</a.mesh>
48-
)
57+
);
4958
};
5059

5160
const Box = () => {
52-
const rotationX = useControl('Rotate X', { group: 'Basic', type: 'number', spring: true });
61+
const ref = React.useRef<THREE.Mesh>();
62+
63+
const rotationX = useControl('Rotate X', {
64+
group: 'Basic',
65+
type: 'number',
66+
spring: true,
67+
});
68+
5369
const rotationY = useControl('Rotate Y', {
5470
type: 'number',
5571
group: 'Basic',
@@ -62,6 +78,11 @@ const Box = () => {
6278
mass: 2,
6379
},
6480
});
81+
const bool = useControl('Boolean', {
82+
group: 'More',
83+
type: 'boolean',
84+
});
85+
6586
const color = useControl('Material color', {
6687
type: 'color',
6788
group: 'Basic',
@@ -72,14 +93,10 @@ const Box = () => {
7293
value: { x: 0, y: 0 },
7394
distance: Math.PI,
7495
});
75-
const bool = useControl('Allowed', {
76-
group: 'More',
77-
type: 'boolean',
78-
});
7996
const dropdown = useControl('Pick one', {
8097
group: 'More',
8198
type: 'select',
82-
items: ['foo', 'bar', 'baz']
99+
items: ['foo', 'bar', 'baz'],
83100
});
84101
const str = useControl('Text', {
85102
group: 'More',
@@ -91,27 +108,22 @@ const Box = () => {
91108
type: 'button',
92109
onClick() {
93110
alert('Hello world');
94-
}
111+
},
95112
});
96113

97-
const MyControl = ({ control, value }) => (
98-
<label>Test:
99-
<input
100-
type="number"
101-
onChange={e => control.set(e.currentTarget.value)}
102-
value={value}
103-
/>
104-
</label>
105-
);
106-
107-
const size = useControl('Test', {
114+
const texture = useControl('Texture', {
108115
group: 'More',
109-
type: 'custom',
110-
value: 1,
111-
component: MyControl
116+
type: 'file',
117+
value: undefined,
118+
loader: new THREE.TextureLoader(),
112119
});
113120

114-
const ref = React.useRef<THREE.Mesh>();
121+
useEffect(() => {
122+
if (ref.current) {
123+
(ref.current.material as THREE.Material).needsUpdate = true;
124+
}
125+
}, [texture]);
126+
115127
return (
116128
<>
117129
<a.mesh
@@ -120,38 +132,48 @@ const Box = () => {
120132
rotation-x={rotationX}
121133
rotation-y={rotationY}
122134
>
123-
<boxGeometry attach="geometry" args={[size, size, size]} />
124-
<a.meshStandardMaterial attach="material"
125-
color={color}
126-
/>
135+
<boxGeometry attach="geometry" args={[1, 1, 1]} />
136+
<a.meshPhongMaterial attach="material" map={texture} color={color} />
127137
</a.mesh>
128138
<Text>{str}</Text>
129139
{dropdown === 'bar' && <Next />}
130140
</>
131-
)
132-
}
141+
);
142+
};
133143

134144
const Hello = () => {
135-
useControl('1', { type: 'number' });
136-
useControl('2', { type: 'number', max: 10 });
137-
useControl('3', { type: 'number', min: -5, max: 5, value: -2.5 });
138-
useControl('4', { type: 'number', min: 0, max: 200, value: 100 });
139-
useControl('5', { type: 'number', scrub: true });
140-
useControl('5', { type: 'number', scrub: true, distance: 1000 });
141-
return (<animated.div style={{ width: 100, height: 100, background: 'red' }} />)
145+
const a1 = useControl('1', { type: 'number' });
146+
const a2 = useControl('2', { type: 'number', max: 10 });
147+
const a3 = useControl('3', { type: 'number', min: -5, max: 5, value: -2.5 });
148+
const a4 = useControl('4', { type: 'number', min: 0, max: 200, value: 100 });
149+
const a5 = useControl('5', { type: 'number', scrub: true });
150+
const a6 = useControl('6', { type: 'number', scrub: true, distance: 1000 });
151+
return (
152+
<animated.div style={{ width: 180, background: 'orange', padding: 20 }}>
153+
<p>This is a div</p>
154+
<div>1: {a1}</div>
155+
<div>2: {a2}</div>
156+
<div>3: {a3}</div>
157+
<div>4: {a4}</div>
158+
<div>5: {a5}</div>
159+
<div>6: {a6}</div>
160+
</animated.div>
161+
);
142162
};
143163

144164
const App = () => {
145165
return (
146-
<div>
166+
<ControlsProvider>
147167
<Canvas style={{ width: 800, height: 600 }}>
148168
<ambientLight intensity={1} />
149169
<pointLight position={[0, 2, 2]} />
150-
<Box />
170+
<React.Suspense fallback={null}>
171+
<Box />
172+
</React.Suspense>
151173
</Canvas>
152-
<Controls />
153174
<Hello />
154-
</div>
175+
<Controls />
176+
</ControlsProvider>
155177
);
156178
};
157179

example/package.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,25 @@
88
"build": "parcel build index.html"
99
},
1010
"dependencies": {
11-
"react-app-polyfill": "^1.0.0",
11+
"react": ">= 16.8.0",
12+
"react-app-polyfill": "^1.0.6",
13+
"react-dom": ">= 16.8.0",
14+
"react-spring": "^8.0.27",
1215
"react-three-fiber": "^4.2.20",
13-
"three": "^0.119.1",
16+
"three": "^0.120.0",
1417
"trim-right": "^1.0.1"
1518
},
1619
"alias": {
1720
"react": "../node_modules/react",
1821
"react-dom": "../node_modules/react-dom/profiling",
1922
"scheduler/tracing": "../node_modules/scheduler/tracing-profiling",
20-
"react-spring": "../node_modules/react-spring"
23+
"@react-spring/web": "../node_modules/@react-spring/web",
24+
"@react-spring/three": "../node_modules/@react-spring/three"
2125
},
2226
"devDependencies": {
23-
"@types/react": "^16.8.15",
24-
"@types/react-dom": "^16.8.4",
27+
"@types/react": "^16.9.48",
28+
"@types/react-dom": "^16.9.8",
2529
"parcel": "^1.12.4",
26-
"typescript": "^3.9.7"
30+
"typescript": "^4.0.2"
2731
}
2832
}

0 commit comments

Comments
 (0)