闭社主体 forked from https://github.com/tootsuite/mastodon
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.1 KiB

  1. import React from 'react';
  2. import ColumnHeader from './column_header';
  3. import PropTypes from 'prop-types';
  4. const easingOutQuint = (x, t, b, c, d) => c*((t=t/d-1)*t*t*t*t + 1) + b;
  5. const scrollTop = (node) => {
  6. const startTime = Date.now();
  7. const offset = node.scrollTop;
  8. const targetY = -offset;
  9. const duration = 1000;
  10. let interrupt = false;
  11. const step = () => {
  12. const elapsed = Date.now() - startTime;
  13. const percentage = elapsed / duration;
  14. if (percentage > 1 || interrupt) {
  15. return;
  16. }
  17. node.scrollTop = easingOutQuint(0, elapsed, offset, targetY, duration);
  18. requestAnimationFrame(step);
  19. };
  20. step();
  21. return () => {
  22. interrupt = true;
  23. };
  24. };
  25. class Column extends React.PureComponent {
  26. constructor (props, context) {
  27. super(props, context);
  28. this.handleHeaderClick = this.handleHeaderClick.bind(this);
  29. this.handleWheel = this.handleWheel.bind(this);
  30. this.setRef = this.setRef.bind(this);
  31. }
  32. handleHeaderClick () {
  33. const scrollable = this.node.querySelector('.scrollable');
  34. if (!scrollable) {
  35. return;
  36. }
  37. this._interruptScrollAnimation = scrollTop(scrollable);
  38. }
  39. handleWheel () {
  40. if (typeof this._interruptScrollAnimation !== 'undefined') {
  41. this._interruptScrollAnimation();
  42. }
  43. }
  44. setRef (c) {
  45. this.node = c;
  46. }
  47. render () {
  48. const { heading, icon, children, active, hideHeadingOnMobile } = this.props;
  49. let columnHeaderId = null
  50. let header = '';
  51. if (heading) {
  52. columnHeaderId = heading.replace(/ /g, '-')
  53. header = <ColumnHeader icon={icon} active={active} type={heading} onClick={this.handleHeaderClick} hideOnMobile={hideHeadingOnMobile} columnHeaderId={columnHeaderId}/>;
  54. }
  55. return (
  56. <div
  57. ref={this.setRef}
  58. role='region'
  59. aria-labelledby={columnHeaderId}
  60. className='column'
  61. onWheel={this.handleWheel}>
  62. {header}
  63. {children}
  64. </div>
  65. );
  66. }
  67. }
  68. Column.propTypes = {
  69. heading: PropTypes.string,
  70. icon: PropTypes.string,
  71. children: PropTypes.node,
  72. active: PropTypes.bool,
  73. hideHeadingOnMobile: PropTypes.bool
  74. };
  75. export default Column;