Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions semcore/core/src/core-types/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ export namespace Intergalactic {
/** @private */
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace InternalTypings {
export type RemoveIndexSignature<T> = {
[K in keyof T as string extends K
? never
: number extends K
? never
: symbol extends K
? never
: K]: T[K];
};

type StripDefaultPrefix<K> = K extends `default${infer Rest}` ? Uncapitalize<Rest> : K;

export type ValidDefaultProps<DefaultProps, MergedProps> = {
Expand Down
2 changes: 1 addition & 1 deletion semcore/feedback-form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "UI-kit team <ui-kit-team@semrush.com>",
"license": "MIT",
"scripts": {
"build": "pnpm semcore-builder --source=js,ts && pnpm vite build"
"build": "pnpm semcore-builder && pnpm vite build"
},
"exports": {
"types": "./lib/types/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box } from '@semcore/base-components';
import Button from '@semcore/button';
import type { Intergalactic } from '@semcore/core';
import { createComponent, Component, sstyled, Root } from '@semcore/core';
import { NoticeSmart } from '@semcore/notice';
import SpinContainer from '@semcore/spin-container';
Expand All @@ -9,9 +10,17 @@ import { Field, Form } from 'react-final-form';

import { FeedbackItem } from './component/feedback-item/FeedbackItem';
import { SubmitButton } from './component/submit-button/SubmitButton';
import type { NSFeedbackForm } from './FeedbackForm.type';
import style from './style/feedback-form.shadow.css';

class FeedbackForm extends Component {
class FeedbackForm extends Component<
Intergalactic.InternalTypings.InferComponentProps<NSFeedbackForm.Component>,
[],
{},
{},
{},
NSFeedbackForm.DefaultProps
> {
static displayName = 'FeedbackForm';
static style = style;
static FinalForm = {
Expand All @@ -24,14 +33,14 @@ class FeedbackForm extends Component {
};

static validate = {
description: (error) => (value = '') => {
description: (error: string) => (value = '') => {
const words = value.split(/\s+/);
const symbols = words.join(' ');
if (symbols.length < 10 || words.length < 3) {
return error;
}
},
email: (error) => (value = '') => {
email: (error: string) => (value = '') => {
if (!/.+@.+\..+/i.test(String(value).toLowerCase())) {
return error;
}
Expand Down Expand Up @@ -79,7 +88,7 @@ class FeedbackForm extends Component {
}
}

function Success(props) {
function Success(props: Intergalactic.InternalTypings.InferComponentProps<NSFeedbackForm.Success.Component>) {
const { Children, styles } = props;
const SSuccess = Root;
const SEmail = 'div';
Expand All @@ -96,24 +105,27 @@ function Success(props) {
// because it is used without a wrapper
Success.style = style;

function Cancel(props) {
function Cancel(props: Intergalactic.InternalTypings.InferComponentProps<NSFeedbackForm.Cancel.Component>) {
const { styles } = props;
const SCancel = Root;
return sstyled(styles)(<SCancel render={Button} type='reset' use='secondary' theme='muted' />);
}

function Notice(props) {
const { styles, theme = 'muted', use = 'secondary' } = props;
function Notice(props: Intergalactic.InternalTypings.InferComponentProps<NSFeedbackForm.Notice.Component>) {
const { styles, theme = 'muted' } = props;
const SNotice = Root;
return sstyled(styles)(<SNotice render={NoticeSmart} use:theme={theme} use:use={use} />);
return sstyled(styles)(<SNotice render={NoticeSmart} use:theme={theme} />);
Comment thread
ilyabrower marked this conversation as resolved.
}

/**
* FeedbackForm
*
* {@link https://developer.semrush.com/intergalactic/components/feedback-form/feedback-form-api/|API} | {@link https://developer.semrush.com/intergalactic/components/feedback-form/feedback-form-code/|Examples}
*/
export default createComponent(FeedbackForm, {
export default createComponent<
NSFeedbackForm.Component,
typeof FeedbackForm
>(FeedbackForm, {
Item: FeedbackItem,
Success,
Submit: SubmitButton,
Expand Down
63 changes: 63 additions & 0 deletions semcore/feedback-form/src/FeedbackForm.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { Box } from '@semcore/base-components';
import type Button from '@semcore/button';
import type { Intergalactic } from '@semcore/core';
import type { NoticeSmart } from '@semcore/notice';
import type { FormProps } from 'react-final-form';

import type { NSFeedbackItem } from './component/feedback-item/FeedbackItem.type';
import type { NSSubmitButton } from './component/submit-button/SubmitButton.type';

declare namespace NSFeedbackForm {
type Props = Intergalactic.InternalTypings.RemoveIndexSignature<FormProps> & {
/** The event is called when the form is submitted */
onSubmit: (values: any, form: any, callback?: (errors?: {}) => void) => {} | Promise<{}> | void;
/**
* The property is in charge of the spinner showing
* */
loading?: boolean;
/**
* Color of container spinner; you can use your own color
*/
background?: string;
/** Spinner theme. There are several default themes or you can use your own color
* @default dark
**/
theme?: 'dark' | 'invert' | string;
};
type DefaultProps = {
onSubmit: () => void;
};

namespace Item {
type Component = NSFeedbackItem.Component;
}

namespace Success {
type Component = typeof Box;
}

namespace Submit {
type Component = NSSubmitButton.Component;
}

namespace Cancel {
type Component = typeof Button;
}

namespace Notice {
type Component = typeof NoticeSmart;
}

type Component = Intergalactic.Component<'form', Props> & {
Item: Item.Component;
Success: Success.Component;
Submit: Submit.Component;
Cancel: Cancel.Component;
Notice: Notice.Component;
};
}

/** @deprecated It will be removed in v18. */
export type FeedbackFormProps = NSFeedbackForm.Props;

export type { NSFeedbackForm };
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Box, Flex } from '@semcore/base-components';
import type Button from '@semcore/button';
import type Checkbox from '@semcore/checkbox';
import { createComponent, Component, sstyled, Root } from '@semcore/core';
import type { Intergalactic } from '@semcore/core';
import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance';
import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance';
import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID';
import CheckM from '@semcore/icon/Check/m';
Expand All @@ -20,38 +19,28 @@ import createFocusDecorator from 'final-form-focus';
import React, { type ReactElement } from 'react';
import { Field, Form } from 'react-final-form';

import type {
FeedbackRatingCheckboxProps,
FeedbackRatingItemProps,
FeedbackRatingProps,
FormConfigItem,
FeedbackRatingDefaultProps,
} from './FeedbackRating.type';
import style from '../../style/feedback-rating.shadow.css';
import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales';
import CheckboxButton from '../checkbox-button/CheckboxButton';
import { FeedbackItem } from '../feedback-item/FeedbackItem';
import SliderRating from '../slider-rating/SliderRating';
import { SubmitButton } from '../submit-button/SubmitButton';

type State = {
error: boolean;
};
import CheckboxButton from './component/checkbox-button/CheckboxButton';
import { FeedbackItem } from './component/feedback-item/FeedbackItem';
import SliderRating from './component/slider-rating/SliderRating';
import { SubmitButton } from './component/submit-button/SubmitButton';
import type { NSFeedbackRating } from './FeedbackRating.type';
import style from './style/feedback-rating.shadow.css';
import { localizedMessages } from './translations/__intergalactic-dynamic-locales';

class FeedbackRatingRoot extends Component<
FeedbackRatingProps,
Intergalactic.InternalTypings.InferComponentProps<NSFeedbackRating.Component>,
typeof FeedbackRatingRoot.enhance,
{},
{},
State,
FeedbackRatingDefaultProps
WithI18nEnhanceProps,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about this...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's need to correctly type i18n prop to have it aligned with DefaultProps

NSFeedbackRating.State,
NSFeedbackRating.DefaultProps
> {
static displayName = 'FeedbackRatingForm';
static style = style;

static enhance = [i18nEnhance(localizedMessages), uniqueIDEnhancement()] as const;

static defaultProps: FeedbackRatingDefaultProps = {
static defaultProps: NSFeedbackRating.DefaultProps = {
onSubmit: () => {},
i18n: localizedMessages,
locale: 'en',
Expand All @@ -74,7 +63,7 @@ class FeedbackRatingRoot extends Component<
},
};

state: State = {
state: NSFeedbackRating.State = {
error: false,
};

Expand Down Expand Up @@ -122,7 +111,7 @@ class FeedbackRatingRoot extends Component<
fn(e);
};

componentDidUpdate(prevProps: Readonly<FeedbackRatingProps>) {
componentDidUpdate(prevProps: typeof this.asProps) {
const { status, getI18nText } = this.asProps;

if (prevProps.status !== status) {
Expand All @@ -144,7 +133,7 @@ class FeedbackRatingRoot extends Component<
}
}

renderCheckbox = (config: FormConfigItem, index: number) => {
renderCheckbox = (config: NSFeedbackRating.FormConfigItem, index: number) => {
const initialValue = this.props.initialValues[config.key];

return (
Expand All @@ -154,15 +143,15 @@ class FeedbackRatingRoot extends Component<
{...input}
id={config.key}
label={config.label}
onChange={(_checked, e) => input.onChange(e)}
onChange={(_: boolean, e?: React.SyntheticEvent<HTMLInputElement>) => input.onChange(e)}
focused={index === 0}
/>
)}
</Field>
);
};

renderTextField = (config: FormConfigItem) => {
renderTextField = (config: NSFeedbackRating.FormConfigItem) => {
const initialValue = this.props.initialValues[config.key];

const label =
Expand Down Expand Up @@ -369,8 +358,6 @@ class FeedbackRatingRoot extends Component<
</SemcoreNotice.Label>
<SemcoreNotice.Content>
{getI18nText('errorMessage', {
// todo: Brauer Ilia - think how to fix type
// @ts-ignore
email: (
<Link href={`mailto:${errorFeedbackEmail}`}>
{errorFeedbackEmail}
Expand Down Expand Up @@ -401,29 +388,23 @@ class FeedbackRatingRoot extends Component<
}
}

function Header(props: any) {
function Header(
props: Intergalactic.InternalTypings.InferChildComponentProps<NSFeedbackRating.Header.Component, typeof FeedbackRatingRoot, 'Header'>,
) {
const { styles } = props;
const SHeader = Root;
return sstyled(styles)(
<SHeader render={Modal.Title} />,
);
}

type FeedbackRatingComponent = Intergalactic.Component<'form', FeedbackRatingProps, {}, typeof FeedbackRatingRoot.enhance> & {
validate: typeof FeedbackRatingRoot.validate;
Item: Intergalactic.Component<'div', FeedbackRatingItemProps>;
Submit: typeof Button;
Checkbox: Intergalactic.Component<typeof Checkbox, FeedbackRatingCheckboxProps>;
Header: typeof Text;
};

/**
* FeedbackRating
*
* {@link https://developer.semrush.com/intergalactic/components/feedback-form/feedback-form-api#feedbackform-feedbackrating|API} | {@link https://developer.semrush.com/intergalactic/components/feedback-form/feedback-form-code/|Examples}
*/
const FeedbackRating = createComponent<
FeedbackRatingComponent,
NSFeedbackRating.Component,
typeof FeedbackRatingRoot
>(FeedbackRatingRoot, {
Header,
Expand Down
Loading
Loading