;
}
@@ -12,7 +12,7 @@ function isIconSvg(icon: ImageProps | SVGIcon): icon is SVGIcon {
return typeof icon === 'function';
}
-const ContentListItemIcon = ({icon, className, qa, gravityIcon}: ListItemProps) => {
+const ContentIcon = ({icon, className, qa, gravityIcon}: ContentIconProps) => {
const theme = useTheme();
const iconThemed = getThemedValue(icon, theme);
const gravityIconThemed = getThemedValue(gravityIcon, theme);
@@ -29,4 +29,4 @@ const ContentListItemIcon = ({icon, className, qa, gravityIcon}: ListItemProps)
return ;
};
-export default ContentListItemIcon;
+export default ContentIcon;
diff --git a/src/components/ContentLabels/ContentLabels.scss b/src/components/ContentLabels/ContentLabels.scss
new file mode 100644
index 000000000..a1201c353
--- /dev/null
+++ b/src/components/ContentLabels/ContentLabels.scss
@@ -0,0 +1,72 @@
+@import '../../../styles/variables.scss';
+@import '../../../styles/mixins.scss';
+
+$block: '.#{$ns}content-labels';
+
+#{$block} {
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+
+ &__label {
+ display: flex;
+ align-items: center;
+ flex-wrap: nowrap;
+ flex-shrink: 0;
+ padding: 5px 11px;
+ background-color: var(--g-color-base-generic);
+ border-radius: 6px;
+
+ &,
+ &-text {
+ color: var(--g-color-text-primary);
+ }
+
+ & > .pc-icon,
+ & > picture {
+ display: flex;
+ }
+
+ &-icon {
+ width: 16px;
+ height: 16px;
+ margin-inline-end: 6px;
+ }
+
+ $label: &;
+ &_theme {
+ &_light {
+ background-color: var(--g-color-private-black-50);
+
+ &,
+ #{$label}-text {
+ color: var(--g-color-text-dark-primary);
+ }
+ }
+
+ &_dark {
+ background-color: var(--g-color-private-white-100);
+
+ &,
+ #{$label}-text {
+ color: var(--g-color-text-light-primary);
+ }
+ }
+ }
+ }
+
+ &_size {
+ &_l,
+ &_m {
+ #{$block}__label {
+ @include text-body-3();
+ }
+ }
+
+ &_s {
+ #{$block}__label {
+ @include text-body-2();
+ }
+ }
+ }
+}
diff --git a/src/components/ContentLabels/ContentLabels.tsx b/src/components/ContentLabels/ContentLabels.tsx
new file mode 100644
index 000000000..9dee547b8
--- /dev/null
+++ b/src/components/ContentLabels/ContentLabels.tsx
@@ -0,0 +1,41 @@
+import {ClassNameProps, ContentLabelsProps, QAProps} from '../../models';
+import {block, getQaAttrubutes} from '../../utils';
+import ContentIcon from '../ContentIcon/ContentIcon';
+
+import './ContentLabels.scss';
+
+const b = block('content-labels');
+
+const ContentLabels = ({
+ className,
+ labels,
+ theme,
+ size = 'l',
+ qa,
+}: ContentLabelsProps & ClassNameProps & QAProps) => {
+ const qaAttributes = getQaAttrubutes(qa, ['icon', 'text']);
+
+ return (
+
+ {labels.map((label) => {
+ const {text, icon, gravityIcon} = label;
+
+ return (
+
+
+
+ {text}
+
+
+ );
+ })}
+
+ );
+};
+
+export default ContentLabels;
diff --git a/src/components/ContentList/ContentList.tsx b/src/components/ContentList/ContentList.tsx
index 152bd88c5..a43c38cd9 100644
--- a/src/components/ContentList/ContentList.tsx
+++ b/src/components/ContentList/ContentList.tsx
@@ -6,10 +6,9 @@ import {ContentListProps, ContentSize} from '../../models';
import {QAProps} from '../../models/common';
import {block} from '../../utils';
import {getQaAttrubutes} from '../../utils/blocks';
+import ContentIcon from '../ContentIcon/ContentIcon';
import YFMWrapper from '../YFMWrapper/YFMWrapper';
-import ItemIcon from './ContentListItemIcon';
-
import './ContentList.scss';
const b = block('content-list');
@@ -33,7 +32,7 @@ const ContentList = ({list, size = 'l', qa, theme}: ContentListProps & QAProps)
const {icon, title, text, gravityIcon} = item;
return (
- (DEFAULT_WIDTH);
export const WindowWidthProvider = ({children}: React.PropsWithChildren) => {
- const {isServer} = React.useContext(SSRContext);
-
const [windowWidth, setWindowWidth] = React.useState(DEFAULT_WIDTH);
React.useEffect(() => {
- if (isServer) {
- return;
- }
-
const handleResize = throttle(
() => {
setWindowWidth(window.innerWidth);
@@ -34,7 +27,7 @@ export const WindowWidthProvider = ({children}: React.PropsWithChildren) => {
// eslint-disable-next-line consistent-return
return () => window.removeEventListener('resize', handleResize);
- }, [isServer]);
+ }, []);
return (
{children}
diff --git a/src/context/windowWidthContext/index.ts b/src/context/windowWidthContext/index.ts
index 236848bc4..5078fa65f 100644
--- a/src/context/windowWidthContext/index.ts
+++ b/src/context/windowWidthContext/index.ts
@@ -1 +1 @@
-export * from './BreakpointContext';
+export * from './WindowWidthContext';
diff --git a/src/hooks/useDeviceValue.ts b/src/hooks/useDeviceValue.ts
new file mode 100644
index 000000000..b5b93ad54
--- /dev/null
+++ b/src/hooks/useDeviceValue.ts
@@ -0,0 +1,36 @@
+import * as React from 'react';
+
+import {BREAKPOINTS} from '../constants';
+import {useWindowWidth} from '../context/windowWidthContext';
+import {Device} from '../models';
+import {DeviceSupporting, isDeviceValue} from '../utils';
+
+const getDeviceBreakpoints = (inclusive?: boolean): [tablet: number, mobile: number] => {
+ const shift = inclusive ? 0 : -1;
+
+ return [BREAKPOINTS.md + shift, BREAKPOINTS.sm + shift];
+};
+
+export function useDeviceValue(value: DeviceSupporting, inclusive?: boolean): T {
+ const windowWidth = useWindowWidth();
+
+ const [tablet, mobile] = React.useMemo(() => getDeviceBreakpoints(inclusive), [inclusive]);
+
+ const isMobile = windowWidth <= mobile;
+ const isTablet = windowWidth <= tablet;
+
+ return React.useMemo(() => {
+ if (!isDeviceValue(value)) {
+ return value;
+ }
+
+ switch (true) {
+ case isMobile:
+ return value[Device.Mobile];
+ case isTablet:
+ return value[Device.Tablet] ?? value[Device.Mobile];
+ default:
+ return value[Device.Desktop];
+ }
+ }, [isMobile, isTablet, value]);
+}
diff --git a/src/models/constructor-items/blocks.ts b/src/models/constructor-items/blocks.ts
index 8c7f24469..be075d38d 100644
--- a/src/models/constructor-items/blocks.ts
+++ b/src/models/constructor-items/blocks.ts
@@ -4,6 +4,7 @@ import {ButtonSize} from '@gravity-ui/uikit';
import {GridColumnSize, GridColumnSizesType, IndentValue} from '../../grid/types';
import {ThemeSupporting} from '../../utils';
+import {DeviceSupporting} from '../../utils/breakpoint';
import {AnalyticsEventsBase} from '../common';
import {
@@ -201,7 +202,10 @@ export interface HeaderBlockProps {
}
export interface ExtendedFeaturesItem
- extends Omit {
+ extends Omit<
+ ContentBlockProps,
+ 'theme' | 'centered' | 'colSizes' | 'size' | 'title' | 'labels'
+ > {
title: string;
label?: string;
icon?: ThemedImage;
@@ -238,7 +242,7 @@ export interface QuestionItem {
}
export interface QuestionsProps
- extends Omit {
+ extends Omit {
items: QuestionItem[];
}
@@ -255,7 +259,7 @@ export interface FoldableListItem {
}
export interface FoldableListProps
- extends Omit {
+ extends Omit {
items: FoldableListItem[];
}
@@ -281,7 +285,7 @@ export interface MediaBaseBlockProps extends Animatable, MediaContentProps {
}
export interface MediaContentProps
- extends Omit {
+ extends Omit {
description?: string;
/** @deprecated Use array of buttons from ContentBlockProps instead**/
button?: ButtonProps;
@@ -306,8 +310,8 @@ export interface InfoBlockProps {
sectionsTitle?: string;
/** @deprecated **/
links?: Pick[];
- leftContent?: Omit;
- rightContent?: Omit;
+ leftContent?: Omit;
+ rightContent?: Omit;
}
export interface TableProps {
@@ -328,7 +332,7 @@ export interface TableBlockProps {
}
export interface TabsBlockItem
- extends Omit,
+ extends Omit,
WithBorder {
tabName: string;
/**
@@ -406,7 +410,7 @@ interface ContentLayoutBlockParams {
}
export interface ContentLayoutBlockProps extends ContentLayoutBlockParams {
- textContent: ContentBlockProps;
+ textContent: Omit;
fileContent?: FileLinkProps[];
}
@@ -425,6 +429,18 @@ export interface ContentListProps {
theme?: ContentTheme;
}
+export interface ContentLabelProps {
+ text: string;
+ icon?: ThemeSupporting;
+ gravityIcon?: ThemeSupporting;
+}
+
+export interface ContentLabelsProps {
+ labels: ContentLabelProps[];
+ size?: ContentSize;
+ theme?: ContentTheme;
+}
+
export interface ContentBlockProps {
title?: TitleItemBaseProps | string;
titleId?: string;
@@ -438,6 +454,7 @@ export interface ContentBlockProps {
centered?: boolean;
theme?: ContentTheme;
list?: ContentItemProps[];
+ labels?: ContentLabelProps[];
controlPosition?: 'default' | 'bottom';
}
@@ -475,12 +492,17 @@ export interface FormBlockHubspotData {
export type FormBlockData = FormBlockYandexData | FormBlockHubspotData;
+export interface FormBlockBackgroundProps extends Omit {
+ style?: DeviceSupporting;
+}
+
export interface FormBlockProps {
formData: FormBlockData;
title?: string;
textContent?: Omit;
direction?: FormBlockDirection;
- background?: ThemeSupporting;
+ background?: ThemeSupporting;
+ customFormNode?: React.ReactNode;
}
//block models
diff --git a/src/models/constructor-items/sub-blocks.ts b/src/models/constructor-items/sub-blocks.ts
index cd2ff5fe2..fbb3b8997 100644
--- a/src/models/constructor-items/sub-blocks.ts
+++ b/src/models/constructor-items/sub-blocks.ts
@@ -147,7 +147,7 @@ export interface BackgroundCardProps
extends CardBaseProps,
AnalyticsEventsBase,
CardLayoutProps,
- Omit {
+ Omit {
url?: string;
urlTitle?: string;
background?: ThemeSupporting;
@@ -159,7 +159,7 @@ export interface BasicCardProps
extends CardBaseProps,
AnalyticsEventsBase,
CardLayoutProps,
- Omit {
+ Omit {
url: string;
urlTitle?: string;
icon?: ThemeSupporting;
@@ -182,7 +182,7 @@ export interface BannerCardProps {
export interface MediaCardProps extends MediaProps, AnalyticsEventsBase, CardBaseProps {}
-export interface PriceCardProps extends CardBaseProps, Pick {
+export interface PriceCardProps extends CardBaseProps, Pick {
title: string;
price: string;
pricePeriod?: string;
@@ -195,7 +195,7 @@ export interface PriceCardProps extends CardBaseProps, Pick;
+ content: Omit;
contentMargin?: LayoutItemContentMargin;
media?: ThemeSupporting;
metaInfo?: string[];
@@ -207,7 +207,7 @@ export interface LayoutItemProps extends ClassNameProps, CardLayoutProps, Analyt
export interface ImageCardProps
extends CardBaseProps,
CardLayoutProps,
- Omit {
+ Omit {
image: ThemeSupporting;
enableImageBorderRadius?: boolean;
margins?: ImageCardMargins;
diff --git a/src/schema/validators/common.ts b/src/schema/validators/common.ts
index 766aebd57..7f8a4de4d 100644
--- a/src/schema/validators/common.ts
+++ b/src/schema/validators/common.ts
@@ -2,6 +2,7 @@ import {ImageProps} from '../../components/Image/schema';
import {
CustomControlsButtonPositioning,
CustomControlsType,
+ Device,
MediaVideoControlsType,
QuoteType,
Theme,
@@ -482,6 +483,30 @@ export function withTheme(value: T) {
};
}
+export function withDevice(value: T) {
+ return {
+ oneOf: [
+ {
+ ...value,
+ optionName: 'no device',
+ },
+ {
+ type: 'object',
+ additionalProperties: false,
+ required: [Device.Desktop, Device.Mobile],
+ properties: Object.values(Device).reduce(
+ (result, deviceName) => ({
+ ...result,
+ [deviceName]: value,
+ }),
+ {},
+ ),
+ optionName: 'devices',
+ },
+ ],
+ };
+}
+
export const AnchorProps = {
type: 'object',
additionalProperties: false,
diff --git a/src/sub-blocks/Content/Content.scss b/src/sub-blocks/Content/Content.scss
index d6feeaac3..f8b6c9d35 100644
--- a/src/sub-blocks/Content/Content.scss
+++ b/src/sub-blocks/Content/Content.scss
@@ -54,6 +54,11 @@ $darkSecondary: var(--g-color-text-dark-secondary);
text-align: center;
}
+ #{$block}__labels {
+ justify-content: center;
+ margin-inline: auto;
+ }
+
#{$block}__list {
margin-inline: auto;
}
@@ -93,11 +98,21 @@ $darkSecondary: var(--g-color-text-dark-secondary);
}
}
+ #{$block}__labels,
#{$block}__list,
#{$block}__links,
#{$block}__notice {
margin-top: $indentXS;
}
+
+ #{$block}__labels {
+ & + #{$block}__list,
+ & + #{$block}__link,
+ & + #{$block}__notice {
+ margin-top: $indentS;
+ }
+ }
+
#{$block}__buttons {
margin-top: $indentS;
}
@@ -131,11 +146,21 @@ $darkSecondary: var(--g-color-text-dark-secondary);
@include text-size(body-2);
}
+ #{$block}__labels,
#{$block}__list,
#{$block}__links,
#{$block}__notice {
margin-top: $indentS;
}
+
+ #{$block}__labels {
+ & + #{$block}__list,
+ & + #{$block}__link,
+ & + #{$block}__notice {
+ margin-top: $indentSM;
+ }
+ }
+
#{$block}__buttons {
margin-top: $indentSM;
}
@@ -166,11 +191,21 @@ $darkSecondary: var(--g-color-text-dark-secondary);
@include text-size(body-2);
}
+ #{$block}__labels,
#{$block}__list,
#{$block}__links,
#{$block}__notice {
margin-top: $indentS;
}
+
+ #{$block}__labels {
+ & + #{$block}__list,
+ & + #{$block}__link,
+ & + #{$block}__notice {
+ margin-top: $indentSM;
+ }
+ }
+
#{$block}__buttons {
margin-top: $indentSM;
}
diff --git a/src/sub-blocks/Content/Content.tsx b/src/sub-blocks/Content/Content.tsx
index e19f31a94..430a50c09 100644
--- a/src/sub-blocks/Content/Content.tsx
+++ b/src/sub-blocks/Content/Content.tsx
@@ -1,6 +1,7 @@
import {useUniqId} from '@gravity-ui/uikit';
import {Buttons, ContentList, Links, Title, YFMWrapper} from '../../components';
+import ContentLabels from '../../components/ContentLabels/ContentLabels';
import {Col} from '../../grid';
import {
ClassNameProps,
@@ -46,10 +47,18 @@ const Content = (props: ContentProps) => {
theme,
className,
list,
+ labels,
qa,
controlPosition,
} = props;
- const qaAttributes = getQaAttrubutes(qa, ['links', 'link', 'buttons', 'button', 'list']);
+ const qaAttributes = getQaAttrubutes(qa, [
+ 'links',
+ 'link',
+ 'buttons',
+ 'button',
+ 'list',
+ 'labels',
+ ]);
const titleProps =
!title || typeof title === 'string'
@@ -85,6 +94,16 @@ const Content = (props: ContentProps) => {
/>
)}
+ {labels?.length ? (
+
+
+
+ ) : null}
{list?.length ? (
diff --git a/src/sub-blocks/Content/README.md b/src/sub-blocks/Content/README.md
index 2085e1d5e..f8e04b30b 100644
--- a/src/sub-blocks/Content/README.md
+++ b/src/sub-blocks/Content/README.md
@@ -12,7 +12,7 @@
`theme?: 'default' | 'dark' | 'light'` — Component's theme: default, dark, or monochrome light ('default' by default).
-- `size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)
+`size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)
`сolSizes?: Object` — Width of buttons tabs, the value ranges from 1 to 12 columns. If 12 columns, buttons takes up the entire width of the row.
@@ -21,3 +21,7 @@
- `md: number` — On a screen wider than 769px.
- `lg: number` — On a screen wider than 1081px.
- `xl: number` — On a screen wider than 1185px.
+
+`list?: Array` - An Array of items with icon - [ContentList](?path=/docs/components-contentlist--docs)
+
+`labels?: Array` - An Array of labels with icons `{text: string; icon?: ImageProps; gravityIcon?: GravityIconProps}`
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-chromium-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-chromium-linux.png
index 59fba3d8c..0b5ec822a 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-chromium-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-chromium-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-webkit-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-webkit-linux.png
index 155be8026..37eb89c57 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-webkit-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Centered-light-webkit-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-chromium-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-chromium-linux.png
index a09236157..556d3aeee 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-chromium-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-chromium-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-webkit-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-webkit-linux.png
index 7a928b3a6..302a998e6 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-webkit-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-ContentVariables-light-webkit-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-chromium-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-chromium-linux.png
index ed73cf245..31a7ec71d 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-chromium-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-chromium-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-webkit-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-webkit-linux.png
index 9cd0b6266..b7259f6f3 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-webkit-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Default-light-webkit-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-chromium-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-chromium-linux.png
index d27d06648..dde4c635f 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-chromium-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-chromium-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-webkit-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-webkit-linux.png
index ca1fa7001..8b03e8b1a 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-webkit-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Size-light-webkit-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-chromium-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-chromium-linux.png
index 01a866a12..1bcc08e70 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-chromium-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-chromium-linux.png differ
diff --git a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-webkit-linux.png b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-webkit-linux.png
index 97b02d813..9916e2322 100644
Binary files a/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-webkit-linux.png and b/src/sub-blocks/Content/__snapshots__/Content.visual.test.tsx-snapshots/Content-render-stories-Theme-light-webkit-linux.png differ
diff --git a/src/sub-blocks/Content/__stories__/Content.mdx b/src/sub-blocks/Content/__stories__/Content.mdx
index 1dc229846..fdf583595 100644
--- a/src/sub-blocks/Content/__stories__/Content.mdx
+++ b/src/sub-blocks/Content/__stories__/Content.mdx
@@ -26,7 +26,7 @@ For a detailed usage guide of the Content sub-block, see [Content Usage](https:/
`theme?: 'default' | 'dark' | 'light'` — Component's theme: default, dark, or monochrome light ('default' by default).
-- `size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)
+`size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)
`сolSizes?: Object` — Width of buttons tabs, the value ranges from 1 to 12 columns. If 12 columns, buttons takes up the entire width of the row.
@@ -36,5 +36,8 @@ For a detailed usage guide of the Content sub-block, see [Content Usage](https:/
- `lg: number` — On a screen wider than 1081px.
- `xl: number` — On a screen wider than 1185px.
-`list: Array` - An Array of items with icon - [ContentList](?path=/docs/components-contentlist--docs)
+`list?: Array` - An Array of items with icon - [ContentList](?path=/docs/components-contentlist--docs)
+
+`labels?: Array` - An Array of labels with icons `{text: string; icon?: ImageProps; gravityIcon?: GravityIconProps}`
+
diff --git a/src/sub-blocks/Content/__stories__/Content.stories.tsx b/src/sub-blocks/Content/__stories__/Content.stories.tsx
index 4eb9eae55..5db25d6fd 100644
--- a/src/sub-blocks/Content/__stories__/Content.stories.tsx
+++ b/src/sub-blocks/Content/__stories__/Content.stories.tsx
@@ -57,6 +57,7 @@ ContentVariables.args = [
{additionalInfo: data.default.additionalInfo},
{links: data.default.links},
{buttons: data.default.buttons},
+ {labels: data.default.labels},
{links: data.default.links, list: data.default.list},
].map((content) => ({
...content,
@@ -76,8 +77,10 @@ Size.args = data.size.map((content) => ({
text: data.default.text,
buttons: data.default.buttons,
list: data.default.list,
+ labels: data.default.labels,
type: data.default.type,
})) as ContentBlockProps[];
+
Size.parameters = {
controls: {
include: Object.keys(Size.args),
@@ -88,6 +91,7 @@ Centered.args = [
{additionalInfo: data.default.additionalInfo},
{links: data.default.links},
{buttons: data.default.buttons},
+ {labels: data.default.labels},
].map((content) => ({
...content,
...data.centered,
@@ -105,6 +109,7 @@ Theme.args = data.theme.map((content) => ({
...content,
text: data.default.text,
additionalInfo: data.default.additionalInfo,
+ labels: data.default.labels,
})) as ContentBlockProps[];
Theme.parameters = {
controls: {
diff --git a/src/sub-blocks/Content/__stories__/data.json b/src/sub-blocks/Content/__stories__/data.json
index 1c150a430..0e14287be 100644
--- a/src/sub-blocks/Content/__stories__/data.json
+++ b/src/sub-blocks/Content/__stories__/data.json
@@ -52,6 +52,19 @@
"title": "Lorem ipsum",
"text": "**Ut enim ad minim veniam** [quis nostrud](https://example.com) exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
}
+ ],
+ "labels": [
+ {
+ "text": "Label 1"
+ },
+ {
+ "text": "Label 2",
+ "icon": "/story-assets/icon_3_light.svg"
+ },
+ {
+ "text": "Label 3",
+ "gravityIcon": {"name": "Gear"}
+ }
]
},
"theme": [
diff --git a/src/sub-blocks/Content/__tests__/Content.test.tsx b/src/sub-blocks/Content/__tests__/Content.test.tsx
index fd7a1ebfc..69588ed15 100644
--- a/src/sub-blocks/Content/__tests__/Content.test.tsx
+++ b/src/sub-blocks/Content/__tests__/Content.test.tsx
@@ -5,6 +5,7 @@ import {
testContentWithButtons,
testContentWithCentered,
testContentWithColSize,
+ testContentWithLabels,
testContentWithLinks,
testContentWithList,
testContentWithSize,
@@ -31,6 +32,12 @@ const contentData: ContentProps = {
text: 'list text',
},
],
+ labels: [
+ {
+ icon: '/mock.png',
+ text: 'label text',
+ },
+ ],
qa: 'content',
};
@@ -39,7 +46,7 @@ const colSizesArray: GridColumnSizesType[] = [
{all: 5, lg: 4, md: 3, sm: 2},
];
-const qaAttributes = getQaAttrubutes(contentData.qa, ['link', 'list']);
+const qaAttributes = getQaAttrubutes(contentData.qa, ['link', 'list', 'labels']);
describe('Content', () => {
test('Render by default', async () => {
@@ -130,4 +137,11 @@ describe('Content', () => {
options: {qaId: qaAttributes.list},
});
});
+
+ test('Render with labels', async () => {
+ testContentWithLabels({
+ props: contentData,
+ options: {qaId: qaAttributes.labels},
+ });
+ });
});
diff --git a/src/sub-blocks/Content/schema.ts b/src/sub-blocks/Content/schema.ts
index 2d5a99092..ea3bd247c 100644
--- a/src/sub-blocks/Content/schema.ts
+++ b/src/sub-blocks/Content/schema.ts
@@ -14,7 +14,14 @@ import {filteredArray} from '../../schema/validators/utils';
export const ContentItem = {
additionalProperties: false,
- required: ['icon'],
+ oneOf: [
+ {
+ required: ['icon'],
+ },
+ {
+ required: ['gravityIcon'],
+ },
+ ],
properties: {
title: {
type: 'string',
@@ -29,6 +36,19 @@ export const ContentItem = {
},
};
+export const ContentLabel = {
+ additionalProperties: false,
+ required: ['text'],
+ properties: {
+ text: {
+ type: 'string',
+ contentType: 'text',
+ },
+ icon: withTheme(ImageProps),
+ gravityIcon: withTheme(GravityIconProps),
+ },
+};
+
export const ContentBase = {
title: {
oneOf: [
@@ -63,6 +83,7 @@ export const ContentBase = {
enum: contentThemes,
},
list: filteredArray(ContentItem),
+ labels: filteredArray(ContentLabel),
controlPosition: {
type: 'string',
enum: ['default', 'bottom'],
diff --git a/src/utils/breakpoint.ts b/src/utils/breakpoint.ts
new file mode 100644
index 000000000..fd13e0e18
--- /dev/null
+++ b/src/utils/breakpoint.ts
@@ -0,0 +1,18 @@
+import {Device} from '../models';
+
+export interface ValueWithDevice extends Partial> {
+ [Device.Desktop]: T;
+ [Device.Mobile]: T;
+}
+
+export type DeviceSupporting = T | ValueWithDevice;
+
+export function isDeviceValue(value: DeviceSupporting): value is ValueWithDevice {
+ return (
+ typeof value === 'object' &&
+ value !== null &&
+ !Array.isArray(value) &&
+ Device.Desktop in value &&
+ Device.Mobile in value
+ );
+}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 372c39071..13dca7be8 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,5 +1,6 @@
export * from './common';
export * from './analytics';
+export * from './breakpoint';
export * from './blocks';
export * from './url';
export * from './cn';
diff --git a/test-utils/shared/content.tsx b/test-utils/shared/content.tsx
index a890974dd..994106f0d 100644
--- a/test-utils/shared/content.tsx
+++ b/test-utils/shared/content.tsx
@@ -130,3 +130,17 @@ export const testContentWithList = ({props, options}: ContentTestFunction) => {
expect(title).toHaveTextContent(props.list?.[0]?.title);
expect(text).toHaveTextContent(props.list?.[0]?.text);
};
+
+export const testContentWithLabels = ({props, options}: ContentTestFunction) => {
+ if (!options?.qaId || !props.labels?.[0]?.icon || !props.labels?.[0]?.text) {
+ throw new Error(ERROR_INPUT_DATA_MESSAGE);
+ }
+
+ const labelsQa = getQaAttrubutes(options.qaId, ['text']);
+
+ render();
+ const image = screen.getByRole('img');
+ const text = screen.getByTestId(labelsQa.text);
+ expect(image).toHaveAttribute('src', props.labels?.[0]?.icon);
+ expect(text).toHaveTextContent(props.labels?.[0]?.text);
+};