From a5840501b41a90ff453b7f8fb28e872a659e2813 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Sun, 29 Mar 2026 20:47:36 +0200
Subject: [PATCH] fix(forms): use Alpine state for password visibility toggles
Replace shared `changePasswordFieldType` JS with component-local Alpine logic
across input, textarea, and env-var-input components. This keeps toggle
behavior consistent, resets visibility on `success` events, and preserves
`truncate` styling only when showing plaintext on enabled fields.
Also adds `PasswordVisibilityComponentTest` to verify Alpine bindings are
rendered and legacy handler references are removed.
---
.../components/forms/env-var-input.blade.php | 26 ++++++++----
.../views/components/forms/input.blade.php | 13 +++---
.../views/components/forms/textarea.blade.php | 18 +++++---
resources/views/layouts/base.blade.php | 26 +-----------
.../PasswordVisibilityComponentTest.php | 41 +++++++++++++++++++
5 files changed, 80 insertions(+), 44 deletions(-)
create mode 100644 tests/Feature/PasswordVisibilityComponentTest.php
diff --git a/resources/views/components/forms/env-var-input.blade.php b/resources/views/components/forms/env-var-input.blade.php
index 2466a57f9..d26e248c1 100644
--- a/resources/views/components/forms/env-var-input.blade.php
+++ b/resources/views/components/forms/env-var-input.blade.php
@@ -10,7 +10,7 @@
@endif
-
@if ($type === 'password' && $allowToPeak)
-
+
+
@endif
merge(['class' => $defaultClass]) }}
@required($required)
@readonly($readonly)
@@ -210,12 +220,10 @@ class="flex absolute inset-y-0 right-0 items-center pr-2 cursor-pointer dark:hov
wire:dirty.class="dark:border-l-warning border-l-coollabs border-l-4"
@endif
wire:loading.attr="disabled"
- @if ($type === 'password')
- :type="type"
- @else
+ @disabled($disabled)
+ @if ($type !== 'password')
type="{{ $type }}"
@endif
- @disabled($disabled)
@if ($htmlId !== 'null') id="{{ $htmlId }}" @endif
name="{{ $name }}"
placeholder="{{ $attributes->get('placeholder') }}"
diff --git a/resources/views/components/forms/input.blade.php b/resources/views/components/forms/input.blade.php
index cf72dfbe9..456aa1da8 100644
--- a/resources/views/components/forms/input.blade.php
+++ b/resources/views/components/forms/input.blade.php
@@ -13,10 +13,11 @@
@endif
@if ($type === 'password')
-
+
@if ($allowToPeak)
-
+
+
@endif
merge(['class' => $defaultClass]) }} @required($required)
@if ($modelBinding !== 'null') wire:model={{ $modelBinding }} wire:dirty.class="[box-shadow:inset_4px_0_0_#6b16ed,inset_0_0_0_2px_#e5e5e5] dark:[box-shadow:inset_4px_0_0_#fcd452,inset_0_0_0_2px_#242424]" @endif
wire:loading.attr="disabled"
- type="{{ $type }}" @readonly($readonly) @disabled($disabled) id="{{ $htmlId }}"
+ @readonly($readonly) @disabled($disabled) id="{{ $htmlId }}"
name="{{ $name }}" placeholder="{{ $attributes->get('placeholder') }}"
aria-placeholder="{{ $attributes->get('placeholder') }}"
@if ($autofocus) x-ref="autofocusInput" @endif>
diff --git a/resources/views/components/forms/textarea.blade.php b/resources/views/components/forms/textarea.blade.php
index 3f8fdb112..22c89fd72 100644
--- a/resources/views/components/forms/textarea.blade.php
+++ b/resources/views/components/forms/textarea.blade.php
@@ -30,18 +30,26 @@ function handleKeydown(e) {
readonly="{{ $readonly }}" label="dockerfile" autofocus="{{ $autofocus }}" />
@else
@if ($type === 'password')
-
+
@if ($allowToPeak)
-
+
+
@endif
merge(['class' => $defaultClassInput]) }} @required($required)
diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php
index 2b4ca6054..33968ee32 100644
--- a/resources/views/layouts/base.blade.php
+++ b/resources/views/layouts/base.blade.php
@@ -203,30 +203,6 @@ function checkTheme() {
let checkHealthInterval = null;
let checkIfIamDeadInterval = null;
- function changePasswordFieldType(event) {
- let element = event.target
- for (let i = 0; i < 10; i++) {
- if (element.className === "relative") {
- break;
- }
- element = element.parentElement;
- }
- element = element.children[1];
- if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
- if (element.type === 'password') {
- element.type = 'text';
- if (element.disabled) return;
- element.classList.add('truncate');
- this.type = 'text';
- } else {
- element.type = 'password';
- if (element.disabled) return;
- element.classList.remove('truncate');
- this.type = 'password';
- }
- }
- }
-
function copyToClipboard(text) {
navigator?.clipboard?.writeText(text) && window.Livewire.dispatch('success', 'Copied to clipboard.');
}
@@ -326,4 +302,4 @@ function copyToClipboard(text) {