Skip to content

Commit 79aa707

Browse files
committed
Fix mobile textarea sizing and placeholder text display
- Fix placeholder text height measurement in textareas - Ensure text boxes properly size to multi-line placeholder text - Improve auto-resize logic to account for empty vs content states - Add proper minimum height handling for single-line text - Enhance initialization and dynamic field addition
1 parent 857b79a commit 79aa707

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

ui/src/components/CreateRecipe.vue

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,26 @@ const checkMobile = () => {
4040
4141
// Auto-resize function for textareas
4242
const 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

Comments
 (0)