2 poin oleh GN⁺ 2024-12-06 | 1 komentar | Bagikan ke WhatsApp
  • @stanko/dual-range-input menggabungkan dua HTML range input native untuk membuat slider rentang ganda, sambil tetap memanfaatkan interaksi bawaan browser dan aksesibilitasnya
  • Implementasinya berpusat pada sekitar 50 baris JavaScript untuk menyinkronkan nilai input serta CSS, sehingga lebih sederhana dibanding pendekatan lama yang membuat ulang drag dan aksesibilitas sendiri
  • Pada kedua input, min, max, dan lebar diperbarui sesuai titik tengah nilai yang dipilih; saat track diklik, thumb yang lebih dekat akan berpindah ke nilai tersebut
  • Karena track pada range input lebih pendek daripada lebar input sebenarnya, lebar thumb ikut ditambahkan dalam perhitungan dan kelebihan lebar diserap dengan padding wrapper
  • Tema dapat disesuaikan dengan variabel CSS dan gradient, sehingga warna rentang terpilih, ukuran thumb, warna track, dan lainnya bisa dioverride

Slider ganda yang dibuat dengan range input native

  • @stanko/dual-range-input mengimplementasikan input rentang ganda dengan menempatkan dua HTML range input secara berdampingan
  • Di sini, “native” bukan berarti satu kontrol browser tunggal, melainkan menggunakan dua range input untuk mempertahankan interaksi bawaan browser dan fitur aksesibilitas
  • Implementasinya terdiri dari sekitar 50 baris JavaScript untuk menyinkronkan input serta CSS untuk penyempurnaan visual
  • Titik awalnya adalah kebutuhan UI pada alat menggambar generatif untuk menyesuaikan nilai minimum dan maksimum parameter
  • Ada dua persyaratan
    • Menggunakan HTML range input native
    • Saat track diklik, thumb yang lebih dekat dari dua thumb harus berpindah ke nilai tersebut

Sinkronisasi nilai dan penanganan klik

  • Ketika salah satu dari dua input berubah, library menghitung titik tengah di antara dua nilai yang dipilih
    • Atribut min dan max dari masing-masing input diatur sesuai titik tengah
    • Lebar kedua input juga diperbarui berdasarkan titik tengah
  • Karena ukuran input disesuaikan agar keduanya bertemu di titik tengah, saat area di antara dua thumb diklik, thumb yang lebih dekat dengan posisi klik akan berpindah
    • Jika jumlah step di antara dua thumb ganjil, input yang terakhir digunakan diprioritaskan

Perhitungan CSS dan styling

  • Track pada range input lebih pendek daripada lebar input penuh, dan browser menyisakan ruang di kedua sisi agar thumb tidak menonjol keluar
    • Jika lebar input hanya dibagi seperti 25% dan 75%, rasio track sebenarnya tidak akan sesuai
    • Implementasi ini menambahkan --dri-thumb-width ke lebar masing-masing input, lalu menambahkan padding pada wrapper untuk menampung kelebihan lebar
  • Styling menggunakan kemampuan styling CSS untuk range input di browser
    • Track dan thumb dihias, dan bagian tengah tempat dua track bertemu ditangani agar tidak muncul border radius
  • Tema dapat dibuat dengan override variabel CSS
    • Variabel utamanya meliputi --dri-height, --dri-thumb-width, --dri-thumb-color, --dri-track-color, --dri-track-filled-color, --dri-track-border-radius, dan lainnya
  • Rentang yang dipilih diwarnai dengan CSS gradient
    • Posisi gradient ditentukan dengan variabel --dri-gradient-position
    • Saat lebar input diperbarui dalam kode, variabel ini juga ikut diperbarui
  • Implementasi ini adalah pendekatan yang sebisa mungkin memanfaatkan elemen native terlebih dahulu, alih-alih membuat ulang drag dan aksesibilitas dengan library kustom

