diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index afa74ac1310..bfd7f2523fc 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -65,7 +65,7 @@ jobs: # Exclude deprecated packages when testing against lowest dependencies if [ "${{ matrix.dependency-version }}" = "lowest" ]; then - EXCLUDED_PACKAGES="$EXCLUDED_PACKAGES|LazyImage" + EXCLUDED_PACKAGES="$EXCLUDED_PACKAGES|LazyImage|TogglePassword" fi PACKAGES=$(find src/ -mindepth 2 -type f -name composer.json -not -path "*/vendor/*" -printf '%h\n' | sed 's/^src\///' | grep -Ev "$EXCLUDED_PACKAGES" | sort | tr '\n' ' ') diff --git a/src/TogglePassword/CHANGELOG.md b/src/TogglePassword/CHANGELOG.md index ae644812580..ee855b97a5e 100644 --- a/src/TogglePassword/CHANGELOG.md +++ b/src/TogglePassword/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.29.0 + +- Deprecate the package + ## 2.13.2 - Revert "Change JavaScript package to `type: module`" diff --git a/src/TogglePassword/README.md b/src/TogglePassword/README.md index 90945a31069..e2311852b7f 100644 --- a/src/TogglePassword/README.md +++ b/src/TogglePassword/README.md @@ -1,5 +1,231 @@ # Symfony UX TogglePassword +> [!WARNING] +> **Deprecated**: This package has been **deprecated** in 2.x and will be removed in the next major version. + +To keep the same functionality in your Symfony application, follow these migration steps: + +1. Remove the `symfony/ux-toggle-password` package from your project: +```bash +composer remove symfony/ux-toggle-password +``` + +2. Create the following files in your project: + +> [!NOTE] +> These files are provided as a reference. +> You can customize them to fit your needs, and even simplify the implementation if you don't need all the features. + + - `src/Form/Extension/TogglePasswordTypeExtension.php` +```php +setDefaults([ + 'toggle' => false, + 'hidden_label' => 'Hide', + 'visible_label' => 'Show', + 'hidden_icon' => 'Default', + 'visible_icon' => 'Default', + 'button_classes' => ['toggle-password-button'], + 'toggle_container_classes' => ['toggle-password-container'], + 'toggle_translation_domain' => null, + 'use_toggle_form_theme' => true, + ]); + + $resolver->setNormalizer( + 'toggle_translation_domain', + static fn (Options $options, $labelTranslationDomain) => $labelTranslationDomain ?? $options['translation_domain'], + ); + + $resolver->setAllowedTypes('toggle', ['bool']); + $resolver->setAllowedTypes('hidden_label', ['string', TranslatableMessage::class, 'null']); + $resolver->setAllowedTypes('visible_label', ['string', TranslatableMessage::class, 'null']); + $resolver->setAllowedTypes('hidden_icon', ['string', 'null']); + $resolver->setAllowedTypes('visible_icon', ['string', 'null']); + $resolver->setAllowedTypes('button_classes', ['string[]']); + $resolver->setAllowedTypes('toggle_container_classes', ['string[]']); + $resolver->setAllowedTypes('toggle_translation_domain', ['string', 'bool', 'null']); + $resolver->setAllowedTypes('use_toggle_form_theme', ['bool']); + } + + public function buildView(FormView $view, FormInterface $form, array $options): void + { + $view->vars['toggle'] = $options['toggle']; + + if (!$options['toggle']) { + return; + } + + if ($options['use_toggle_form_theme']) { + array_splice($view->vars['block_prefixes'], -1, 0, 'toggle_password'); + } + + $controllerName = 'toggle-password'; + $view->vars['attr']['data-controller'] = trim(\sprintf('%s %s', $view->vars['attr']['data-controller'] ?? '', $controllerName)); + + if (false !== $options['toggle_translation_domain']) { + $controllerValues['hidden-label'] = $this->translateLabel($options['hidden_label'], $options['toggle_translation_domain']); + $controllerValues['visible-label'] = $this->translateLabel($options['visible_label'], $options['toggle_translation_domain']); + } else { + $controllerValues['hidden-label'] = $options['hidden_label']; + $controllerValues['visible-label'] = $options['visible_label']; + } + + $controllerValues['hidden-icon'] = $options['hidden_icon']; + $controllerValues['visible-icon'] = $options['visible_icon']; + $controllerValues['button-classes'] = json_encode($options['button_classes'], \JSON_THROW_ON_ERROR); + + foreach ($controllerValues as $name => $value) { + $view->vars['attr'][\sprintf('data-%s-%s-value', $controllerName, $name)] = $value; + } + + $view->vars['toggle_container_classes'] = $options['toggle_container_classes']; + } + + private function translateLabel(string|TranslatableMessage|null $label, ?string $translationDomain): ?string + { + if (null === $this->translator || null === $label) { + return $label; + } + + if ($label instanceof TranslatableMessage) { + return $label->trans($this->translator); + } + + return $this->translator->trans($label, domain: $translationDomain); + } +} +``` + - `template/form_theme.html.twig`, and follow the [How to work with form themes](https://symfony.com/doc/current/form/form_themes.html) documentation to register it. +```twig +{%- block toggle_password_widget -%} +
{{ block('password_widget') }}
+{%- endblock toggle_password_widget -%} +``` + - `assets/controllers/toggle_password_controller.js` +```javascript +import { Controller } from '@hotwired/stimulus'; +import '../styles/toggle_password.css'; + +export default class extends Controller { + static values = { + visibleLabel: { type: String, default: 'Show' }, + visibleIcon: { type: String, default: 'Default' }, + hiddenLabel: { type: String, default: 'Hide' }, + hiddenIcon: { type: String, default: 'Default' }, + buttonClasses: Array, + }; + + isDisplayed = false; + visibleIcon = ` + + +`; + hiddenIcon = ` + + +`; + + connect() { + if (this.visibleIconValue !== 'Default') { + this.visibleIcon = this.visibleIconValue; + } + + if (this.hiddenIconValue !== 'Default') { + this.hiddenIcon = this.hiddenIconValue; + } + + const button = this.createButton(); + + this.element.insertAdjacentElement('afterend', button); + this.dispatchEvent('connect', { element: this.element, button }); + } + + /** + * @returns {HTMLButtonElement} + */ + createButton() { + const button = document.createElement('button'); + button.type = 'button'; + button.classList.add(...this.buttonClassesValue); + button.setAttribute('tabindex', '-1'); + button.addEventListener('click', this.toggle.bind(this)); + button.innerHTML = `${this.visibleIcon} ${this.visibleLabelValue}`; + return button; + } + + /** + * Toggle input type between "text" or "password" and update label accordingly + */ + toggle(event) { + this.isDisplayed = !this.isDisplayed; + const toggleButtonElement = event.currentTarget; + toggleButtonElement.innerHTML = this.isDisplayed + ? `${this.hiddenIcon} ${this.hiddenLabelValue}` + : `${this.visibleIcon} ${this.visibleLabelValue}`; + this.element.setAttribute('type', this.isDisplayed ? 'text' : 'password'); + this.dispatchEvent(this.isDisplayed ? 'show' : 'hide', { element: this.element, button: toggleButtonElement }); + } + + dispatchEvent(name, payload) { + this.dispatch(name, { detail: payload, prefix: 'toggle-password' }); + } +} +``` + - `assets/styles/toggle_password.css` +```css +.toggle-password-container { + position: relative; +} +.toggle-password-icon { + height: 1rem; + width: 1rem; +} +.toggle-password-button { + align-items: center; + background-color: transparent; + border: none; + column-gap: 0.25rem; + display: flex; + flex-direction: row; + font-size: 0.875rem; + justify-items: center; + height: 1rem; + line-height: 1.25rem; + position: absolute; + right: 0.5rem; + top: -1.25rem; +} +``` + +You're done! + +--- + Symfony UX TogglePassword is a Symfony bundle providing visibility toggle for password inputs in Symfony Forms. It is part of [the Symfony UX initiative](https://ux.symfony.com/). diff --git a/src/TogglePassword/doc/index.rst b/src/TogglePassword/doc/index.rst index 51d79800d49..111e3db33e9 100644 --- a/src/TogglePassword/doc/index.rst +++ b/src/TogglePassword/doc/index.rst @@ -1,6 +1,13 @@ Symfony UX TogglePassword ========================= +.. warning:: + + **Deprecated: This package has been deprecated in 2.x and will be removed in the next major version.** + + To keep the same functionality in your Symfony application, please follow the migration steps + from the `Symfony UX TogglePassword README.md`_. + Symfony UX TogglePassword is a Symfony bundle providing visibility toggle for password inputs in Symfony Forms. It is part of `the Symfony UX initiative`_. @@ -306,3 +313,4 @@ https://symfony.com/doc/current/contributing/code/bc.html .. _StimulusBundle configured in your app: https://symfony.com/bundles/StimulusBundle/current/index.html .. _Heroicons: https://heroicons.com/ .. _`@symfony/ux-toggle-password npm package`: https://www.npmjs.com/package/@symfony/ux-toggle-password +.. _`Symfony UX TogglePassword README.md`: https://github.com/symfony/ux/tree/2.x/src/TogglePassword/README.md diff --git a/src/TogglePassword/phpunit.xml.dist b/src/TogglePassword/phpunit.xml.dist index 56293693f2c..77cf27958b1 100644 --- a/src/TogglePassword/phpunit.xml.dist +++ b/src/TogglePassword/phpunit.xml.dist @@ -11,7 +11,7 @@ - + diff --git a/src/TogglePassword/src/DependencyInjection/TogglePasswordExtension.php b/src/TogglePassword/src/DependencyInjection/TogglePasswordExtension.php index 48d111ad389..c88e4ea7ccb 100644 --- a/src/TogglePassword/src/DependencyInjection/TogglePasswordExtension.php +++ b/src/TogglePassword/src/DependencyInjection/TogglePasswordExtension.php @@ -20,6 +20,8 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\UX\TogglePassword\Form\TogglePasswordTypeExtension; +trigger_deprecation('symfony/ux-toggle-password', '2.29.0', 'The package is deprecated and will be removed in 3.0. Follow the migration steps in https://github.com/symfony/ux/tree/2.x/src/TogglePassword to keep using TogglePassword in your Symfony application.'); + /** * @author Félix Eymonot */ diff --git a/src/TogglePassword/src/Form/TogglePasswordTypeExtension.php b/src/TogglePassword/src/Form/TogglePasswordTypeExtension.php index 75f02912793..a78679bd1d7 100644 --- a/src/TogglePassword/src/Form/TogglePasswordTypeExtension.php +++ b/src/TogglePassword/src/Form/TogglePasswordTypeExtension.php @@ -20,6 +20,8 @@ use Symfony\Component\Translation\TranslatableMessage; use Symfony\Contracts\Translation\TranslatorInterface; +trigger_deprecation('symfony/ux-toggle-password', '2.29.0', 'The package is deprecated and will be removed in 3.0. Follow the migration steps in https://github.com/symfony/ux/tree/2.x/src/TogglePassword to keep using TogglePassword in your Symfony application.'); + /** * @author Félix Eymonot */ diff --git a/src/TogglePassword/src/TogglePasswordBundle.php b/src/TogglePassword/src/TogglePasswordBundle.php index 8c35c4da849..fbfb00ede56 100644 --- a/src/TogglePassword/src/TogglePasswordBundle.php +++ b/src/TogglePassword/src/TogglePasswordBundle.php @@ -13,6 +13,8 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; +trigger_deprecation('symfony/ux-toggle-password', '2.29.0', 'The package is deprecated and will be removed in 3.0. Follow the migration steps in https://github.com/symfony/ux/tree/2.x/src/TogglePassword to keep using TogglePassword in your Symfony application.'); + /** * @author Félix Eymonot */ diff --git a/src/TogglePassword/tests/baseline-ignore b/src/TogglePassword/tests/baseline-ignore new file mode 100644 index 00000000000..3321cdbc818 --- /dev/null +++ b/src/TogglePassword/tests/baseline-ignore @@ -0,0 +1 @@ +%Since symfony/ux-toggle-password 2\.29\.0: The package is deprecated and will be removed in 3\.0\.% diff --git a/ux.symfony.com/tests/baseline-ignore b/ux.symfony.com/tests/baseline-ignore index bb9ff61b48d..6297f114800 100644 --- a/ux.symfony.com/tests/baseline-ignore +++ b/ux.symfony.com/tests/baseline-ignore @@ -1,3 +1,4 @@ %Since symfony/ux-typed 2\.27\.0: The package is deprecated and will be removed in 3\.0\.% %Since symfony/ux-lazy-image 2\.27\.0: The package is deprecated and will be removed in 3\.0\.% %Since symfony/ux-swup 2\.27\.0: The package is deprecated and will be removed in 3\.0\.% +%Since symfony/ux-toggle-password 2\.29\.0: The package is deprecated and will be removed in 3\.0\.%