From 30e80055bbebd31551293164b25555364f9a3adf Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sun, 2 Jul 2023 20:21:32 +0800 Subject: [PATCH] Attempt to make tag input work Integrate tag input styling to tag input component. --- .../web-kitchensink-reactnext/package.json | 1 + .../web-kitchensink-reactnext/pnpm-lock.yaml | 15 +- .../react/components/TagInput/index.tsx | 130 +++++++++++------- .../components/TagInput/style.module.css | 36 +++++ .../src/pages/categories/option/index.tsx | 5 +- .../src/styles/globals.css | 11 ++ 6 files changed, 143 insertions(+), 55 deletions(-) create mode 100644 packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/style.module.css diff --git a/packages/web-kitchensink-reactnext/package.json b/packages/web-kitchensink-reactnext/package.json index e2ce2a1..65c6cad 100644 --- a/packages/web-kitchensink-reactnext/package.json +++ b/packages/web-kitchensink-reactnext/package.json @@ -26,6 +26,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-refractor": "^2.1.7", + "react-tag-input-component": "^2.0.2", "tailwindcss": "3.3.2", "typescript": "5.1.3", "wavesurfer.js": "7.0.0-beta.11" diff --git a/packages/web-kitchensink-reactnext/pnpm-lock.yaml b/packages/web-kitchensink-reactnext/pnpm-lock.yaml index d56ab8f..823d98f 100644 --- a/packages/web-kitchensink-reactnext/pnpm-lock.yaml +++ b/packages/web-kitchensink-reactnext/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -56,6 +56,9 @@ dependencies: react-refractor: specifier: ^2.1.7 version: 2.1.7(react@18.2.0) + 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 @@ -2570,6 +2573,16 @@ packages: unist-util-visit-parents: 3.1.1 dev: false + /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@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} diff --git a/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx b/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx index 712bd4e..5682668 100644 --- a/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx +++ b/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx @@ -1,7 +1,10 @@ import * as React from 'react'; +import { TagsInput } from 'react-tag-input-component'; import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; import clsx from 'clsx'; import {useEnhanced} from '@/packages/react-utils'; +import styles from './style.module.css'; +import {delegateTriggerChangeEvent} from '@/utils/event'; type TagInputDerivedElement = HTMLInputElement; @@ -43,6 +46,7 @@ export interface TagInputProps extends Omit( hiddenLabel = false, className, enhanced: enhancedProp = false, + separator = ',', + onChange, + defaultValue, ...etcProps }: TagInputProps, forwardedRef, @@ -72,9 +79,20 @@ export const TagInput = React.forwardRef( const defaultRef = React.useRef(null); const ref = forwardedRef ?? defaultRef; const labelId = React.useId(); - const dummyInputRef = React.useRef(null); + const tags = React.useMemo(() => { + if (defaultValue === undefined) { + return []; + } + if (typeof defaultValue === 'string') { + return defaultValue.split(separator); + } + if (typeof defaultValue === 'number') { + return [defaultValue.toString()]; + } + return defaultValue as string[]; + }, [defaultValue, separator]); - const handleFocus: React.FocusEventHandler = (e) => { + const handleTagsInputChange = (tags: string[]) => { if (!(typeof ref === 'object' && ref)) { return; } @@ -82,80 +100,86 @@ export const TagInput = React.forwardRef( if (!input) { return; } - input.focus(); + input.value = tags.join(separator); + setTimeout(() => { + delegateTriggerChangeEvent(input); + }); }; - const handleChange: React.ChangeEventHandler = (e) => { - if (!(typeof dummyInputRef === 'object' && dummyInputRef)) { - return; - } - const { current: input } = dummyInputRef; - if (!input) { - return; - } - input.value = e.currentTarget.value; - }; + const inputClassName = clsx( + 'bg-negative rounded-inherit w-full block', + 'focus:outline-0', + 'disabled:opacity-50 disabled:cursor-not-allowed', + { + 'text-xxs': size === 'small', + 'text-xs': size === 'medium', + }, + { + 'pl-4': variant === 'default', + 'pl-1.5': variant === 'alternate', + }, + { + 'pt-4': variant === 'alternate', + }, + { + 'pr-4': variant === 'default' && !indicator, + 'pr-1.5': variant === 'alternate' && !indicator, + }, + { + 'pr-10': indicator && size === 'small', + 'pr-12': indicator && size === 'medium', + 'pr-16': indicator && size === 'large', + }, + ); return (
{enhanced && ( - )} { @@ -164,7 +188,7 @@ export const TagInput = React.forwardRef( data-testid="label" id={labelId} className={clsx( - 'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative', + 'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 group-focus-within:text-secondary text-primary leading-none bg-negative', { 'sr-only': hiddenLabel, }, @@ -233,7 +257,7 @@ export const TagInput = React.forwardRef( border && ( ) } diff --git a/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/style.module.css b/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/style.module.css new file mode 100644 index 0000000..a37241e --- /dev/null +++ b/packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/style.module.css @@ -0,0 +1,36 @@ +.tag-input input + div { + padding: 0.625rem; +} + +.tag-input-small input + div { + padding: 0.5rem; + min-height: 2.5rem; +} + +.tag-input-small input + div > input { + font-size: 0.75rem; +} + +.tag-input-small input + div { + gap: 0.25rem; +} + +.tag-input-medium input + div { + gap: 0.375rem; + min-height: 3rem; +} + +.tag-input-large input + div { + gap: 0.375rem; + min-height: 4rem; +} + +.tag-input input + div > span { + padding: 0.25rem; + border-radius: 0.25rem; + line-height: 1; +} + +.tag-input input + div > input { + +} diff --git a/packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx b/packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx index 3f32bb0..ca86552 100644 --- a/packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx +++ b/packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx @@ -1460,11 +1460,14 @@ const OptionPage: NextPage = ({
{ + console.log(e.currentTarget, e.currentTarget.value, typeof e.currentTarget.value); + }} />
diff --git a/packages/web-kitchensink-reactnext/src/styles/globals.css b/packages/web-kitchensink-reactnext/src/styles/globals.css index a1a5050..3212c69 100644 --- a/packages/web-kitchensink-reactnext/src/styles/globals.css +++ b/packages/web-kitchensink-reactnext/src/styles/globals.css @@ -96,6 +96,17 @@ } } +:root .rti--container { + --rti-bg: rgb(var(--color-negative)); + --rti-border: #ccc; + --rti-main: transparent; + --rti-radius: 0; + --rti-s: 0.5rem; + --rti-tag: rgb(var(--color-positive) / 25%); + --rti-tag-remove: #e53e3e; + --rti-tag-padding: 0 0; +} + .highlight .token.number { color: rgb(var(--color-code-number)); } .highlight .token.keyword { color: rgb(var(--color-code-keyword)); } .highlight .token.tag { color: rgb(var(--color-code-keyword)); }