Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Error message is not showing properly with framer-motion #1023

Open
galih56 opened this issue Apr 26, 2024 · 0 comments
Open

[Bug]: Error message is not showing properly with framer-motion #1023

galih56 opened this issue Apr 26, 2024 · 0 comments

Comments

@galih56
Copy link

galih56 commented Apr 26, 2024

Tremor Version

8.0.9

Link to minimal reproduction

https://codesandbox.io/p/devbox/zod-react-hook-formc-storybook-tremor-so-f6d8my

Steps to reproduce

I have zod, react-hook-form, and framer-motion installed

I'm using storybook for easier access of component implementation.

Can be seen below.

// Import necessary libraries
import React, { useState } from 'react';
import { StoryFn, Meta } from '@storybook/react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button, Select, SelectItem, TextInput } from '@tremor/react';
import { PhoneNumberInput } from '../elements/PhoneNumberInput';
import { motion } from 'framer-motion';
import './../../styles/index.css';

const regionOptions : string[] = [ "bpsum", "bpb", "bpjtg", "bpjtm", "bpkalsul","bpho" ];
const FormDataSchema = z.object({
    phoneNumber: z.string().min(1, 'Nomor Telephone harus diisi'),
    price: z.string().min(1, 'Harga harus diisi'),
    region: z.custom((value) => Boolean(regionOptions.filter(option => option === value).length), {
      message : 'Wilayah harus diisi'
    }),
  });
  
  
type Inputs = z.infer<typeof FormDataSchema>;


const steps = [
    {
      id: 'Step 1',
      name: 'Basic Information',
      fields: ['phoneNumber', 'price', 'region' ]
    },
    { id: 'Step 3', name: 'Complete' }
  ]
