Compare commits

...
Author SHA1 Message Date
Omar Basem d433285acb selectable-input 2023-05-04 10:26:51 +04:00
Omar Basem eb16f4b6c4 revert podfile.lock 2023-05-04 09:17:53 +04:00
Omar Basem 9268060aa9 review 2023-05-04 09:16:53 +04:00
Omar Basem 7ab9e7abd0 review 2023-05-04 09:16:52 +04:00
Omar Basem 2430bde3d5 review 2023-05-04 09:16:52 +04:00
Omar Basem 739556f2b4 review 2023-05-04 09:16:52 +04:00
Omar Basem f4ac7a4c51 lint 2023-05-04 09:16:51 +04:00
Omar Basem 36fac66eac feat: mentions new design
review

lint

review

udpates

updates

updates

udpates

updates

updates

lint

updates

composer shell button

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates

updates
2023-05-04 09:16:51 +04:00
9 changed files with 352 additions and 129 deletions
+15 -11
View File
@@ -3,6 +3,7 @@
[quo.react :as react] [quo.react :as react]
[quo.react-native :as rn] [quo.react-native :as rn]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im2.config :as config]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[native-module.core :as native-module])) [native-module.core :as native-module]))
@@ -167,17 +168,20 @@
cursor (+ at-sign-idx (count primary-name) 2)] cursor (+ at-sign-idx (count primary-name) 2)]
(rf/merge (rf/merge
cofx cofx
{:db (-> db (let [common {:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil)) (assoc-in [:chats/mention-suggestions chat-id] nil))
:set-text-input-value [chat-id new-text text-input-ref] :dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]} extra (if (not config/new-composer-enabled?)
;; NOTE(rasom): Some keyboards do not react on selection property passed to ;; NOTE(rasom): Some keyboards do not react on selection property passed to
;; text input (specifically Samsung keyboard with predictive text set on). ;; text input (specifically Samsung keyboard with predictive text set on).
;; In this case, if the user continues typing after the programmatic change, ;; In this case, if the user continues typing after the programmatic change,
;; the new text is added to the last known cursor position before ;; the new text is added to the last known cursor position before
;; programmatic change. By calling `reset-text-input-cursor` we force the ;; programmatic change. By calling `reset-text-input-cursor` we force the
;; keyboard's cursor position to be changed before the next input. ;; keyboard's cursor position to be changed before the next input.
(reset-text-input-cursor text-input-ref cursor) {:set-text-input-value [chat-id new-text text-input-ref]
:reset-text-input-cursor (reset-text-input-cursor text-input-ref cursor)}
{})]
(merge common extra))
(recheck-at-idxs public-key)))) (recheck-at-idxs public-key))))
(rf/defn clear-suggestions (rf/defn clear-suggestions
+1 -1
View File
@@ -159,4 +159,4 @@
(def default-kdf-iterations 3200) (def default-kdf-iterations 3200)
(def ^:const new-composer-enabled? false) (def ^:const new-composer-enabled? true)
@@ -21,6 +21,8 @@
(def ^:const edit-container-height 32) (def ^:const edit-container-height 32)
(def ^:const mentions-max-height 240)
(def ^:const extra-content-offset (if platform/ios? 6 0)) (def ^:const extra-content-offset (if platform/ios? 6 0))
(def ^:const content-change-threshold 10) (def ^:const content-change-threshold 10)
@@ -1,11 +1,12 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.handlers (ns status-im2.contexts.chat.bottom-sheet-composer.handlers
(:require [react-native.reanimated :as reanimated] (:require
[reagent.core :as reagent] [react-native.reanimated :as reanimated]
[oops.core :as oops] [reagent.core :as reagent]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants] [oops.core :as oops]
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb] [status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils] [status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
[utils.re-frame :as rf])) [status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[utils.re-frame :as rf]))
(defn focus (defn focus
[{:keys [input-ref] :as props} [{:keys [input-ref] :as props}
@@ -70,7 +71,8 @@
(reanimated/animate height new-height) (reanimated/animate height new-height)
(reanimated/set-shared-value saved-height new-height)) (reanimated/set-shared-value saved-height new-height))
(when (= new-height max-height) (when (= new-height max-height)
(reset! maximized? true)) (reset! maximized? true)
(rf/dispatch [:chat.ui/set-input-maximized true]))
(if (utils/show-background? saved-height max-height new-height) (if (utils/show-background? saved-height max-height new-height)
(do (do
(reanimated/set-shared-value background-y 0) (reanimated/set-shared-value background-y 0)
@@ -82,10 +84,12 @@
(defn scroll (defn scroll
[event [event
{:keys [scroll-y]}
{:keys [gradient-z-index focused?]} {:keys [gradient-z-index focused?]}
{:keys [gradient-opacity]} {:keys [gradient-opacity]}
{:keys [lines max-lines]}] {:keys [lines max-lines]}]
(let [y (oops/oget event "nativeEvent.contentOffset.y")] (let [y (oops/oget event "nativeEvent.contentOffset.y")]
(reset! scroll-y y)
(when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?) (when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?)
(reset! gradient-z-index 1) (reset! gradient-z-index 1)
(js/setTimeout #(reanimated/animate gradient-opacity 1) 0)) (js/setTimeout #(reanimated/animate gradient-opacity 1) 0))
@@ -105,10 +109,12 @@
(when @recording? (when @recording?
(@record-reset-fn) (@record-reset-fn)
(reset! recording? false)) (reset! recording? false))
(rf/dispatch [:chat.ui/set-chat-input-text text])) (rf/dispatch [:chat.ui/set-chat-input-text text])
(rf/dispatch [:mention/on-change-text text]))
(defn selection-change (defn selection-change
[event {:keys [lock-selection? cursor-position]}] [event {:keys [lock-selection? cursor-position]}]
(println "selectionc ahnge")
(when-not @lock-selection? (when-not @lock-selection?
(reset! cursor-position (oops/oget event "nativeEvent.selection.end")))) (reset! cursor-position (oops/oget event "nativeEvent.selection.end"))))
@@ -0,0 +1,30 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
(defn shadow
[]
(if platform/ios?
{:shadow-radius (colors/theme-colors 30 50)
:shadow-opacity (colors/theme-colors 0.1 0.7)
:shadow-color colors/neutral-100
:shadow-offset {:width 0 :height (colors/theme-colors 8 12)}}
{:elevation 10}))
(defn container
[opacity bottom]
(reanimated/apply-animations-to-style
{:opacity opacity}
(merge
{:position :absolute
:bottom bottom
:left 8
:right 8
:border-radius 16
:z-index 4
:max-height constants/mentions-max-height
:background-color (colors/theme-colors colors/white colors/neutral-95)}
(shadow))))
@@ -0,0 +1,67 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.view
(:require
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.contexts.chat.bottom-sheet-composer.mentions.style :as style]))
(defn update-cursor
[user {:keys [cursor-position input-ref]}]
(when platform/android?
(let [new-cursor-pos (+ (count (:primary-name user)) @cursor-position)]
(reset! cursor-position new-cursor-pos)
(reagent/next-tick #(when @input-ref
(.setNativeProps ^js @input-ref
(clj->js {:selection {:start new-cursor-pos
:end
new-cursor-pos}})))))))
(defn mention-item
[user _ _ render-data]
[contact-list-item/contact-list-item
{:on-press (fn []
(rf/dispatch [:chat.ui/select-mention nil user])
(update-cursor user render-data))}
user])
(defn- f-view
[suggestions-atom props state animations max-height cursor-pos]
(let [{:keys [keyboard-height]} (hooks/use-keyboard)
suggestions (rf/sub [:chat/mention-suggestions])
opacity (reanimated/use-shared-value (if (seq suggestions) 1 0))
size (count suggestions)
data {:keyboard-height keyboard-height
:insets (safe-area/get-insets)
:curr-height (reanimated/get-shared-value (:height animations))
:window-height (rf/sub [:dimensions/window-height])
:reply (rf/sub [:chats/reply-message])
:edit (rf/sub [:chats/edit-message])}
mentions-pos (utils/calc-suggestions-position cursor-pos max-height size state data)]
(rn/use-effect
(fn []
(if (seq suggestions)
(reset! suggestions-atom suggestions)
(js/setTimeout #(reset! suggestions-atom suggestions) 300))
(reanimated/animate opacity (if (seq suggestions) 1 0)))
[(seq suggestions)])
[reanimated/view
{:style (style/container opacity mentions-pos)}
[rn/flat-list
{:keyboard-should-persist-taps :always
:data (vals @suggestions-atom)
:key-fn :key
:render-fn mention-item
:render-data {:cursor-position (:cursor-position state)
:input-ref (:input-ref props)}
:accessibility-label :mentions-list}]]))
(defn view
[props state animations max-height cursor-pos]
(let [suggestions-atom (reagent/atom {})]
[:f> f-view suggestions-atom props state animations max-height cursor-pos]))
@@ -0,0 +1,42 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view
(:require [utils.i18n :as i18n]))
(declare first-level-menu-items second-level-menu-items)
(defn calculate-input-text
[{:keys [full-text selection-start selection-end]} content]
(let [head (subs full-text 0 selection-start)
tail (subs full-text selection-end)]
(str head content tail)))
(defn reset-to-first-level-menu
[first-level menu-items]
(reset! first-level true)
(reset! menu-items first-level-menu-items))
(defn append-markdown-char
[{:keys [first-level menu-items content selection-start selection-end text-input-handle
selection-event]
:as params} wrap-chars]
(let [content (str wrap-chars content wrap-chars)
new-text (calculate-input-text params content)
len-wrap-chars (count wrap-chars)
selection-start (+ selection-start len-wrap-chars)
selection-end (+ selection-end len-wrap-chars)]
;don't update selection directly here, process it within on-selection-change instead
;so that we can avoid java.lang.IndexOutOfBoundsException: setSpan..
(reset! selection-event {:start selection-start
:end selection-end
:text-input-handle text-input-handle})
;(update-input-text params new-text)
(reset-to-first-level-menu first-level menu-items)))
(def second-level-menus
{:bold #(append-markdown-char % "**")
:italic #(append-markdown-char % "*")
:strikethrough #(append-markdown-char % "~~")})
(def second-level-menu-items (map i18n/label (keys second-level-menus)))
@@ -1,5 +1,6 @@
(ns status-im2.contexts.chat.bottom-sheet-composer.utils (ns status-im2.contexts.chat.bottom-sheet-composer.utils
(:require (:require
[clojure.string :as string]
[oops.core :as oops] [oops.core :as oops]
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
@@ -90,3 +91,53 @@
(reanimated/set-shared-value last-height constants/input-height)) (reanimated/set-shared-value last-height constants/input-height))
(reset! text-value "") (reset! text-value "")
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height])) (rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
(defn update-input
[{:keys [input-ref]}
{:keys [text-value]}
input-text]
(when (and input-text (not= @text-value input-text))
(reset! text-value input-text)
(when @input-ref
(.setNativeProps ^js @input-ref (clj->js {:text input-text})))))
(defn count-lines
[s]
(-> s
(string/split #"\n" -1)
(butlast)
count))
(defn cursor-y-position-relative-to-container
[{:keys [scroll-y]}
{:keys [cursor-position text-value]}]
(let [sub-text (subs @text-value 0 @cursor-position)
sub-text-lines (count-lines sub-text)
scrolled-lines (Math/round (/ @scroll-y constants/line-height))
sub-text-lines-in-view (- sub-text-lines scrolled-lines)]
(* sub-text-lines-in-view constants/line-height)))
(defn calc-suggestions-position
[cursor-pos max-height size
{:keys [maximized?]}
{:keys [insets curr-height window-height keyboard-height edit reply]}]
(let [base (+ constants/composer-default-height (:bottom insets) 8)
base (+ base (- curr-height constants/input-height))
base (if edit
(+ base constants/edit-container-height)
base)
base (if reply
(+ base constants/reply-container-height)
base)
view-height (- window-height keyboard-height (:top insets))
container-height (bounded-val
(* (/ constants/mentions-max-height 4) size)
(/ constants/mentions-max-height 4)
constants/mentions-max-height)]
(if @maximized?
(if (< (+ cursor-pos container-height) max-height)
(+ constants/actions-container-height (:bottom insets))
(+ constants/actions-container-height (:bottom insets) (- max-height cursor-pos) 18))
(if (< (+ base container-height) view-height)
base
(+ constants/actions-container-height (:bottom insets) (- curr-height cursor-pos) 18)))))
@@ -7,11 +7,13 @@
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[reagent.core :as reagent] [reagent.core :as reagent]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf]
[oops.core :as oops]
[status-im2.contexts.chat.bottom-sheet-composer.style :as style] [status-im2.contexts.chat.bottom-sheet-composer.style :as style]
[status-im2.contexts.chat.bottom-sheet-composer.images.view :as images] [status-im2.contexts.chat.bottom-sheet-composer.images.view :as images]
[status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply] [status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply]
[utils.re-frame :as rf]
[status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit] [status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit]
[status-im2.contexts.chat.bottom-sheet-composer.mentions.view :as mentions]
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils] [status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants] [status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
[status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions] [status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions]
@@ -20,131 +22,150 @@
[status-im2.contexts.chat.bottom-sheet-composer.effects :as effects] [status-im2.contexts.chat.bottom-sheet-composer.effects :as effects]
[status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture] [status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture]
[status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler] [status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler]
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients])) [status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]
[status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view :as selectable-input]))
(defn sheet (defn sheet
[insets window-height blur-height opacity background-y] [insets window-height blur-height opacity background-y]
[:f> [:f>
(fn [] (fn []
(let [props {:input-ref (atom nil) (let [props {:input-ref (atom nil)
:keyboard-show-listener (atom nil) :keyboard-show-listener (atom nil)
:keyboard-frame-listener (atom nil) :keyboard-frame-listener (atom nil)
:keyboard-hide-listener (atom nil) :keyboard-hide-listener (atom nil)
:emoji-kb-extra-height (atom nil) :emoji-kb-extra-height (atom nil)
:saved-emoji-kb-extra-height (atom nil) :saved-emoji-kb-extra-height (atom nil)
:replying? (atom nil) :replying? (atom nil)
:sending-images? (atom nil) :sending-images? (atom nil)
:editing? (atom nil) :editing? (atom nil)
:record-permission? (atom nil) :record-permission? (atom nil)
:record-reset-fn (atom nil)} :record-reset-fn (atom nil)
state {:text-value (reagent/atom "") :scroll-y (atom 0)}
:cursor-position (reagent/atom 0) state {:text-value (reagent/atom "")
:saved-cursor-position (reagent/atom 0) :cursor-position (reagent/atom 0)
:gradient-z-index (reagent/atom 0) :saved-cursor-position (reagent/atom 0)
:kb-default-height (reagent/atom nil) :gradient-z-index (reagent/atom 0)
:gesture-enabled? (reagent/atom true) :kb-default-height (reagent/atom nil)
:lock-selection? (reagent/atom true) :gesture-enabled? (reagent/atom true)
:focused? (reagent/atom false) :lock-selection? (reagent/atom true)
:lock-layout? (reagent/atom false) :focused? (reagent/atom false)
:maximized? (reagent/atom false) :lock-layout? (reagent/atom false)
:recording? (reagent/atom false)}] :maximized? (reagent/atom false)
:recording? (reagent/atom false)}
selectable-input-ref (atom nil)
menu-items (reagent/atom selectable-input/first-level-menu-items)
manager (rn/selectable-text-input-manager)]
[:f> [:f>
(fn [] (fn []
(let [images (rf/sub [:chats/sending-image]) (let [images (rf/sub [:chats/sending-image])
audio (rf/sub [:chats/sending-audio]) audio (rf/sub [:chats/sending-audio])
reply (rf/sub [:chats/reply-message]) reply (rf/sub [:chats/reply-message])
edit (rf/sub [:chats/edit-message]) edit (rf/sub [:chats/edit-message])
{:keys [input-text input-content-height] {:keys [input-text input-content-height]
:as chat-input} (rf/sub [:chats/current-chat-input]) :as chat-input} (rf/sub [:chats/current-chat-input])
content-height (reagent/atom (or input-content-height content-height (reagent/atom (or input-content-height
constants/input-height)) constants/input-height))
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard) {:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
kb-height (kb/get-kb-height keyboard-height kb-height (kb/get-kb-height keyboard-height
@(:kb-default-height state)) @(:kb-default-height state))
max-height (utils/calc-max-height window-height max-height (utils/calc-max-height window-height
kb-height kb-height
insets insets
(seq images) (boolean (seq images))
reply reply
edit) edit)
lines (utils/calc-lines @content-height) lines (utils/calc-lines @content-height)
max-lines (utils/calc-lines max-height) max-lines (utils/calc-lines max-height)
initial-height (if (> lines 1) initial-height (if (> lines 1)
constants/multiline-minimized-height constants/multiline-minimized-height
constants/input-height) constants/input-height)
animations {:gradient-opacity (reanimated/use-shared-value animations {:gradient-opacity (reanimated/use-shared-value
0) 0)
:container-opacity (reanimated/use-shared-value :container-opacity (reanimated/use-shared-value
(if (utils/empty-input? (if (utils/empty-input?
input-text input-text
images images
reply reply
audio) audio)
0.7 0.7
1)) 1))
:height (reanimated/use-shared-value :height (reanimated/use-shared-value
initial-height) initial-height)
:saved-height (reanimated/use-shared-value :saved-height (reanimated/use-shared-value
initial-height) initial-height)
:last-height (reanimated/use-shared-value :last-height (reanimated/use-shared-value
(utils/bounded-val (utils/bounded-val
@content-height @content-height
constants/input-height constants/input-height
max-height)) max-height))
:opacity opacity :opacity opacity
:background-y background-y} :background-y background-y}
dimensions {:content-height content-height dimensions {:content-height content-height
:max-height max-height :max-height max-height
:window-height window-height :window-height window-height
:lines lines :lines lines
:max-lines max-lines} :max-lines max-lines}
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)] show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)
cursor-pos (utils/cursor-y-position-relative-to-container
props
state)]
(effects/initialize props (effects/initialize props
state state
animations animations
dimensions dimensions
chat-input chat-input
keyboard-height keyboard-height
(seq images) (boolean (seq images))
reply reply
edit edit
audio) audio)
[gesture/gesture-detector (rn/use-effect (fn []
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)} (let [selectable-text-input-handle (rn/find-node-handle @selectable-input-ref)
[reanimated/view text-input-handle (rn/find-node-handle @(:input-ref props))]
{:style (style/sheet-container insets state animations) (oops/ocall manager :setupMenuItems selectable-text-input-handle text-input-handle))))
:on-layout #(handler/layout % state blur-height)} (utils/update-input props state input-text)
[sub-view/bar] [:<>
[reply/view state] [mentions/view props state animations max-height cursor-pos]
[edit/view edit #(utils/cancel-edit-message state animations)] [gesture/gesture-detector
[reanimated/touchable-opacity {:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
{:active-opacity 1 [reanimated/view
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props))) {:style (style/sheet-container insets state animations)
:style (style/input-container (:height animations) max-height) :on-layout #(handler/layout % state blur-height)}
:accessibility-label :message-input-container} [sub-view/bar]
[rn/text-input [reply/view state]
{:ref #(reset! (:input-ref props) %) [edit/view edit #(utils/cancel-edit-message state animations)]
:default-value @(:text-value state) [reanimated/touchable-opacity
:on-focus #(handler/focus props state animations dimensions) {:active-opacity 1
:on-blur #(handler/blur state animations dimensions images reply) :on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
:on-content-size-change #(handler/content-size-change % :style (style/input-container (:height animations) max-height)
state :accessibility-label :message-input-container}
animations [rn/selectable-text-input {:ref #(reset! selectable-input-ref %)
dimensions :menuItems @menu-items}
(or keyboard-shown edit)) [rn/text-input
:on-scroll #(handler/scroll % state animations dimensions) {:ref #(reset! (:input-ref props) %)
:on-change-text #(handler/change-text % props state) :default-value @(:text-value state)
:on-selection-change #(handler/selection-change % state) :on-focus #(handler/focus props state animations dimensions)
:max-height max-height :on-blur #(handler/blur state animations dimensions images reply)
:max-font-size-multiplier 1 :on-content-size-change #(handler/content-size-change %
:multiline true state
:placeholder (i18n/label :t/type-something) animations
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50) dimensions
:style (style/input props state) (or keyboard-shown edit))
:accessibility-label :chat-message-input}] :on-scroll #(handler/scroll % props state animations dimensions)
[gradients/view props state animations show-bottom-gradient?]] :on-change-text #(handler/change-text % props state)
[images/images-list] :on-selection-change #(handler/selection-change % state)
[actions/view props state animations window-height insets (seq images)]]]))]))]) :on-selection (fn [e] (println "onselection"))
:max-height max-height
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input props state)
:accessibility-label :chat-message-input}]]
[gradients/view props state animations show-bottom-gradient?]]
[images/images-list]
[actions/view props state animations window-height insets
(boolean (seq images))]]]]))]))])
(defn f-bottom-sheet-composer (defn f-bottom-sheet-composer
[insets] [insets]