1867 timebox add storybook tests on meta typesinputcomponents (#1972)
* working on DateFieldInput story * wip * wip * wip * Fix story * Fix other story * finish stories for BooleanFieldInput and DateFieldInput * reorganize stories in UI/Field in Input and Display folders * unite FieldDisplayContextProvider and FieldInputContextProvider in one file FieldContextProvider --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -3,17 +3,17 @@ import {
|
|||||||
GenericFieldContextType,
|
GenericFieldContextType,
|
||||||
} from '@/ui/field/contexts/FieldContext';
|
} from '@/ui/field/contexts/FieldContext';
|
||||||
|
|
||||||
type FieldDisplayContextProviderProps = {
|
type FieldContextProviderProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
fieldDefinition: GenericFieldContextType['fieldDefinition'];
|
fieldDefinition: GenericFieldContextType['fieldDefinition'];
|
||||||
entityId?: string;
|
entityId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FieldDisplayContextProvider = ({
|
export const FieldContextProvider = ({
|
||||||
children,
|
children,
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
entityId,
|
entityId,
|
||||||
}: FieldDisplayContextProviderProps) => {
|
}: FieldContextProviderProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -3,11 +3,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useDateField } from '../../../hooks/useDateField';
|
import { useDateField } from '../../../hooks/useDateField';
|
||||||
import { DateFieldDisplay } from '../DateFieldDisplay';
|
import { DateFieldDisplay } from '../DateFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const formattedDate = new Date();
|
const formattedDate = new Date();
|
||||||
|
|
||||||
const DateFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const DateFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
@ -30,7 +29,7 @@ const DateFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: DateFieldDisplayWithContextProps) => {
|
}: DateFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'date',
|
key: 'date',
|
||||||
name: 'Date',
|
name: 'Date',
|
||||||
@ -43,12 +42,12 @@ const DateFieldDisplayWithContext = ({
|
|||||||
>
|
>
|
||||||
<DateFieldValueSetterEffect value={value} />
|
<DateFieldValueSetterEffect value={value} />
|
||||||
<DateFieldDisplay />
|
<DateFieldDisplay />
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/DateFieldDisplay',
|
title: 'UI/Field/Display/DateFieldDisplay',
|
||||||
component: DateFieldDisplayWithContext,
|
component: DateFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useDoubleTextField } from '../../../hooks/useDoubleTextField';
|
import { useDoubleTextField } from '../../../hooks/useDoubleTextField';
|
||||||
import { DoubleTextFieldDisplay } from '../DoubleTextFieldDisplay'; // Import your component
|
import { DoubleTextFieldDisplay } from '../DoubleTextFieldDisplay'; // Import your component
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const DoubleTextFieldDisplayValueSetterEffect = ({
|
const DoubleTextFieldDisplayValueSetterEffect = ({
|
||||||
firstValue,
|
firstValue,
|
||||||
secondValue,
|
secondValue,
|
||||||
@ -37,7 +36,7 @@ const DoubleTextFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: DoubleTextFieldDisplayWithContextProps) => {
|
}: DoubleTextFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'double-text',
|
key: 'double-text',
|
||||||
name: 'Double-Text',
|
name: 'Double-Text',
|
||||||
@ -56,12 +55,12 @@ const DoubleTextFieldDisplayWithContext = ({
|
|||||||
secondValue={secondValue}
|
secondValue={secondValue}
|
||||||
/>
|
/>
|
||||||
<DoubleTextFieldDisplay />
|
<DoubleTextFieldDisplay />
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/DoubleTextFieldDisplay',
|
title: 'UI/Field/Display/DoubleTextFieldDisplay',
|
||||||
component: DoubleTextFieldDisplayWithContext,
|
component: DoubleTextFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useEmailField } from '../../../hooks/useEmailField';
|
import { useEmailField } from '../../../hooks/useEmailField';
|
||||||
import { EmailFieldDisplay } from '../EmailFieldDisplay';
|
import { EmailFieldDisplay } from '../EmailFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const EmailFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const EmailFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = useEmailField();
|
const { setFieldValue } = useEmailField();
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ const EmailFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: EmailFieldDisplayWithContextProps) => {
|
}: EmailFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'email',
|
key: 'email',
|
||||||
name: 'Email',
|
name: 'Email',
|
||||||
@ -45,12 +44,12 @@ const EmailFieldDisplayWithContext = ({
|
|||||||
<EmailFieldValueSetterEffect value={value} />
|
<EmailFieldValueSetterEffect value={value} />
|
||||||
<EmailFieldDisplay />
|
<EmailFieldDisplay />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/EmailFieldDisplay',
|
title: 'UI/Field/Display/EmailFieldDisplay',
|
||||||
component: EmailFieldDisplayWithContext,
|
component: EmailFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,10 @@ import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
|
|||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
import { CatalogStory } from '~/testing/types';
|
import { CatalogStory } from '~/testing/types';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useMoneyField } from '../../../hooks/useMoneyField';
|
import { useMoneyField } from '../../../hooks/useMoneyField';
|
||||||
import { MoneyFieldDisplay } from '../MoneyFieldDisplay';
|
import { MoneyFieldDisplay } from '../MoneyFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const MoneyFieldValueSetterEffect = ({ value }: { value: number }) => {
|
const MoneyFieldValueSetterEffect = ({ value }: { value: number }) => {
|
||||||
const { setFieldValue } = useMoneyField();
|
const { setFieldValue } = useMoneyField();
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ const MoneyFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: MoneyFieldDisplayWithContextProps) => {
|
}: MoneyFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'money',
|
key: 'money',
|
||||||
name: 'Money',
|
name: 'Money',
|
||||||
@ -46,12 +45,12 @@ const MoneyFieldDisplayWithContext = ({
|
|||||||
>
|
>
|
||||||
<MoneyFieldValueSetterEffect value={value} />
|
<MoneyFieldValueSetterEffect value={value} />
|
||||||
<MoneyFieldDisplay />
|
<MoneyFieldDisplay />
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/MoneyFieldDisplay',
|
title: 'UI/Field/Display/MoneyFieldDisplay',
|
||||||
component: MoneyFieldDisplayWithContext,
|
component: MoneyFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,10 @@ import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
|
|||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
import { CatalogStory } from '~/testing/types';
|
import { CatalogStory } from '~/testing/types';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useNumberField } from '../../../hooks/useNumberField';
|
import { useNumberField } from '../../../hooks/useNumberField';
|
||||||
import { NumberFieldDisplay } from '../NumberFieldDisplay';
|
import { NumberFieldDisplay } from '../NumberFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const NumberFieldValueSetterEffect = ({ value }: { value: number }) => {
|
const NumberFieldValueSetterEffect = ({ value }: { value: number }) => {
|
||||||
const { setFieldValue } = useNumberField();
|
const { setFieldValue } = useNumberField();
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ const NumberFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: NumberFieldDisplayWithContextProps) => {
|
}: NumberFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'number',
|
key: 'number',
|
||||||
name: 'Number',
|
name: 'Number',
|
||||||
@ -46,12 +45,12 @@ const NumberFieldDisplayWithContext = ({
|
|||||||
>
|
>
|
||||||
<NumberFieldValueSetterEffect value={value} />
|
<NumberFieldValueSetterEffect value={value} />
|
||||||
<NumberFieldDisplay />
|
<NumberFieldDisplay />
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/NumberFieldDisplay',
|
title: 'UI/Field/Display/NumberFieldDisplay',
|
||||||
component: NumberFieldDisplayWithContext,
|
component: NumberFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { usePhoneField } from '../../../hooks/usePhoneField';
|
import { usePhoneField } from '../../../hooks/usePhoneField';
|
||||||
import { PhoneFieldDisplay } from '../PhoneFieldDisplay';
|
import { PhoneFieldDisplay } from '../PhoneFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const PhoneFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const PhoneFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = usePhoneField();
|
const { setFieldValue } = usePhoneField();
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ const PhoneFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: PhoneFieldDisplayWithContextProps) => {
|
}: PhoneFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'phone',
|
key: 'phone',
|
||||||
name: 'Phone',
|
name: 'Phone',
|
||||||
@ -45,12 +44,12 @@ const PhoneFieldDisplayWithContext = ({
|
|||||||
<PhoneFieldValueSetterEffect value={value} />
|
<PhoneFieldValueSetterEffect value={value} />
|
||||||
<PhoneFieldDisplay />
|
<PhoneFieldDisplay />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/PhoneFieldDisplay',
|
title: 'UI/Field/Display/PhoneFieldDisplay',
|
||||||
component: PhoneFieldDisplayWithContext,
|
component: PhoneFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,10 @@ import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
|
|||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
import { CatalogStory } from '~/testing/types';
|
import { CatalogStory } from '~/testing/types';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useTextField } from '../../../hooks/useTextField';
|
import { useTextField } from '../../../hooks/useTextField';
|
||||||
import { TextFieldDisplay } from '../TextFieldDisplay';
|
import { TextFieldDisplay } from '../TextFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = useTextField();
|
const { setFieldValue } = useTextField();
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ const TextFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: TextFieldDisplayWithContextProps) => {
|
}: TextFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'text',
|
key: 'text',
|
||||||
name: 'Text',
|
name: 'Text',
|
||||||
@ -45,12 +44,12 @@ const TextFieldDisplayWithContext = ({
|
|||||||
>
|
>
|
||||||
<TextFieldValueSetterEffect value={value} />
|
<TextFieldValueSetterEffect value={value} />
|
||||||
<TextFieldDisplay />
|
<TextFieldDisplay />
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/TextFieldDisplay',
|
title: 'UI/Field/Display/TextFieldDisplay',
|
||||||
component: TextFieldDisplayWithContext,
|
component: TextFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,10 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
import { useURLField } from '../../../hooks/useURLField';
|
import { useURLField } from '../../../hooks/useURLField';
|
||||||
import { URLFieldDisplay } from '../URLFieldDisplay';
|
import { URLFieldDisplay } from '../URLFieldDisplay';
|
||||||
|
|
||||||
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
|
|
||||||
|
|
||||||
const URLFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const URLFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = useURLField();
|
const { setFieldValue } = useURLField();
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ const URLFieldDisplayWithContext = ({
|
|||||||
entityId,
|
entityId,
|
||||||
}: URLFieldDisplayWithContextProps) => {
|
}: URLFieldDisplayWithContextProps) => {
|
||||||
return (
|
return (
|
||||||
<FieldDisplayContextProvider
|
<FieldContextProvider
|
||||||
fieldDefinition={{
|
fieldDefinition={{
|
||||||
key: 'URL',
|
key: 'URL',
|
||||||
name: 'URL',
|
name: 'URL',
|
||||||
@ -45,12 +44,12 @@ const URLFieldDisplayWithContext = ({
|
|||||||
<URLFieldValueSetterEffect value={value} />
|
<URLFieldValueSetterEffect value={value} />
|
||||||
<URLFieldDisplay />
|
<URLFieldDisplay />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</FieldDisplayContextProvider>
|
</FieldContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta = {
|
const meta: Meta = {
|
||||||
title: 'UI/Field/URLFieldDisplay',
|
title: 'UI/Field/Display/URLFieldDisplay',
|
||||||
component: URLFieldDisplayWithContext,
|
component: URLFieldDisplayWithContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,15 @@ import { useBooleanField } from '../../hooks/useBooleanField';
|
|||||||
|
|
||||||
import { FieldInputEvent } from './DateFieldInput';
|
import { FieldInputEvent } from './DateFieldInput';
|
||||||
|
|
||||||
type BooleanFieldInputProps = {
|
export type BooleanFieldInputProps = {
|
||||||
onSubmit?: FieldInputEvent;
|
onSubmit?: FieldInputEvent;
|
||||||
|
testId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BooleanFieldInput = ({ onSubmit }: BooleanFieldInputProps) => {
|
export const BooleanFieldInput = ({
|
||||||
|
onSubmit,
|
||||||
|
testId,
|
||||||
|
}: BooleanFieldInputProps) => {
|
||||||
const { fieldValue } = useBooleanField();
|
const { fieldValue } = useBooleanField();
|
||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
@ -18,5 +22,11 @@ export const BooleanFieldInput = ({ onSubmit }: BooleanFieldInputProps) => {
|
|||||||
onSubmit?.(() => persistField(newValue));
|
onSubmit?.(() => persistField(newValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
return <BooleanInput value={fieldValue ?? ''} onToggle={handleToggle} />;
|
return (
|
||||||
|
<BooleanInput
|
||||||
|
value={fieldValue ?? ''}
|
||||||
|
onToggle={handleToggle}
|
||||||
|
testId={testId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useDateField } from '../../hooks/useDateField';
|
|||||||
|
|
||||||
export type FieldInputEvent = (persist: () => void) => void;
|
export type FieldInputEvent = (persist: () => void) => void;
|
||||||
|
|
||||||
type DateFieldInputProps = {
|
export type DateFieldInputProps = {
|
||||||
onClickOutside?: FieldInputEvent;
|
onClickOutside?: FieldInputEvent;
|
||||||
onEnter?: FieldInputEvent;
|
onEnter?: FieldInputEvent;
|
||||||
onEscape?: FieldInputEvent;
|
onEscape?: FieldInputEvent;
|
||||||
|
|||||||
@ -0,0 +1,100 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { jest } from '@storybook/jest';
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { userEvent, within } from '@storybook/testing-library';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
|
import { useBooleanField } from '../../../hooks/useBooleanField';
|
||||||
|
import {
|
||||||
|
BooleanFieldInput,
|
||||||
|
BooleanFieldInputProps,
|
||||||
|
} from '../BooleanFieldInput';
|
||||||
|
|
||||||
|
const BooleanFieldValueSetterEffect = ({ value }: { value: boolean }) => {
|
||||||
|
const { setFieldValue } = useBooleanField();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFieldValue(value);
|
||||||
|
}, [setFieldValue, value]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BooleanFieldInputWithContextProps = BooleanFieldInputProps & {
|
||||||
|
value: boolean;
|
||||||
|
entityId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BooleanFieldInputWithContext = ({
|
||||||
|
value,
|
||||||
|
entityId,
|
||||||
|
onSubmit,
|
||||||
|
}: BooleanFieldInputWithContextProps) => {
|
||||||
|
return (
|
||||||
|
<FieldContextProvider
|
||||||
|
fieldDefinition={{
|
||||||
|
key: 'boolean',
|
||||||
|
name: 'Boolean',
|
||||||
|
type: 'boolean',
|
||||||
|
metadata: {
|
||||||
|
fieldName: 'Boolean',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
entityId={entityId}
|
||||||
|
>
|
||||||
|
<BooleanFieldValueSetterEffect value={value} />
|
||||||
|
<BooleanFieldInput onSubmit={onSubmit} testId="boolean-field-input" />
|
||||||
|
</FieldContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'UI/Field/Input/BooleanFieldInput',
|
||||||
|
component: BooleanFieldInputWithContext,
|
||||||
|
args: {
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof BooleanFieldInputWithContext>;
|
||||||
|
|
||||||
|
const submitJestFn = jest.fn();
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const Toggle: Story = {
|
||||||
|
args: {
|
||||||
|
onSubmit: submitJestFn,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
onSubmit: {
|
||||||
|
control: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
const input = canvas.getByTestId('boolean-field-input');
|
||||||
|
|
||||||
|
const trueText = await within(input).findByText('True');
|
||||||
|
|
||||||
|
await expect(trueText).toBeInTheDocument();
|
||||||
|
|
||||||
|
await expect(submitJestFn).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
await userEvent.click(input);
|
||||||
|
|
||||||
|
await expect(input).toHaveTextContent('False');
|
||||||
|
|
||||||
|
await expect(submitJestFn).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
await userEvent.click(input);
|
||||||
|
|
||||||
|
await expect(input).toHaveTextContent('True');
|
||||||
|
|
||||||
|
await expect(submitJestFn).toHaveBeenCalledTimes(2);
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { expect } from '@storybook/jest';
|
||||||
|
import { jest } from '@storybook/jest';
|
||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { userEvent, within } from '@storybook/testing-library';
|
||||||
|
|
||||||
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
|
||||||
|
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||||
|
import { useDateField } from '../../../hooks/useDateField';
|
||||||
|
import { DateFieldInput, DateFieldInputProps } from '../DateFieldInput';
|
||||||
|
|
||||||
|
const formattedDate = new Date();
|
||||||
|
|
||||||
|
const DateFieldValueSetterEffect = ({ value }: { value: Date }) => {
|
||||||
|
const { setFieldValue } = useDateField();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFieldValue(value.toISOString());
|
||||||
|
}, [setFieldValue, value]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DateFieldInputWithContextProps = DateFieldInputProps & {
|
||||||
|
value: Date;
|
||||||
|
entityId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DateFieldInputWithContext = ({
|
||||||
|
value,
|
||||||
|
entityId,
|
||||||
|
onEscape,
|
||||||
|
onEnter,
|
||||||
|
onClickOutside,
|
||||||
|
}: DateFieldInputWithContextProps) => {
|
||||||
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHotkeyScope('hotkey-scope');
|
||||||
|
}, [setHotkeyScope]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<FieldContextProvider
|
||||||
|
fieldDefinition={{
|
||||||
|
key: 'date',
|
||||||
|
name: 'Date',
|
||||||
|
type: 'date',
|
||||||
|
metadata: {
|
||||||
|
fieldName: 'Date',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
entityId={entityId}
|
||||||
|
>
|
||||||
|
<DateFieldValueSetterEffect value={value} />
|
||||||
|
<DateFieldInput
|
||||||
|
onEscape={onEscape}
|
||||||
|
onEnter={onEnter}
|
||||||
|
onClickOutside={onClickOutside}
|
||||||
|
/>
|
||||||
|
</FieldContextProvider>
|
||||||
|
<div data-testid="data-field-input-click-outside-div"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const escapeJestFn = jest.fn();
|
||||||
|
const enterJestFn = jest.fn();
|
||||||
|
const clickOutsideJestFn = jest.fn();
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'UI/Field/Input/DateFieldInput',
|
||||||
|
component: DateFieldInputWithContext,
|
||||||
|
args: {
|
||||||
|
value: formattedDate,
|
||||||
|
onEscape: escapeJestFn,
|
||||||
|
onEnter: enterJestFn,
|
||||||
|
onClickOutside: clickOutsideJestFn,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
onEscape: {
|
||||||
|
control: false,
|
||||||
|
},
|
||||||
|
onEnter: {
|
||||||
|
control: false,
|
||||||
|
},
|
||||||
|
onClickOutside: {
|
||||||
|
control: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof DateFieldInputWithContext>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const ClickOutside: Story = {
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
await expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div');
|
||||||
|
await userEvent.click(emptyDiv);
|
||||||
|
|
||||||
|
await expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Escape: Story = {
|
||||||
|
play: async () => {
|
||||||
|
await expect(escapeJestFn).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
await userEvent.keyboard('{esc}');
|
||||||
|
|
||||||
|
await expect(escapeJestFn).toHaveBeenCalledTimes(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Enter: Story = {
|
||||||
|
play: async () => {
|
||||||
|
await expect(enterJestFn).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
await userEvent.keyboard('{enter}');
|
||||||
|
|
||||||
|
await expect(enterJestFn).toHaveBeenCalledTimes(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -20,9 +20,14 @@ const StyledEditableBooleanFieldValue = styled.div`
|
|||||||
type BooleanInputProps = {
|
type BooleanInputProps = {
|
||||||
value: boolean;
|
value: boolean;
|
||||||
onToggle?: (newValue: boolean) => void;
|
onToggle?: (newValue: boolean) => void;
|
||||||
|
testId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BooleanInput = ({ value, onToggle }: BooleanInputProps) => {
|
export const BooleanInput = ({
|
||||||
|
value,
|
||||||
|
onToggle,
|
||||||
|
testId,
|
||||||
|
}: BooleanInputProps) => {
|
||||||
const [internalValue, setInternalValue] = useState(value);
|
const [internalValue, setInternalValue] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -37,7 +42,10 @@ export const BooleanInput = ({ value, onToggle }: BooleanInputProps) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledEditableBooleanFieldContainer onClick={handleClick}>
|
<StyledEditableBooleanFieldContainer
|
||||||
|
onClick={handleClick}
|
||||||
|
data-testid={testId}
|
||||||
|
>
|
||||||
{internalValue ? (
|
{internalValue ? (
|
||||||
<IconCheck size={theme.icon.size.sm} />
|
<IconCheck size={theme.icon.size.sm} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user