const MyForm = () => {
    const [previousStep, setPreviousStep] = useState(0);
    const [currentStep, setCurrentStep] = useState(0);
    const delta = currentStep - previousStep;


    // Initialize react-hook-form
    const  { register, handleSubmit, formState: { errors }, control, trigger, reset } = useForm<Inputs>({
        resolver: zodResolver(FormDataSchema)
    });


    const triggerFields = async () => {
        const fields = steps[currentStep].fields
        return await trigger(fields as FieldName[], { shouldFocus: true });
    }

    const processForm: SubmitHandler<Inputs> = async values => {
        console.log(values);
        // reset();
    }

    const next = async () => {
        const output = await triggerFields();
    
        if (!output) return;
    
        if (currentStep < steps.length - 1) {
          if (currentStep === steps.length - 2) {
            await handleSubmit(processForm)()
          }
          setPreviousStep(currentStep)
          setCurrentStep(step => step + 1)
        }
      }
    
      const prev = () => {
        if (currentStep > 0) {
          setPreviousStep(currentStep)
          setCurrentStep(step => step - 1)
        }
      }
    type FieldName = keyof Inputs
    // Function to handle form submission
    const onSubmit = (data: any) => {
        console.log(data); // Here you can do whatever you want with the form data
    };

    return (
        <div className="w-full">
            {/* steps */}
            <nav aria-label='Progress'>
                <ol role='list' className='space-y-4 md:flex md:space-x-8 md:space-y-0'>
                    {steps.map((step, index) => (
                    <li key={step.name} className='md:flex-1'>
                        {currentStep > index ? (
                        <div className='group flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4'>
                            <span className='text-sm font-medium text-sky-600 transition-colors '>
                            {step.id}
                            </span>
                            <span className='text-sm font-medium'>{step.name}</span>
                        </div>
                        ) : currentStep === index ? (
                        <div
                            className='flex w-full flex-col border-l-4 border-sky-600 py-2 pl-4 md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4'
                            aria-current='step'
                        >
                            <span className='text-sm font-medium text-sky-600'>
                            {step.id}
                            </span>
                            <span className='text-sm font-medium'>{step.name}</span>
                        </div>
                        ) : (
                        <div className='group flex w-full flex-col border-l-4 border-gray-200 py-2 pl-4 transition-colors md:border-l-0 md:border-t-4 md:pb-0 md:pl-0 md:pt-4'>
                            <span className='text-sm font-medium text-gray-500 transition-colors'>
                            {step.id}
                            </span>
                            <span className='text-sm font-medium'>{step.name}</span>
                        </div>
                        )}
                    </li>
                    ))}
                </ol>
            </nav>
        
            <form onSubmit={handleSubmit(onSubmit)}>
            {currentStep === 0 && (
                <motion.div
                initial={{ x: delta >= 0 ? '50%' : '-50%', opacity: 0 }}
                animate={{ x: 0, opacity: 1 }}
                transition={{ duration: 0.3, ease: 'easeInOut' }}
                >
                <div className="mt-2">
                    <TextInput {...register('price', { required: 'Harga' })} error={!!errors.price} errorMessage={errors.price?.message}/>
                </div>
                <div className="mt-2">
                    <PhoneNumberInput control={control} {...register('phoneNumber', { required: 'Nomor Telephone' })} error={!!errors.phoneNumber} errorMessage={errors.phoneNumber?.message} />
                </div>
                <div className="mt-2">
                    
                <label
                    htmlFor='region'
                    className='block text-sm font-medium leading-6 text-gray-900'
                    >
                    Wilayah
                    </label>
                    <Controller
                        name="region"
                        control={control}
                        render={({ field }) => (
                        <Select {...field} className='mt-2' id="region"
                            error={Boolean(errors.region?.message)}
                            errorMessage={errors.region?.message as string}
                            >
                            {regionOptions.map(item => (<SelectItem key={item} value={item}>{item.toUpperCase()}</SelectItem>))}
                        </Select>
                        )}
                    />
                </div>
                <div className="mt-2">
                    <Button type="submit">Submit</Button>
                </div>
                
                </motion.div>
            )}

                {currentStep === 1 && (
                    <>
                    <h2 className='text-base font-semibold leading-7 text-gray-900'>
                        Complete
                    </h2>
                    <p className='mt-1 text-sm leading-6 text-gray-600'>
                        Thank you for your submission.
                    </p>
                    </>
                )}
                {/* Navigation */}
                <div className='my-8 py-6'>
                    <div className='flex justify-between'>
                        <button type='button' onClick={prev}
                        className='rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50'>
                        <svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' strokeWidth='1.5' stroke='currentColor' className='h-6 w-6'>
                            <path strokeLinecap='round' strokeLinejoin='round' d='M15.75 19.5L8.25 12l7.5-7.5'/>
                        </svg>
                        </button> 
                        <button type='button' onClick={next} disabled={currentStep === steps.length - 1} className='rounded bg-white px-2 py-1 text-sm font-semibold text-sky-900 shadow-sm ring-1 ring-inset ring-sky-300 hover:bg-sky-50 disabled:cursor-not-allowed disabled:opacity-50'>
                        <svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' strokeWidth='1.5' stroke='currentColor' className='h-6 w-6'>
                            <path strokeLinecap='round' strokeLinejoin='round' d='M8.25 4.5l7.5 7.5-7.5 7.5' />
                        </svg>
                        </button>
                    </div>
                </div>
            </form>
        </div>
    );
};

// Define your Storybook story
export default {
  title: 'Form',
  component: MyForm,
};

const Template: StoryFn = () => <MyForm />;

// Export the story
export const Default = Template.bind({});

What is expected?

Correct appearance
On Focus
image

On change
image

What is actually happening?

When the errors are triggered, error messages are displayed properly. But when i change the inputs, They must hide the error messages immediately. But the error messages keeps showing instead.

first error trigger
image

Input on focus
image

Input on change
image

As you can see, the text color and the border appers different when i use motion.div.
I notice this issue when i tried to remove the motion.div temporary.

This issue occurs on all kind of tremor Input components

What browsers are you seeing the problem on?

Chrome, Microsoft Edge, Safari, Firefox, Brave

Any additional comments?

Thank you for the great UI Library :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant