diff --git a/playground/entries/InlineInput.tsx b/playground/entries/InlineInput.tsx index 06f51b1481..6c82712453 100644 --- a/playground/entries/InlineInput.tsx +++ b/playground/entries/InlineInput.tsx @@ -1,12 +1,12 @@ import InlineInput from '@semcore/ui/inline-input'; -import type { InlineInputProps } from '@semcore/ui/inline-input'; +import type { NSInlineInput } from '@semcore/ui/inline-input'; import React from 'react'; import type { JSXProps } from '../types/JSXProps'; import type { PlaygroundEntry } from '../types/Playground'; import createGithubLink from '../utils/createGHLink'; -export type InlineInputJSXProps = JSXProps; +export type InlineInputJSXProps = JSXProps; function getJSX({ handleControlChange, ...inlineInputProps }: InlineInputJSXProps) { return ( diff --git a/semcore/inline-input/src/InlineInput.tsx b/semcore/inline-input/src/InlineInput.tsx index 4c02f10af5..bc7be7da45 100644 --- a/semcore/inline-input/src/InlineInput.tsx +++ b/semcore/inline-input/src/InlineInput.tsx @@ -1,90 +1,20 @@ import { Box, InvalidStateBox } from '@semcore/base-components'; import { ButtonLink } from '@semcore/button'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, sstyled, Root, lastInteraction } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { hasParent } from '@semcore/core/lib/utils/hasParent'; import CheckM from '@semcore/icon/Check/m'; import CloseM from '@semcore/icon/Close/m'; -import InputNumber, { type NSInputNumber } from '@semcore/input-number'; +import InputNumber from '@semcore/input-number'; import Spin from '@semcore/spin'; -import type { TooltipProps } from '@semcore/tooltip'; import React from 'react'; -import type { InlineInputComponent } from './index.type'; +import type { NSInlineInput } from './InlineInput.type'; import style from './style/inline-input.shadow.css'; -import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; -type OnConfirm = ( - value: string, - event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent, -) => void; -type OnCancel = ( - prevValue: string, - event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent, -) => void; -type RootAsProps = { - state?: 'normal' | 'valid' | 'invalid'; - loading?: boolean; - disabled?: boolean; - onConfirm?: OnConfirm; - onCancel?: OnCancel; - value?: string; - defaultValue?: string; - autoFocus?: boolean; - placeholder?: string; - onChange?: (value: string, event: React.ChangeEvent) => void; - onBlur?: (event: React.FocusEvent) => void; - onFocus?: (event: React.FocusEvent) => void; - onBlurBehavior?: 'cancel' | 'confirm'; - styles?: React.CSSProperties; - Children: React.FC; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; - locale?: string; -}; - -type AddonAsProps = { - styles?: React.CSSProperties; - Children: React.FC; -}; - -type ControlAsProps = { - Children: React.FC; - children: React.ReactNode; - styles?: React.CSSProperties; - title?: string; - $tooltipsProps?: TooltipProps; - loading?: boolean; - disabled?: boolean; - onCancel?: OnCancel; - value?: string; - icon?: React.FC; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; -type ConfirmControlAsProps = ControlAsProps & { - onConfirm?: OnConfirm; - onCancel?: OnCancel; - inputRef?: React.RefObject; -}; -type CancelControlAsProps = ControlAsProps & { - onCancel?: OnCancel; -}; -type NumberValueAsProps = NSInputNumber.Value.Props & { - increment?: (event: WheelEvent) => void; - decrement?: (event: WheelEvent) => void; -}; -type NumberControlsAsProps = ControlAsProps & { - increment?: (event: React.SyntheticEvent) => void; - decrement?: (event: React.SyntheticEvent) => void; -}; -type DefaultProps = { - state: 'normal'; - onBlurBehavior: 'confirm'; - i18n: LocalizedMessages; - locale: 'en'; -}; - const pointInsideOfRect = ({ x, y, @@ -98,16 +28,16 @@ const pointInsideOfRect = ({ }; class InlineInputBase extends Component< - RootAsProps, - [], + Intergalactic.InternalTypings.InferComponentProps, + typeof InlineInputBase.enhance, {}, WithI18nEnhanceProps, {}, - DefaultProps + NSInlineInput.DefaultProps > { static displayName = 'InlineInput'; - static enhance = [i18nEnhance(localizedMessages)]; + static enhance = [i18nEnhance(localizedMessages)] as const; static defaultProps = { state: 'normal', onBlurBehavior: 'confirm', @@ -140,7 +70,7 @@ class InlineInputBase extends Component< document.body.addEventListener('keydown', this.handleDocumentKeyDown); } - componentDidUpdate(prevProps: Readonly): void { + componentDidUpdate(prevProps: typeof this.asProps): void { if (prevProps.disabled !== this.asProps.disabled) { this.updateInert(); } @@ -308,8 +238,12 @@ class InlineInputBase extends Component< } } -class Value extends Component { - static defaultProps = { +class Value extends Component< + Intergalactic.InternalTypings.InferChildComponentProps, + [], + NSInlineInput.Value.Handlers +> { + static defaultProps: NSInlineInput.Value.DefaultProps = { defaultValue: '', }; @@ -326,12 +260,16 @@ class Value extends Component { } } -function Addon(props: AddonAsProps) { +function Addon( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SAddon = Root; - return sstyled(props.styles)() as React.ReactElement; + return sstyled(props.styles)(); } -function ConfirmControl(props: ConfirmControlAsProps) { +function ConfirmControl( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SAddon = Root; const { Children, children: hasChildren, inputRef, onCancel } = props; const title = props.title ?? props.getI18nText('confirm'); @@ -362,7 +300,7 @@ function ConfirmControl(props: ConfirmControlAsProps) { if (props.loading) { return sstyled(props.styles)( {hasChildren ? : }, - ) as React.ReactElement; + ); } const sstyles = sstyled(props.styles); @@ -376,7 +314,7 @@ function ConfirmControl(props: ConfirmControlAsProps) { ) : ( )} , - ) as React.ReactElement; + ); } -function CancelControl(props: CancelControlAsProps) { +function CancelControl( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SAddon = Root; const { Children, children: hasChildren } = props; const title = props.title ?? props.getI18nText('discard'); @@ -414,7 +354,7 @@ function CancelControl(props: CancelControlAsProps) { if (props.disabled) { return sstyled(props.styles)( {hasChildren ? : }, - ) as React.ReactElement; + ); } const sstyles = sstyled(props.styles); @@ -429,7 +369,7 @@ function CancelControl(props: CancelControlAsProps) { : ( )} , - ) as React.ReactElement; + ); } -function NumberValue(props: NumberValueAsProps) { +function NumberValue( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SValue = Root; - return sstyled(props.styles)() as React.ReactElement; + return sstyled(props.styles)(); }; -function NumberControls(props: NumberControlsAsProps) { +function NumberControls( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SControls = Root; return sstyled(props.styles)( , - ) as React.ReactElement; + ); } /** @@ -460,7 +404,7 @@ function NumberControls(props: NumberControlsAsProps) { * {@link https://developer.semrush.com/intergalactic/components/inline-input/inline-input-api/|API} | {@link https://developer.semrush.com/intergalactic/components/inline-input/inline-input-code/|Examples} */ const InlineInput = createComponent< - InlineInputComponent, + NSInlineInput.Component, typeof InlineInputBase >(InlineInputBase, { Addon, diff --git a/semcore/inline-input/src/InlineInput.type.ts b/semcore/inline-input/src/InlineInput.type.ts new file mode 100644 index 0000000000..c2788effbb --- /dev/null +++ b/semcore/inline-input/src/InlineInput.type.ts @@ -0,0 +1,173 @@ +import type { BoxProps } from '@semcore/base-components'; +import type { ButtonLinkComponent } from '@semcore/button'; +import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { NSInputNumber } from '@semcore/input-number'; +import type React from 'react'; + +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + +declare namespace NSInlineInput { + type Props = BoxProps & { + /** + * Visual state of inline input + * @default normal + */ + state?: 'normal' | 'valid' | 'invalid'; + /** + * Disabled input and shows spinner instead of confirm control + * @default false + */ + loading?: boolean; + /** + * Disabled input and controls + * @default false + */ + disabled?: boolean; + /** + * Fired with entered value when user clicks confirm control or hits `Enter` or `Space` + */ + onConfirm?: (value: string, event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent) => void; + /** + * Fired with value (or defaultValue) that was provided during component mount when user clicks cancel control or hits `Escape` + */ + onCancel?: (prevValue: string, event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent) => void; + /** + * defines callback (`onCancel` or `onConfirm`) triggered when `blur` event out of container fired + * Triggered after all previous macrotasks completed (internally called inside of `setTimeout`) + */ + onBlurBehavior?: 'cancel' | 'confirm' | 'none'; + /** Specifies the locale for i18n support */ + locale?: string; + }; + type DefaultProps = { + state: 'normal'; + onBlurBehavior: 'confirm'; + i18n: LocalizedMessages; + locale: 'en'; + }; + type Ctx = { + getAddonProps: PropGetterFn; + getConfirmControlProps: PropGetterFn; + getCancelControlProps: PropGetterFn; + getValueProps: PropGetterFn; + }; + + namespace Addon { + type Props = BoxProps; + + type Component = Intergalactic.Component<'div', Props>; + } + + namespace Value { + type Props = BoxProps & { + /** + * id attribute of input tag + */ + id?: string; + /** + * when `true`, element is focused immediately after mount + */ + autoFocus?: boolean; + /** + * value of input tag + */ + value?: string; + /** + * uncontrolled value of input tag + */ + defaultValue?: string; + /** + * callback invoked on every change of input tag value + */ + onChange?: (value: string, event: React.ChangeEvent) => void; + /** + * disables interactive elements + */ + disabled?: boolean; + /** + * gray text in empty input tag + */ + placeholder?: string; + }; + type DefaultProps = { + defaultValue: ''; + }; + type Handlers = { + value: (event: React.ChangeEvent) => Props['value']; + }; + + type Component = Intergalactic.Component<'input', Props>; + } + + namespace ConfirmControl { + type Props = BoxProps & { + /** + * Text of tooltip + * @default Confirm + */ + title?: string; + /** + * Icon component + * @default CheckM + */ + icon?: React.FC; + }; + + type Component = Intergalactic.Component; + } + + namespace CancelControl { + type Props = BoxProps & { + /** + * Text of tooltip + * @default Cancel + */ + title?: string; + /** + * Icon component + * @default CloseM + */ + icon?: React.FC; + }; + + type Component = Intergalactic.Component; + } + + namespace NumberValue { + type Props = {}; + /* + Looks like it should be `type Component = NSInputNumber.Value.Component;`. + Leave it as it is, since the change to NSInputNumber breaks types for `defaultValue` and maybe others. + It expects `string` (coming from NSInput.Props['defaultValue']) while at the moment `defaultValue` comes from React HTML Attributes. + */ + type Component = Intergalactic.Component<'div', Props>; + } + + namespace NumberControls { + type Component = NSInputNumber.Controls.Component; + } + + type Component = Intergalactic.Component<'div', Props, Ctx> & { + Addon: Addon.Component; + Value: Value.Component; + ConfirmControl: ConfirmControl.Component; + CancelControl: CancelControl.Component; + NumberValue: NumberValue.Component; + NumberControls: NumberControls.Component; + }; +} + +/** @deprecated It will be removed in v19. */ +export type InlineInputProps = NSInlineInput.Props; +/** @deprecated It will be removed in v19. */ +export type InlineInputAddonProps = NSInlineInput.Addon.Props; +/** @deprecated It will be removed in v19. */ +export type InlineInputValueProps = NSInlineInput.Value.Props; +/** @deprecated It will be removed in v19. */ +export type InlineInputConfirmControlProps = NSInlineInput.ConfirmControl.Props; +/** @deprecated It will be removed in v19. */ +export type InlineInputCancelControlProps = NSInlineInput.CancelControl.Props; +/** @deprecated It will be removed in v19. */ +export type InlineInputComponent = NSInlineInput.Component; + +export type { NSInlineInput }; diff --git a/semcore/inline-input/src/index.ts b/semcore/inline-input/src/index.ts index d17a8df2da..39805cbe6c 100644 --- a/semcore/inline-input/src/index.ts +++ b/semcore/inline-input/src/index.ts @@ -1,6 +1,6 @@ -import type { InlineInputProps, InlineInputValueProps } from './index.type'; import InlineInputBase from './InlineInput'; +import type { InlineInputProps, InlineInputValueProps, NSInlineInput } from './InlineInput.type'; export default InlineInputBase; -export type { InlineInputProps, InlineInputValueProps }; +export type { InlineInputProps, InlineInputValueProps, NSInlineInput }; diff --git a/semcore/inline-input/src/index.type.ts b/semcore/inline-input/src/index.type.ts deleted file mode 100644 index 4b003ba24c..0000000000 --- a/semcore/inline-input/src/index.type.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { BoxProps } from '@semcore/base-components'; -import type { ButtonLinkComponent } from '@semcore/button'; -import type { PropGetterFn, Intergalactic } from '@semcore/core'; -import type { NSInputNumber } from '@semcore/input-number'; -import type React from 'react'; - -export type InlineInputProps = BoxProps & { - /** - * Visual state of inline input - * @default normal - */ - state?: 'normal' | 'valid' | 'invalid'; - /** - * Disabled input and shows spinner instead of confirm control - * @default false - */ - loading?: boolean; - /** - * Disabled input and controls - * @default false - */ - disabled?: boolean; - /** - * Fired with entered value when user clicks confirm control or hits `Enter` or `Space` - */ - onConfirm?: ( - value: string, - event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent, - ) => void; - /** - * Fired with value (or defaultValue) that was provided during component mount when user clicks cancel control or hits `Escape` - */ - onCancel?: ( - prevValue: string, - event: React.MouseEvent | React.FocusEvent | React.KeyboardEvent, - ) => void; - /** - * defines callback (`onCancel` or `onConfirm`) triggered when `blur` event out of container fired - * Triggered after all previous macrotasks completed (internally called inside of `setTimeout`) - */ - onBlurBehavior?: 'cancel' | 'confirm' | 'none'; - /** Specifies the locale for i18n support */ - locale?: string; -}; - -export type InlineInputAddonProps = BoxProps & {}; - -export type InlineInputValueProps = BoxProps & { - /** - * id attribute of input tag - */ - id?: string; - /** - * when `true`, element is focused immediately after mount - */ - autoFocus?: boolean; - /** - * value of input tag - */ - value?: string; - /** - * uncontrolled value of input tag - */ - defaultValue?: string; - /** - * callback invoked on every change of input tag value - */ - onChange?: (value: string, event: React.ChangeEvent) => void; - /** - * disables interactive elements - */ - disabled?: boolean; - /** - * gray text in empty input tag - */ - placeholder?: string; -}; - -export type InlineInputConfirmControlProps = BoxProps & { - /** - * Text of tooltip - * @default Confirm - */ - title?: string; - /** - * Icon component - * @default CheckM - */ - icon?: React.FC; -}; - -export type InlineInputCancelControlProps = BoxProps & { - /** - * Text of tooltip - * @default Cancel - */ - title?: string; - /** - * Icon component - * @default CloseM - */ - icon?: React.FC; -}; - -type InlineInputCtx = { - getAddonProps: PropGetterFn; - getConfirmControlProps: PropGetterFn; - getCancelControlProps: PropGetterFn; - getValueProps: PropGetterFn; -}; - -export type InlineInputComponent = Intergalactic.Component<'div', InlineInputProps, InlineInputCtx> & { - Addon: Intergalactic.Component<'div', InlineInputAddonProps, InlineInputProps>; - Value: Intergalactic.Component<'input', InlineInputValueProps, InlineInputProps>; - ConfirmControl: Intergalactic.Component< - ButtonLinkComponent, - InlineInputConfirmControlProps, - InlineInputProps - >; - CancelControl: Intergalactic.Component< - ButtonLinkComponent, - InlineInputCancelControlProps, - InlineInputProps - >; - NumberValue: Intergalactic.Component<'div', {}, InlineInputProps>; - NumberControls: Intergalactic.Component<'div', NSInputNumber.Controls.Props, InlineInputProps>; -}; diff --git a/stories/components/inline-input/docs/examples/basic_usage.tsx b/stories/components/inline-input/docs/examples/basic_usage.tsx index 44576765fc..e73230113a 100644 --- a/stories/components/inline-input/docs/examples/basic_usage.tsx +++ b/stories/components/inline-input/docs/examples/basic_usage.tsx @@ -1,5 +1,5 @@ import InlineInput from '@semcore/ui/inline-input'; -import type { InlineInputProps, InlineInputValueProps } from '@semcore/ui/inline-input'; +import type { NSInlineInput } from '@semcore/ui/inline-input'; import React from 'react'; const BasicUsage = ({ @@ -8,7 +8,7 @@ const BasicUsage = ({ state, autoFocus, defaultValue = 'John Doe', -}: InlineInputProps & InlineInputValueProps): JSX.Element => { +}: NSInlineInput.Props & NSInlineInput.Value.Props): JSX.Element => { return ( { const { disabled, loading, state, autoFocus, defaultValue, placeholder, showControls, onBlurBehavior } = props; diff --git a/website/docs/components/inline-input/inline-input-api.md b/website/docs/components/inline-input/inline-input-api.md index 66c85385dd..029f2ac417 100644 --- a/website/docs/components/inline-input/inline-input-api.md +++ b/website/docs/components/inline-input/inline-input-api.md @@ -12,7 +12,7 @@ import InlineInput from '@semcore/ui/inline-input'; ; ``` - + ## InlineInput.Value @@ -23,7 +23,7 @@ import InlineInput from '@semcore/ui/inline-input'; ; ``` - + ## InlineInput.Addon @@ -47,7 +47,7 @@ import InlineInput from '@semcore/ui/inline-input'; ; ``` - + ## InlineInput.CancelControl @@ -58,6 +58,6 @@ import InlineInput from '@semcore/ui/inline-input'; ; ``` - +