Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"parser": "babel-eslint",
"plugins": [
"react",
"css-modules"
"css-modules",
"react-hooks"
],
"extends": [
"plugin:react/recommended",
Expand All @@ -14,6 +15,8 @@
"node": true,
},
"rules": {
"react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
"react-hooks/exhaustive-deps": "warn", // Checks effect dependencies
"prefer-const": 1,
"space-infix-ops": ["error", {"int32Hint": false}],
"no-unused-expressions": "error",
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
.env.development.local
.env.test.local
.env.production.local
.vscode

npm-debug.log*
yarn-debug.log*
Expand Down Expand Up @@ -113,3 +114,4 @@ stats.json
*.vtt
*.ttml
*.itt
.vscode
9,925 changes: 5,459 additions & 4,466 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@
"publish:dry:run": "npm publish --dry-run"
},
"jest": {
"setupFilesAfterEnv": [
"<rootDir>packages/components/setupTests.js"
],
"moduleFileExtensions": [
"js",
"jsx"
"jsx",
"json"
],
"moduleDirectories": [
"node_modules"
Expand All @@ -54,6 +58,8 @@
"mousetrap": "1.5.2",
"number-to-words": "^1.2.4",
"prop-types": "^15.6.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-fast-compare": "^2.0.4",
"react-keyboard-shortcuts": "^1.1.3",
"react-simple-tooltip": "^2.3.3",
Expand All @@ -78,28 +84,35 @@
"@storybook/addon-viewport": "^5.0.8",
"@storybook/addons": "^5.0.8",
"@storybook/react": "^5.0.8",
"@testing-library/dom": "^6.2.0",
"@testing-library/react": "^9.1.4",
"babel-eslint": "^10.0.1",
"babel-jest": "^24.7.1",
"babel-loader": "^8.0.5",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-minify": "^0.5.0",
"chai": "^4.2.0",
"css-loader": "^2.1.1",
"enzyme": "^3.7.0",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"eslint": "^5.16.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-css-modules": "^2.11.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-react": "^7.12.4",
"eslint-plugin-react": "^7.14.3",
"eslint-plugin-react-hooks": "^2.0.1",
"gh-pages": "^2.0.1",
"husky": "^1.1.3",
"jest": "^24.7.1",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0",
"prettier-stylelint": "^0.4.2",
"react-test-renderer": "^16.9.0",
"react-testing-library": "^5.2.3",
"regenerator-runtime": "^0.12.1",
"rimraf": "^2.6.2",
"sass-loader": "^7.1.0",
"sinon": "^7.4.2",
"style-loader": "^0.23.1",
"stylelint-config-standard": "^18.2.0",
"webpack": "^4.29.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/media-player/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,4 @@ MediaPlayer.propTypes = {
handleSaveTranscript: PropTypes.func
};

export default hotkeys(MediaPlayer);
export default hotkeys(MediaPlayer);
20 changes: 10 additions & 10 deletions packages/components/media-player/src/PlayerControls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,22 @@ class PlayerControls extends React.Component {
}

PlayerControls.propTypes = {
playMedia: PropTypes.func,
currentTime: PropTypes.string,
timecodeOffset: PropTypes.string,
promptSetCurrentTime: PropTypes.func,
rollback: PropTypes.func,
handleMuteVolume: PropTypes.func,
duration: PropTypes.string,
isPlaying: PropTypes.bool,
handleMuteVolume: PropTypes.func,
handleSaveTranscript: PropTypes.func,
isMute: PropTypes.bool,
skipBackward: PropTypes.func,
skipForward: PropTypes.func,
isPlaying: PropTypes.bool,
pictureInPicture: PropTypes.func,
playMedia: PropTypes.func,
playbackRate: PropTypes.number,
playbackRateOptions: PropTypes.array,
promptSetCurrentTime: PropTypes.func,
rollback: PropTypes.func,
setPlayBackRate: PropTypes.func,
pictureInPicture: PropTypes.func,
handleSaveTranscript: PropTypes.func
skipBackward: PropTypes.func,
skipForward: PropTypes.func,
timecodeOffset: PropTypes.string
};

export default PlayerControls;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ function returnHotKeys(self) {
priority: 1,
handler: () => {
self.togglePlayMedia();

self.props.handleAnalyticsEvents({
category: 'defaultHotKeys',
action: 'alt+k',
Expand Down
5 changes: 5 additions & 0 deletions packages/components/setupTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// setup file
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });
31 changes: 31 additions & 0 deletions packages/components/timed-text-editor/MemoEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import PropTypes from 'prop-types';

import {
Editor,
} from 'draft-js';

const MemoEditor = (props) => {

return (
<Editor data-testid="editor"
editorState={ props.editorState }
onChange={ props.onChange }
stripPastedStyles
blockRendererFn={ props.blockRendererFn }
handleKeyCommand={ props.handleKeyCommand }
keyBindingFn={ props.keyBindingFn }
spellCheck={ props.spellCheck }
/>);
};

MemoEditor.propTypes = {
keyBindingFn: PropTypes.any,
editorState: PropTypes.any,
handleKeyCommand: PropTypes.any,
onChange: PropTypes.any,
blockRendererFn: PropTypes.any,
spellCheck: PropTypes.any
};

export default React.memo(MemoEditor);
155 changes: 58 additions & 97 deletions packages/components/timed-text-editor/WrapperBlock.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import { EditorBlock, Modifier, EditorState, SelectionState } from 'draft-js';

import SpeakerLabel from './SpeakerLabel';
// import { shortTimecode, secondsToTimecode } from '../../Util/timecode-converter/';
import PropTypes from 'prop-types';

import {
shortTimecode,
Expand All @@ -11,60 +11,22 @@ import {

import style from './WrapperBlock.module.css';

class WrapperBlock extends React.Component {
constructor(props) {
super(props);
const WrapperBlock = (props) => {
const [ speaker, setSpeaker ] = useState(props.block.getData().get('speaker'));
const [ startTimecode, setStartTimeCode ] = useState(props.block.getData().get('start'));
const timecodeOffset = props.blockProps.timecodeOffset;

this.state = {
speaker: '',
start: 0,
timecodeOffset: this.props.blockProps.timecodeOffset
};
if (timecodeOffset) {
setStartTimeCode(() => startTimecode + timecodeOffset);
}

componentDidMount() {
const { block } = this.props;
const speaker = block.getData().get('speaker');

const start = block.getData().get('start');

this.setState({
speaker: speaker,
start: start
});
}
// reducing unnecessary re-renders
shouldComponentUpdate = (nextProps, nextState) => {
if (nextProps.block.getText() !== this.props.block.getText()) {
return true;
}

if (nextProps.blockProps.showSpeakers !== this.props.blockProps.showSpeakers) {
return true;
}

if (nextProps.blockProps.showTimecodes !== this.props.blockProps.showTimecodes) {
return true;
}

if (nextProps.blockProps.timecodeOffset !== this.props.blockProps.timecodeOffset) {
return true;
}

if (nextState.speaker !== this.state.speaker) {
return true;
}

return false;
};

handleOnClickEdit = () => {
const handleOnClickEdit = () => {
const newSpeakerName = prompt('New Speaker Name?');

if (newSpeakerName !== '' && newSpeakerName !== null) {
this.setState({ speaker: newSpeakerName });
if (this.props.blockProps.handleAnalyticsEvents) {
this.props.blockProps.handleAnalyticsEvents({
if (newSpeakerName && newSpeakerName !== '') {
setSpeaker(newSpeakerName);
if (props.blockProps.handleAnalyticsEvents) {
props.blockProps.handleAnalyticsEvents({
category: 'WrapperBlock',
action: 'handleOnClickEdit',
name: 'newSpeakerName',
Expand All @@ -78,12 +40,13 @@ class WrapperBlock extends React.Component {
// and the offset value is the character offset within the block.

// Get key of the currentBlock
const keyForCurrentCurrentBlock = this.props.block.getKey();
const keyForCurrentCurrentBlock = props.block.getKey();
// create empty selection for current block
// https://draftjs.org/docs/api-reference-selection-state#createempty
const currentBlockSelection = SelectionState.createEmpty(
keyForCurrentCurrentBlock
);

const editorStateWithSelectedCurrentBlock = EditorState.acceptSelection(
this.props.blockProps.editorState,
currentBlockSelection
Expand All @@ -94,63 +57,61 @@ class WrapperBlock extends React.Component {

// https://draftjs.org/docs/api-reference-modifier#mergeblockdata
const newContentState = Modifier.mergeBlockData(
this.props.contentState,
props.contentState,
currentBlockSelectionState,
newBlockDataWithSpeakerName
);

this.props.blockProps.setEditorNewContentState(newContentState);
props.blockProps.setEditorNewContentState(newContentState);
}
};

handleTimecodeClick = () => {
this.props.blockProps.onWordClick(this.state.start);
if (this.props.blockProps.handleAnalyticsEvents) {
this.props.blockProps.handleAnalyticsEvents({
const handleTimecodeClick = () => {
props.blockProps.onWordClick(startTimecode);

if (props.blockProps.handleAnalyticsEvents) {
props.blockProps.handleAnalyticsEvents({
category: 'WrapperBlock',
action: 'handleTimecodeClick',
name: 'onWordClick',
value: secondsToTimecode(this.state.start)
value: secondsToTimecode(startTimecode)
});
}
};

render() {
// console.log('render wrapper block');
let startTimecode = this.state.start;
if (this.props.blockProps.timecodeOffset) {
startTimecode += this.props.blockProps.timecodeOffset;
}

const speakerElement = (
<SpeakerLabel
name={ this.state.speaker }
handleOnClickEdit={ this.handleOnClickEdit }
/>
);

const timecodeElement = (
<span className={ style.time } onClick={ this.handleTimecodeClick }>
{shortTimecode(startTimecode)}
</span>
);

return (
<div className={ style.WrapperBlock }>
<div
className={ [ style.markers, style.unselectable ].join(' ') }
contentEditable={ false }
>
{this.props.blockProps.showSpeakers ? speakerElement : ''}

{this.props.blockProps.showTimecodes ? timecodeElement : ''}
</div>
<div className={ style.text }>
<EditorBlock { ...this.props } />
</div>
const speakerElement = (
<SpeakerLabel
name={ speaker }
handleOnClickEdit={ handleOnClickEdit }
/>
);

const timecodeElement = (
<span className={ style.time } onClick={ handleTimecodeClick }>
{shortTimecode(startTimecode)}
</span>
);

return (
<div className={ style.WrapperBlock }>
<div
className={ [ style.markers, style.unselectable ].join(' ') }
contentEditable={ false }
>
{props.blockProps.showSpeakers ? speakerElement : ''}

{props.blockProps.showTimecodes ? timecodeElement : ''}
</div>
);
}
}
<div className={ style.text }>
<EditorBlock { ...props } />
</div>
</div>
);
};

WrapperBlock.propTypes = {
block: PropTypes.any,
blockProps: PropTypes.any,
contentState: PropTypes.any
};

export default WrapperBlock;
export default WrapperBlock;
Loading