1 komentar

 
GN⁺ 2024-12-06
Komentar Hacker News
  • Menurut saya slider semacam ini area tengahnya juga harus selalu bisa di-drag. Artinya, jika bagian tengah dipegang, kedua handle bergerak bersamaan
    Sebagai referensi, Unity menanganinya seperti ini: https://docs.unity3d.com/StaticFiles/ScriptRefImages/EditorG...

    • Sebaliknya, saya rasanya sama sekali tidak akan terpikir untuk mengklik area tengah. Di kepala saya, ini terlihat bukan widget yang sepenuhnya baru, melainkan slider yang dimodifikasi
      “Selalu” mungkin agak berlebihan
  • Saya penulisnya. Senang melihat ini muncul di HN
    Saya melihat orang-orang mulai meninggalkan issue dan laporan bug di sini, dan karena di sini sudah larut, saya akan memeriksanya besok
    Saya membuatnya karena membutuhkannya untuk pekerjaan gambar generatif, dan saya lebih suka men-drag slider sambil melihat bagaimana gambar berubah daripada memasukkan angka
    Saya berusaha menjaganya tetap minimalis sebisa mungkin

    • Saya sangat suka tulisan ini. Sambil minum kopi pagi, saya menikmati penjelasan tentang proses perhitungan dan mode debugging, dan merasa ini cara yang cerdas memanfaatkan komponen native
      Saat ini saya memakai SwiftUI, dan membuat komponen sendiri hampir terlalu mudah. Namun seperti yang dijelaskan penulis, itu tidak selalu pilihan terbaik, dan komponen native sering kali punya fitur yang cukup lengkap
      Saya juga mengecek tulisannya di browser yang agak tidak biasa, Firefox di iOS, dan semuanya berjalan baik. Dibuat dengan sangat bagus
  • Saat mencoba langsung, saya segera menemukan bug. Setelah men-drag slider ke 100 - 100, lalu mencoba membuatnya menjadi 99 - 99, itu tidak bisa
    Dari 99 - 100 juga tidak bisa, dan dari 98 - 99 juga tidak bisa. Satu-satunya cara menuju 99 - 99 adalah menarik batas bawah ke lebih rendah dari 98
    Jika dari kondisi 98 - 99 diturunkan menjadi 97 - 99, barulah bisa menuju 99 - 99
    Bug ini bisa terjadi di mana saja; 99 - 99 hanya paling mudah direproduksi karena dekat dengan ujung slider. Secara umum, dari suatu kondisi X - X, jika salah satu ujung digeser 1 langkah, ujung lainnya tidak bisa ditarik masuk ke celah itu. Untuk menutup jaraknya, ujung lainnya harus ditarik lebih jauh dulu

    • Temuan bagus! Sebenarnya saya sudah memikirkan kasus ini dan di Chrome serta Firefox bekerja, tetapi Safari sepertinya tidak memicu event focus saat mouse down, dan baru memicunya ketika slider mulai digerakkan
      Terima kasih atas laporannya, pasti akan saya perbaiki
    • Di Chromium pada desktop Linux, 100-100 → 99-100 → 99-99 berjalan baik
      Namun ada bug visual lain. Jika mulai dari 23-25 lalu di-drag ke 24-25, handle kanan yang ada di 25 bergerak beberapa piksel. Jika handle kiri dikembalikan ke 23, handle kanan juga ikut kembali
    • Karena itulah saya suka membuat developer tools
  • Keren! Saya selalu berpikir HTML input memang perlu implementasi input rentang dua nilai, karena itu sangat masuk akal
    Misalnya ada use case seperti “ingin memfilter produk yang memiliki minimal X widget dan maksimal Y widget”
    Namun saya menemukan bug di Firefox yang ingin saya soroti. Setiap kali mengklik handle minimum atau maksimum, nilainya berubah satu langkah naik atau turun
    Jika berusaha mengklik tepat di tengah handle, nilainya tidak berubah, tetapi jika mengklik sedikit di kiri, nilai pilihan turun satu langkah, dan jika mengklik sedikit di kanan, nilainya naik
    Perilaku yang diharapkan adalah nilai hanya berubah ketika ada aksi perubahan eksplisit, yaitu saat tombol ditekan dan pointer mouse benar-benar digerakkan

    • Jujur, menurut saya itu bukan bug. Semua contohnya cukup rapat, dan handle menutupi beberapa langkah pada track
      Firefox menafsirkan klik seperti itu seolah-olah klik langsung pada track. Library ini sama sekali tidak ikut campur di situ; itu memang cara kerja Firefox
  • Bagus sekali bahwa ini berfungsi dengan keyboard. Berjalan dengan benar, sehingga jika menahan Shift-Tab, kita juga bisa bergerak mundur
    Benar-benar dibuat dengan baik, dan meski ini detail sangat kecil, saya berterima kasih karena interaksi itu diimplementasikan dengan tepat

  • Di design system perusahaan kami, seorang intern juga membuat proof of concept berdampingan seperti ini, tetapi selalu ada fenomena piksel salah satu input sedikit melompat, dan akhirnya tidak pernah berhasil dibuat dengan benar
    Jadi intern kedua mengusulkan solusi memakai 2 input range yang ditumpuk

  • Setiap kali membutuhkan input rentang, saya memakai slider jQuery UI, dan harus menambahkan jQuery serta jQuery UI ke halaman hanya demi satu slider. Ini benar-benar bagus
    Edit: Apakah ada kemungkinan menyediakan file JS biasa yang siap pakai, alih-alih modul ESM?

  • Entah apakah boleh melaporkan bug di sini. Handle pada dua contoh pertama mengambil alih interaksi sentuh sehingga mencegah scrolling. Tiga contoh berikutnya tidak begitu
    Efek sampingnya, label di bawah jari tidak bisa dibuat terlihat dengan men-drag ke atas, dan halaman malah di-scroll sehingga label tetap berada di bawah jari

    • Jika bisa direproduksi, akan bagus kalau membuka GitHub issue [1]
      Saya penasaran browser dan sistem operasi apa yang dipakai. Library ini memakai input native, jadi tidak melakukan apa pun terkait pemblokiran scroll
      Di ponsel iOS saya, scrolling diblokir pada semua elemen input[type=range], terlepas dari apakah styling diterapkan atau tidak
      [1] https://github.com/Stanko/dual-range-input/issues
  • Bagian “native” masih bisa diperdebatkan. Katanya karena library ini memakai dua input range HTML native, interaksi native dan fitur aksesibilitas tetap dipertahankan, tetapi standar saya jelas
    Jika agar bekerja sesuai maksudnya membutuhkan JavaScript, maka itu bukan native lagi

    • Setuju. Saya rasa biasanya istilah itu juga dipakai begitu
      Meski begitu, saya paham maksud penulisnya. Karena ini menggabungkan slider biasa alih-alih mengimplementasikan sendiri tumpukan div yang digerakkan JS, solusinya jauh lebih dekat ke native. Jika CSS cerdas tidak bisa menggantikan JavaScript, mungkin ini cara yang sedekat mungkin
      Terlepas dari native atau bukan, widget seperti ini sangat berguna jika tersedia, dan di area itu implementasinya masih kurang
    • Biasanya memang begitu, tetapi batasnya tidak sepenuhnya tegas. Elemennya native, tetapi ada kasus ketika JavaScript diperlukan untuk membukanya dalam state modal
      Sebelum atribut popover muncul, sama sekali tidak bisa dibuka tanpa JavaScript
      Ada juga metode JavaScript vanilla native yang layak dibedakan dari library yang sama sekali tidak memakai alat validasi internal browser, seperti validasi form
  • Saya sedang mencari hal seperti ini saat membuat https://spodj.intermer.net/
    Untuk mendapatkan fungsi yang dibutuhkan, saya harus memakai React secara serampangan, karena saya tidak begitu mahir dalam pengembangan frontend