mirror of
https://github.com/tabler/tabler.git
synced 2026-08-29 13:21:29 +04:00
94 lines
3.7 KiB
Plaintext
94 lines
3.7 KiB
Plaintext
---
|
|
import Icon from './Icon.astro'
|
|
import CaptureScript from '../components/CaptureScript.astro'
|
|
|
|
interface Props {
|
|
type?: astroHTML.JSX.HTMLInputTypeAttribute
|
|
placeholder?: string
|
|
value?: string
|
|
flat?: boolean
|
|
class?: string
|
|
inputClass?: string
|
|
id?: string
|
|
prepend?: string
|
|
append?: string
|
|
appendButton?: { icon: string; description: string; pressed?: boolean }[]
|
|
autocomplete?: string
|
|
}
|
|
|
|
const { type = 'text', placeholder, value, flat, class: className, inputClass, id, prepend, append, appendButton, autocomplete } = Astro.props
|
|
|
|
const appendButtons = appendButton ?? []
|
|
// A password field's "eye" button gets a working show/hide toggle instead of a static icon —
|
|
// it needs the field's id to target the input, so falls back to a plain icon button without one.
|
|
const hasPasswordToggle = type === 'password' && appendButtons.some((button) => button.icon === 'eye' && id)
|
|
|
|
// Built as a string (not a literal <script> tag) so Astro doesn't hoist/process it — see
|
|
// Signature.astro for the same pattern. CaptureScript renders this into the string it
|
|
// registers, and a real <script> element there would get extracted before that capture runs.
|
|
const toggleScript = `<!-- BEGIN INPUT GROUP PASSWORD TOGGLE -->
|
|
<script>
|
|
if (!window.__tablerPasswordToggleInit) {
|
|
window.__tablerPasswordToggleInit = true
|
|
document.addEventListener("click", (e) => {
|
|
const btn = e.target.closest("[data-password-toggle]")
|
|
if (!btn) return
|
|
const input = document.getElementById(btn.getAttribute("data-password-toggle"))
|
|
if (!input) return
|
|
const showing = input.type === "password"
|
|
input.type = showing ? "text" : "password"
|
|
const label = showing ? "Hide password" : "Show password"
|
|
btn.setAttribute("aria-pressed", showing ? "true" : "false")
|
|
btn.setAttribute("aria-label", label)
|
|
btn.setAttribute("title", label)
|
|
btn.setAttribute("data-bs-original-title", label)
|
|
btn.querySelector(".icon-toggle-show")?.classList.toggle("d-none", showing)
|
|
btn.querySelector(".icon-toggle-hide")?.classList.toggle("d-none", !showing)
|
|
})
|
|
}
|
|
</script>
|
|
<!-- END INPUT GROUP PASSWORD TOGGLE -->`
|
|
---
|
|
|
|
<div class:list={['input-group', flat && 'input-group-flat', className]}>
|
|
{prepend && <span class="input-group-text">{prepend}</span>}
|
|
<input type={type} class:list={['form-control', inputClass]} placeholder={placeholder} value={value} autocomplete={autocomplete} id={id} />
|
|
{append && <span class="input-group-text">{append}</span>}
|
|
{
|
|
appendButtons.length > 0 && (
|
|
<span class="input-group-text">
|
|
{appendButtons.map(({ icon, description, pressed }, index) => {
|
|
const isPasswordToggle = icon === 'eye' && type === 'password' && id
|
|
return (
|
|
<button
|
|
type="button"
|
|
class:list={['link-secondary input-group-link border-0 bg-transparent p-0', index > 0 && 'ms-2']}
|
|
title={description}
|
|
aria-label={description}
|
|
aria-pressed={isPasswordToggle || pressed !== undefined ? ((pressed ?? false) ? 'true' : 'false') : undefined}
|
|
data-bs-toggle="tooltip"
|
|
data-password-toggle={isPasswordToggle ? id : undefined}
|
|
>
|
|
{isPasswordToggle ? (
|
|
<Fragment>
|
|
<Icon name="eye" class="icon-toggle-show" />
|
|
<Icon name="eye-off" class="icon-toggle-hide d-none" />
|
|
</Fragment>
|
|
) : (
|
|
<Icon name={icon} />
|
|
)}
|
|
</button>
|
|
)
|
|
})}
|
|
</span>
|
|
)
|
|
}
|
|
</div>
|
|
{
|
|
hasPasswordToggle && (
|
|
<CaptureScript>
|
|
<Fragment set:html={toggleScript} />
|
|
</CaptureScript>
|
|
)
|
|
}
|