react-epoch-picker
Version:
A React UI component for choosing an date epoch, starting zoomed out at millenniums and going down through the centuries, decades and years.
109 lines (98 loc) • 3.57 kB
JavaScript
import React from "react";
import merge from "lodash.merge";
import PropTypes, {
selectedPropTypes,
dataPropTypes,
breadcrumbsLayoutPropTypes,
epochsLayoutPropTypes,
} from "./utils/propTypes";
import Breadcrumbs from "./components/Breadcrumbs";
import ArrayEpoch from "./components/ArrayEpoch";
import ObjectEpoch from "./components/ObjectEpoch";
import getSelected from "./utils/getSelected";
import nestedLookup from "./utils/nestedLookup";
import findEpochArrayIndex from "./utils/findEpochArrayIndex";
const defaultProps = {
layout: {
epochs: {
wrapper: (props) => <div {...props} />,
key: (props) => <button {...props} />,
step: (props) => <button {...props} />,
selectedStep: (props) => <button {...props} disabled style={{ opacity: 0.5 }} />,
},
breadcrumbs: {
wrapper: (props) => <div {...props} />,
spacer: (props) => (
<small {...props} style={{ opacity: 0.5 }}>
>
</small>
),
crumb: (props) => <span {...props} style={{ opacity: 0.5 }} />,
selectedCrumb: (props) => <span {...props} />,
},
},
};
/**
* the main EpochPicker component renders a list of epochs which can be traversed up or down to the desired granularity to find the epoch you want to select.
*/
const EpochPicker = function ({ data, selected, onChange, layout }) {
data = data instanceof Array ? data : [data];
const { keychain, values } = getSelected(data, selected);
const { activeEpoch, isFinal, isArray } = nestedLookup(data, keychain);
function onClickOption(value) {
if (isFinal) {
return;
}
const key = isArray ? findEpochArrayIndex(data, value) : activeEpoch.epochs.key;
onChange({
keychain: [...keychain, key],
values: { ...values, [key]: value },
key,
});
}
return (
<>
{isArray ? (
<ArrayEpoch
data={data}
activeEpoch={activeEpoch}
keychain={keychain}
values={values}
onClick={onClickOption}
isFinal={isFinal}
layout={merge({}, defaultProps.layout.epochs, layout.epochs || {})}
/>
) : (
<ObjectEpoch
data={data}
activeEpoch={activeEpoch}
keychain={keychain}
values={values}
onClick={onClickOption}
isFinal={isFinal}
layout={merge({}, defaultProps.layout.epochs, layout.epochs || {})}
/>
)}
<Breadcrumbs
data={data}
keychain={keychain}
values={values}
onChange={onChange}
layout={merge({}, defaultProps.layout.breadcrumbs, layout.breadcrumbs || {})}
/>
</>
);
};
EpochPicker.defaultProps = defaultProps;
EpochPicker.propTypes = {
// required
data: dataPropTypes.isRequired,
onChange: PropTypes.func.isRequired,
// optional
selected: selectedPropTypes,
layout: PropTypes.shape({
epochs: epochsLayoutPropTypes,
breadcrumbs: breadcrumbsLayoutPropTypes,
}),
};
export default EpochPicker;