Initial release — Astro Rocket v1.0.0

This commit is contained in:
Claude
2026-04-06 07:31:47 +00:00
commit ddd0c22311
275 changed files with 38839 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
---
/**
* PasswordInput Pattern
* Composition example: Input with show/hide password toggle.
* Demonstrates building interactive patterns from UI primitives.
*/
import type { HTMLAttributes } from 'astro/types';
import { cn } from '@/lib/cn';
import { generateId } from '@/lib/utils';
import { inputVariants, inputSizeConfig } from '@/components/ui/form/Input/input.variants';
import Icon from '@/components/ui/primitives/Icon/Icon.astro';
interface Props extends HTMLAttributes<'input'> {
label?: string;
error?: string;
hint?: string;
size?: 'sm' | 'md' | 'lg';
placeholder?: string;
class?: string;
id?: string;
autocomplete?: string;
}
const {
label,
error,
hint,
size = 'md',
placeholder = 'Enter password',
autocomplete = 'current-password',
class: className,
id,
...rest
} = Astro.props;
const inputId = id || generateId('password');
const config = inputSizeConfig[size];
const inputStyles = cn(
inputVariants({ size }),
error && 'border-destructive focus-visible:ring-destructive',
config.baseLeftPadding,
config.trailingPadding
);
---
<div class={cn('space-y-1.5', className)}>
{label && (
<label for={inputId} class="text-sm font-medium leading-none">
{label}
</label>
)}
<div class="relative">
<input
type="password"
id={inputId}
class={inputStyles}
placeholder={placeholder}
autocomplete={autocomplete}
aria-invalid={error ? 'true' : undefined}
aria-describedby={error ? `${inputId}-error` : hint ? `${inputId}-hint` : undefined}
data-password-input
{...rest}
/>
<button
type="button"
class={cn(
'absolute right-0 top-0 flex items-center justify-center h-full',
'text-foreground-muted hover:text-foreground transition-colors',
config.iconWrapper
)}
data-password-toggle
aria-label="Toggle password visibility"
>
<span data-icon-show><Icon name="eye" size="sm" /></span>
<span data-icon-hide class="hidden"><Icon name="eye-off" size="sm" /></span>
</button>
</div>
{error && (
<p id={`${inputId}-error`} class="text-sm text-destructive">{error}</p>
)}
{hint && !error && (
<p id={`${inputId}-hint`} class="text-sm text-muted-foreground">{hint}</p>
)}
</div>
<script>
function initPasswordInputs() {
document.querySelectorAll('[data-password-toggle]').forEach((el) => {
const btn = el as HTMLElement;
if (btn.dataset.initialized) return;
btn.dataset.initialized = 'true';
btn.addEventListener('click', () => {
const input = btn.parentElement?.querySelector('[data-password-input]') as HTMLInputElement;
const showIcon = btn.querySelector('[data-icon-show]') as HTMLElement;
const hideIcon = btn.querySelector('[data-icon-hide]') as HTMLElement;
if (!input || !showIcon || !hideIcon) return;
const isPassword = input.type === 'password';
input.type = isPassword ? 'text' : 'password';
showIcon.classList.toggle('hidden', isPassword);
hideIcon.classList.toggle('hidden', !isPassword);
});
});
}
initPasswordInputs();
document.addEventListener('astro:page-load', initPasswordInputs);
</script>