From 0ff5787efbf11ad5f9951b3b3bcd96aabc706a9a Mon Sep 17 00:00:00 2001 From: Jelle Ages Date: Mon, 24 Oct 2022 14:25:59 +0200 Subject: [PATCH 1/2] supporting the ability to have multiple values per tag --- README.md | 32 ++++++++-------- src/index.tsx | 69 +++++++++++++++++++++++++--------- src/styles.css | 15 +++++++- src/tag.tsx | 19 ++++++++-- stories/tags-input.stories.tsx | 26 ++++++++++++- 5 files changed, 122 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 387075c..8eb10dc 100644 --- a/README.md +++ b/README.md @@ -55,21 +55,23 @@ export default Example; ## 👀 Props -| Prop | Description | Type | Default | -| ------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------- | --------------- | -| `name` | value for name of input | `string` | | -| `placeholder` | placeholder for text input | `string` | | -| `value` | initial tags | `string[]` | `[]` | -| `onChange` | onChange callback (added/removed) | `string[]` | | -| `classNames` | className for styling input and tags (i.e {tag:'tag-cls', input: 'input-cls'}) | `object[tag, input]` | | -| `onKeyUp` | input `onKeyUp` callback | `event` | | -| `onBlur` | input `onBlur` callback | `event` | | -| `separators` | when to add tag (i.e. `Space`,`Enter`) | `string[]` | `["Enter"]` | -| `removers` | Remove last tag if textbox empty and `Backspace` is pressed | `string[]` | `["Backspace"]` | -| `onExisting` | if tag is already added then callback | `(tag: string) => void` | | -| `onRemoved` | on tag removed callback | `(tag: string) => void` | | -| `beforeAddValidate` | Custom validation before adding tag | `(tag: string, existingTags: string[]) => boolean` | | -| `isEditOnRemove` | Remove the tag but keep the word in the input to edit it on using Backscape Key | `boolean` | `false` | +| Prop | Description | Type | Default | +| ----------------------| ------------------------------------------------------------------------------- | -------------------------------------------------- | --------------- | +| `name` | value for name of input | `string` | | +| `placeholder` | placeholder for text input | `string` | | +| `value` | initial tags | `string[]` | `[]` | +| `onChange` | onChange callback (added/removed) | `string[]` | | +| `classNames` | className for styling input and tags (i.e {tag:'tag-cls', input: 'input-cls'}) | `object[tag, input]` | | +| `onKeyUp` | input `onKeyUp` callback | `event` | | +| `onBlur` | input `onBlur` callback | `event` | | +| `separators` | when to add tag (i.e. `Space`,`Enter`) | `string[]` | `["Enter"]` | +| `removers` | Remove last tag if textbox empty and `Backspace` is pressed | `string[]` | `["Backspace"]` | +| `onExisting` | if tag is already added then callback | `(tag: string) => void` | | +| `onRemoved` | on tag removed callback | `(tag: string) => void` | | +| `beforeAddValidate` | Custom validation before adding tag | `(tag: string, existingTags: string[]) => boolean` | | +| `isEditOnRemove` | Remove the tag but keep the word in the input to edit it on using Backscape Key | `boolean` | `false` | +| `multipleValues` | Using multiple values per tag | `boolean` | `false` | +| `numberOfValuesPerTag`| The number of values a tag can have, if 'multipleValues' is true | `number` | | ## 💅 Themeing diff --git a/src/index.tsx b/src/index.tsx index b535239..b021229 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -23,28 +23,34 @@ export interface TagsInputProps { classNames?: { input?: string; tag?: string; + tagInput?:string }; + multiValueTags?: boolean; + numberOfValuesPerTag?: number; } const defaultSeparators = ["Enter"]; export const TagsInput = ({ - name, - placeHolder, - value, - onChange, - onBlur, - separators, - disableBackspaceRemove, - onExisting, - onRemoved, - disabled, - isEditOnRemove, - beforeAddValidate, - onKeyUp, - classNames, -}: TagsInputProps) => { + name, + placeHolder, + value, + onChange, + onBlur, + separators, + disableBackspaceRemove, + onExisting, + onRemoved, + disabled, + isEditOnRemove, + beforeAddValidate, + onKeyUp, + classNames, + multiValueTags, + numberOfValuesPerTag, + }: TagsInputProps) => { const [tags, setTags] = useState(value || []); + const [openTag, setOpenTag] = useState(false); useDidUpdateEffect(() => { onChange && onChange(tags); @@ -56,6 +62,7 @@ export const TagsInput = ({ } }, [value]); + const handleOnKeyUp = e => { e.stopPropagation(); @@ -79,23 +86,49 @@ export const TagsInput = ({ onExisting && onExisting(text); return; } - setTags([...tags, text]); - e.target.value = ""; + + + if (multiValueTags) { + !openTag && setTags([...tags, [text]]); + + if (openTag) { + let lastTag = JSON.parse(JSON.stringify(tags[tags.length - 1])); + console.log("Lasttag",lastTag) + + setTags([...tags.slice(0, -1), [...lastTag,text]]) + + numberOfValuesPerTag && ([...lastTag,text].length == numberOfValuesPerTag) && setOpenTag(false) + } + else { + setOpenTag(true); + + } + e.target.value = ""; + + + } else { + setTags([...tags, text]); + e.target.value = ""; + } } }; const onTagRemove = text => { setTags(tags.filter(tag => tag !== text)); onRemoved && onRemoved(text); + setOpenTag(false) }; return (
- {tags.map(tag => ( + {tags.map((tag, index:number) => ( diff --git a/src/styles.css b/src/styles.css index 836c931..6a999e4 100644 --- a/src/styles.css +++ b/src/styles.css @@ -36,8 +36,19 @@ font-size: inherit; line-height: inherit; width: 50%; -} +} +.rti--input--tag { + border: 0; + outline: 0; + font-size: inherit; + line-height: inherit; + margin-left:5px; + margin-right:5px; + height:20px; + border-radius: 5px; + background-color: rgba(256,256,256,0.6); +} .rti--tag { align-items: center; background: var(--rti-tag); @@ -58,4 +69,4 @@ .rti--tag button:hover { color: var(--rti-tag-remove); -} \ No newline at end of file +} diff --git a/src/tag.tsx b/src/tag.tsx index ed10d09..3b33bb7 100644 --- a/src/tag.tsx +++ b/src/tag.tsx @@ -2,13 +2,16 @@ import React from "react"; import cc from "./classnames"; interface TagProps { - text: string; + text: string | string[]; remove: any; + openTag?:boolean; disabled?: boolean; className?: string; + classNameInput?:string; + handleKeyUp?:(e) => void; } -export default function Tag({ text, remove, disabled, className }: TagProps) { +export default function Tag({ text, remove, disabled, className,openTag,handleKeyUp,classNameInput }: TagProps) { const handleOnRemove = e => { e.stopPropagation(); remove(text); @@ -16,7 +19,17 @@ export default function Tag({ text, remove, disabled, className }: TagProps) { return ( - {text} + + {!Array.isArray(text) && {text}} + + {Array.isArray(text) && text.map((item, index:number) => { + return {item}{index < text.length - 1 && '->'} + })} + + {openTag && ( + + )} + {!disabled && (
Keep Words on Backspace: {JSON.stringify(isEditOnRemove)}
+ + +
+ +
Multiple values per tag: {JSON.stringify(multipleValues)}
+
+ +
+ + setNumberOfValues(Number(e.target.value))}/> + +
Number of values per tag: {JSON.stringify(numberOfValues)}
+
+