@@ -40,8 +40,26 @@ const checkMobile = () => {
4040
4141// Auto-resize function for textareas
4242const autoResize = (element : HTMLTextAreaElement ) => {
43+ // Temporarily set height to auto to get proper scrollHeight
4344 element .style .height = ' auto' ;
44- element .style .height = element .scrollHeight + ' px' ;
45+
46+ // Get the actual scrollHeight which accounts for both content and placeholder
47+ let newHeight = element .scrollHeight ;
48+
49+ // If textarea is empty, ensure it's tall enough for the placeholder
50+ if (! element .value .trim ()) {
51+ // Temporarily set the placeholder as value to measure its height
52+ const originalValue = element .value ;
53+ element .value = element .placeholder ;
54+ element .style .height = ' auto' ;
55+ const placeholderHeight = element .scrollHeight ;
56+
57+ // Restore original value
58+ element .value = originalValue ;
59+ newHeight = Math .max (placeholderHeight , 44 );
60+ }
61+
62+ element .style .height = newHeight + ' px' ;
4563};
4664
4765// Handle ingredient input changes
@@ -59,13 +77,9 @@ const onIngredientInput = (index: number, value: string, event: Event) => {
5977 // If typing in the last field and it's not empty, add a new field
6078 if (index === ingredients .value .length - 1 && value .trim ()) {
6179 ingredients .value .push ({description: " " });
62- // Auto-resize the new field after it's added to the DOM
80+ // Auto-resize all textareas after the new field is added to the DOM
6381 nextTick (() => {
64- const textareas = document .querySelectorAll (' .ingredient-textarea' );
65- const newTextarea = textareas [textareas .length - 1 ] as HTMLTextAreaElement ;
66- if (newTextarea ) {
67- autoResize (newTextarea );
68- }
82+ autoResizeAllTextareas ();
6983 });
7084 }
7185
@@ -95,13 +109,9 @@ const onStepInput = (index: number, value: string, event: Event) => {
95109 // If typing in the last field and it's not empty, add a new field
96110 if (index === preparationSteps .value .length - 1 && value .trim ()) {
97111 preparationSteps .value .push ({description: " " });
98- // Auto-resize the new field after it's added to the DOM
112+ // Auto-resize all textareas after the new field is added to the DOM
99113 nextTick (() => {
100- const textareas = document .querySelectorAll (' .step-textarea' );
101- const newTextarea = textareas [textareas .length - 1 ] as HTMLTextAreaElement ;
102- if (newTextarea ) {
103- autoResize (newTextarea );
104- }
114+ autoResizeAllTextareas ();
105115 });
106116 }
107117
@@ -177,13 +187,17 @@ onMounted(async () => {
177187 preparationSteps .value = [... recipe .preparationSteps , {description: " " }];
178188
179189 // Auto-resize all textareas after loading the data
180- autoResizeAllTextareas ();
190+ nextTick (() => {
191+ autoResizeAllTextareas ();
192+ });
181193 } catch (err ) {
182194 error .value = " Failed to load recipe for editing." ;
183195 }
184196 } else {
185197 // Auto-resize textareas on initial mount for new recipes
186- autoResizeAllTextareas ();
198+ nextTick (() => {
199+ autoResizeAllTextareas ();
200+ });
187201 }
188202});
189203
@@ -406,7 +420,7 @@ const cancelEdit = () => {
406420 :value =" ingredient.description"
407421 @input =" onIngredientInput(index, ($event.target as HTMLTextAreaElement).value, $event)"
408422 rows =" 1"
409- class =" ingredient-textarea bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-green-500 focus:border-green-500 block w-full p-2.5 pr-10 resize-none overflow-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-green-500 dark:focus:border-green-500"
423+ class =" ingredient-textarea bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-green-500 focus:border-green-500 block w-full p-2.5 pr-10 resize-none overflow-hidden min-h-[44px] dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-green-500 dark:focus:border-green-500"
410424 placeholder =" Add ingredient. Example: 3 tomatoes (diced)" ></textarea >
411425 <button
412426 v-if =" ingredients.length > 1 && index !== ingredients.length - 1"
@@ -473,7 +487,7 @@ const cancelEdit = () => {
473487 :value =" step.description"
474488 @input =" onStepInput(index, ($event.target as HTMLTextAreaElement).value, $event)"
475489 rows =" 1"
476- class =" step-textarea bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-green-500 focus:border-green-500 block w-full p-2.5 pr-10 resize-none overflow-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-green-500 dark:focus:border-green-500"
490+ class =" step-textarea bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-green-500 focus:border-green-500 block w-full p-2.5 pr-10 resize-none overflow-hidden min-h-[44px] dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-green-500 dark:focus:border-green-500"
477491 placeholder =" Add instruction step. Example: simmer the tomatoes" ></textarea >
478492 <button
479493 v-if =" preparationSteps.length > 1 && index !== preparationSteps.length - 1"
0 commit comments