Files
WRNexusJS/packages/ui/components/TogglePassword.wrn
T
2026-08-01 01:09:58 +05:30

157 lines
6.0 KiB
Plaintext

component TogglePassword {
outputs {
input(payload: { name?: string; value: string | number | boolean | null | object; visible: boolean })
change(payload: { name?: string; value: string | number | boolean | null | object; visible: boolean })
toggle(payload: { visible: boolean })
}
props {
size: string = "default"
color: string = "primary"
label: string = "Password"
name: string = "password"
value: string = ""
placeholder: string = "Enter your password"
autocomplete: string = "current-password"
minlength: string = ""
maxlength: string = ""
pattern: string = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"
fields: unknown[] = []
visible: boolean = false
toggleable: boolean = true
toggleMode: string = "button"
checkboxLabel: string = "Show password"
showLabel: string = "Show password"
hideLabel: string = "Hide password"
disabled: boolean = false
readonly: boolean = false
required: boolean = false
invalid: boolean = false
helpText: string = ""
validationMessage: string = ""
class: string = ""
}
state revealed = visible
functions {
shared function toggleVisibility() {
if (disabled || readonly || !toggleable) {
return
}
revealed = !revealed
}
shared function fieldId(field, index) {
return field.id || field.name || name + "-" + index
}
shared function fieldName(field, index) {
return field.name || name + "-" + index
}
}
view {
<fieldset
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toggle-password {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-wrn-toggle-password
data-visible="{revealed ? 'true' : 'false'}"
>
{#if fields.length}
<div class="wire-next__password-fields">
{#each fields as field, index}
<div class="wire-next__password-field">
<label for="{fieldId(field, index)}">{field.label || label}</label>
<div class="wire-next__password-control">
<input
id="{fieldId(field, index)}"
type="{revealed ? 'text' : 'password'}"
name="{fieldName(field, index)}"
value="{field.value || ''}"
placeholder="{field.placeholder || placeholder}"
autocomplete="{field.autocomplete || autocomplete}"
minlength="{field.minlength || minlength}"
maxlength="{field.maxlength || maxlength}"
pattern="{field.pattern || pattern}"
disabled="{disabled || field.disabled}"
readonly="{readonly || field.readonly}"
required="{required || field.required}"
aria-invalid="{invalid ? 'true' : 'false'}"
@input="output.input({ name: event.target.name, value: event.target.value, visible: revealed })"
@change="output.change({ name: event.target.name, value: event.target.value, visible: revealed })"
/>
{#if toggleable && toggleMode === "button"}
<button
type="button"
class="wire-next__password-toggle"
aria-label="{revealed ? hideLabel : showLabel}"
title="{revealed ? hideLabel : showLabel}"
aria-pressed="{revealed ? 'true' : 'false'}"
disabled="{disabled || readonly}"
@click="toggleVisibility(); output.toggle({ visible: revealed })"
>
<span class="wire-next__password-icon wire-next__password-icon--show" aria-hidden="true"></span>
</button>
{/if}
</div>
</div>
{/each}
</div>
{:else}
<label for="{name}-password">{label}</label>
<div class="wire-next__password-control">
<input
{...attrs}
id="{name}-password"
type="{revealed ? 'text' : 'password'}"
name="{name}"
value="{value}"
placeholder="{placeholder}"
autocomplete="{autocomplete}"
minlength="{minlength}"
maxlength="{maxlength}"
pattern="{pattern}"
disabled="{disabled}"
readonly="{readonly}"
required="{required}"
aria-invalid="{invalid ? 'true' : 'false'}"
aria-describedby="{validationMessage ? name + '-validation' : helpText ? name + '-help' : ''}"
@input="output.input({ value: event.target.value, visible: revealed })"
@change="output.change({ value: event.target.value, visible: revealed })"
/>
{#if toggleable && toggleMode === "button"}
<button
type="button"
class="wire-next__password-toggle"
aria-label="{revealed ? hideLabel : showLabel}"
title="{revealed ? hideLabel : showLabel}"
aria-pressed="{revealed ? 'true' : 'false'}"
disabled="{disabled || readonly}"
@click="toggleVisibility(); output.toggle({ visible: revealed })"
>
<span class="wire-next__password-icon wire-next__password-icon--show" aria-hidden="true"></span>
</button>
{/if}
</div>
{/if}
{#if toggleable && toggleMode === "checkbox"}
<label class="wire-next__password-checkbox">
<input
type="checkbox"
checked="{revealed}"
disabled="{disabled || readonly}"
@change="revealed = event.target.checked; output.toggle({ visible: revealed })"
/>
<span>{checkboxLabel}</span>
</label>
{/if}
{#if helpText && !validationMessage}<small id="{name}-help">{helpText}</small>{/if}
<small
id="{name}-validation"
class="wire-next__validation"
data-error="{name}"
>{validationMessage}</small>
</fieldset>
}
}