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 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 UriContext} from './context/uri';
|
||||
export {default as useProject} from './hooks/use-project';
|
||||
|
|
Loading…
Reference in New Issue
Block a user