Как лучше реализовать форму ввода как в веб-версии chatGPT?
Сейчас ситуация такая: делаю проект в связке next.js 16 + tailwind v4. Это просто обертка над llm под капотом (если не углубляться). На днях пытался сделать форму ввода как в веб-версии chatGPT. Изображения прикрепил ниже, вживуюТут.
По вводным: в какой-то момент пришел к выводу, что наилучшим решением будет делать гридами. Ещё понял, что нужно заводить два как бы кадра, между которыми будет происходить анимация, пускай называются до/после. Для флага, который переключает эти кадры заведем состояние isExpanded. Теперь получается вот такая разметка, если рассмотреть ее по грид-ареа:
- По вводным: первый кадр (isExpanded === false) --> у нас в грид сетке 1 ряд, 3 колонки, выглядит вот так:
По вводным: | button | textarea | button button |
По вводным: это повторяет разметку обычной формы ввода, которую сейчас пихают в ai приложения. Внутри формы слева-направо: кнопка с иконкой, поле ввода (textarea, contenteditable элемент), контейнер, внутри которого еще две кнопки с иконкой.
- По вводным: второй кадр (isExpanded === true) --> в грид сетке становится 2 ряда и 3 колонки, выглядит вот так:
По вводным: | textarea | textarea | textarea |
По вводным: | button | тут пусто| button button |По вводным: это уже разложенное состояние. В целом все понятно - сверху широкое поле ввода, а снизу остается ряд с кнопками для взаимодействия.
По вводным: все хорошо, но что должно триггерить изменение значения у isExpanded? Кажется, что все просто, нам ведь известна ширина элемента, она стабильна, потому что грид-ареа textarea стоит статично между двумя блоками, а родитель ограничен по ширине. То есть когда контент в textarea достигает границы ширины, то происходит перенос строки, далее textarea вырастет в высоту в два раза, потому что начнется вторая строка. Будто можно брать этот момент за флаг, который будет переключать isExpanded в состояние true.
Тут не знаю, стоит ли пояснять, но по начальной задумке одна строка в текстаре равна по высоте всем остальным элементам формы (как в chatGPT), все стоит ровно, горизонтально и классно.
Сейчас ситуация такая: тут случится проблема - isExpanded переключилось и, соответственно, вся форма поменяла грид-сетку на состояние второго кадра и ширина грид-ареа textarea увеличилась, потому что элемент теперь в верхнем ряду, а значит к нему добавилась ширина других двух колонок грида. Вот тут самый прикол - при вводе следующего символа состояние isExpanded снова изменится, потому что теперь первая строка символов норм помещается в этот ряд, а потом еще раз так, и еще раз. И с каждым таким переключение isExpanded будет переключаться, форму будет переключать между первым и вторым кадром туда-сюда. В какой-то момент предел будет достигнут и форма статично встанет во второй кадр. Такое не пойдет.
По вводным: вот тут кажется логичным и простым решением зафиксировать флаг isExpanded в состояние true в самый первый момент изменения высоты textarea, чтобы форма зафиксировалась во втором кадре и дальше такой и оставалась, а при удалении символов можно просто сбрасывать обратно первый кадр, когда удалены все до последнего символы в поле ввода.
Сейчас ситуация такая: вроде бы схема рабочая, подумал я и пошел делать. Далее встал вопрос анимации, потому что до текущего момента это было просто слайд-шоу из двух кадров. А анимировать я не сумел, только очень коряво. Я проверял анимировать гриды, потому что знал, что вроде как их можно анимировать нативным css, но выходило очень некрасиво, кнопки могли терять форму (сжаться/развернуться) в процессе, текст перескакивал невнятно и очень неуверенно. Я далее попроверял поиграться с паддингами у textarea, вроде выровнял таким образом, что сдвига текста сильно не видно и при этом сама форма выглядит органично.
По вводным: в целом результат получился на 5/10. Очень странные и смешаные чувства испытал я в этот момент и пошел искать другие решения. Вспомнил про библиотеку framer, которая умеет анимировать изменения лейаута. Зашел в документацию, прочитал, подумал, начал делать. В результате пришлось все равно долго разбираться в настройке анимации, хотя сперва думал, что минут 30 это максимум займет. Настроил изменение лейаута через этот же пропс layout на каждом элементе и вроде как сработало. Выглядело лучше, чем анимация на чистом css, но все равно очень тупо и неказисто.
По вводным: вот тут и встает вопрос, а как можно реализовать форму ввода, которая будет повторять поведение формы ввода как в веб-версии chatGPT? Если у кого-то есть хорошие идеи, предложения, рекомендации, примеры кода, какие-то пояснения, хоть что-то -Дайте знать,.
Сейчас ситуация такая: ещё важный момент - поле ввода, именно куда вводится текст будущего промпта, может быть реализовано по сути либо элементом textarea, либо же contenteditable div, потому что оба имеют возможность расти в высоту. Я и попроверял, но результат был плюс-минус таким же. Большую часть времени я все-таки тестил это дело с textarea внутри, потому что в chatGPT используется именно contenteditable компонент, потому что есть возможность вставлять туда изображения и прикреплять вложения. В мои задачи это не входило, потому что я не планирую добавлять этот функционал, хоты бы пока. Поэтому самым простым решением и было вставить textarea. Тут ещё просто для справки стоит сказать, что в gpt все-таки учтена адаптивность, поэтому не помню на каком разрешении contenteditable элемент меняется на обычный textarea.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос


