Eduard Kuzmenko
4 years ago
19 changed files with 515 additions and 352 deletions
@ -1,33 +1,119 @@
@@ -1,33 +1,119 @@
|
||||
const InputField = (placeholder: string, label: string, name: string, maxLength?: number, showLengthOn: number = maxLength ? maxLength / 3 : 0) => { |
||||
import { getRichValue, isInputEmpty } from "../helpers/dom"; |
||||
import { checkRTL } from "../helpers/string"; |
||||
import RichTextProcessor from "../lib/richtextprocessor"; |
||||
|
||||
let init = () => { |
||||
document.addEventListener('paste', (e) => { |
||||
if(!(e.target as HTMLElement).hasAttribute('contenteditable') && !(e.target as HTMLElement).parentElement.hasAttribute('contenteditable')) { |
||||
return; |
||||
} |
||||
//console.log('document paste');
|
||||
|
||||
//console.log('messageInput paste');
|
||||
|
||||
e.preventDefault(); |
||||
// @ts-ignore
|
||||
let text = (e.originalEvent || e).clipboardData.getData('text/plain'); |
||||
|
||||
let entities = RichTextProcessor.parseEntities(text); |
||||
//console.log('messageInput paste', text, entities);
|
||||
entities = entities.filter(e => e._ == 'messageEntityEmoji' || e._ == 'messageEntityLinebreak'); |
||||
//text = RichTextProcessor.wrapEmojiText(text);
|
||||
text = RichTextProcessor.wrapRichText(text, {entities, noLinks: true}); |
||||
|
||||
// console.log('messageInput paste after', text);
|
||||
|
||||
// @ts-ignore
|
||||
//let html = (e.originalEvent || e).clipboardData.getData('text/html');
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('paste text', text, );
|
||||
window.document.execCommand('insertHTML', false, text); |
||||
}); |
||||
|
||||
init = null; |
||||
}; |
||||
|
||||
const InputField = (options: { |
||||
placeholder?: string, |
||||
label?: string, |
||||
name: string, |
||||
maxLength?: number, |
||||
showLengthOn?: number, |
||||
plainText?: true |
||||
}) => { |
||||
const div = document.createElement('div'); |
||||
div.classList.add('input-field'); |
||||
|
||||
div.innerHTML = ` |
||||
<input type="text" name="${name}" id="input-${name}" placeholder="${placeholder}" autocomplete="off" required=""> |
||||
<label for="input-${name}">${label}</label> |
||||
`;
|
||||
if(options.maxLength) { |
||||
options.showLengthOn = Math.round(options.maxLength / 3); |
||||
} |
||||
|
||||
const {placeholder, label, maxLength, showLengthOn, name, plainText} = options; |
||||
|
||||
if(!plainText) { |
||||
if(init) { |
||||
init(); |
||||
} |
||||
|
||||
div.innerHTML = ` |
||||
<div id="input-${name}" ${placeholder ? `data-placeholder="${placeholder}"` : ''} contenteditable="true" class="input-field-input"></div> |
||||
${label ? `<label for="input-${name}">${label}</label>` : ''} |
||||
`;
|
||||
|
||||
const input = div.firstElementChild as HTMLElement; |
||||
const observer = new MutationObserver((mutationsList, observer) => { |
||||
const isEmpty = isInputEmpty(input); |
||||
console.log('input', isEmpty); |
||||
|
||||
const char = input.innerText[0]; |
||||
let direction = 'ltr'; |
||||
if(char && checkRTL(char)) { |
||||
direction = 'rtl'; |
||||
} |
||||
|
||||
input.style.direction = direction; |
||||
|
||||
if(processInput) { |
||||
processInput(); |
||||
} |
||||
}); |
||||
|
||||
// ! childList for paste first symbol
|
||||
observer.observe(input, {characterData: true, childList: true, subtree: true}); |
||||
} else { |
||||
div.innerHTML = ` |
||||
<input type="text" name="${name}" id="input-${name}" ${placeholder ? `placeholder="${placeholder}"` : ''} autocomplete="off" required="" class="input-field-input"> |
||||
${label ? `<label for="input-${name}">${label}</label>` : ''} |
||||
`;
|
||||
} |
||||
|
||||
let processInput: () => void; |
||||
if(maxLength) { |
||||
const input = div.firstElementChild as HTMLInputElement; |
||||
const labelEl = div.lastElementChild as HTMLLabelElement; |
||||
let showingLength = false; |
||||
input.addEventListener('input', (e) => { |
||||
|
||||
processInput = () => { |
||||
const wasError = input.classList.contains('error'); |
||||
const diff = maxLength - input.value.length; |
||||
const inputLength = plainText ? input.value.length : getRichValue(input).length; |
||||
const diff = maxLength - inputLength; |
||||
const isError = diff < 0; |
||||
input.classList.toggle('error', isError); |
||||
|
||||
if(isError || diff <= showLengthOn) { |
||||
labelEl.innerText = label + ` (${maxLength - input.value.length})`; |
||||
labelEl.innerText = label + ` (${maxLength - inputLength})`; |
||||
if(!showingLength) showingLength = true; |
||||
} else if((wasError && !isError) || showingLength) { |
||||
labelEl.innerText = label; |
||||
showingLength = false; |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
input.addEventListener('input', processInput); |
||||
} |
||||
|
||||
return div; |
||||
return {container: div, input: div.firstElementChild as HTMLInputElement}; |
||||
}; |
||||
|
||||
export default InputField; |
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
.input-wrapper { |
||||
width: 360px; |
||||
margin: 0 auto; |
||||
} |
||||
|
||||
.input-field { |
||||
position: relative; |
||||
|
||||
.arrow-down { |
||||
position: absolute; |
||||
content: " "; |
||||
top: 50%; |
||||
bottom: 0; |
||||
right: 21px; |
||||
cursor: pointer; |
||||
|
||||
height: 0; |
||||
width: 0; |
||||
|
||||
border: solid #707579; |
||||
border-radius: 1px; |
||||
border-width: 0 2px 2px 0; |
||||
display: inline-block; |
||||
padding: 5px; |
||||
vertical-align: middle; |
||||
|
||||
z-index: 2; |
||||
|
||||
margin-top: -9px; |
||||
transform: rotate(45deg); |
||||
-webkit-transform: rotate(45deg); |
||||
transition: .2s all; |
||||
} |
||||
|
||||
label { |
||||
position: absolute; |
||||
color: $placeholder-color; |
||||
left: 1rem; |
||||
right: auto; |
||||
z-index: 2; |
||||
top: 50%; |
||||
transform: translateY(-50%); |
||||
background-color: #fff; |
||||
transition: .2s all, .1s opacity; |
||||
display: inline-block; |
||||
pointer-events: none; |
||||
} |
||||
|
||||
input, &-input { |
||||
--border-width: 1px; |
||||
--border-width-top: 2px; |
||||
border: var(--border-width) solid #DADCE0; |
||||
border-radius: $border-radius-medium; |
||||
//padding: 0 1rem; |
||||
padding: calc(1rem - var(--border-width-top)) calc(1rem - var(--border-width)); |
||||
box-sizing: border-box; |
||||
width: 100%; |
||||
min-height: 54px; |
||||
transition: .2s border-color; |
||||
position: relative; |
||||
z-index: 1; |
||||
//line-height: calc(54px - var(--border-width)); |
||||
/* overflow: hidden; |
||||
white-space: nowrap; */ |
||||
|
||||
html.no-touch & { |
||||
&:hover:not(:focus):not(.error):not(.valid) { |
||||
border-color: var(--color-gray); |
||||
} |
||||
} |
||||
|
||||
@include respond-to(handhelds) { |
||||
height: 50px; |
||||
} |
||||
/* font-weight: 500; */ |
||||
|
||||
/* &:hover { |
||||
border-color: #000; |
||||
} */ |
||||
|
||||
&:focus { |
||||
--border-width: 2px; |
||||
--border-width-top: 3px; |
||||
border-color: $button-primary-background; |
||||
//padding: 0 calc(1rem - 1px); |
||||
} |
||||
|
||||
&:disabled { |
||||
background-color: #fff; |
||||
color: #000; |
||||
} |
||||
|
||||
&.error { |
||||
border-color: $color-error; |
||||
|
||||
& + label { |
||||
color: $color-error!important; |
||||
} |
||||
} |
||||
|
||||
&.valid { |
||||
border-color: #26962F; |
||||
|
||||
& + label { |
||||
color: #26962F !important; |
||||
} |
||||
} |
||||
|
||||
/* &.error, &.valid { |
||||
transition: .2s border-width; |
||||
} */ |
||||
|
||||
&:focus ~ .arrow-down { |
||||
margin-top: -4px; |
||||
transform: rotate(225deg); |
||||
-webkit-transform: rotate(225deg); |
||||
border-color: $button-primary-background; |
||||
} |
||||
|
||||
&:focus + label { |
||||
color: $button-primary-background; |
||||
} |
||||
|
||||
&:focus + label, &:valid + label, &:not(:empty) + label, &:disabled + label { |
||||
top: -.5rem; |
||||
transform: none; |
||||
padding: 0 5px; |
||||
left: .75rem; |
||||
font-size: 0.75rem!important; |
||||
//color: #666; |
||||
opacity: 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.input-wrapper > * + * { |
||||
margin-top: 1.5rem; |
||||
} |
||||
|
||||
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ |
||||
color: #909192; |
||||
opacity: 1; /* Firefox */ |
||||
} |
||||
|
||||
:-ms-input-placeholder { /* Internet Explorer 10-11 */ |
||||
color: #a2acb4; |
||||
} |
||||
|
||||
::-ms-input-placeholder { /* Microsoft Edge */ |
||||
color: #a2acb4; |
||||
} |
||||
|
||||
input:focus, button:focus { |
||||
outline: none; |
||||
} |
Loading…
Reference in new issue