{# # ============================================================================ # ATOM: INPUT # ============================================================================ # # Champ de saisie paramétrable utilisant 100% Tailwind CSS. # # ============================================================================ # PARAMÈTRES # ============================================================================ # # | Paramètre | Type | Défaut | Description | # |----------------|---------|-----------|------------------------------------------| # | type | string | 'text' | Type: text, email, password, number, etc.| # | label | string | null | Label du champ | # | placeholder | string | '' | Placeholder | # | value | string | '' | Valeur du champ | # | name | string | null | Attribut name | # | id | string | null | Attribut id (auto-généré si absent) | # | required | bool | false | Champ obligatoire | # | disabled | bool | false | Champ désactivé | # | readonly | bool | false | Champ en lecture seule | # | error | string | null | Message d'erreur | # | hint | string | null | Texte d'aide | # | icon | string | null | Nom de l'icône | # | iconPosition | string | 'left' | Position: left, right | # | size | string | 'md' | Taille: sm, md, lg | # | variant | string | 'default' | Style: default, filled | # | rows | number | 4 | Lignes pour textarea | # | class | string | '' | Classes additionnelles | # | attr | object | {} | Attributs HTML additionnels | # # ============================================================================ # EXEMPLES D'UTILISATION # ============================================================================ # # Input simple: # {% include '_atoms/form/input.html.twig' with { # label: 'Email', # type: 'email', # placeholder: 'votre@email.com' # } %} # # Avec icône et erreur: # {% include '_atoms/form/input.html.twig' with { # label: 'Mot de passe', # type: 'password', # icon: 'lock', # error: 'Le mot de passe est requis' # } %} # # Textarea: # {% include '_atoms/form/input.html.twig' with { # type: 'textarea', # label: 'Description', # rows: 6 # } %} # # ============================================================================ #} {# ============================================================================ CONFIGURATION DES VALEURS PAR DÉFAUT ============================================================================ #} {% set type = type ?? 'text' %} {% set label = label ?? null %} {% set placeholder = placeholder ?? '' %} {% set value = value ?? '' %} {% set name = name ?? null %} {% set id = id ?? (name ? 'input-' ~ name : 'input-' ~ random()) %} {% set required = required ?? false %} {% set disabled = disabled ?? false %} {% set readonly = readonly ?? false %} {% set error = error ?? null %} {% set hint = hint ?? null %} {% set icon = icon ?? null %} {% set iconPosition = iconPosition ?? 'left' %} {% set size = size ?? 'md' %} {% set variant = variant ?? 'default' %} {% set rows = rows ?? 4 %} {% set maxlength = maxlength ?? null %} {% set showCount = showCount ?? false %} {% set class = class ?? '' %} {% set attr = attr ?? {} %} {# ============================================================================ CLASSES TAILWIND - BASE ============================================================================ #} {% set baseClasses = 'w-full font-primary transition-all duration-base ease-default border-2 outline-none focus:border-primary focus:ring-2 focus:ring-primary/20' %} {# ============================================================================ CLASSES TAILWIND - VARIANTES ============================================================================ #} {% set variantClasses = { 'default': 'bg-white border-gray-300 text-black placeholder-gray-400', 'filled': 'bg-gray-100 border-transparent text-black placeholder-gray-500 focus:bg-white focus:border-primary' } %} {# ============================================================================ CLASSES TAILWIND - TAILLES padding: 16px 20px = py-4 px-5 (pour md) border-radius: lg ============================================================================ #} {% set sizeClasses = { 'sm': 'py-2.5 px-4 text-sm rounded-lg', 'md': 'py-4 px-5 text-base rounded-lg', 'lg': 'py-5 px-6 text-lg rounded-xl' } %} {% set textareaSizeClasses = { 'sm': 'py-2.5 px-4 text-sm rounded-lg', 'md': 'py-4 px-5 text-base rounded-lg', 'lg': 'py-5 px-6 text-lg rounded-xl' } %} {% set labelSizeClasses = { 'sm': 'text-xs', 'md': 'text-sm', 'lg': 'text-base' } %} {% set iconSizes = { 'sm': 'sm', 'md': 'md', 'lg': 'lg' } %} {# ============================================================================ CLASSES TAILWIND - ÉTATS ============================================================================ #} {% set errorClasses = error ? 'border-error focus:ring-error/20 focus:border-error' : '' %} {% set disabledClasses = disabled ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : '' %} {# Padding pour icône #} {% set iconPaddingClasses = '' %} {% if icon %} {% if iconPosition == 'left' %} {% set iconPaddingClasses = size == 'sm' ? 'pl-10' : (size == 'lg' ? 'pl-14' : 'pl-12') %} {% else %} {% set iconPaddingClasses = size == 'sm' ? 'pr-10' : (size == 'lg' ? 'pr-14' : 'pr-12') %} {% endif %} {% endif %} {# Position de l'icône (centrée dans l'espace réservé) sm: pl-10 (40px) → centre à ~12px (left-3) md: pl-12 (48px) → centre à ~16px (left-4) lg: pl-14 (56px) → centre à ~20px (left-5) #} {% set iconLeftPositions = { 'sm': 'left-3', 'md': 'left-4', 'lg': 'left-5' } %} {% set iconRightPositions = { 'sm': 'right-3', 'md': 'right-4', 'lg': 'right-5' } %} {# ============================================================================ ASSEMBLAGE DES CLASSES ============================================================================ #} {% set inputClasses = [ baseClasses, variantClasses[variant] ?? variantClasses['default'], type == 'textarea' ? (textareaSizeClasses[size] ?? textareaSizeClasses['md']) : (sizeClasses[size] ?? sizeClasses['md']), errorClasses, disabledClasses, iconPaddingClasses, class ]|join(' ')|trim %} {# ============================================================================ RENDU HTML ============================================================================ #}
{# ----- Label ----- #} {% if label %} {% endif %} {# ----- Input wrapper (pour icône) ----- #}
{# ----- Icône gauche ----- #} {% if icon and iconPosition == 'left' %} {% include '_atoms/icon/icon.html.twig' with { name: icon, size: iconSizes[size] ?? 'md', color: error ? 'error' : 'muted' } only %} {% endif %} {# ----- Input ou Textarea ----- #} {% if type == 'textarea' %} {% else %} {% endif %} {# ----- Icône droite ----- #} {% if icon and iconPosition == 'right' %} {% include '_atoms/icon/icon.html.twig' with { name: icon, size: iconSizes[size] ?? 'md', color: error ? 'error' : 'muted' } only %} {% endif %}
{# ----- Footer (hint, error, count) — n'est rendu que si nécessaire ----- #} {% if hint or error or (showCount and maxlength) %}
{% if hint and not error %}

{{ hint }}

{% endif %} {% if error %}

{{ error }}

{% endif %}
{% if showCount and maxlength %}

{{ value|length }}/{{ maxlength }}

{% endif %}
{% endif %}