uiconfig-blueprint 0.0.1
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/LICENSE +190 -0
- package/README.md +129 -0
- package/dist/ConfigObject.d.ts +16 -0
- package/dist/UiConfigRendererBlueprint.d.ts +13 -0
- package/dist/allPaths-PklnL3F6.js +23 -0
- package/dist/allPaths-PklnL3F6.js.map +1 -0
- package/dist/allPathsLoader-2dOu0jQ3.js +27 -0
- package/dist/allPathsLoader-2dOu0jQ3.js.map +1 -0
- package/dist/bpComponents/BPButtonComponent.d.ts +8 -0
- package/dist/bpComponents/BPColorInputComponent.d.ts +25 -0
- package/dist/bpComponents/BPComponent.d.ts +25 -0
- package/dist/bpComponents/BPContainerComponent.d.ts +21 -0
- package/dist/bpComponents/BPDropdownInputComponent.d.ts +16 -0
- package/dist/bpComponents/BPFileComponent.d.ts +26 -0
- package/dist/bpComponents/BPFolderComponent.d.ts +16 -0
- package/dist/bpComponents/BPInputComponent.d.ts +11 -0
- package/dist/bpComponents/BPLabelledComponent.d.ts +8 -0
- package/dist/bpComponents/BPNumberInputComponent.d.ts +11 -0
- package/dist/bpComponents/BPPanelComponent.d.ts +17 -0
- package/dist/bpComponents/BPSliderInputComponent.d.ts +15 -0
- package/dist/bpComponents/BPTextInputComponent.d.ts +8 -0
- package/dist/bpComponents/BPToggleInputComponent.d.ts +9 -0
- package/dist/bpComponents/BPTreeComponent.d.ts +32 -0
- package/dist/bpComponents/BPTreeFolderComponent.d.ts +10 -0
- package/dist/bpComponents/BPValueComponent.d.ts +16 -0
- package/dist/bpComponents/BPVectorInputComponent.d.ts +20 -0
- package/dist/components/DraggableIcon.d.ts +17 -0
- package/dist/components/ExtendedNumericInput.d.ts +23 -0
- package/dist/components/FileComponent.d.ts +7 -0
- package/dist/components/FormGroupComponent.d.ts +6 -0
- package/dist/components/InspectorStackComponent.d.ts +5 -0
- package/dist/components/VisualStyleContext.d.ts +110 -0
- package/dist/components/bpIconWrapper.d.ts +2 -0
- package/dist/components/variableIcons.d.ts +41 -0
- package/dist/contexts.d.ts +1 -0
- package/dist/index-PTojlie-.js +29271 -0
- package/dist/index-PTojlie-.js.map +1 -0
- package/dist/index-iM9IChdK.js +604 -0
- package/dist/index-iM9IChdK.js.map +1 -0
- package/dist/index-tqa0R-I0.js +604 -0
- package/dist/index-tqa0R-I0.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +292 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +12 -0
- package/dist/index.mjs.map +1 -0
- package/dist/splitPathsBySizeLoader-QNLjzk6A.js +36 -0
- package/dist/splitPathsBySizeLoader-QNLjzk6A.js.map +1 -0
- package/dist/threejs.d.ts +2 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +120 -0
- package/docs/assets/main.js +58 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1279 -0
- package/docs/classes/UI.html +403 -0
- package/docs/classes/UiConfigRendererBlueprint.html +404 -0
- package/docs/index.html +134 -0
- package/docs/modules.html +50 -0
- package/package.json +127 -0
- package/src/ConfigObject.tsx +137 -0
- package/src/UiConfigRendererBlueprint.tsx +85 -0
- package/src/bpComponents/BPButtonComponent.scss +8 -0
- package/src/bpComponents/BPButtonComponent.tsx +27 -0
- package/src/bpComponents/BPColorInputComponent.tsx +138 -0
- package/src/bpComponents/BPComponent.tsx +93 -0
- package/src/bpComponents/BPContainerComponent.tsx +57 -0
- package/src/bpComponents/BPDropdownInputComponent.tsx +80 -0
- package/src/bpComponents/BPFileComponent.tsx +73 -0
- package/src/bpComponents/BPFolderComponent.scss +107 -0
- package/src/bpComponents/BPFolderComponent.tsx +91 -0
- package/src/bpComponents/BPInputComponent.tsx +33 -0
- package/src/bpComponents/BPLabelledComponent.tsx +19 -0
- package/src/bpComponents/BPNumberInputComponent.tsx +35 -0
- package/src/bpComponents/BPPanelComponent.tsx +50 -0
- package/src/bpComponents/BPSliderInputComponent.tsx +71 -0
- package/src/bpComponents/BPTextInputComponent.tsx +26 -0
- package/src/bpComponents/BPToggleInputComponent.tsx +31 -0
- package/src/bpComponents/BPTreeComponent.scss +3 -0
- package/src/bpComponents/BPTreeComponent.tsx +127 -0
- package/src/bpComponents/BPTreeFolderComponent.tsx +31 -0
- package/src/bpComponents/BPValueComponent.tsx +46 -0
- package/src/bpComponents/BPVectorInputComponent.tsx +163 -0
- package/src/bpComponents/index.scss +3 -0
- package/src/components/DraggableIcon.tsx +75 -0
- package/src/components/ExtendedNumericInput.tsx +219 -0
- package/src/components/FileComponent.tsx +79 -0
- package/src/components/FormGroupComponent.tsx +22 -0
- package/src/components/InspectorStackComponent.tsx +72 -0
- package/src/components/VisualStyleContext.tsx +69 -0
- package/src/components/bpIconWrapper.tsx +20 -0
- package/src/components/common.scss +21 -0
- package/src/components/variableIcons.tsx +177 -0
- package/src/contexts.ts +1 -0
- package/src/index.ts +8 -0
- package/src/renderer.scss +193 -0
- package/src/threejs.ts +3 -0
- package/tsconfig.json +40 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {BPComponent, BPComponentProps, BPComponentState, UiConfigRendererContextType} from "./BPComponent";
|
|
2
|
+
|
|
3
|
+
export type BPLabelledComponentState = BPComponentState & {
|
|
4
|
+
label: string
|
|
5
|
+
}
|
|
6
|
+
export abstract class BPLabelledComponent<TValue, TState, TProps extends BPComponentProps<TValue> = BPComponentProps<TValue>> extends BPComponent<TValue, TState&BPLabelledComponentState, TProps> {
|
|
7
|
+
|
|
8
|
+
protected constructor(props: TProps, context: UiConfigRendererContextType, state: TState) {
|
|
9
|
+
super(props, context, {label: 'Input', ...state});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getUpdatedState(state: TState & BPLabelledComponentState): TState & BPLabelledComponentState {
|
|
13
|
+
return super.getUpdatedState({
|
|
14
|
+
...state,
|
|
15
|
+
label: this.context.methods.getLabel(this.props.config) || state.label,
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {BPInputComponent} from "./BPInputComponent";
|
|
4
|
+
import {ExtendedNumericInput} from "../components/ExtendedNumericInput";
|
|
5
|
+
import {BPValueComponentState} from "./BPValueComponent";
|
|
6
|
+
|
|
7
|
+
export class BPNumberInputComponent extends BPInputComponent<number> {
|
|
8
|
+
constructor(props: BPComponentProps<number>, context: UiConfigRendererContextType) {
|
|
9
|
+
super(props, context, {value: 0, label: 'Number'});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private _inputs = [React.createRef<ExtendedNumericInput>()]
|
|
13
|
+
|
|
14
|
+
async refreshConfigState(state?: BPValueComponentState<number>): Promise<void> {
|
|
15
|
+
await super.refreshConfigState(state);
|
|
16
|
+
await this._inputs[0].current?.setValue(this.state.value)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private _onChange = (v: number, last?: boolean) => {
|
|
20
|
+
this.setValue(v, last); // todo: set loading while this promise is happening.
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
renderInput() {
|
|
24
|
+
return (
|
|
25
|
+
<ExtendedNumericInput
|
|
26
|
+
className="numericInput"
|
|
27
|
+
disabled={this.state.disabled}
|
|
28
|
+
readOnly={this.state.readOnly}
|
|
29
|
+
defaultValue={this.state.value}
|
|
30
|
+
ref={this._inputs[0]}
|
|
31
|
+
key={this.props.config.uuid}
|
|
32
|
+
onChange2={this._onChange} fill={false}/>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {ConfigObject} from "../ConfigObject";
|
|
4
|
+
import {BPLabelledComponentState} from "./BPLabelledComponent";
|
|
5
|
+
import {PanelActions} from "@blueprintjs/core/lib/esm/components/panel-stack2/panelTypes";
|
|
6
|
+
import {UiObjectConfig} from 'uiconfig.js'
|
|
7
|
+
import {safeSetProperty} from 'ts-browser-helpers'
|
|
8
|
+
import {BPContainerComponent} from './BPContainerComponent'
|
|
9
|
+
|
|
10
|
+
export type BPPanelComponentState = BPLabelledComponentState & {
|
|
11
|
+
children: UiObjectConfig[]
|
|
12
|
+
expanded: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class BPPanelComponent extends BPContainerComponent<BPPanelComponentState> {
|
|
16
|
+
constructor(props: BPComponentProps<void>&PanelActions, context: UiConfigRendererContextType) {
|
|
17
|
+
super(props, context, {
|
|
18
|
+
children: [],
|
|
19
|
+
expanded: false,
|
|
20
|
+
label: 'Panel'
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setExpanded = (e: boolean) => {
|
|
25
|
+
if (e === this.state.expanded) return
|
|
26
|
+
this.setState({...this.state, expanded: e})
|
|
27
|
+
safeSetProperty(this.props.config, "expanded", e, true)
|
|
28
|
+
// if (e) this.state.children.forEach(c => Array.isArray(c) ? null : c.uiRefresh?.("postFrame", true, 1)) // todo: handle array and functions
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
componentDidMount() {
|
|
32
|
+
super.componentDidMount();
|
|
33
|
+
this.setExpanded(true)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
componentWillUnmount() {
|
|
37
|
+
this.setExpanded(false)
|
|
38
|
+
super.componentWillUnmount();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render() {
|
|
42
|
+
return !this.state.hidden ? (
|
|
43
|
+
<div
|
|
44
|
+
key={this.props.config.uuid}
|
|
45
|
+
className="folder-children" style={{listStyleType: "none", paddingLeft: "0"}}>
|
|
46
|
+
{this.state.children.map((c, i) => <ConfigObject key={'c' + i} {...this.props} config={c}/>)}
|
|
47
|
+
</div>
|
|
48
|
+
) : null
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {NumericInput, Slider} from "@blueprintjs/core";
|
|
4
|
+
import {BPInputComponent} from "./BPInputComponent";
|
|
5
|
+
import {BPValueComponentState} from "./BPValueComponent";
|
|
6
|
+
import {getOrCall} from "ts-browser-helpers";
|
|
7
|
+
|
|
8
|
+
export type BPSliderComponentState = BPValueComponentState<number> & {
|
|
9
|
+
min: number,
|
|
10
|
+
max: number,
|
|
11
|
+
step: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class BPSliderInputComponent extends BPInputComponent<number, BPSliderComponentState> {
|
|
15
|
+
constructor(props: BPComponentProps<number>, context: UiConfigRendererContextType) {
|
|
16
|
+
super(props, context, {
|
|
17
|
+
value: 0,
|
|
18
|
+
label: 'Slider',
|
|
19
|
+
min: 0,
|
|
20
|
+
max: 1,
|
|
21
|
+
step: 0.01,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getUpdatedState(state: BPSliderComponentState): BPSliderComponentState {
|
|
26
|
+
const bounds = getOrCall(this.props.config.bounds)
|
|
27
|
+
const max = (bounds?.length ?? 0) >= 2 ? bounds![1] : 1
|
|
28
|
+
const min = (bounds?.length ?? 0) >= 1 ? bounds![0] : 0
|
|
29
|
+
const step = getOrCall(this.props.config.stepSize) || (Math.pow(10, Math.floor(Math.log10((max - min) / 100))))
|
|
30
|
+
return super.getUpdatedState({
|
|
31
|
+
...state,
|
|
32
|
+
min, max, step
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
flexBasis = "75%"
|
|
37
|
+
|
|
38
|
+
renderInput() {
|
|
39
|
+
return [(
|
|
40
|
+
<Slider
|
|
41
|
+
value={Math.min(this.state.max, Math.max(this.state.min, this.state.value))}
|
|
42
|
+
key={this.props.config.uuid + '_slider'}
|
|
43
|
+
disabled={this.state.disabled}
|
|
44
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
45
|
+
labelRenderer={false}
|
|
46
|
+
// labelStepSize={(max - min)}
|
|
47
|
+
// labelValues={[]}
|
|
48
|
+
onChange={(v) => {
|
|
49
|
+
if(this.state.readOnly) return
|
|
50
|
+
this.setValue(v)
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
),(
|
|
54
|
+
<NumericInput
|
|
55
|
+
style={{maxWidth: "4rem", minWidth: "3rem"}}
|
|
56
|
+
// defaultValue={state}
|
|
57
|
+
disabled={this.state.disabled}
|
|
58
|
+
value={Math.min(this.state.max, Math.max(this.state.min, this.state.value))}
|
|
59
|
+
key={this.props.config.uuid + '_input'}
|
|
60
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
61
|
+
minorStepSize={this.state.step/10}
|
|
62
|
+
majorStepSize={this.state.step*10}
|
|
63
|
+
buttonPosition="none"
|
|
64
|
+
onValueChange={(v) => {
|
|
65
|
+
if(this.state.readOnly) return
|
|
66
|
+
this.setValue(v)
|
|
67
|
+
}}
|
|
68
|
+
/>)
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, {ChangeEventHandler} from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {InputGroup} from "@blueprintjs/core";
|
|
4
|
+
import {BPInputComponent} from "./BPInputComponent";
|
|
5
|
+
|
|
6
|
+
export class BPTextInputComponent extends BPInputComponent<string> {
|
|
7
|
+
constructor(props: BPComponentProps<string>, context: UiConfigRendererContextType) {
|
|
8
|
+
super(props, context, {value: '', label: 'Input'});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
private _onChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
12
|
+
this.setValue(e.target.value); // todo: set loading while this promise is happening.
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
renderInput() {
|
|
16
|
+
return (
|
|
17
|
+
<InputGroup
|
|
18
|
+
// defaultValue={this.state.value} // for uncontrolled usage, we will also need ref and set ref.value on change: https://reactjs.org/docs/uncontrolled-components.html
|
|
19
|
+
value={this.state.value}
|
|
20
|
+
disabled={this.state.disabled}
|
|
21
|
+
readOnly={this.state.readOnly}
|
|
22
|
+
key={this.props.config.uuid}
|
|
23
|
+
onChange={this._onChange}/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, {ChangeEventHandler} from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {Switch} from "@blueprintjs/core";
|
|
4
|
+
import {BPInputComponent} from "./BPInputComponent";
|
|
5
|
+
|
|
6
|
+
export class BPToggleInputComponent extends BPInputComponent<boolean> {
|
|
7
|
+
constructor(props: BPComponentProps<boolean>, context: UiConfigRendererContextType) {
|
|
8
|
+
super(props, context, {value: false, label: 'Input'});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
private _onChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
12
|
+
this.setValue(e.target.checked); // todo: set loading while this promise is happening.
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
renderInput() {
|
|
16
|
+
return (
|
|
17
|
+
<Switch alignIndicator="right" defaultChecked={this.state.value}
|
|
18
|
+
disabled={this.state.disabled} readOnly={this.state.readOnly}
|
|
19
|
+
label={this.state.label} onChange={this._onChange}
|
|
20
|
+
className="switch" innerLabelChecked="on" innerLabel="off"/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
render() {
|
|
25
|
+
return !this.state.hidden ? (
|
|
26
|
+
<div className="xPaddedContent folderContent" style={{flexBasis: "100%"}}>
|
|
27
|
+
{this.renderInput()}
|
|
28
|
+
</div>
|
|
29
|
+
) : null
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {BPComponent, BPComponentProps, BPComponentState, UiConfigRendererContextType} from "./BPComponent";
|
|
2
|
+
import {Tree, TreeNodeInfo} from "@blueprintjs/core";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
export type BPTreeComponentState<T = {}> = BPComponentState & {
|
|
6
|
+
nodes: TreeNodeInfo<T>[]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function forEachTreeNode<T>(nodes: TreeNodeInfo<T>[] | undefined, callback: (node: TreeNodeInfo<T>) => void) {
|
|
10
|
+
if (!nodes) return;
|
|
11
|
+
for (const node of nodes) {
|
|
12
|
+
callback(node);
|
|
13
|
+
forEachTreeNode(node.childNodes, callback);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export abstract class BPTreeComponent<T = {}, TConfigVal = void> extends BPComponent<TConfigVal, BPTreeComponentState<T>> {
|
|
18
|
+
constructor(props: BPComponentProps<TConfigVal>, context: UiConfigRendererContextType) {
|
|
19
|
+
super(props, context, {nodes: []});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected _infoMap = new Map<string, TreeNodeInfo<T>>()
|
|
23
|
+
|
|
24
|
+
protected _createNodeInfo(id: string, obj: T) {
|
|
25
|
+
return {
|
|
26
|
+
id,
|
|
27
|
+
label: 'unnamed',
|
|
28
|
+
nodeData: obj,
|
|
29
|
+
childNodes: [],
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected abstract _getNodeId(obj: T): string
|
|
34
|
+
|
|
35
|
+
protected abstract _updateNodeInfo(node: TreeNodeInfo<T>, obj: T): TreeNodeInfo<T>;
|
|
36
|
+
|
|
37
|
+
protected abstract _getRootNodes(): T[]
|
|
38
|
+
|
|
39
|
+
protected async _onNodeClick(_node: TreeNodeInfo<T>) {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected async _onNodeDoubleClick(_node: TreeNodeInfo<T>) {
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected async _onNodeExpand(node: TreeNodeInfo<T>) {
|
|
46
|
+
node.isExpanded = !node.isExpanded
|
|
47
|
+
await this.setStatePromise(this.state)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected async _onNodeCollapse(node: TreeNodeInfo<T>) {
|
|
51
|
+
node.isExpanded = !node.isExpanded
|
|
52
|
+
await this.setStatePromise(this.state)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected async _onNodeContextMenu(_node: TreeNodeInfo<T>) {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected buildData(data: TreeNodeInfo<T>[], obj: T, _?: any, _2?: any) {
|
|
59
|
+
if (!obj) return data
|
|
60
|
+
const id = this._getNodeId(obj)
|
|
61
|
+
if (!this._infoMap.has(id)) this._infoMap.set(id, this._createNodeInfo(id, obj))
|
|
62
|
+
const node = this._infoMap.get(id)!
|
|
63
|
+
const node2 = this._updateNodeInfo(node, obj)
|
|
64
|
+
if (node2 !== node) this._infoMap.set(id, node2)
|
|
65
|
+
data.push(node2)
|
|
66
|
+
return data
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getUpdatedState(_state: BPTreeComponentState<T>): BPTreeComponentState<T> {
|
|
70
|
+
if (!this._infoMap) this._infoMap = new Map()
|
|
71
|
+
const children = this._getRootNodes()
|
|
72
|
+
const nodes = children.map(c => {
|
|
73
|
+
return this.buildData([], c)[0]
|
|
74
|
+
}).filter(v => v)
|
|
75
|
+
console.log('update', nodes, children)
|
|
76
|
+
return super.getUpdatedState({
|
|
77
|
+
nodes
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
deselectAll() {
|
|
82
|
+
forEachTreeNode(this.state.nodes, (n) => n.isSelected = false)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async setSelected(node?: TreeNodeInfo<T>) {
|
|
86
|
+
this.deselectAll()
|
|
87
|
+
if (node) {
|
|
88
|
+
node.isSelected = true
|
|
89
|
+
await this.setStatePromise(this.state)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
componentDidMount() {
|
|
94
|
+
super.componentDidMount();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
componentWillUnmount() {
|
|
98
|
+
super.componentWillUnmount();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
render() {
|
|
102
|
+
console.log('render tree', this.state.nodes)
|
|
103
|
+
const TreeT = Tree.ofType<T>()
|
|
104
|
+
return !this.state.hidden ? (
|
|
105
|
+
<TreeT
|
|
106
|
+
contents={this.state.nodes}
|
|
107
|
+
className="folderContent"
|
|
108
|
+
onNodeExpand={(node, _path, _e) => {
|
|
109
|
+
this._onNodeExpand(node)
|
|
110
|
+
}}
|
|
111
|
+
onNodeCollapse={(node, _path, _e) => {
|
|
112
|
+
this._onNodeCollapse(node)
|
|
113
|
+
}}
|
|
114
|
+
onNodeClick={(node, _path, _e) => {
|
|
115
|
+
this._onNodeClick(node)
|
|
116
|
+
}}
|
|
117
|
+
onNodeDoubleClick={(node, _path, _e) => {
|
|
118
|
+
this._onNodeDoubleClick(node)
|
|
119
|
+
}}
|
|
120
|
+
onNodeContextMenu={(node, _path, _e) => {
|
|
121
|
+
this._onNodeContextMenu(node)
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
) : null
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {v4} from "uuid";
|
|
2
|
+
import {TreeNodeInfo} from "@blueprintjs/core";
|
|
3
|
+
import {BPTreeComponent} from "./BPTreeComponent";
|
|
4
|
+
import {UiObjectConfig} from 'uiconfig.js'
|
|
5
|
+
import {getOrCall} from 'ts-browser-helpers'
|
|
6
|
+
|
|
7
|
+
export class BPTreeFolderComponent extends BPTreeComponent<UiObjectConfig> {
|
|
8
|
+
|
|
9
|
+
protected _getNodeId(obj: UiObjectConfig) {
|
|
10
|
+
return obj.uuid || v4();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected _updateNodeInfo(node: TreeNodeInfo<UiObjectConfig>, obj: UiObjectConfig) {
|
|
14
|
+
node.label = getOrCall(obj.label) || 'unnamed'
|
|
15
|
+
node.childNodes = this.context.methods.getChildren(this.props.config).reduce<any[]>((...args) => this.buildData(...args), [])
|
|
16
|
+
return node;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected _getRootNodes(): UiObjectConfig[] {
|
|
20
|
+
return (this.props.config.children || []).map(c => getOrCall(c) || {}).flat(2) as UiObjectConfig[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected async _onNodeClick(_node: TreeNodeInfo<UiObjectConfig>) {
|
|
24
|
+
console.log("TODO: Tree node clicked")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
protected async _onNodeDoubleClick(_node: TreeNodeInfo<UiObjectConfig>) {
|
|
28
|
+
console.log("TODO: Tree node double clicked")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
2
|
+
import {BPLabelledComponent, BPLabelledComponentState} from "./BPLabelledComponent";
|
|
3
|
+
|
|
4
|
+
export type BPValueComponentState<TStateValue> = BPLabelledComponentState & {
|
|
5
|
+
value: TStateValue
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export abstract class BPValueComponent<TValue, TState extends BPValueComponentState<TStateValue>, TStateValue> extends BPLabelledComponent<TValue, TState> {
|
|
9
|
+
|
|
10
|
+
protected constructor(props: BPComponentProps<TValue>, context: UiConfigRendererContextType, state: TState) {
|
|
11
|
+
super(props, context, state);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
abstract convertValueToState(value: TValue, state: TState): TState;
|
|
15
|
+
|
|
16
|
+
abstract convertStateToValue(state: TState): Promise<TValue>;
|
|
17
|
+
|
|
18
|
+
getUpdatedState(state: TState): TState {
|
|
19
|
+
const val = this.context.methods.getValue(this.props.config)
|
|
20
|
+
state = super.getUpdatedState(state)
|
|
21
|
+
return val ? this.convertValueToState(val, state) : state
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected _previousLast = false
|
|
25
|
+
|
|
26
|
+
doesNeedRefresh(state: TState, _last?: boolean): boolean {
|
|
27
|
+
return this._previousLast !== _last || this.state.value !== state.value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async setValue(value: TStateValue, last?: boolean) {
|
|
31
|
+
return this.updateStateValue({...this.state, value}, last)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
forceOnChange: boolean = false
|
|
35
|
+
|
|
36
|
+
async updateStateValue(state: TState, last?: boolean) {
|
|
37
|
+
if (!this.doesNeedRefresh(state, last)) {
|
|
38
|
+
await this.setStatePromise(state)
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
let val = await this.convertStateToValue(state)
|
|
42
|
+
await this.context.methods.setValue(this.props.config, val, {last}, this.forceOnChange)
|
|
43
|
+
await this.refreshConfigState(state)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {BPComponentProps, UiConfigRendererContextType} from "./BPComponent";
|
|
3
|
+
import {BPInputComponent} from "./BPInputComponent";
|
|
4
|
+
import {BPValueComponentState} from "./BPValueComponent";
|
|
5
|
+
import type {Vector2, Vector3, Vector4} from "three";
|
|
6
|
+
import {ExtendedNumericInput} from "../components/ExtendedNumericInput";
|
|
7
|
+
import {wIcon3, xIcon3, yIcon3, zIcon3} from "../components/variableIcons";
|
|
8
|
+
import {getOrCall} from 'ts-browser-helpers'
|
|
9
|
+
|
|
10
|
+
export type BPVectorComponentState = BPValueComponentState<Vector2|Vector3|Vector4> & {
|
|
11
|
+
min: number,
|
|
12
|
+
max: number,
|
|
13
|
+
step: number,
|
|
14
|
+
components: 1|2|3|4,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vector4, BPVectorComponentState> {
|
|
18
|
+
constructor(props: BPComponentProps<Vector2|Vector3|Vector4>, context: UiConfigRendererContextType) {
|
|
19
|
+
super(props, context, {
|
|
20
|
+
value: new context.THREE!.Vector2(),
|
|
21
|
+
label: 'Vector',
|
|
22
|
+
min: -Infinity,
|
|
23
|
+
max: Infinity,
|
|
24
|
+
step: 0.01,
|
|
25
|
+
components: 2,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
forceOnChange: boolean = true
|
|
30
|
+
|
|
31
|
+
doesNeedRefresh(_: BPVectorComponentState): boolean {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getUpdatedState(state: BPVectorComponentState): BPVectorComponentState {
|
|
36
|
+
const bounds = getOrCall(this.props.config.bounds)
|
|
37
|
+
const max = (bounds?.length ?? 0) >= 2 ? bounds![1] : Infinity
|
|
38
|
+
const min = (bounds?.length ?? 0) >= 1 ? bounds![0] : -Infinity
|
|
39
|
+
const step = getOrCall(this.props.config.stepSize) || (isFinite(max) && isFinite(min) ? (Math.pow(10, Math.floor(Math.log10((max - min) / 100)))) : 0.01)
|
|
40
|
+
state = super.getUpdatedState({
|
|
41
|
+
...state,
|
|
42
|
+
min, max, step
|
|
43
|
+
});
|
|
44
|
+
// console.warn(state.value)
|
|
45
|
+
let com = this.props.config.type!.replace('vector', '').replace('vec', '')
|
|
46
|
+
let components: any = 0;
|
|
47
|
+
// console.log(com, components)
|
|
48
|
+
if(!com.length){
|
|
49
|
+
let v = state.value as any;
|
|
50
|
+
// console.log(v)
|
|
51
|
+
if(typeof v.w === "number") components = 4
|
|
52
|
+
else if (typeof v.z === "number") components = 3
|
|
53
|
+
else if (typeof v.y === "number") components = 2
|
|
54
|
+
else if (typeof v.x === "number") components = 1
|
|
55
|
+
} else {
|
|
56
|
+
components = Math.min(4, Math.max(1, parseInt(com)))
|
|
57
|
+
}
|
|
58
|
+
state.components = components
|
|
59
|
+
return state
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private _inputs = [React.createRef<ExtendedNumericInput>(), React.createRef<ExtendedNumericInput>(), React.createRef<ExtendedNumericInput>(), React.createRef<ExtendedNumericInput>()]
|
|
63
|
+
|
|
64
|
+
async refreshConfigState(state?: BPVectorComponentState): Promise<void> {
|
|
65
|
+
await super.refreshConfigState(state);
|
|
66
|
+
await this._inputs[0].current?.setValue(this.state.value.x)
|
|
67
|
+
await this._inputs[1].current?.setValue(this.state.value.y)
|
|
68
|
+
await this._inputs[2].current?.setValue((this.state.value as any).z)
|
|
69
|
+
await this._inputs[3].current?.setValue((this.state.value as any).w)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
renderInput() {
|
|
73
|
+
let ret = []
|
|
74
|
+
if (!this.state.value) return <></>;
|
|
75
|
+
|
|
76
|
+
// console.warn(this.state.value)
|
|
77
|
+
if (this.state.components > 0) {
|
|
78
|
+
const x = (
|
|
79
|
+
<ExtendedNumericInput
|
|
80
|
+
style={{maxWidth: "8rem", minWidth: "2rem"}}
|
|
81
|
+
disabled={this.state.disabled} readOnly={this.state.readOnly}
|
|
82
|
+
// defaultValue={state}
|
|
83
|
+
leftIcon={xIcon3}
|
|
84
|
+
value={this.state.value.x}
|
|
85
|
+
key={this.props.config.uuid + '_x'}
|
|
86
|
+
ref={this._inputs[0]}
|
|
87
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
88
|
+
minorStepSize={this.state.step / 10}
|
|
89
|
+
majorStepSize={this.state.step * 10}
|
|
90
|
+
buttonPosition="none"
|
|
91
|
+
onChange2={(v, last) => {
|
|
92
|
+
this.state.value.x = v
|
|
93
|
+
this.setValue(this.state.value, last) // todo: does need refresh?
|
|
94
|
+
}}
|
|
95
|
+
/>)
|
|
96
|
+
ret.push(x)
|
|
97
|
+
}
|
|
98
|
+
if(this.state.components>1) {
|
|
99
|
+
const y = (
|
|
100
|
+
<ExtendedNumericInput
|
|
101
|
+
style={{maxWidth: "8rem", minWidth: "2rem"}}
|
|
102
|
+
// defaultValue={state}
|
|
103
|
+
disabled={this.state.disabled} readOnly={this.state.readOnly}
|
|
104
|
+
value={this.state.value.y}
|
|
105
|
+
leftIcon={yIcon3}
|
|
106
|
+
key={this.props.config.uuid + '_y'}
|
|
107
|
+
ref={this._inputs[1]}
|
|
108
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
109
|
+
minorStepSize={this.state.step / 10}
|
|
110
|
+
majorStepSize={this.state.step * 10}
|
|
111
|
+
buttonPosition="none"
|
|
112
|
+
onChange2={(v, last) => {
|
|
113
|
+
this.state.value.y = v
|
|
114
|
+
this.setValue(this.state.value, last) // todo: does need refresh?
|
|
115
|
+
}}
|
|
116
|
+
/>)
|
|
117
|
+
ret.push(y)
|
|
118
|
+
}
|
|
119
|
+
if(this.state.components>2) {
|
|
120
|
+
const z = (
|
|
121
|
+
<ExtendedNumericInput
|
|
122
|
+
style={{maxWidth: "8rem", minWidth: "2rem"}}
|
|
123
|
+
// defaultValue={state}
|
|
124
|
+
disabled={this.state.disabled} readOnly={this.state.readOnly}
|
|
125
|
+
value={(this.state.value as Vector3|Vector4).z}
|
|
126
|
+
key={this.props.config.uuid + '_z'}
|
|
127
|
+
leftIcon={zIcon3}
|
|
128
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
129
|
+
ref={this._inputs[2]}
|
|
130
|
+
minorStepSize={this.state.step / 10}
|
|
131
|
+
majorStepSize={this.state.step * 10}
|
|
132
|
+
buttonPosition="none"
|
|
133
|
+
onChange2={(v, last) => {
|
|
134
|
+
(this.state.value as Vector3 | Vector4).z = v
|
|
135
|
+
this.setValue(this.state.value, last) // todo: does need refresh?
|
|
136
|
+
}}
|
|
137
|
+
/>)
|
|
138
|
+
ret.push(z)
|
|
139
|
+
}
|
|
140
|
+
if(this.state.components>3) {
|
|
141
|
+
const z = (
|
|
142
|
+
<ExtendedNumericInput
|
|
143
|
+
style={{maxWidth: "8rem", minWidth: "2rem"}}
|
|
144
|
+
// defaultValue={state}
|
|
145
|
+
disabled={this.state.disabled} readOnly={this.state.readOnly}
|
|
146
|
+
value={(this.state.value as Vector4).w}
|
|
147
|
+
key={this.props.config.uuid + '_w'}
|
|
148
|
+
leftIcon={wIcon3}
|
|
149
|
+
ref={this._inputs[3]}
|
|
150
|
+
min={this.state.min} max={this.state.max} stepSize={this.state.step}
|
|
151
|
+
minorStepSize={this.state.step / 10}
|
|
152
|
+
majorStepSize={this.state.step * 10}
|
|
153
|
+
buttonPosition="none"
|
|
154
|
+
onChange2={(v, last) => {
|
|
155
|
+
(this.state.value as Vector4).w = v
|
|
156
|
+
this.setValue(this.state.value, last) // todo: does need refresh?
|
|
157
|
+
}}
|
|
158
|
+
/>)
|
|
159
|
+
ret.push(z)
|
|
160
|
+
}
|
|
161
|
+
return ret
|
|
162
|
+
}
|
|
163
|
+
}
|