diff --git a/src/Components/Inputs/TagsInput/TagsInput.stories.tsx b/src/Components/Inputs/TagsInput/TagsInput.stories.tsx new file mode 100644 index 0000000..ef6a625 --- /dev/null +++ b/src/Components/Inputs/TagsInput/TagsInput.stories.tsx @@ -0,0 +1,23 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { WrapForm } from 'src/utils/storybook/decorators'; + +import TagsInput from './TagsInput'; + +export default { + title: 'Shared/TagsInput', + component: TagsInput, + argTypes: { + backgroundColor: { control: 'color' }, + }, + decorators: [WrapForm()] +} as ComponentMeta; + + +const Template: ComponentStory = (args) =>
+

+ Enter Tags: +

+ +
+ +export const Default = Template.bind({}); diff --git a/src/Components/Inputs/TagsInput/TagsInput.tsx b/src/Components/Inputs/TagsInput/TagsInput.tsx new file mode 100644 index 0000000..621b373 --- /dev/null +++ b/src/Components/Inputs/TagsInput/TagsInput.tsx @@ -0,0 +1,75 @@ +import { motion } from "framer-motion"; +import { useState } from "react"; +import { useController } from "react-hook-form"; +import Badge from "src/Components/Badge/Badge"; +import { Tag as ApiTag } from "src/utils/interfaces"; + +type Tag = Pick + +interface Props { + classes?: { + container?: string + input?: string + } + placeholder?: string + [k: string]: any +} + + + +export default function TagsInput({ + classes, + placeholder = 'Write some tags', + ...props }: Props) { + + + const [inputText, setInputText] = useState(""); + + const { field: { value, onChange, onBlur } } = useController({ + name: props.name ?? "tags", + control: props.control, + }) + + const handleSubmit = () => { + onChange([...value, { title: inputText }]); + setInputText(''); + onBlur(); + } + + const handleRemove = (idx: number) => { + onChange((value as Tag[]).filter((_, i) => idx !== i)) + onBlur(); + } + + + return ( +
+
+ setInputText(e.target.value)} + onKeyPress={e => { + if (e.key === 'Enter' && inputText.trim().length > 1) { e.preventDefault(); handleSubmit() } + }} + /> + {inputText.length > 2 && + Enter to Insert + } +
+
+ {(value as Tag[]).map((tag, idx) => handleRemove(idx)} >{tag.title})} +
+
+ ) +} diff --git a/src/Components/Inputs/TextEditor/SaveModule.tsx b/src/Components/Inputs/TextEditor/SaveModule.tsx index be9633e..16b2054 100644 --- a/src/Components/Inputs/TextEditor/SaveModule.tsx +++ b/src/Components/Inputs/TextEditor/SaveModule.tsx @@ -1,11 +1,12 @@ -import React from 'react' +import React, { useCallback } from 'react' import { EditorComponent, Remirror, useHelpers, useRemirror, useEvent, useEditorState } from '@remirror/react'; import { Control, useController } from 'react-hook-form'; interface Props { control?: Control, - name?: string + name?: string, + } export default function SaveModule(props: Props) { @@ -17,10 +18,12 @@ export default function SaveModule(props: Props) { name: props.name ?? 'content' }) - useEvent('blur', () => { + const listener = (d: any) => { onChange(getMarkdown(state)); onBlur() - }) + }; + + useEvent('blur', listener) return <> } diff --git a/src/Components/Inputs/TextEditor/TextEditor.tsx b/src/Components/Inputs/TextEditor/TextEditor.tsx index d461bb1..0f3d604 100644 --- a/src/Components/Inputs/TextEditor/TextEditor.tsx +++ b/src/Components/Inputs/TextEditor/TextEditor.tsx @@ -81,10 +81,12 @@ export default function TextEditor({ placeholder, initialContent }: Props) { [linkExtension, placeholder], ); - const { manager, } = useRemirror({ + + const { manager } = useRemirror({ extensions, stringHandler: 'markdown', }); + return (
{ switch (typeof value) { @@ -28,7 +29,7 @@ const schema = yup.object({ interface IFormInputs { title: string - tags: string + tags: NestedValue cover_image: NestedValue | string body: string } @@ -41,14 +42,16 @@ export default function StoryForm() { const formMethods = useForm({ resolver: yupResolver(schema) as Resolver, defaultValues: { + title: '', + tags: [{ + title: 'tag 1' + }], body: '', cover_image: 'https://i.picsum.photos/id/10/1600/900.jpg?hmac=9R7fIkKwC5JxHx8ayZAKNMt6FvJXqKKyiv8MClikgDo' } }); - const { handleSubmit, control, register, formState: { isValid, errors }, watch, } = formMethods; - - console.log(errors); + const { handleSubmit, control, register, formState: { errors }, watch, } = formMethods; const onSubmit: SubmitHandler = data => console.log(data); @@ -96,14 +99,10 @@ export default function StoryForm() {

Tags

-
- -
+ {errors.tags &&

{errors.tags.message}

} diff --git a/src/utils/storybook/decorators.tsx b/src/utils/storybook/decorators.tsx index c341385..8ed41a3 100644 --- a/src/utils/storybook/decorators.tsx +++ b/src/utils/storybook/decorators.tsx @@ -16,6 +16,7 @@ import "react-multi-carousel/lib/styles.css"; import 'react-loading-skeleton/dist/skeleton.css' import { ApolloProvider } from '@apollo/client'; import { apolloClient } from '../apollo'; +import { FormProvider, useForm, UseFormProps } from 'react-hook-form'; // Enable the Mocks Service Worker @@ -96,4 +97,15 @@ export const centerDecorator: DecoratorFn = (Story) => { return
-} \ No newline at end of file +} + +export const WrapForm: (options?: Partial) => DecoratorFn = options => { + const Func: DecoratorFn = (Story) => { + const methods = useForm(options); + return + + + } + return Func +} +