<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import LocalClient from '../../stores/local-client.stores.jsx';
import Lifespan from 'lifespan';
import DOM from '../../helpers/dom.helpers.js';

import HandlegripLetter from './handlegrip-letter.components.jsx';
import RegularLetter from './regular-letter.components.jsx';

/**
*	Component : Text in prototypo-word
*	Where you can set spacing on a specific letter
*	@extends React.Component
*/
export default class HandlegripText extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			spacingLeft: 0,
			spacingRight: 0,
			baseSpacingLeft: 0,
			baseSpacingRight: 0,
			advanceWidth: 0,
			trackingX: 0,
			letterFontSize: 0,
			tracking: false,
			fontValues: null,
		};
		this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);

		// retrieve the initial values, only once
		fontInstance.addOnceListener('worker.fontLoaded', () => {
			fontInstance.getGlyphProperty(
				this.getSelectedLetter(),
				['advanceWidth', 'spacingLeft', 'spacingRight', 'baseSpacingLeft', 'baseSpacingRight'],
				({advanceWidth, spacingLeft, spacingRight, baseSpacingLeft, baseSpacingRight}) => {
					this.setState({
						advanceWidth,
						spacingLeft,
						spacingRight,
						baseSpacingLeft,
						baseSpacingRight,
					});
				}
			);
		});

		// function bindings
		this.handleUp = this.handleUp.bind(this);
		this.handleMove = this.handleMove.bind(this);
		this.handleSelectstart = this.handleSelectstart.bind(this);
		this.dispatchAllFromFontinstance = this.dispatchAllFromFontinstance.bind(this);
	}

	componentWillMount() {
		this.client = LocalClient.instance();
		this.lifespan = new Lifespan();

		this.client.getStore('/prototypoStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					tracking: head.toJS().uiSpacingTracking,
					letterFontSize: head.toJS().uiLetterSpacingLetterFontSize || this.state.letterFontSize,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		this.client.getStore('/undoableStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					fontValues: head.toJS().controlsValues,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		this.client.getStore('/fastStuffStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					trackingX: head.toJS().uiTrackingX,
					baseSpacingLeft: head.toJS().baseSpacingLeft !== undefined ? head.toJS().baseSpacingLeft : this.state.baseSpacingLeft,
					baseSpacingRight: head.toJS().baseSpacingRight !== undefined ?head.toJS().baseSpacingRight : this.state.baseSpacingRight,
					spacingLeft: head.toJS().spacingLeft !== undefined ? head.toJS().spacingLeft : this.state.spacingLeft,
					spacingRight: head.toJS().spacingRight !== undefined ? head.toJS().spacingRight : this.state.spacingRight,
					unClampedOldValue: head.toJS().unClampedOldValue,
					advanceWidth: head.toJS().advanceWidth !== undefined ? head.toJS().advanceWidth : this.state.advanceWidth,
					clampedValue: head.toJS().clampedValue,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		// make sure there is no selection while dragging
		document.addEventListener('selectstart', this.handleSelectstart);
	}

	componentDidMount() {
		const handlegripDOM = ReactDOM.findDOMNode(this);

		handlegripDOM.addEventListener('mouseup', this.handleUp);
		handlegripDOM.addEventListener('mousemove', this.handleMove);
	}

	componentDidUpdate(prevProps, prevState) {
		if ((prevState.fontValues !== this.state.fontValues) && !this.state.tracking) {
			this.dispatchAdvancewidthFromFontinstance();
		}
	}

	componentWillUnmount() {
		const handlegripDOM = ReactDOM.findDOMNode(this);

		this.lifespan.release();

		document.removeEventListener('selectstart', this.handleSelectstart);
		handlegripDOM.removeEventListener('mouseup', this.handleUp);
		handlegripDOM.removeEventListener('mousemove', this.handleMove);
	}

	handleUp(e) {
		if (!this.state.tracking) {
			return;
		}

		this.client.dispatchAction('/change-letter-spacing', {
			value: this.state.clampedValue,
			side: this.state.tracking,
			letter: this.getSelectedLetter(),
			label: 'spacing',
			force: true,
		});

		this.client.dispatchAction('/store-value-fast', {unClampedOldValue: undefined});

		this.dispatchAllFromFontinstance();

		e.stopPropagation();
	}

	handleMove(e) {
		if (!this.state.tracking) {<commit_msg>fixing handlebar preventing selection inside text component<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import LocalClient from '../../stores/local-client.stores.jsx';
import Lifespan from 'lifespan';
import DOM from '../../helpers/dom.helpers.js';

import HandlegripLetter from './handlegrip-letter.components.jsx';
import RegularLetter from './regular-letter.components.jsx';

/**
*	Component : Text in prototypo-word
*	Where you can set spacing on a specific letter
*	@extends React.Component
*/
export default class HandlegripText extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			spacingLeft: 0,
			spacingRight: 0,
			baseSpacingLeft: 0,
			baseSpacingRight: 0,
			advanceWidth: 0,
			trackingX: 0,
			letterFontSize: 0,
			tracking: false,
			fontValues: null,
		};
		this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);

		// retrieve the initial values, only once
		fontInstance.addOnceListener('worker.fontLoaded', () => {
			fontInstance.getGlyphProperty(
				this.getSelectedLetter(),
				['advanceWidth', 'spacingLeft', 'spacingRight', 'baseSpacingLeft', 'baseSpacingRight'],
				({advanceWidth, spacingLeft, spacingRight, baseSpacingLeft, baseSpacingRight}) => {
					this.setState({
						advanceWidth,
						spacingLeft,
						spacingRight,
						baseSpacingLeft,
						baseSpacingRight,
					});
				}
			);
		});

		// function bindings
		this.handleUp = this.handleUp.bind(this);
		this.handleMove = this.handleMove.bind(this);
		this.handleSelectstart = this.handleSelectstart.bind(this);
		this.dispatchAllFromFontinstance = this.dispatchAllFromFontinstance.bind(this);
	}

	componentWillMount() {
		this.client = LocalClient.instance();
		this.lifespan = new Lifespan();

		this.client.getStore('/prototypoStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					tracking: head.toJS().uiSpacingTracking,
					letterFontSize: head.toJS().uiLetterSpacingLetterFontSize || this.state.letterFontSize,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		this.client.getStore('/undoableStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					fontValues: head.toJS().controlsValues,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		this.client.getStore('/fastStuffStore', this.lifespan)
			.onUpdate(({head}) => {
				this.setState({
					trackingX: head.toJS().uiTrackingX,
					baseSpacingLeft: head.toJS().baseSpacingLeft !== undefined ? head.toJS().baseSpacingLeft : this.state.baseSpacingLeft,
					baseSpacingRight: head.toJS().baseSpacingRight !== undefined ?head.toJS().baseSpacingRight : this.state.baseSpacingRight,
					spacingLeft: head.toJS().spacingLeft !== undefined ? head.toJS().spacingLeft : this.state.spacingLeft,
					spacingRight: head.toJS().spacingRight !== undefined ? head.toJS().spacingRight : this.state.spacingRight,
					unClampedOldValue: head.toJS().unClampedOldValue,
					advanceWidth: head.toJS().advanceWidth !== undefined ? head.toJS().advanceWidth : this.state.advanceWidth,
					clampedValue: head.toJS().clampedValue,
				});
			})
			.onDelete(() => {
				this.setState(undefined);
			});

		// make sure there is no selection while dragging
		document.addEventListener('selectstart', this.handleSelectstart);
	}

	componentDidMount() {
		const handlegripDOM = ReactDOM.findDOMNode(this);

		handlegripDOM.addEventListener('mouseup', this.handleUp);
		handlegripDOM.addEventListener('mousemove', this.handleMove);
	}

	componentDidUpdate(prevProps, prevState) {
		if ((prevState.fontValues !== this.state.fontValues) && !this.state.tracking) {
			this.dispatchAdvancewidthFromFontinstance();
		}
	}

	componentWillUnmount() {
		const handlegripDOM = ReactDOM.findDOMNode(this);

		this.lifespan.release();

		document.removeEventListener('selectstart', this.handleSelectstart);
		handlegripDOM.removeEventListener('mouseup', this.handleUp);
		handlegripDOM.removeEventListener('mousemove', this.handleMove);
	}

	handleUp(e) {
		if (!this.state.tracking) {
			return;
		}

		this.client.dispatchAction('/change-letter-spacing', {
			value: this.state.clampedValue,
			side: this.state.tracking,
			letter: this.getSelectedLetter(),
			label: 'spacing',
			force: true,
		});

		this.client.dispatchAction('/store-value-fast', {unClampedOldValue: undefined});
		this.client.dispatchAction('/store-value', {uiSpacingTracking: undefined});

		this.dispatchAllFromFontinstance();

		e.stopPropagation();
	}

	handleMove(e) {
		if (!this.state.tracking) {
{'fraction_non_alphanumeric': 0.14131383675250983, 'fraction_numerical': 0.0015277171540811873, 'mean_word_length': 4.372215709261431, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2014238', 'n_tokens_mistral': 3376, 'n_tokens_neox': 2836, 'n_words': 473}