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.
Files changed (97) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +129 -0
  3. package/dist/ConfigObject.d.ts +16 -0
  4. package/dist/UiConfigRendererBlueprint.d.ts +13 -0
  5. package/dist/allPaths-PklnL3F6.js +23 -0
  6. package/dist/allPaths-PklnL3F6.js.map +1 -0
  7. package/dist/allPathsLoader-2dOu0jQ3.js +27 -0
  8. package/dist/allPathsLoader-2dOu0jQ3.js.map +1 -0
  9. package/dist/bpComponents/BPButtonComponent.d.ts +8 -0
  10. package/dist/bpComponents/BPColorInputComponent.d.ts +25 -0
  11. package/dist/bpComponents/BPComponent.d.ts +25 -0
  12. package/dist/bpComponents/BPContainerComponent.d.ts +21 -0
  13. package/dist/bpComponents/BPDropdownInputComponent.d.ts +16 -0
  14. package/dist/bpComponents/BPFileComponent.d.ts +26 -0
  15. package/dist/bpComponents/BPFolderComponent.d.ts +16 -0
  16. package/dist/bpComponents/BPInputComponent.d.ts +11 -0
  17. package/dist/bpComponents/BPLabelledComponent.d.ts +8 -0
  18. package/dist/bpComponents/BPNumberInputComponent.d.ts +11 -0
  19. package/dist/bpComponents/BPPanelComponent.d.ts +17 -0
  20. package/dist/bpComponents/BPSliderInputComponent.d.ts +15 -0
  21. package/dist/bpComponents/BPTextInputComponent.d.ts +8 -0
  22. package/dist/bpComponents/BPToggleInputComponent.d.ts +9 -0
  23. package/dist/bpComponents/BPTreeComponent.d.ts +32 -0
  24. package/dist/bpComponents/BPTreeFolderComponent.d.ts +10 -0
  25. package/dist/bpComponents/BPValueComponent.d.ts +16 -0
  26. package/dist/bpComponents/BPVectorInputComponent.d.ts +20 -0
  27. package/dist/components/DraggableIcon.d.ts +17 -0
  28. package/dist/components/ExtendedNumericInput.d.ts +23 -0
  29. package/dist/components/FileComponent.d.ts +7 -0
  30. package/dist/components/FormGroupComponent.d.ts +6 -0
  31. package/dist/components/InspectorStackComponent.d.ts +5 -0
  32. package/dist/components/VisualStyleContext.d.ts +110 -0
  33. package/dist/components/bpIconWrapper.d.ts +2 -0
  34. package/dist/components/variableIcons.d.ts +41 -0
  35. package/dist/contexts.d.ts +1 -0
  36. package/dist/index-PTojlie-.js +29271 -0
  37. package/dist/index-PTojlie-.js.map +1 -0
  38. package/dist/index-iM9IChdK.js +604 -0
  39. package/dist/index-iM9IChdK.js.map +1 -0
  40. package/dist/index-tqa0R-I0.js +604 -0
  41. package/dist/index-tqa0R-I0.js.map +1 -0
  42. package/dist/index.d.ts +4 -0
  43. package/dist/index.js +292 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/index.mjs +12 -0
  46. package/dist/index.mjs.map +1 -0
  47. package/dist/splitPathsBySizeLoader-QNLjzk6A.js +36 -0
  48. package/dist/splitPathsBySizeLoader-QNLjzk6A.js.map +1 -0
  49. package/dist/threejs.d.ts +2 -0
  50. package/docs/.nojekyll +1 -0
  51. package/docs/assets/highlight.css +120 -0
  52. package/docs/assets/main.js +58 -0
  53. package/docs/assets/search.js +1 -0
  54. package/docs/assets/style.css +1279 -0
  55. package/docs/classes/UI.html +403 -0
  56. package/docs/classes/UiConfigRendererBlueprint.html +404 -0
  57. package/docs/index.html +134 -0
  58. package/docs/modules.html +50 -0
  59. package/package.json +127 -0
  60. package/src/ConfigObject.tsx +137 -0
  61. package/src/UiConfigRendererBlueprint.tsx +85 -0
  62. package/src/bpComponents/BPButtonComponent.scss +8 -0
  63. package/src/bpComponents/BPButtonComponent.tsx +27 -0
  64. package/src/bpComponents/BPColorInputComponent.tsx +138 -0
  65. package/src/bpComponents/BPComponent.tsx +93 -0
  66. package/src/bpComponents/BPContainerComponent.tsx +57 -0
  67. package/src/bpComponents/BPDropdownInputComponent.tsx +80 -0
  68. package/src/bpComponents/BPFileComponent.tsx +73 -0
  69. package/src/bpComponents/BPFolderComponent.scss +107 -0
  70. package/src/bpComponents/BPFolderComponent.tsx +91 -0
  71. package/src/bpComponents/BPInputComponent.tsx +33 -0
  72. package/src/bpComponents/BPLabelledComponent.tsx +19 -0
  73. package/src/bpComponents/BPNumberInputComponent.tsx +35 -0
  74. package/src/bpComponents/BPPanelComponent.tsx +50 -0
  75. package/src/bpComponents/BPSliderInputComponent.tsx +71 -0
  76. package/src/bpComponents/BPTextInputComponent.tsx +26 -0
  77. package/src/bpComponents/BPToggleInputComponent.tsx +31 -0
  78. package/src/bpComponents/BPTreeComponent.scss +3 -0
  79. package/src/bpComponents/BPTreeComponent.tsx +127 -0
  80. package/src/bpComponents/BPTreeFolderComponent.tsx +31 -0
  81. package/src/bpComponents/BPValueComponent.tsx +46 -0
  82. package/src/bpComponents/BPVectorInputComponent.tsx +163 -0
  83. package/src/bpComponents/index.scss +3 -0
  84. package/src/components/DraggableIcon.tsx +75 -0
  85. package/src/components/ExtendedNumericInput.tsx +219 -0
  86. package/src/components/FileComponent.tsx +79 -0
  87. package/src/components/FormGroupComponent.tsx +22 -0
  88. package/src/components/InspectorStackComponent.tsx +72 -0
  89. package/src/components/VisualStyleContext.tsx +69 -0
  90. package/src/components/bpIconWrapper.tsx +20 -0
  91. package/src/components/common.scss +21 -0
  92. package/src/components/variableIcons.tsx +177 -0
  93. package/src/contexts.ts +1 -0
  94. package/src/index.ts +8 -0
  95. package/src/renderer.scss +193 -0
  96. package/src/threejs.ts +3 -0
  97. 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,3 @@
1
+ .bpTreeComponent {
2
+ width: 100%;
3
+ }
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ @import "BPButtonComponent";
2
+ @import "BPFolderComponent";
3
+ @import "BPTreeComponent";