From 2ff7c7050fcb8e9454240a7374a0533f52a5afd9 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Sat, 20 Mar 2021 15:48:09 +0400 Subject: [PATCH] reimplementing multiselect chat input animation --- src/components/chat/input.ts | 12 +- src/components/chat/selection.ts | 32 +++- src/scss/partials/_chat.scss | 276 +++++++++++++------------------ 3 files changed, 151 insertions(+), 169 deletions(-) diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index fb4a5480..d61be16f 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -58,7 +58,7 @@ export default class ChatInput { public rowsWrapper: HTMLDivElement; private newMessageWrapper: HTMLDivElement; private btnToggleEmoticons: HTMLButtonElement; - private btnSendContainer: HTMLDivElement; + public btnSendContainer: HTMLDivElement; public attachMenu: HTMLButtonElement; private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[]; @@ -128,9 +128,15 @@ export default class ChatInput { this.inputContainer.classList.add('chat-input-container'); this.rowsWrapper = document.createElement('div'); - this.rowsWrapper.classList.add('rows-wrapper'); + this.rowsWrapper.classList.add('rows-wrapper', 'chat-input-wrapper'); - this.inputContainer.append(this.rowsWrapper); + const fakeRowsWrapper = document.createElement('div'); + fakeRowsWrapper.classList.add('fake-wrapper', 'fake-rows-wrapper'); + + const fakeSelectionWrapper = document.createElement('div'); + fakeSelectionWrapper.classList.add('fake-wrapper', 'fake-selection-wrapper'); + + this.inputContainer.append(this.rowsWrapper, fakeRowsWrapper, fakeSelectionWrapper); this.chatInput.append(this.inputContainer); this.goDownBtn = Button('bubbles-go-down btn-corner btn-circle z-depth-1 hide', {icon: 'arrow_down'}); diff --git a/src/components/chat/selection.ts b/src/components/chat/selection.ts index 04e14353..8e674089 100644 --- a/src/components/chat/selection.ts +++ b/src/components/chat/selection.ts @@ -21,6 +21,7 @@ export default class ChatSelection { public selectedMids: Set = new Set(); public isSelecting = false; + private selectionInputWrapper: HTMLElement; private selectionContainer: HTMLElement; private selectionCountEl: HTMLElement; public selectionSendNowBtn: HTMLElement; @@ -274,12 +275,27 @@ export default class ChatSelection { blurActiveElement(); // * for mobile keyboards + let transform = ''; const forwards = !!this.selectedMids.size || forceSelection; + if(forwards) { + const p = this.input.rowsWrapper.parentElement; + const widthFrom = p.querySelector('.fake-rows-wrapper').scrollWidth; + const widthTo = p.querySelector('.fake-selection-wrapper').scrollWidth; + const btnSendWidth = this.input.btnSendContainer.scrollWidth - (.5625 * 16); + + if(widthFrom !== widthTo) { + const scale = widthTo / widthFrom; + transform = `translateX(${btnSendWidth * scale}px) scaleX(${scale})`; + //scale = widthTo / widthFrom; + } + } + SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200); + this.input.rowsWrapper.style.transform = transform; SetTransition(bubblesContainer, 'is-selecting', forwards, 200, () => { if(!this.isSelecting) { - this.selectionContainer.remove(); - this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null; + this.selectionInputWrapper.remove(); + this.selectionInputWrapper = this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null; this.selectedText = undefined; } @@ -292,6 +308,9 @@ export default class ChatSelection { if(this.isSelecting) { if(!this.selectionContainer) { + this.selectionInputWrapper = document.createElement('div'); + this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper'); + this.selectionContainer = document.createElement('div'); this.selectionContainer.classList.add('selection-container'); @@ -329,7 +348,12 @@ export default class ChatSelection { this.selectionContainer.append(...[btnCancel, this.selectionCountEl, this.selectionSendNowBtn, this.selectionForwardBtn, this.selectionDeleteBtn].filter(Boolean)); - this.input.rowsWrapper.append(this.selectionContainer); + this.selectionInputWrapper.style.opacity = '0'; + this.selectionInputWrapper.append(this.selectionContainer); + this.input.rowsWrapper.parentElement.append(this.selectionInputWrapper); + + void this.selectionInputWrapper.offsetLeft; // reflow + this.selectionInputWrapper.style.opacity = ''; } } @@ -461,4 +485,4 @@ export default class ChatSelection { public canSelectBubble(bubble: HTMLElement) { return !bubble.classList.contains('service') && !bubble.classList.contains('is-sending'); } -} \ No newline at end of file +} diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index 65f8f834..09f3cf10 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -203,6 +203,7 @@ $chat-helper-size: 39px; } .btn-send { + transition: .2s transform !important; color: #9e9e9e; z-index: 3; @@ -357,24 +358,13 @@ $chat-helper-size: 39px; width: 0px; } } + + .new-message-wrapper, .pinned-container { + opacity: 1; + transition: opacity .1s 0s; + } .bubbles.is-selecting ~ & { - .new-message-wrapper, .pinned-container { - html:not(.is-safari) & { - transition: .1s opacity; - } - } - - .selection-container { - opacity: 0; - } - - .btn-send { - html:not(.is-safari) & { - transition: .2s transform; - } - } - .new-message-wrapper { pointer-events: none; } @@ -385,27 +375,15 @@ $chat-helper-size: 39px; opacity: 0; } - .selection-container { - html:not(.is-safari) & { - animation: fade-in-opacity .1s .1s forwards; - } - - html.is-safari & { - opacity: 1; - } + .selection-wrapper { + opacity: 1; } .rows-wrapper { max-height: var(--chat-input-size); - width: 28.75rem; - //max-width: 28.75rem; + //box-shadow: none; } - /* .reply-wrapper { - transform: none !important; - border-radius: inherit; - } */ - .reply-wrapper { height: 0 !important; } @@ -417,15 +395,11 @@ $chat-helper-size: 39px; .bubbles.is-selecting.backwards ~ & { .new-message-wrapper, .pinned-container { - html:not(.is-safari) & { - transition-delay: .1s; - } + transition: opacity .1s .1s; } - .selection-container { - html:not(.is-safari) & { - animation: fade-in-backwards-opacity .1s forwards; - } + .selection-wrapper { + transition: opacity .1s 0s; } } @@ -611,7 +585,7 @@ $chat-helper-size: 39px; } } -.rows-wrapper { +.chat-input-wrapper { --padding-vertical: .3125rem; --padding-horizontal: .5rem; --padding: var(--padding-vertical) var(--padding-horizontal); @@ -636,86 +610,128 @@ $chat-helper-size: 39px; body.animation-level-0 & { transition: none; } +} - .chat-input.type-pinned & { - width: 17.125rem; - } - - .chat-input.type-pinned.can-pin & { - width: 13.125rem; - } +.selection-wrapper { + position: absolute; + left: 50%; + top: 0; + width: 28.75rem; + transform: translateX(-50%); + border-radius: $border-radius-big; + //z-index: 2; + box-shadow: none; + transition: opacity .1s .1s; + opacity: 0; - &.is-centering { - html:not(.is-safari) & { - transition: width .2s, max-height .2s, border-bottom-right-radius .1s, transform .2s; + .selection-container { + display: flex; + justify-content: space-between; + height: 100%; + //background-color: #ccc; + border-radius: inherit; + padding: inherit; + user-select: none; + font-size: 15px; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; - &:after { - transition: transform .1s; - } + &-count { + color: #000; + font-weight: 500; + flex-grow: 1; + white-space: nowrap; + //padding-left: .5rem; } - html.is-safari & { - transition: none; + .btn-icon { + margin: 0 5px 0 6px; + color: #3f454a; + height: 42px; + width: 42px; + line-height: 42px; } - - //will-change: transform; - } - &.is-centering:not(.backwards), &.is-centered { - border-bottom-right-radius: 12px; - transform-origin: left; - transform: translate3d(25%, 0, 0); - //transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0); - //transform: translate3d(#{calc(28.75rem / 4)}, 0, 0); + .btn-primary { + height: 2.5rem; + width: auto; - /* html.is-safari & { - max-width: 28.75rem; - } */ - /* transform: translateX(-50%); - left: 50%; - position: absolute; */ + @include respond-to(handhelds) { + padding: 0 .5rem; - // left sidebar (420px) + 728px chat max width - @media only screen and (min-width: $floating-left-sidebar + 1) and (max-width: $large-screen / 4 + $messages-container-width) { - //transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding})); - transform: translate3d(calc((100vw - min(100vw / 2.5, #{$large-screen / 4}) - 100%) / 2 - #{$chat-padding}), 0, 0) !important; - } + &.tgico-send2 { + padding: 0 2px; + } + } - @media only screen and (max-width: 728px) { - //transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding})); - transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding}), 0, 0) !important; + @media only screen and (max-width: 380px) { + font-size: 0; + + &:before { + margin: 0; + } + } } - @include respond-to(handhelds) { - transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding-handhelds}), 0, 0) !important; + &-forward { + &:before { + margin-right: 14px; + } } - &:after { - transform: scaleX(-1) translateX(#{.5625rem * 2}); + &-delete { + margin-right: .625rem; + margin-left: .375rem; + + &:before { + margin-right: 10px; + } } } +} - &.is-centered, &.is-centered.is-centering:not(.backwards) { - transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0); +.fake-wrapper { + position: absolute; + z-index: -1; + visibility: hidden; +} + +.fake-rows-wrapper { + width: calc(100% - var(--chat-input-size) - (var(--padding-horizontal) * 2) - .5625rem); +} + +.fake-selection-wrapper { + width: 460px; +} + +.rows-wrapper { + transform: scaleX(1); + transition: transform .2s, width .2s, max-height .2s, border-bottom-right-radius .1s; + + &:after { + transition: transform .1s; } - // ! Need due to reply transform under the container - &:before { - position: absolute; - z-index: 2; - left: 0; - top: 0; - bottom: 0; - right: 0; - background: inherit; - content: " "; - display: block; - border-radius: inherit; + .chat-input.type-pinned & { + width: 17.125rem; + } + + .chat-input.type-pinned.can-pin & { + width: 13.125rem; } - /* #chat-input.is-helper-active & { - border-top-left-radius: 0; - border-top-right-radius: 0; + &.is-centering:not(.backwards), &.is-centered { + border-bottom-right-radius: 12px; + + &:after { + transform: scaleX(-1) translateX(#{.5625rem * 2}); + } + } + + /* &.is-centered, &.is-centered.is-centering:not(.backwards) { + transform: translate3d(calc(((var(--messages-container-width) - var(--chat-input-padding) * 2) - 100%) / 2), 0, 0); } */ @include respond-to(handhelds) { @@ -851,70 +867,6 @@ $chat-helper-size: 39px; } } - .selection-container { - position: absolute; - left: 0; - top: 0; - height: 100%; - //background-color: #ccc; - border-radius: inherit; - padding: inherit; - user-select: none; - font-size: 15px; - - &-count { - color: #000; - font-weight: 500; - flex-grow: 1; - white-space: nowrap; - //padding-left: .5rem; - } - - .btn-icon { - margin: 0 5px 0 6px; - color: #3f454a; - height: 42px; - width: 42px; - line-height: 42px; - } - - .btn-primary { - height: 2.5rem; - width: auto; - - @include respond-to(handhelds) { - padding: 0 .5rem; - - &.tgico-send2 { - padding: 0 2px; - } - } - - @media only screen and (max-width: 380px) { - font-size: 0; - - &:before { - margin: 0; - } - } - } - - &-forward { - &:before { - margin-right: 14px; - } - } - - &-delete { - margin-right: .625rem; - margin-left: .375rem; - - &:before { - margin-right: 10px; - } - } - } - .pinned-container { width: 17.125rem;