aboutsummaryrefslogtreecommitdiff
path: root/src/console/components/console/Completion.tsx
blob: 9b4cf15efa8db5a08655ca74516effc633c68902 (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
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;