aboutsummaryrefslogtreecommitdiff
path: root/src/console/components/console/Completion.tsx
blob: e2fa1de6e34c5f33abec8cfc1ae2e5bb168dd921 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import React from 'react';
import CompletionItem from './CompletionItem';
import CompletionTitle from './CompletionTitle';

interface Item {
  icon?: string;
  caption?: string;
  url?: string;
}

interface Group {
  name: string;
  items: Item[];
}

interface Props {
  select: number;
  size: number;
  completions: Group[];
}

interface State {
  viewOffset: number;
  select: number;
}

class Completion extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { viewOffset: 0, select: -1 };
  }

  static getDerivedStateFromProps(nextProps: Props, prevState: State) {
    if (prevState.select === nextProps.select) {
      return null;
    }

    const viewSelect = (() => {
      let index = 0;
      for (let i = 0; i < nextProps.completions.length; ++i) {
        ++index;
        const g = nextProps.completions[i];
        if (nextProps.select + i + 1 < index + g.items.length) {
          return nextProps.select + i + 1;
        }
        index += g.items.length;
      }
      return -1;
    })();

    let viewOffset = 0;
    if (nextProps.select < 0) {
      viewOffset = 0;
    } else if (prevState.select < nextProps.select) {
      viewOffset = Math.max(prevState.viewOffset,
        viewSelect - nextProps.size + 1);
    } else if (prevState.select > nextProps.select) {
      viewOffset = Math.min(prevState.viewOffset, viewSelect);
    }
    return { viewOffset, select: nextProps.select };
  }

  render() {
    let eles = [];
    let index = 0;

    for (const group of this.props.completions) {
      eles.push(<CompletionTitle
        key={`group-${index}`}
        title={ group.name }
      />);
      for (const item of group.items) {
        eles.push(<CompletionItem
          key={`item-${index}`}
          icon={item.icon}
          caption={item.caption}
          url={item.url}
          highlight={index === this.props.select}
        / >);
        ++index;
      }
    }

    const viewOffset = this.state.viewOffset;
    eles = eles.slice(viewOffset, viewOffset + this.props.size);

    return (
      <ul className='vimvixen-console-completion'>
        { eles }
      </ul>
    );
  }
}

export default Completion;