Skip to content

Commit

Permalink
feat(textContent): refactor textContent (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
NasgulNexus authored Sep 1, 2023
1 parent 1e64716 commit f15ab7d
Show file tree
Hide file tree
Showing 20 changed files with 283 additions and 57 deletions.
66 changes: 40 additions & 26 deletions docs/spec.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/lib/core/components/Form/Controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const Controller = <Value extends FieldValue, SpecType extends Spec>({
__mirror,
);

if (_.isString(name) && isCorrectSpec(spec)) {
if (_.isString(name) && isCorrectSpec(spec) && !spec.viewSpec.hideInput) {
return withSearch(render(renderProps));
}

Expand Down
13 changes: 12 additions & 1 deletion src/lib/core/types/specs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {LabelProps} from '@gravity-ui/uikit';
import {ColorTextBaseProps} from '@gravity-ui/uikit/build/esm/components/Text/colorText/colorText';

import {ReadAsMethod, SpecTypes} from '../constants';

Expand Down Expand Up @@ -30,6 +31,7 @@ export interface ArraySpec<LinkType = any> {
link?: LinkType;
placeholder?: string;
addButtonPosition?: 'down' | 'right';
hideInput?: boolean;
};
}

Expand All @@ -46,6 +48,7 @@ export interface BooleanSpec<LinkType = any> {
layoutDescription?: string;
layoutOpen?: boolean;
link?: LinkType;
hideInput?: boolean;
};
}

Expand All @@ -67,6 +70,7 @@ export interface NumberSpec<LinkType = any> {
link?: LinkType;
placeholder?: string;
copy?: boolean;
hideInput?: boolean;
};
}

Expand All @@ -90,6 +94,7 @@ export interface ObjectSpec<LinkType = any> {
toggler?: 'select' | 'radio' | 'card';
};
placeholder?: string;
hideInput?: boolean;
};
}

Expand Down Expand Up @@ -123,7 +128,13 @@ export interface StringSpec<LinkType = any> {
};
hideValues?: string[];
placeholder?: string;
themeLabel?: LabelProps['theme'];
hideInput?: boolean;
textContentParams?: {
themeLabel?: LabelProps['theme'];
text: string;
icon?: string;
iconColor?: ColorTextBaseProps['color'];
};
fileInput?: {
accept?: string;
readAsMethod?: ReadAsMethod;
Expand Down
14 changes: 14 additions & 0 deletions src/lib/kit/components/Inputs/TextContent/TextContent.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,18 @@
text-align: initial;
white-space: initial;
}

&__icon {
display: flex;
align-items: center;
margin-right: 4px;
}

&__wrapper {
display: flex;
}

&__separator {
margin: 0 4px;
}
}
57 changes: 49 additions & 8 deletions src/lib/kit/components/Inputs/TextContent/TextContent.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react';

import {Label} from '@gravity-ui/uikit';
import {Label, Text} from '@gravity-ui/uikit';
import _ from 'lodash';

import {StringIndependentInputProps} from '../../../../core';
import {block} from '../../../utils';
import {LazyLoader} from '../../LazyLoader';

import {loadIcon} from './utils';

import './TextContent.scss';

