diff --git a/playground/entries/InputTags.tsx b/playground/entries/InputTags.tsx index 83ee720fce..a9f9f6068e 100644 --- a/playground/entries/InputTags.tsx +++ b/playground/entries/InputTags.tsx @@ -1,6 +1,6 @@ import type { NSInput } from '@semcore/ui/input'; import InputTags from '@semcore/ui/input-tags'; -import type { InputTagsProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import React from 'react'; import type { JSXProps } from '../types/JSXProps'; @@ -16,7 +16,7 @@ type AdditionalJSXProps = { closable: boolean; }; }; -export type InputTagsJSXProps = JSXProps & AdditionalJSXProps; +export type InputTagsJSXProps = JSXProps & AdditionalJSXProps; function getJSX(props: InputTagsJSXProps) { return ( diff --git a/semcore/input-tags/src/InputTags.tsx b/semcore/input-tags/src/InputTags.tsx index 9d266360cc..6606f6ef38 100644 --- a/semcore/input-tags/src/InputTags.tsx +++ b/semcore/input-tags/src/InputTags.tsx @@ -1,13 +1,10 @@ import { ScrollArea, Portal, ScreenReaderOnly } from '@semcore/base-components'; -import type { NSScrollArea } from '@semcore/base-components'; import { createComponent, Component, sstyled, Root, - type PropGetterFn, type Intergalactic, - type IRootComponentProps, } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; @@ -15,74 +12,21 @@ import { extractFrom, isAdvanceMode } from '@semcore/core/lib/utils/findComponen import fire from '@semcore/core/lib/utils/fire'; import { getAccessibleName } from '@semcore/core/lib/utils/getAccessibleName'; import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID'; -import Input, { type NSInput } from '@semcore/input'; -import Tag, { type NSTag, TagContainer } from '@semcore/tag'; +import Input from '@semcore/input'; +import Tag, { TagContainer } from '@semcore/tag'; import React from 'react'; +import type { NSInputTags } from './InputTags.type'; import style from './style/input-tag.shadow.css'; -import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; -export type InputTagsValueProps = NSInput.Value.Props & {}; - -export type InputTagsSize = 'l' | 'm'; - -export type InputTagsProps = Omit & - NSScrollArea.Props & { - /** - * Component size - * @default m - */ - size?: InputTagsSize; - /** Event is called when tags need to be added */ - onAppend?: (values: string[], event: React.KeyboardEvent | React.ClipboardEvent) => void; - /** Event is called when tags need to be removed */ - onRemove?: (event: React.KeyboardEvent | React.MouseEvent) => void; - /** List delimiter of tags. Don't forget to add 'Enter' and 'Tab' to hande corresponding hotkeys. - * @default [',', ';', '|', 'Enter', 'Tab'] - * */ - delimiters?: string[]; - /** Specifies the locale for i18n support */ - locale?: string; - }; - -export type InputTagsDefaultProps = { - size: 'm'; - delimiters: InputTagsProps['delimiters']; - i18n: LocalizedMessages; - locale: 'en'; -}; - -export type InputTagsTagProps = NSTag.Props & { - /** Property enabling the ability to remove a tag on click */ - editable?: boolean; -}; - -export type InputTagsContext = InputTagsProps & { - getValueProps: PropGetterFn; - getTagProps: PropGetterFn; -}; - -export type InputTagsComponent = Intergalactic.Component<'div', InputTagsProps, InputTagsContext> & { - Value: typeof Input.Value; - TagsContainer: Intergalactic.Component<'ul'>; - Tag: Intergalactic.Component<'div', InputTagsTagProps> & { - Text: Intergalactic.Component<'div', NSTag.Props, NSTag.Ctx> & { - Content: Intergalactic.Component<'div', NSTag.Text.Props>; - }; - Close: typeof TagContainer.Close; - Addon: typeof Tag.Addon; - Circle: typeof Tag.Circle; - }; -}; - class InputTagsRoot extends Component< - InputTagsProps, + Intergalactic.InternalTypings.InferComponentProps, typeof InputTagsRoot.enhance, {}, WithI18nEnhanceProps, {}, - InputTagsDefaultProps + NSInputTags.DefaultProps > { static displayName = 'InputTags'; static style = style; @@ -188,7 +132,7 @@ class InputTagsRoot extends Component< } }; - onTagClick = (event: React.MouseEvent) => { + onTagClick = (event: React.MouseEvent | React.KeyboardEvent) => { fire(this, 'onRemove', event); }; @@ -278,7 +222,9 @@ class InputTagsRoot extends Component< } } -class Value extends Component { +class Value extends Component< + Intergalactic.InternalTypings.InferChildComponentProps +> { private _spacer = React.createRef(); state = { @@ -289,7 +235,7 @@ class Value extends Component { this.updateInputStyles(this.asProps.value!); } - componentDidUpdate(prevProps: any) { + componentDidUpdate(prevProps: typeof this.asProps) { const { value, placeholder } = this.asProps; if (value !== prevProps.value || placeholder !== prevProps.placeholder) { this.updateInputStyles(value!); @@ -333,11 +279,14 @@ class Value extends Component { } } -function InputTagsContainer({ - Children, - tagsContainerAriaLabel, - styles, -}: IRootComponentProps & { tagsContainerAriaLabel: string }) { +function InputTagsContainer( + props: Intergalactic.InternalTypings.InferChildComponentProps< + NSInputTags.TagsContainer.Component, + typeof InputTagsRoot, + 'TagsContainer' + >, +) { + const { Children, tagsContainerAriaLabel, styles } = props; const SListAriaWrapper = 'ul'; return sstyled(styles)( @@ -347,7 +296,9 @@ function InputTagsContainer({ ); } -function InputTagContainer(props: any) { +function InputTagContainer( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const STag = Root; const onKeyDown = React.useCallback( @@ -365,7 +316,6 @@ function InputTagContainer(props: any) { return sstyled(props.styles)( , ); } -function InputTagContainerTag(props: any) { +function InputTagContainerTag( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const STag = Root; const { getI18nText } = props; @@ -402,11 +354,15 @@ function InputTagContainerTag(props: any) { ); } -function TagContainerTextContent(props: IRootComponentProps) { +function TagContainerTextContent( + props: Intergalactic.InternalTypings.InferComponentProps, +) { return sstyled(props.styles)(); } -function TagCloseButton(props: IRootComponentProps) { +function TagCloseButton( + props: Intergalactic.InternalTypings.InferComponentProps, +) { const STagContainerClose = Root; return sstyled(props.styles)(); } @@ -417,7 +373,7 @@ function TagCloseButton(props: IRootComponentProps) { * {@link https://developer.semrush.com/intergalactic/components/input-tags/input-tags-api/|API} | {@link https://developer.semrush.com/intergalactic/components/input-tags/input-tags-code/|Examples} */ const InputTags = createComponent< - InputTagsComponent, + NSInputTags.Component, typeof InputTagsRoot >(InputTagsRoot, { Value, diff --git a/semcore/input-tags/src/InputTags.type.ts b/semcore/input-tags/src/InputTags.type.ts new file mode 100644 index 0000000000..d70dd86ca1 --- /dev/null +++ b/semcore/input-tags/src/InputTags.type.ts @@ -0,0 +1,112 @@ +import type { NSScrollArea } from '@semcore/base-components'; +import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { NSInput } from '@semcore/input'; +import type { NSTag } from '@semcore/tag'; + +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + +declare namespace NSInputTags { + type Size = 'l' | 'm'; + type Props = Omit & + NSScrollArea.Props & { + /** + * Component size + * @default m + */ + size?: NSInputTags.Size; + /** Event is called when tags need to be added */ + onAppend?: (values: string[], event: React.KeyboardEvent | React.ClipboardEvent) => void; + /** Event is called when tags need to be removed */ + onRemove?: (event: React.KeyboardEvent | React.MouseEvent) => void; + /** List delimiter of tags. Don't forget to add 'Enter' and 'Tab' to hande corresponding hotkeys. + * @default [',', ';', '|', 'Enter', 'Tab'] + * */ + delimiters?: string[]; + /** Specifies the locale for i18n support */ + locale?: string; + }; + type DefaultProps = { + size: 'm'; + delimiters: NSInputTags.Props['delimiters']; + i18n: LocalizedMessages; + locale: 'en'; + }; + type Ctx = { + getValueProps: PropGetterFn; + getTagProps: PropGetterFn; + }; + + namespace Value { + type Props = NSInput.Value.Props; + + type Component = NSInput.Value.Component; + } + + namespace TagsContainer { + type Component = Intergalactic.Component<'ul'>; + } + + namespace Tag { + type Props = NSTag.Props & { + /** Property enabling the ability to remove a tag on click */ + editable?: boolean; + }; + + namespace Text { + type Props = NSTag.Props; + type Ctx = NSTag.Ctx; + + namespace Content { + type Props = NSTag.Text.Props; + + type Component = Intergalactic.Component<'div', Props>; + } + + type Component = Intergalactic.Component<'div', Props, Ctx> & { + Content: Content.Component; + }; + } + + namespace Close { + type Component = NSTag.Close.Component; + } + + namespace Addon { + type Component = NSTag.Addon.Component; + } + + namespace Circle { + type Component = NSTag.Circle.Component; + } + + type Component = Intergalactic.Component<'div', Props> & { + Text: Text.Component; + Close: Close.Component; + Addon: Addon.Component; + Circle: Circle.Component; + }; + } + + type Component = Intergalactic.Component<'div', Props, Ctx> & { + Value: Value.Component; + TagsContainer: TagsContainer.Component; + Tag: Tag.Component; + }; +} + +/** @deprecated It will be removed in v19. */ +export type InputTagsSize = NSInputTags.Size; +/** @deprecated It will be removed in v19. */ +export type InputTagsProps = NSInputTags.Props; +/** @deprecated It will be removed in v19. */ +export type InputTagsDefaultProps = NSInput.DefaultProps; +/** @deprecated It will be removed in v19. */ +export type InputTagsContext = NSInputTags.Ctx; +/** @deprecated It will be removed in v19. */ +export type InputTagsTagProps = NSInputTags.Tag.Props; +/** @deprecated It will be removed in v19. */ +export type InputTagsComponent = NSInputTags.Component; +/** @deprecated It will be removed in v19. */ +export type InputTagsValueProps = NSInputTags.Value.Props; + +export type { NSInputTags }; diff --git a/semcore/input-tags/src/index.tsx b/semcore/input-tags/src/index.tsx index 24236846d0..07b6dfbbf4 100644 --- a/semcore/input-tags/src/index.tsx +++ b/semcore/input-tags/src/index.tsx @@ -1,2 +1,2 @@ export { default } from './InputTags'; -export * from './InputTags'; +export * from './InputTags.type'; diff --git a/stories/components/ellipsis/docs/examples/input-tags.tsx b/stories/components/ellipsis/docs/examples/input-tags.tsx index cbf3234bb2..c5235ea1d8 100644 --- a/stories/components/ellipsis/docs/examples/input-tags.tsx +++ b/stories/components/ellipsis/docs/examples/input-tags.tsx @@ -1,11 +1,11 @@ import { Flex } from '@semcore/ui/base-components'; import Ellipsis from '@semcore/ui/ellipsis'; -import type { InputTagsProps, InputTagsValueProps, InputTagsTagProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import InputTags from '@semcore/ui/input-tags'; import { Text } from '@semcore/ui/typography'; import React from 'react'; -type ExampleInputTagsProps = InputTagsProps & InputTagsValueProps; +type ExampleInputTagsProps = NSInputTags.Props & NSInputTags.Value.Props; const Demo = (props: ExampleInputTagsProps) => { const inputValueRef = React.useRef(null); diff --git a/stories/components/input-tags/docs/examples/entering_and_editing_tags.tsx b/stories/components/input-tags/docs/examples/entering_and_editing_tags.tsx index 9f4fb8a987..633b223ab5 100644 --- a/stories/components/input-tags/docs/examples/entering_and_editing_tags.tsx +++ b/stories/components/input-tags/docs/examples/entering_and_editing_tags.tsx @@ -1,10 +1,10 @@ import { Flex } from '@semcore/ui/base-components'; -import type { InputTagsProps, InputTagsValueProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import InputTags from '@semcore/ui/input-tags'; import { Text } from '@semcore/ui/typography'; import React from 'react'; -type ExampleInputTagsProps = InputTagsProps & InputTagsValueProps; +type ExampleInputTagsProps = NSInputTags.Props & NSInputTags.Value.Props; const Demo = (props: ExampleInputTagsProps) => { const inputValueRef = React.useRef(null); diff --git a/stories/components/input-tags/docs/examples/wrapping_email_in_tag.tsx b/stories/components/input-tags/docs/examples/wrapping_email_in_tag.tsx index eab878fa57..c590109f50 100644 --- a/stories/components/input-tags/docs/examples/wrapping_email_in_tag.tsx +++ b/stories/components/input-tags/docs/examples/wrapping_email_in_tag.tsx @@ -1,13 +1,13 @@ import { Flex } from '@semcore/ui/base-components'; import InputTags from '@semcore/ui/input-tags'; -import type { InputTagsTagProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import { Text } from '@semcore/ui/typography'; import React from 'react'; const isValidEmail = (value: string) => /.+@.+\..+/i.test(value.toLowerCase()); const defaultTags = ['bob@email.com', 'alice@domain.net', 'mary@website.com', 'steve@company.com']; -type ExampleInputTagsProps = InputTagsTagProps; +type ExampleInputTagsProps = NSInputTags.Tag.Props; const Demo = (props: ExampleInputTagsProps) => { const [tags, setTags] = React.useState(defaultTags); diff --git a/stories/components/input-tags/tests/examples/entering_and_editing_tags.tsx b/stories/components/input-tags/tests/examples/entering_and_editing_tags.tsx index 5555623f08..3a89466bc0 100644 --- a/stories/components/input-tags/tests/examples/entering_and_editing_tags.tsx +++ b/stories/components/input-tags/tests/examples/entering_and_editing_tags.tsx @@ -1,10 +1,10 @@ import { Flex } from '@semcore/ui/base-components'; -import type { InputTagsProps, InputTagsValueProps, InputTagsTagProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import InputTags from '@semcore/ui/input-tags'; import { Text } from '@semcore/ui/typography'; import React from 'react'; -type ExampleInputTagsProps = InputTagsProps & InputTagsValueProps & InputTagsTagProps & { +type ExampleInputTagsProps = NSInputTags.Props & NSInputTags.Value.Props & NSInputTags.Tag.Props & { hintPlacement?: 'top' | 'bottom' | 'left' | 'right'; hintProps?: false; }; diff --git a/stories/components/input-tags/tests/examples/tags-with-addons.tsx b/stories/components/input-tags/tests/examples/tags-with-addons.tsx index 204a8eabc5..ead874f4fd 100644 --- a/stories/components/input-tags/tests/examples/tags-with-addons.tsx +++ b/stories/components/input-tags/tests/examples/tags-with-addons.tsx @@ -2,10 +2,10 @@ import Check from '@semcore/icon/Check/m'; import Edit from '@semcore/icon/Edit/m'; import { Box, Flex } from '@semcore/ui/base-components'; import InputTags from '@semcore/ui/input-tags'; -import type { InputTagsTagProps } from '@semcore/ui/input-tags'; +import type { NSInputTags } from '@semcore/ui/input-tags'; import React from 'react'; -type ExampleInputTagsProps = InputTagsTagProps; +type ExampleInputTagsProps = NSInputTags.Tag.Props; const Demo = (props: ExampleInputTagsProps) => { return ( diff --git a/website/docs/components/input-tags/input-tags-api.md b/website/docs/components/input-tags/input-tags-api.md index 6a39262e43..332f840138 100644 --- a/website/docs/components/input-tags/input-tags-api.md +++ b/website/docs/components/input-tags/input-tags-api.md @@ -10,7 +10,7 @@ tabs: Design('input-tags'), A11y('input-tags-a11y'), API('input-tags-api'), Exam import InputTags from '@semcore/ui/input-tags'; ``` - + ## InputTags.Value @@ -19,7 +19,7 @@ import InputTags from '@semcore/ui/input-tags'; ; ``` - + ## InputTags.Tag @@ -30,7 +30,7 @@ import InputTags from '@semcore/ui/input-tags'; ; ``` - + ## InputTags.Tag.Addon