// Copyright 2017-2020 @polkadot/react-components authors & contributors // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. import { BareProps } from './types'; import React, { useState } from 'react'; import SUIInput from 'semantic-ui-react/dist/commonjs/elements/Input/Input'; import { isUndefined } from '@polkadot/util'; import Labelled from './Labelled'; type Input$Type = 'number' | 'password' | 'text'; interface Props extends BareProps { autoFocus?: boolean; children?: React.ReactNode; defaultValue?: any; help?: React.ReactNode; icon?: React.ReactNode; inputClassName?: string; isAction?: boolean; isDisabled?: boolean; isDisabledError?: boolean; isEditable?: boolean; isError?: boolean; isFull?: boolean; isHidden?: boolean; isReadOnly?: boolean; label?: React.ReactNode; labelExtra?: React.ReactNode; max?: any; maxLength?: number; min?: any; name?: string; onEnter?: () => void; onEscape?: () => void; onChange?: (value: string) => void; onBlur?: () => void; onKeyDown?: (event: React.KeyboardEvent) => void; onKeyUp?: (event: React.KeyboardEvent) => void; onKeyPress?: (event: React.KeyboardEvent) => void; onPaste?: (event: React.ClipboardEvent) => void; placeholder?: string; tabIndex?: number; type?: Input$Type; value?: any; withLabel?: boolean; withEllipsis?: boolean; } // Find decimal separator used in current locale const getDecimalSeparator = (): string => 1.1 .toLocaleString() .replace(/\d/g, ''); // note: KeyboardEvent.keyCode and KeyboardEvent.which are deprecated const KEYS = { A: 'a', ALT: 'Alt', ARROW_LEFT: 'ArrowLeft', ARROW_RIGHT: 'ArrowRight', BACKSPACE: 'Backspace', C: 'c', CMD: 'Meta', CTRL: 'Control', ENTER: 'Enter', ESCAPE: 'Escape', TAB: 'Tab', V: 'v', X: 'x', ZERO: '0', DECIMAL: getDecimalSeparator() }; const KEYS_PRE: any[] = [KEYS.ALT, KEYS.CMD, KEYS.CTRL]; // reference: degrade key to keyCode for cross-browser compatibility https://www.w3schools.com/jsref/event_key_keycode.asp const isCopy = (key: string, isPreKeyDown: boolean): boolean => isPreKeyDown && key === KEYS.C; const isCut = (key: string, isPreKeyDown: boolean): boolean => isPreKeyDown && key === KEYS.X; const isPaste = (key: string, isPreKeyDown: boolean): boolean => isPreKeyDown && key === KEYS.V; const isSelectAll = (key: string, isPreKeyDown: boolean): boolean => isPreKeyDown && key === KEYS.A; let counter = 0; function Input ({ autoFocus = false, children, className, defaultValue, help, icon, inputClassName, isEditable = false, isAction = false, isDisabled = false, isDisabledError = false, isError = false, isFull = false, isHidden = false, isReadOnly = false, label, labelExtra, max, maxLength, min, name, onBlur, onChange, onEnter, onEscape, onKeyDown, onKeyUp, onPaste, placeholder, style, tabIndex, type = 'text', value, withEllipsis, withLabel }: Props): React.ReactElement { const [stateName] = useState(`in_${counter++}_at_${Date.now()}`); const _onBlur = (): void => { onBlur && onBlur(); }; const _onChange = ({ target }: React.SyntheticEvent): void => { onChange && onChange((target as HTMLInputElement).value); }; const _onKeyDown = (event: React.KeyboardEvent): void => { onKeyDown && onKeyDown(event); }; const _onKeyUp = (event: React.KeyboardEvent): void => { onKeyUp && onKeyUp(event); if (onEnter && event.keyCode === 13) { (event.target as any).blur(); onEnter(); } if (onEscape && event.keyCode === 27) { (event.target as any).blur(); onEscape(); } }; const _onPaste = (event: React.ClipboardEvent): void => { onPaste && onPaste(event); }; return ( ); } export default React.memo(Input); export { isCopy, isCut, isPaste, isSelectAll, KEYS, KEYS_PRE };