Commit 02a5ab2d by Vladislav Lagunov

Добавлен компонент Pagination

parent 1d693782
import * as React from 'react';
import * as classNames from 'classnames';
import Icon from '@material-ui/core/Icon';
import { fade } from '@material-ui/core/styles/colorManipulator';
import withStyles, { StyleRules, WithStyles } from '@material-ui/core/styles/withStyles';
import { Theme } from '@material-ui/core/styles/createMuiTheme';
import { sprintf, dcnpgettext, pgettext, Translations } from '../utils/gettext';
/** react props */
export interface Props {
ctx: { translations: Translations };
className?: string;
limit: number;
offset: number;
total: number;
listenKeyboard?: boolean;
reactHint?: boolean;
// коллбеки
onGotoNext?(): void; /// deprecated use `onOffsetChange`
onGotoPrev?(): void; /// deprecated use `onOffsetChange`
onOffsetChange?(offset: number): void;
}
class Pagination extends React.Component<Props & WithStyles> {
unlisten: Function|null = null;
componentDidMount() {
if (this.props.listenKeyboard === true) this.listenKeyboard();
}
componentWillUnmount() {
this.unlisten && this.unlisten();
}
componentWillReceiveProps(nextProps: Props) {
if (this.props.listenKeyboard && !nextProps.listenKeyboard) this.unlisten && this.unlisten();
if (!this.props.listenKeyboard && nextProps.listenKeyboard) this.listenKeyboard();
}
listenKeyboard() {
window.addEventListener('keydown', this.handleKeyDown);
this.unlisten = () => window.removeEventListener('keydown', this.handleKeyDown);
}
handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'ArrowRight' && e.ctrlKey) {
this.handleRight();
}
if (e.key === 'ArrowLeft' && e.ctrlKey) {
this.handleLeft();
}
if (e.key === 'ArrowUp' && e.ctrlKey) {
this.handleUp();
}
if (e.key === 'ArrowDown' && e.ctrlKey) {
this.handleDown();
}
};
handleLeft = () => {
const { offset, limit, onOffsetChange, onGotoPrev } = this.props;
if (offset <= 0) return;
onGotoPrev && onGotoPrev();
const nextOffset = Math.max(offset - limit, 0);
offset !== nextOffset && onOffsetChange && onOffsetChange(nextOffset);
}
handleRight = () => {
const { offset, limit, onOffsetChange, onGotoNext, total } = this.props;
const nextOffset = offset + limit;
if (nextOffset >= total) return;
onGotoNext && onGotoNext();
offset !== nextOffset && onOffsetChange && onOffsetChange(nextOffset);
};
handleUp = () => {
const { offset, limit, total, onOffsetChange } = this.props;
const nextOffset = total % limit === 0 ? total - limit : Math.floor(total / limit) * limit;
offset !== nextOffset && onOffsetChange && onOffsetChange(nextOffset);
};
handleDown = () => {
const { offset, onOffsetChange } = this.props;
offset !== 0 && onOffsetChange && onOffsetChange(0);
};
render() {
const { className: classNameProps, limit, offset, total, reactHint, listenKeyboard, classes, ctx } = this.props;
const __ = k => pgettext(ctx, 'pagination', k);
const nextDisabled = offset + limit >= total;
const prevDisabled = offset <= 0;
const to = offset + limit > total ? total : offset + limit;
const className = classNames(classes.root, classNameProps);
const prevClassName = classNames(classes.button, prevDisabled ? classes.disabled : undefined);
const nextClassName = classNames(classes.button, nextDisabled ? classes.disabled : undefined);
const itemsClaim = sprintf(
dcnpgettext(
ctx.translations,
'messages',
'pagination',
'<b>%d</b>&ndash;<b>%d</b> of <b>%d</b>',
'<b>%d</b>&ndash;<b>%d</b> of <b>%d</b>',
total,
),
offset + 1,
to,
total
);
const prevHint = reactHint && listenKeyboard ? __('Go back (CTRL+LEFT)') : undefined;
const nextHint = reactHint && listenKeyboard ? __('Go forward (CTRL+RIGHT)') : undefined;
return (
<div className={className}>
<span dangerouslySetInnerHTML={{ __html: itemsClaim }} className={classes.claim}/>
<div className={classes.navigationGroup}>
<span className={prevClassName} onClick={this.handleLeft} data-rh={prevHint}><Icon>navigate_before</Icon></span>
<span className={nextClassName} onClick={this.handleRight} data-rh={nextHint}><Icon>navigate_next</Icon></span>
</div>
</div>
);
}
}
export default withStyles(styles)(Pagination);
// Styles
export function styles(theme: Theme): StyleRules {
const { unit } = theme.spacing;
const borderRadius = 2;
const buttonHeight = 36;
const buttonWidth = buttonHeight * 1.0;
return {
root: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
navigationGroup: {
boxShadow: '0 1px 6px rgba(0,0,0,.12),0 1px 4px rgba(0,0,0,.12)',
background: 'white',
borderRadius: borderRadius,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
tratatata: '',
marginLeft: unit * 2,
'& > * + *': {
borderLeft: `solid 1px ${theme.palette.divider}`,
},
'& > *:first-child': {
borderLeft: 'none',
borderTopLeftRadius: borderRadius,
borderBottomLeftRadius: borderRadius,
},
'& > *:last-child': {
borderTopRightRadius: borderRadius,
borderBottomRightRadius: borderRadius,
},
},
claim: {
fontSize: 14,
color: theme.palette.text.primary,
'& b': {
fontWeight: 500,
},
},
button: {
height: buttonHeight,
width: buttonWidth,
textAlign: 'center',
background: 'white',
color: theme.palette.text.secondary,
userSelect: 'none',
cursor: 'pointer',
'&:hover': {
background: fade(theme.palette.text.primary, 0.1),
color: theme.palette.text.primary,
},
'& > *': {
display: 'inline-block',
verticalAlign: 'middle',
},
'&:after': {
content: '""',
display: 'inline-block',
verticalAlign: 'middle',
width: 0.1,
height: '100%',
}
},
disabled: {
background: 'white !important',
color: `${theme.palette.text.secondary} !important`,
cursor: 'not-allowed !important',
}
};
};
export * from './Pagination';
export { default } from './Pagination';
export * from '../maybe';
......@@ -7,5 +7,5 @@
"private": true,
"repository": "ssh://g@git.bitmaster.ru:34022/npm/common.git",
"author": "Vladislav Lagunov <lagunov@taximaster2.ru>",
"license": "MIT",
"license": "MIT"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment