7
Pembungkusan Elemen input dan img
Elemen input dan img tidak bisa menampung anak elemen <div class="waves-ripple">, sehingga ripple tidak akan pernah tampil. TagWrapper adalah objek internal di src/js/waves.js yang menyelesaikan masalah itu: ia adalah kumpulan fungsi pembungkus untuk elemen HTML yang hanya punya satu tag, yaitu <input> dan <img> src/js/waves.js:202-2061. Setiap fungsi mengubah struktur DOM sebelum kelas waves-effect dipasang pada elemen.
Titik masuk pembungkusan
Pembungkusan hanya dipicu dari Waves.attach. Di dalam loop, tagName diambil dari element.tagName.toLowerCase(), lalu diperiksa terhadap daftar ['input', 'img']. Jika cocok, TagWrapper[tagName](element) dipanggil dan variabel element langsung diganti dengan element.parentElement, yaitu wrapper hasil pembungkusan src/js/waves.js:507-5152. Setelah itu barulah kelas waves-effect dan kelas tambahan ditempelkan ke elemen yang sekarang menunjuk ke wrapper src/js/waves.js:517-5193.
graph TD
A["Waves.attach: loop elemen"] --> B["tagName = element.tagName.toLowerCase"]
B --> C{"tagName ada di daftar input atau img"}
C -- tidak --> Z["className += ' waves-effect' + classes"]
C -- input --> D{"parent i sudah punya waves-effect"}
C -- img --> L{"parent i sudah punya waves-effect"}
D -- ya --> S["return: pass through tanpa pembungkusan"]
L -- ya --> S
D -- tidak --> E["wrapper = createElement i"]
E --> F["wrapper.className = element.className + waves-input-wrapper"]
F --> G["element.className = waves-button-input"]
G --> H["parent.replaceChild lalu wrapper.appendChild"]
H --> I["getComputedStyle: color dan backgroundColor"]
I --> J["wrapper style color + background"]
J --> K["element style background-color:rgba 0 0 0 0"]
L -- tidak --> M["wrapper = createElement i"]
M --> N["parent.replaceChild lalu wrapper.appendChild"]
K --> Z
N --> Z
Z --> O["element = element.parentElement"]
style A fill:#f59e0b,color:#000
style C fill:#f59e0b,color:#000
style D fill:#f59e0b,color:#000
style L fill:#f59e0b,color:#000
style S fill:#dc2626,color:#fff
style J fill:#8b5cf6,color:#fff
style K fill:#8b5cf6,color:#fff
style O fill:#2d7d46,color:#fff
%% fig: Urutan pembungkusan input dan img di Waves.attach
%% desc: attach memeriksa tagName, memilih jalur input atau img, membungkus elemen dengan i, lalu menempelkan waves-effect pada wrapper. Jalur input menyalin warna, jalur img tidak.Jalur input: kelas, gaya, dan warna
Fungsi TagWrapper.input mulai dengan penjaga pembungkusan ganda. Jika parentNode sudah berupa tag i yang memuat kelas waves-effect, fungsi langsung return tanpa menyentuh DOM src/js/waves.js:209-2164. Penjaga ini membuat Waves.attach aman dipanggil berulang pada elemen yang sama.
Bila belum dibungkus, fungsi membuat elemen i baru dan memindahkan identitas elemen ke wrapper: wrapper.className = element.className + ' waves-input-wrapper', sedangkan kelas asli pada input diganti menjadi waves-button-input src/js/waves.js:218-2255. Pertukaran lalu dilakukan dengan parent.replaceChild(wrapper, element) diikuti wrapper.appendChild(element), sehingga input menjadi anak wrapper pada posisi yang sama src/js/waves.js:218-2255.
Langkah terakhir menyalin warna. window.getComputedStyle(element, null) dibaca untuk mengambil color dan backgroundColor, keduanya ditulis sebagai atribut style pada wrapper, lalu input sendiri diberi background-color:rgba(0,0,0,0) agar latar aslinya tidak menutupi ripple src/js/waves.js:227-2336.
Jalur img: pembungkusan tanpa penyalinan gaya
Fungsi TagWrapper.img memakai penjaga yang sama persis: parent bertag i dengan kelas waves-effect berarti elemen sudah dibungkus dan fungsi berhenti src/js/waves.js:238-2457. Jika belum, fungsi hanya membuat elemen i, memanggil parent.replaceChild(wrapper, element), lalu wrapper.appendChild(element) src/js/waves.js:247-2508. Tidak ada pemindahan kelas, tidak ada getComputedStyle, dan tidak ada penulisan atribut style. Wrapper img baru memperoleh kelas waves-effect saat kendali kembali ke Waves.attach.
| Aspek | input | img |
|---|---|---|
| Penjaga pembungkusan ganda | parent i + waves-effect → return src/js/waves.js:209-2164 | parent i + waves-effect → return src/js/waves.js:238-2457 |
| Kelas pada wrapper | element.className + ' waves-input-wrapper' src/js/waves.js:218-2255 | tidak diisi |
| Kelas pada elemen | diganti waves-button-input src/js/waves.js:218-2255 | tidak diubah src/js/waves.js:247-2508 |
Nilai color dan backgroundColor | disalin ke wrapper lewat setAttribute('style', ...) src/js/waves.js:227-2336 | tidak disalin |
| Latar elemen | dipaksa rgba(0,0,0,0) src/js/waves.js:227-2336 | tidak diubah |
| Operasi DOM | replaceChild lalu appendChild src/js/waves.js:218-2255 | replaceChild lalu appendChild src/js/waves.js:247-2508 |
Mengapa wrapper yang menerima efek
Effect.show menempelkan ripple sebagai anak dari elemen yang dianggap memicu efek, yaitu document.createElement('div') dengan kelas waves-ripple waves-rippling yang di-appendChild ke elemen tersebut src/js/waves.js:120-1229. Elemen itu dicari oleh getWavesEffectElement, yang menelusuri target.parentElement sampai menemukan node dengan kelas waves-effect src/js/waves.js:366-38310. Karena kelas waves-effect ditempel pada wrapper <i>, ripple selalu lahir di dalam wrapper, bukan di dalam input atau img.
Penelusuran ke atas juga menjelaskan mengapa wrapper harus menjadi wadah ripple: .waves-effect menetapkan position: relative dan overflow: hidden src/less/waves.less:29-3311, sehingga .waves-ripple yang memakai position: absolute dengan ukuran 100px terpotong rapi pada kotak wrapper src/less/waves.less:29-3311. Tanpa wrapper, tidak ada kotak ber-overflow: hidden yang bisa memotong ripple pada elemen input atau img.
Gaya yang menyertai wrapper
.waves-input-wrapper menambahkan border-radius: 0.2em dan vertical-align: bottom, menetralkan padding bila wrapper juga memakai .waves-button, dan membuat .waves-button-input di dalamnya menjadi position: relative dengan top: 0, left: 0, serta z-index: 1 src/less/waves.less:119-13312. Aturan terakhir ini penting karena input yang sudah dipindah ke dalam wrapper harus tetap berada di atas lapisan ripple.
.waves-button-input sendiri masuk satu grup selektor dengan .waves-button, yang menetapkan border: none, outline: none, background-color: rgba(0, 0, 0, 0), cursor: pointer, dan z-index: 1 src/less/waves.less:91-10713. Inilah sebabnya input hasil pembungkusan tampak tanpa border dan latar transparan meski atribut style-nya ditimpa.
⚠️
TagWrapper.inputmemanggilelement.setAttribute('style', 'background-color:rgba(0,0,0,0);'), yang mengganti seluruh atributstylepadainput. Gaya inline lain sepertiwidthataupaddingpadainputikut hilang dan harus dipindahkan ke wrapper atau ke aturan CSS src/js/waves.js:227-2336.
⚠️ Warna yang disalin hanya
colordanbackgroundColorhasilgetComputedStyle. Latar berupa gradient ataubackground-imagepadainputtidak terbawa ke wrapper, sehingga ripple berjalan di atas latar transparan src/js/waves.js:227-2336.
Untuk melihat bagaimana elemen hasil pembungkusan menerima event dan menghitung koordinat ripple, lihat Alur Efek Klik dari Event ke Elemen. Untuk urutan kelas yang dipakai ripple saat muncul dan hilang, lihat Siklus Hidup Ripple.