Expand All @@ -12,29 +16,66 @@ const b = block('text-content');
export const TextContent: React.FC<StringIndependentInputProps> = ({
spec,
Layout,
input,
...restProps
}) => {
const {themeLabel, layoutDescription} = spec.viewSpec;
const {textContentParams, layoutDescription} = spec.viewSpec;

const text = React.useMemo(
() => (textContentParams?.text ? textContentParams?.text : layoutDescription),
[layoutDescription, textContentParams?.text],
);

if (!layoutDescription) {
if (!text) {
return null;
}

let content = <span dangerouslySetInnerHTML={{__html: layoutDescription}} />;
const iconLib = textContentParams?.icon ? (
<LazyLoader component={loadIcon(textContentParams?.icon)} />
) : null;

if (themeLabel) {
let content = <span dangerouslySetInnerHTML={{__html: text}} />;

if (textContentParams?.themeLabel) {
content = (
<Label size="m" theme={themeLabel} className={b()}>
<Label
size="m"
theme={textContentParams.themeLabel}
className={b()}
value={input.value}
icon={iconLib}
>
{content}
</Label>
);
} else {
content = (
<div className={b('wrapper')}>
{iconLib ? (
<Text color={spec.viewSpec.textContentParams?.iconColor} className={b('icon')}>
{iconLib}
</Text>
) : null}
{content}
{input.value ? (
<React.Fragment>
<span className={b('separator')}>:</span>
<Text color="secondary">{input.value}</Text>
</React.Fragment>
) : null}
</div>
);
}

if (Layout) {
const _spec = {...spec, viewSpec: {...spec.viewSpec, layoutDescription: undefined}};
const _spec = _.cloneDeep(spec);

if (!textContentParams?.text) {
_spec.viewSpec.layoutDescription = undefined;
}

return (
<Layout spec={_spec} {...restProps}>
<Layout spec={_spec} input={input} {...restProps}>
{content}
</Layout>
);
Expand Down
23 changes: 23 additions & 0 deletions src/lib/kit/components/Inputs/TextContent/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

export const loadIcon = (name: string) => {
const Icon = React.lazy(() => {
return new Promise((resolve) => {
const icon = import(`@gravity-ui/icons`).then((module) => {
if (module[name]) {
return {default: module[name]} as {
default: never;
};
}

return {
default: () => null,
} as {default: never};
});

resolve(icon);
});
});

return Icon;
};
34 changes: 34 additions & 0 deletions src/lib/kit/components/LazyLoader/LazyLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';

import _ from 'lodash';

export type LazyLoaderProps = {
component: React.LazyExoticComponent<React.ComponentType<any>>;
initialFallback?: JSX.Element;
};

export const LazyLoader = ({
component,
initialFallback = <React.Fragment></React.Fragment>,
}: LazyLoaderProps): JSX.Element => {
const fallback = React.useRef(() => initialFallback);
const Component = component;

const updateFallback = async (): Promise<void> => {
const result = await component._result;

if (!_.isUndefined(result)) {
fallback.current = (result as any).default;
}
};

React.useEffect(() => {
updateFallback();
}, [component]);

return (
<React.Suspense fallback={<fallback.current />}>
<Component />
</React.Suspense>
);
};
1 change: 1 addition & 0 deletions src/lib/kit/components/LazyLoader/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LazyLoader';
1 change: 1 addition & 0 deletions src/lib/kit/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './ErrorWrapper';
export * from './GroupIndent';
export * from './Inputs';
export * from './Layouts';
export * from './LazyLoader';
export * from './LongValue';
export * from './SimpleVerticalAccordeon';
export * from './TogglerCard';
Expand Down
12 changes: 11 additions & 1 deletion src/lib/kit/utils/__tests__/common.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,17 @@ describe('kit/utils/common', () => {
});

expect(prepareSpec({viewSpec: {themeLabel: 'WARNING'}} as any)).toMatchObject({
viewSpec: {themeLabel: 'warning'},
viewSpec: {textContentParams: {themeLabel: 'warning'}},
});

expect(prepareSpec({viewSpec: {oneOfParams: {toggler: 'SELECT'}}} as any)).toMatchObject({
viewSpec: {oneOfParams: {toggler: 'select'}},
});

expect(
prepareSpec({viewSpec: {textContentParams: {themeLabel: 'WARNING'}}} as any),
).toMatchObject({
viewSpec: {textContentParams: {themeLabel: 'warning'}},
});

expect(prepareSpec({validator: 'CUSTOM'} as any)).toMatchObject({validator: 'custom'});
Expand Down
14 changes: 13 additions & 1 deletion src/lib/kit/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,19 @@ export const prepareSpec = <Type extends Spec>(
}

if (_.isString(result.viewSpec?.themeLabel)) {
result.viewSpec.themeLabel = result.viewSpec.themeLabel.toLowerCase();
result.viewSpec.textContentParams = {
...result.viewSpec.textContentParams,
themeLabel: result.viewSpec.themeLabel.toLowerCase(),
};
}

if (_.isString(result.viewSpec?.oneOfParams?.toggler)) {
result.viewSpec.oneOfParams.toggler = result.viewSpec.oneOfParams.toggler.toLowerCase();
}

if (_.isString(result.viewSpec?.textContentParams?.themeLabel)) {
result.viewSpec.textContentParams.themeLabel =
result.viewSpec.textContentParams.themeLabel.toLowerCase();
}

if (_.isString(result.validator)) {
Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringBase.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
];

Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringFileInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.placeholder',
'viewSpec.layoutOpen',
];
Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringMonaco.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.placeholder',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
'viewSpec.copy',
];
Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringNumberWithScale.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const excludeOptions = [
'description',
'viewSpec.type',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
];

Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringPassword.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
'viewSpec.copy',
];
Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringSelect.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
];

Expand Down
2 changes: 1 addition & 1 deletion src/stories/StringTextArea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const excludeOptions = [
'viewSpec.type',
'viewSpec.sizeParams',
'viewSpec.monacoParams',
'viewSpec.themeLabel',
'viewSpec.textContentParams',
'viewSpec.fileInput',
];

Expand Down
24 changes: 21 additions & 3 deletions src/stories/StringTextContent.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ const baseSpec: StringSpec = {
type: SpecTypes.String,
viewSpec: {
type: 'text_content',
layoutDescription: 'Lorem ipsum dolor sit, amet consectetur adipisicing elit',
textContentParams: {
text: 'Lorem ipsum dolor sit, amet consectetur adipisicing elit',
icon: 'TriangleExclamation',
iconColor: 'warning',
},
},
};

Expand All @@ -40,9 +44,16 @@ const excludeOptions = [
'viewSpec.copy',
];

const value = 'value';

const template = (spec: StringSpec = baseSpec) => {
const Template: StoryFn<typeof TextContent> = (__, {viewMode}) => (
<InputPreview spec={spec} excludeOptions={excludeOptions} viewMode={viewMode} />
<InputPreview
spec={spec}
excludeOptions={excludeOptions}
viewMode={viewMode}
value={value}
/>
);

return Template;
Expand All @@ -52,5 +63,12 @@ export const Text = template();

export const Label = template({
...baseSpec,
viewSpec: {...baseSpec.viewSpec, themeLabel: 'info'},
viewSpec: {
...baseSpec.viewSpec,
textContentParams: {
text: 'Lorem ipsum dolor sit, amet consectetur adipisicing elit',
themeLabel: 'info',
icon: 'CircleInfo',
},
},
});
Loading

0 comments on commit f15ab7d

Please sign in to comment.