feat: Vector & VectorRange
This commit is contained in:
parent
a7a74a0775
commit
b4a879d573
104
packages/core/src/components/vector-range/index.jsx
Normal file
104
packages/core/src/components/vector-range/index.jsx
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
import {
|
||||||
|
PropTypes,
|
||||||
|
React,
|
||||||
|
useState,
|
||||||
|
} from '@latus/react';
|
||||||
|
|
||||||
|
import Vector from '../vector';
|
||||||
|
|
||||||
|
const VectorRange = ({
|
||||||
|
integer,
|
||||||
|
onChange,
|
||||||
|
range,
|
||||||
|
}) => {
|
||||||
|
const [isSingle, setIsSingle] = useState(Array.isArray(range));
|
||||||
|
return (
|
||||||
|
<div className="vector-range">
|
||||||
|
<Vector
|
||||||
|
integer={integer}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange?.(
|
||||||
|
isSingle
|
||||||
|
? value
|
||||||
|
: {
|
||||||
|
min: value,
|
||||||
|
max: range.max,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
vector={isSingle ? range : range.min}
|
||||||
|
/>
|
||||||
|
<label className="vector-range__to-label">
|
||||||
|
to
|
||||||
|
{isSingle && '?'}
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={!isSingle}
|
||||||
|
onChange={(event) => {
|
||||||
|
setIsSingle(!event.target.checked);
|
||||||
|
onChange?.(
|
||||||
|
!event.target.checked
|
||||||
|
? range.min
|
||||||
|
: {
|
||||||
|
min: range,
|
||||||
|
max: range,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{!isSingle && (
|
||||||
|
<Vector
|
||||||
|
integer={integer}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange?.({
|
||||||
|
min: range.min,
|
||||||
|
max: value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
vector={range.max}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createVectorRangePropType = (isRequired) => (props, propName, componentName) => {
|
||||||
|
const fail = (why) => new Error(
|
||||||
|
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
||||||
|
);
|
||||||
|
const range = props[propName];
|
||||||
|
if (!range && isRequired) {
|
||||||
|
return fail('Is required but missing');
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
'undefined' === typeof range.min
|
||||||
|
|| 'undefined' === typeof range.max
|
||||||
|
)
|
||||||
|
&& (
|
||||||
|
!Array.isArray(range)
|
||||||
|
|| 2 !== range.length
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return fail('Expected {min, max} or a Vector');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
export const vectorRangePropType = createVectorRangePropType(false);
|
||||||
|
vectorRangePropType.isRequired = createVectorRangePropType(true);
|
||||||
|
|
||||||
|
VectorRange.defaultProps = {
|
||||||
|
integer: false,
|
||||||
|
onChange: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
VectorRange.propTypes = {
|
||||||
|
integer: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
range: vectorRangePropType.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VectorRange;
|
11
packages/core/src/components/vector-range/index.scss
Normal file
11
packages/core/src/components/vector-range/index.scss
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.vector-range {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vector-range__to-label {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vector-range input[type="number"] {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
74
packages/core/src/components/vector/index.jsx
Normal file
74
packages/core/src/components/vector/index.jsx
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
import {PropTypes, React} from '@latus/react';
|
||||||
|
import Number from '../number';
|
||||||
|
|
||||||
|
const Vector = ({
|
||||||
|
integer,
|
||||||
|
labels,
|
||||||
|
onChange,
|
||||||
|
vector,
|
||||||
|
}) => (
|
||||||
|
<div className="vector">
|
||||||
|
<label>
|
||||||
|
{labels[0]}
|
||||||
|
<Number
|
||||||
|
integer={integer}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange?.([
|
||||||
|
value,
|
||||||
|
vector[1],
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
value={vector[0]}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
{labels[1]}
|
||||||
|
<Number
|
||||||
|
integer={integer}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange?.([
|
||||||
|
vector[0],
|
||||||
|
value,
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
value={vector[1]}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const createVectorPropType = (isRequired) => (props, propName, componentName) => {
|
||||||
|
const fail = (why) => new Error(
|
||||||
|
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
||||||
|
);
|
||||||
|
const vector = props[propName];
|
||||||
|
if (!vector && isRequired) {
|
||||||
|
return fail('Is required but missing');
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!Array.isArray(vector)
|
||||||
|
|| 2 !== vector.length
|
||||||
|
) {
|
||||||
|
return fail('Expected 2-length array vector');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
export const vectorPropType = createVectorPropType(false);
|
||||||
|
vectorPropType.isRequired = createVectorPropType(true);
|
||||||
|
|
||||||
|
Vector.defaultProps = {
|
||||||
|
integer: false,
|
||||||
|
onChange: null,
|
||||||
|
labels: ['X', 'Y'],
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector.propTypes = {
|
||||||
|
integer: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
labels: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
vector: vectorPropType.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Vector;
|
3
packages/core/src/components/vector/index.scss
Normal file
3
packages/core/src/components/vector/index.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.vector {
|
||||||
|
display: flex;
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ import {projects, user} from './state';
|
||||||
|
|
||||||
export {default as Number} from './components/number';
|
export {default as Number} from './components/number';
|
||||||
export {default as Range, rangePropType} from './components/range';
|
export {default as Range, rangePropType} from './components/range';
|
||||||
|
export {default as Vector, vectorPropType} from './components/vector';
|
||||||
|
export {default as VectorRange, vectorRangePropType} from './components/vector-range';
|
||||||
export {default as ProjectContext} from './context/project';
|
export {default as ProjectContext} from './context/project';
|
||||||
export {default as UriContext} from './context/uri';
|
export {default as UriContext} from './context/uri';
|
||||||
export {default as useProject} from './hooks/use-project';
|
export {default as useProject} from './hooks/use-project';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user