diff --git a/plugins/view-transitions/includes/admin.php b/plugins/view-transitions/includes/admin.php index 83e81e45e3..c5132b7ab2 100644 --- a/plugins/view-transitions/includes/admin.php +++ b/plugins/view-transitions/includes/admin.php @@ -27,9 +27,12 @@ function plvt_print_view_transitions_admin_style(): void { if ( ! isset( $options['enable_admin_transitions'] ) || true !== $options['enable_admin_transitions'] ) { return; } + + $duration_seconds = absint( $options['default_transition_animation_duration'] ) / 1000; ?> 'string', 'enum' => array_keys( plvt_get_view_transition_animation_labels() ), ), + 'default_transition_animation_duration' => array( + 'description' => __( 'Duration of the view transition animation in milliseconds.', 'view-transitions' ), + 'type' => 'integer', + 'minimum' => PLVT_MIN_ANIMATION_DURATION, + 'maximum' => PLVT_MAX_ANIMATION_DURATION, + ), ), 'additionalProperties' => false, ), @@ -325,9 +350,14 @@ static function (): void { 'description' => __( 'Choose the animation that is used for the default view transition type.', 'view-transitions' ), ), 'default_transition_animation_duration' => array( - 'section' => 'plvt_view_transitions', - 'title' => __( 'Transition Animation Duration', 'view-transitions' ), - 'description' => __( 'Control the duration of the view transition. Enter the value in milliseconds (e.g., 500, 1000, 2000).', 'view-transitions' ), + 'section' => 'plvt_view_transitions', + 'title' => __( 'Transition Animation Duration', 'view-transitions' ), + 'description' => __( 'Control the duration of the view transition. Enter the value in milliseconds (e.g., 500, 1000, 2000).', 'view-transitions' ), + 'min' => PLVT_MIN_ANIMATION_DURATION, + 'max' => PLVT_MAX_ANIMATION_DURATION, + 'step' => 50, + 'unit' => 'ms', + 'show_seconds' => true, ), 'header_selector' => array( 'section' => 'plvt_view_transitions', @@ -473,10 +503,68 @@ function plvt_render_settings_field( array $args ): void { + " + value="" + class="small-text" + + min="" + + max="" + + step="" + + aria-describedby="" + + > + + + ' . esc_html( (string) $seconds ) . 's' + ); + wp_print_inline_script_tag( + sprintf( + 'document.getElementById( %s ).addEventListener( "input", function( e ) { document.getElementById( %s ).textContent = ( parseInt( e.target.value, 10 ) / 1000 ) + "s"; } );', + wp_json_encode( $field_id ), + wp_json_encode( $field_id . '-seconds' ) + ) + ); + } else { + echo esc_html( $args['unit'] ); + } + ?> + + id="" name="" value="" diff --git a/plugins/view-transitions/tests/test-admin.php b/plugins/view-transitions/tests/test-admin.php new file mode 100644 index 0000000000..3edc8beca7 --- /dev/null +++ b/plugins/view-transitions/tests/test-admin.php @@ -0,0 +1,60 @@ + false ) ); + + ob_start(); + plvt_print_view_transitions_admin_style(); + $output = ob_get_clean(); + + $this->assertEmpty( $output ); + } + + /** + * @covers ::plvt_print_view_transitions_admin_style + */ + public function test_plvt_print_view_transitions_admin_style_enabled(): void { + update_option( + 'plvt_view_transitions', + array( + 'enable_admin_transitions' => true, + 'default_transition_animation_duration' => 500, + ) + ); + + ob_start(); + plvt_print_view_transitions_admin_style(); + $output = ob_get_clean(); + + $this->assertStringContainsString( '@view-transition { navigation: auto; }', $output ); + $this->assertStringContainsString( 'animation-duration: 0.5s', $output ); + } + + /** + * @covers ::plvt_print_view_transitions_admin_style + */ + public function test_plvt_print_view_transitions_admin_style_uses_default_duration(): void { + update_option( + 'plvt_view_transitions', + array( 'enable_admin_transitions' => true ) + ); + + ob_start(); + plvt_print_view_transitions_admin_style(); + $output = ob_get_clean(); + + // Default duration is 400ms = 0.4s. + $this->assertStringContainsString( 'animation-duration: 0.4s', $output ); + } +} diff --git a/plugins/view-transitions/tests/test-settings.php b/plugins/view-transitions/tests/test-settings.php new file mode 100644 index 0000000000..93954fce1c --- /dev/null +++ b/plugins/view-transitions/tests/test-settings.php @@ -0,0 +1,89 @@ +assertSame( plvt_get_setting_default(), plvt_sanitize_setting( null ) ); + $this->assertSame( plvt_get_setting_default(), plvt_sanitize_setting( 'string' ) ); + $this->assertSame( plvt_get_setting_default(), plvt_sanitize_setting( 123 ) ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_clamps_duration_minimum(): void { + $input = array( 'default_transition_animation_duration' => 50 ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( PLVT_MIN_ANIMATION_DURATION, $result['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_clamps_duration_maximum(): void { + $input = array( 'default_transition_animation_duration' => 10000 ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( PLVT_MAX_ANIMATION_DURATION, $result['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_accepts_valid_duration(): void { + $input = array( 'default_transition_animation_duration' => 500 ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( 500, $result['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_handles_negative_duration(): void { + $input = array( 'default_transition_animation_duration' => -500 ); + $result = plvt_sanitize_setting( $input ); + // absint converts negative to positive, then clamps. + $this->assertSame( 500, $result['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_handles_string_duration(): void { + $input = array( 'default_transition_animation_duration' => '750' ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( 750, $result['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_get_setting_default + */ + public function test_plvt_get_setting_default_has_valid_duration(): void { + $defaults = plvt_get_setting_default(); + $this->assertArrayHasKey( 'default_transition_animation_duration', $defaults ); + $this->assertIsInt( $defaults['default_transition_animation_duration'] ); + $this->assertGreaterThanOrEqual( PLVT_MIN_ANIMATION_DURATION, $defaults['default_transition_animation_duration'] ); + $this->assertLessThanOrEqual( PLVT_MAX_ANIMATION_DURATION, $defaults['default_transition_animation_duration'] ); + } + + /** + * @covers ::plvt_sanitize_setting + */ + public function test_plvt_sanitize_setting_validates_animation_type(): void { + $input = array( 'default_transition_animation' => 'invalid-animation' ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( 'fade', $result['default_transition_animation'] ); + + $input = array( 'default_transition_animation' => 'slide-from-right' ); + $result = plvt_sanitize_setting( $input ); + $this->assertSame( 'slide-from-right', $result['default_transition_animation'] ); + } +} diff --git a/plugins/view-transitions/tests/test-theme.php b/plugins/view-transitions/tests/test-theme.php index 7879c72f73..c675ccd903 100644 --- a/plugins/view-transitions/tests/test-theme.php +++ b/plugins/view-transitions/tests/test-theme.php @@ -48,4 +48,36 @@ public function test_plvt_load_view_transitions(): void { $this->assertTrue( wp_style_is( 'plvt-view-transitions', 'registered' ) ); $this->assertTrue( wp_style_is( 'plvt-view-transitions', 'enqueued' ) ); } + + /** + * @covers ::plvt_inject_animation_duration + */ + public function test_plvt_inject_animation_duration_with_existing_css(): void { + $css = '::view-transition-old(*) { animation-name: test; }'; + $result = plvt_inject_animation_duration( $css, 500 ); + + $this->assertStringContainsString( '--plvt-view-transition-animation-duration: 0.5s', $result ); + $this->assertStringContainsString( $css, $result ); + } + + /** + * @covers ::plvt_inject_animation_duration + */ + public function test_plvt_inject_animation_duration_with_empty_css(): void { + $result = plvt_inject_animation_duration( '', 400 ); + + $this->assertStringContainsString( 'animation-duration: 0.4s', $result ); + $this->assertStringNotContainsString( '--plvt-view-transition-animation-duration', $result ); + } + + /** + * @covers ::plvt_inject_animation_duration + */ + public function test_plvt_inject_animation_duration_converts_milliseconds_to_seconds(): void { + $result = plvt_inject_animation_duration( '', 1000 ); + $this->assertStringContainsString( '1s', $result ); + + $result = plvt_inject_animation_duration( '', 250 ); + $this->assertStringContainsString( '0.25s', $result ); + } }