Browse Source

Fork react-tag-input-component

Fork package to enable custom styling.
master
TheoryOfNekomata 1 year ago
parent
commit
c8e2763b7d
4 changed files with 152 additions and 19 deletions
  1. +0
    -1
      categories/web/multichoice/react/package.json
  2. +4
    -5
      categories/web/multichoice/react/src/components/TagInput/index.tsx
  3. +148
    -0
      categories/web/multichoice/react/src/components/TagInput/internal.tsx
  4. +0
    -13
      pnpm-lock.yaml

+ 0
- 1
categories/web/multichoice/react/package.json View File

@@ -65,7 +65,6 @@
"@modal-sh/react-utils": "workspace:*",
"@tesseract-design/web-base": "workspace:*",
"clsx": "^1.2.1",
"react-tag-input-component": "^2.0.2",
"tailwindcss": "3.3.2"
},
"types": "./dist/types/index.d.ts",


+ 4
- 5
categories/web/multichoice/react/src/components/TagInput/index.tsx View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { TagsInput } from 'react-tag-input-component';
import { TagsInput } from './internal';
import clsx from 'clsx';
import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-utils';
import { TextControl } from '@tesseract-design/web-base';
@@ -95,6 +95,9 @@ export interface TagInputProps extends Omit<React.HTMLProps<TagInputDerivedEleme
export const tagInputPlugin = plugin(({ addComponents }) => {
addComponents({
'.tag-input': {
'&[data-size] label + * + div': {
'background': 'red',
},
'& label + * + div > input': {
'flex': 'auto',
},
@@ -462,10 +465,6 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(
{clientSide && (
<TagsInput
value={tags}
classNames={{
input: 'peer bg-transparent font-inherit',
tag: 'text-xs p-2 select-none font-inherit',
}}
isEditOnRemove={editOnRemove}
placeHolder={placeholder}
disabled={disabled}


+ 148
- 0
categories/web/multichoice/react/src/components/TagInput/internal.tsx View File

@@ -0,0 +1,148 @@
import * as React from "react";

const useDidUpdateEffect = (fn: () => void, inputs: unknown[]) => {
const didMountRef = React.useRef(false);

React.useEffect(() => {
if (didMountRef.current) fn();
else didMountRef.current = true;
}, inputs);
}

interface TagProps {
text: string;
remove: any;
disabled?: boolean;
className?: string;
}

export const Tag = ({ text, remove, disabled }: TagProps) => {
const handleOnRemove: React.MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();
remove(text);
};

return (
<span className="text-xs p-2 select-none font-inherit">
<span>{text}</span>
{!disabled && (
<button
type="button"
onClick={handleOnRemove}
aria-label={`remove ${text}`}
>
&#10005;
</button>
)}
</span>
);
}

export interface TagsInputProps {
name?: string;
placeHolder?: string;
value?: string[];
onChange?: (tags: string[]) => void;
onBlur?: any;
separators?: string[];
disableBackspaceRemove?: boolean;
onExisting?: (tag: string) => void;
onRemoved?: (tag: string) => void;
disabled?: boolean;
isEditOnRemove?: boolean;
beforeAddValidate?: (tag: string, existingTags: string[]) => boolean;
onKeyUp?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
classNames?: {
input?: string;
tag?: string;
};
}

const defaultSeparators = ["Enter"];

export const TagsInput = ({
name,
placeHolder,
value,
onChange,
onBlur,
separators,
disableBackspaceRemove,
onExisting,
onRemoved,
disabled,
isEditOnRemove,
beforeAddValidate,
onKeyUp,
classNames,
}: TagsInputProps) => {
const [tags, setTags] = React.useState<any>(value || []);

useDidUpdateEffect(() => {
onChange && onChange(tags);
}, [tags]);

useDidUpdateEffect(() => {
if (JSON.stringify(value) !== JSON.stringify(tags)) {
setTags(value);
}
}, [value]);

const handleOnKeyUp: React.KeyboardEventHandler<HTMLInputElement> = (e) => {
e.stopPropagation();

const text = e.currentTarget.value;

if (
!text &&
!disableBackspaceRemove &&
tags.length &&
e.key === "Backspace"
) {
e.currentTarget.value = isEditOnRemove ? `${tags.at(-1)} ` : "";
setTags([...tags.slice(0, -1)]);
}

if (text && (separators || defaultSeparators).includes(e.key)) {
e.preventDefault();
if (beforeAddValidate && !beforeAddValidate(text, tags)) return;

if (tags.includes(text)) {
onExisting && onExisting(text);
return;
}
setTags([...tags, text]);
e.currentTarget.value = "";
}
};

const onTagRemove = (text: string) => {
setTags(tags.filter((tag: string) => tag !== text));
onRemoved && onRemoved(text);
};

return (
<div aria-labelledby={name} className="rti--container">
{tags.map((tag: string) => (
<Tag
key={tag}
className={classNames?.tag}
text={tag}
remove={onTagRemove}
disabled={disabled}
/>
))}

<input
className="peer bg-transparent font-inherit focus:outline-0"
type="text"
name={name}
placeholder={placeHolder}
onKeyDown={handleOnKeyUp}
onBlur={onBlur}
disabled={disabled}
onKeyUp={onKeyUp}
/>
</div>
);
};

+ 0
- 13
pnpm-lock.yaml View File

@@ -516,9 +516,6 @@ importers:
clsx:
specifier: ^1.2.1
version: 1.2.1
react-tag-input-component:
specifier: ^2.0.2
version: 2.0.2(react-dom@18.2.0)(react@18.2.0)
tailwindcss:
specifier: 3.3.2
version: 3.3.2
@@ -7814,16 +7811,6 @@ packages:
react-is: 18.2.0
dev: true

/react-tag-input-component@2.0.2(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg==}
peerDependencies:
react: ^16 || ^17 || ^18
react-dom: ^16 || ^17 || ^18
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false

/react-test-renderer@18.2.0(react@18.2.0):
resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==}
peerDependencies:


Loading…
Cancel
Save