1- import * as React from 'react'
1+ import React from 'react'
22
33import Mark , { MarkProps } from './Mark'
44import { selectionIsEmpty , selectionIsBackwards , splitTokensWithOffsets } from './utils'
5+ import { Span } from './span'
56
67interface TokenProps {
78 i : number
@@ -18,40 +19,26 @@ const Token: React.SFC<TokenProps> = props => {
1819 return < span data-i = { props . i } > { props . content } </ span >
1920}
2021
21- export interface TokenAnnotatorProps
22+ export interface TokenAnnotatorProps < T >
2223 extends Omit < React . HTMLAttributes < HTMLDivElement > , 'onChange' > {
2324 tokens : string [ ]
24- value : TokenSpan [ ]
25- onChange : ( value : TokenSpan [ ] ) => any
26- getSpan ?: ( span : TokenSpan ) => TokenSpan
25+ value : T [ ]
26+ onChange : ( value : T [ ] ) => any
27+ getSpan ?: ( span : TokenSpan ) => T
2728 renderMark ?: ( props : MarkProps ) => JSX . Element
2829 // TODO: determine whether to overwrite or leave intersecting ranges.
2930}
3031
31- // TODO: When React 16.3 types are ready, remove casts.
32- class TokenAnnotator extends React . Component < TokenAnnotatorProps , { } > {
33- static defaultProps = {
34- renderMark : props => < Mark { ...props } /> ,
35- }
36-
37- rootRef : React . RefObject < HTMLDivElement >
38-
39- constructor ( props ) {
40- super ( props )
41-
42- this . rootRef = React . createRef ( )
43- }
32+ const TokenAnnotator = < T extends Span > ( props : TokenAnnotatorProps < T > ) => {
33+ const renderMark = props . renderMark || ( props => < Mark { ...props } /> )
4434
45- componentDidMount ( ) {
46- this . rootRef . current . addEventListener ( 'mouseup' , this . handleMouseUp )
35+ const getSpan = ( span : TokenSpan ) : T => {
36+ if ( props . getSpan ) return props . getSpan ( span )
37+ return { start : span . start , end : span . end } as T
4738 }
4839
49- componentWillUnmount ( ) {
50- this . rootRef . current . removeEventListener ( 'mouseup' , this . handleMouseUp )
51- }
52-
53- handleMouseUp = ( ) => {
54- if ( ! this . props . onChange ) return
40+ const handleMouseUp = ( ) => {
41+ if ( ! props . onChange ) return
5542
5643 const selection = window . getSelection ( )
5744
@@ -74,48 +61,35 @@ class TokenAnnotator extends React.Component<TokenAnnotatorProps, {}> {
7461
7562 end += 1
7663
77- this . props . onChange ( [
78- ...this . props . value ,
79- this . getSpan ( { start, end, tokens : this . props . tokens . slice ( start , end ) } ) ,
80- ] )
64+ props . onChange ( [ ...props . value , getSpan ( { start, end, tokens : props . tokens . slice ( start , end ) } ) ] )
8165 window . getSelection ( ) . empty ( )
8266 }
8367
84- handleSplitClick = ( { start, end} ) => {
68+ const handleSplitClick = ( { start, end} ) => {
8569 // Find and remove the matching split.
86- const splitIndex = this . props . value . findIndex ( s => s . start === start && s . end === end )
70+ const splitIndex = props . value . findIndex ( s => s . start === start && s . end === end )
8771 if ( splitIndex >= 0 ) {
88- this . props . onChange ( [
89- ...this . props . value . slice ( 0 , splitIndex ) ,
90- ...this . props . value . slice ( splitIndex + 1 ) ,
91- ] )
72+ props . onChange ( [ ...props . value . slice ( 0 , splitIndex ) , ...props . value . slice ( splitIndex + 1 ) ] )
9273 }
9374 }
9475
95- getSpan = ( span : TokenSpan ) => {
96- if ( this . props . getSpan ) return this . props . getSpan ( span )
97- return span
98- }
99-
100- render ( ) {
101- const { tokens, value, renderMark, onChange, getSpan, ...divProps } = this . props
102- const splits = splitTokensWithOffsets ( tokens , value )
103- return (
104- < div ref = { this . rootRef } { ...divProps } >
105- { splits . map ( ( split , i ) =>
106- split . mark ? (
107- renderMark ( {
108- key : `${ split . start } -${ split . end } ` ,
109- ...split ,
110- onClick : this . handleSplitClick ,
111- } )
112- ) : (
113- < Token key = { split . i } { ...split } />
114- )
115- ) }
116- </ div >
117- )
118- }
76+ const { tokens, value, onChange, getSpan : _ , ...divProps } = props
77+ const splits = splitTokensWithOffsets ( tokens , value )
78+ return (
79+ < div { ...divProps } onMouseUp = { handleMouseUp } >
80+ { splits . map ( ( split , i ) =>
81+ split . mark ? (
82+ renderMark ( {
83+ key : `${ split . start } -${ split . end } ` ,
84+ ...split ,
85+ onClick : handleSplitClick ,
86+ } )
87+ ) : (
88+ < Token key = { split . i } { ...split } />
89+ )
90+ ) }
91+ </ div >
92+ )
11993}
12094
12195export default TokenAnnotator
0 commit comments