Skip to content
Merged
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
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