diff --git a/app/assets/stylesheets/autoresize.css b/app/assets/stylesheets/autoresize.css
new file mode 100644
index 000000000..ac16e04a4
--- /dev/null
+++ b/app/assets/stylesheets/autoresize.css
@@ -0,0 +1,27 @@
+@layer components {
+ @supports not (field-sizing: content) {
+ .autoresize__wrapper {
+ display: grid !important;
+ position: relative;
+
+ > *, &::after {
+ grid-area: 1 / 1 / 2 / 2;
+ }
+
+ &::after {
+ content: attr(data-autoresize-clone-value) " ";
+ font: inherit;
+ line-height: inherit;
+ visibility: hidden;
+ white-space: pre-wrap;
+ }
+ }
+
+ .autoresize__textarea {
+ inset: 0;
+ overflow: hidden;
+ position: absolute;
+ resize: none;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css
index d13b60498..53315b8a6 100644
--- a/app/assets/stylesheets/cards.css
+++ b/app/assets/stylesheets/cards.css
@@ -174,6 +174,12 @@
line-height: 1.2;
text-wrap: balance;
+ @supports not (field-sizing: content) {
+ &:has(textarea) {
+ text-wrap: unset; /* Safari is annoying if you have text-wrap: balance in textareas */
+ }
+ }
+
.card-field__title {
&:is(textarea)::placeholder {
color: inherit;
diff --git a/app/javascript/controllers/autoresize_controller.js b/app/javascript/controllers/autoresize_controller.js
new file mode 100644
index 000000000..02b6cc501
--- /dev/null
+++ b/app/javascript/controllers/autoresize_controller.js
@@ -0,0 +1,13 @@
+import { Controller } from "@hotwired/stimulus"
+
+export default class extends Controller {
+ static targets = ["textarea", "wrapper"]
+
+ connect() {
+ this.resize()
+ }
+
+ resize() {
+ this.wrapperTarget.setAttribute("data-autoresize-clone-value", this.textareaTarget.value)
+ }
+}
diff --git a/app/views/cards/container/_title.html.erb b/app/views/cards/container/_title.html.erb
index 8bbe68550..1767fd854 100644
--- a/app/views/cards/container/_title.html.erb
+++ b/app/views/cards/container/_title.html.erb
@@ -10,12 +10,12 @@
<% end %>
<% else %>
- <%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "card__content", data: { controller: "auto-save" } do |form| %>
-
+ <%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "card__content", data: { controller: "autoresize auto-save" } do |form| %>
+
<%= form.text_area :title, placeholder: "Name it…",
- class: "input input--textarea full-width borderless txt-align-start",
- autofocus: card.title.blank?,
- data: { action: "auto-save#change blur->auto-save#submit keydown.enter->auto-save#submit:prevent keydown.ctrl+enter->auto-save#submit:prevent" } %>
+ class: "input input--textarea full-width borderless txt-align-start autoresize__textarea",
+ autofocus: card.title.blank?, rows: 1,
+ data: { autoresize_target: "textarea", action: "input->autoresize#resize auto-save#change blur->auto-save#submit keydown.enter->auto-save#submit:prevent keydown.ctrl+enter->auto-save#submit:prevent" } %>
<%= form.rich_textarea :description, class: "card-field__description",
diff --git a/app/views/cards/edit.html.erb b/app/views/cards/edit.html.erb
index c02e2a635..6a8d37e13 100644
--- a/app/views/cards/edit.html.erb
+++ b/app/views/cards/edit.html.erb
@@ -1,11 +1,10 @@
<%= turbo_frame_tag @card, :edit do %>
- <%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "card__content", data: { controller: "form" } do |form| %>
+ <%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "card__content", data: { controller: "autoresize form" } do |form| %>
- <%= form.label :title, class: "flex flex-column align-center" do %>
- <%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card-field__title",
- required: true, autofocus: true, placeholder: "Name it…",
- rows: 1,
- data: { action: "keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" } %>
+ <%= form.label :title, class: "flex flex-column align-center autoresize__wrapper", data: { autoresize_target: "wrapper", autoresize_clone_value: "" } do %>
+ <%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card-field__title autoresize__textarea",
+ required: true, autofocus: true, placeholder: "Name it…", rows: 1,
+ data: { autoresize_target: "textarea", action: "input->autoresize#resize keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" } %>
<% end %>