Skip to content

Commit

Permalink
feat(OneOfTogglerCard): added new display toggler card (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
NasgulNexus authored Aug 31, 2023
1 parent ff23507 commit caa76bc
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 16 deletions.
6 changes: 3 additions & 3 deletions docs/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec;

#### OneOfParams

| Property | Type | Required | Description |
| :------- | :------------------- | :------: | :---------- |
| toggler | `'select'` `'radio'` | | Switch type |
| Property | Type | Required | Description |
| :------- | :---------------------------- | :------: | :---------- |
| toggler | `'select'` `'radio'` `'card'` | | Switch type |

#### FileInput

Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/types/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export interface ObjectSpec<LinkType = any> {
order?: string[];
link?: LinkType;
oneOfParams?: {
toggler?: 'select' | 'radio';
toggler?: 'select' | 'radio' | 'card';
};
placeholder?: string;
};
Expand Down
22 changes: 22 additions & 0 deletions src/lib/kit/components/TogglerCard/TogglerCard.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import '../../styles/variables.scss';

.#{$ns}toggler-card {
width: 254px;
padding: 10px;
height: 88px;

&__header {
display: flex;
justify-content: space-between;
align-items: baseline;
}

&__text {
margin-top: 12px;
display: block;
margin-right: 15px;
height: 36px;
overflow: hidden;
text-overflow: ellipsis;
}
}
51 changes: 51 additions & 0 deletions src/lib/kit/components/TogglerCard/TogglerCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';

import {HelpPopover} from '@gravity-ui/components';
import {Card, Text} from '@gravity-ui/uikit';

import {block} from '../../utils';

import './TogglerCard.scss';

const b = block('toggler-card');

interface TogglerCardProps {
description?: string;
title: string;
text: string;
onClick: () => void;
disabled?: boolean;
selected: boolean;
}

export const TogglerCard: React.FC<TogglerCardProps> = ({
description,
title,
text,
onClick,
disabled,
selected,
}) => {
return (
<Card
onClick={onClick}
type="selection"
disabled={disabled ? !selected : disabled}
selected={selected}
size="m"
className={b()}
>
<div className={b('header')}>
<Text variant="subheader-2" ellipsis>
{title}
</Text>
{description ? (
<HelpPopover htmlContent={description} placement={['bottom', 'top']} />
) : null}
</div>
<Text variant="body-1" color="secondary" className={b('text')}>
{text}
</Text>
</Card>
);
};
1 change: 1 addition & 0 deletions src/lib/kit/components/TogglerCard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './TogglerCard';
1 change: 1 addition & 0 deletions src/lib/kit/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export * from './Inputs';
export * from './Layouts';
export * from './LongValue';
export * from './SimpleVerticalAccordeon';
export * from './TogglerCard';
export * from './Views';
export * from './ViewLayouts';
17 changes: 17 additions & 0 deletions src/lib/kit/hooks/useOneOf/useOneOf.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,22 @@
max-width: unset;
}
}

&_card {
& + .#{$ns}group-indent {
& > .#{$ns}use-search:not(.#{$ns}group-indent) {
padding-top: 0px;
margin-top: 15px;
}
}
}
}

&__card {
display: flex;

& > :first-child {
margin-right: 8px;
}
}
}
60 changes: 51 additions & 9 deletions src/lib/kit/hooks/useOneOf/useOneOf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {RadioButton, Select} from '@gravity-ui/uikit';
import _ from 'lodash';

import {ObjectIndependentInputProps} from '../../../core';
import {TogglerCard} from '../../components';
import {block} from '../../utils';

import './useOneOf.scss';
Expand Down Expand Up @@ -68,17 +69,49 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => {
[spec.description, spec.viewSpec.order, specProperties],
);

const selectToggler = React.useMemo(
() =>
const togglerType = React.useMemo(() => {
if (spec.viewSpec.oneOfParams?.toggler === 'card' && options.length < 3) {
return 'card';
}

if (
spec.viewSpec.oneOfParams?.toggler !== 'radio' &&
(spec.viewSpec.oneOfParams?.toggler === 'select' ||
options.length > 3 ||
_.some(options, ({title}) => title.length > MAX_TAB_TITLE_LENGTH)),
[options, spec.viewSpec.oneOfParams?.toggler],
);
_.some(options, ({title}) => title.length > MAX_TAB_TITLE_LENGTH))
) {
return 'select';
}

return 'radio';
}, [options, spec.viewSpec.oneOfParams?.toggler]);

const togglerInput = React.useMemo(() => {
if (selectToggler) {
if (togglerType === 'card') {
return (
<div className={b('card')}>
{options.map(({value}) => {
const onClick = () => {
onOneOfChange([value]);
};

return (
<TogglerCard
title={specProperties[value]?.viewSpec.layoutTitle || ''}
disabled={spec.viewSpec.disabled}
text={spec.description?.[value] || ''}
description={specProperties[value]?.viewSpec.layoutDescription}
onClick={onClick}
selected={oneOfValue === value}
key={value}
/>
);
})}
</div>
);
}

if (togglerType === 'select') {
return (
<Select
width="max"
Expand Down Expand Up @@ -106,14 +139,23 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => {
))}
</RadioButton>
);
}, [selectToggler, oneOfValue, spec.viewSpec.disabled, name, options, onOneOfChange]);
}, [
togglerType,
oneOfValue,
spec.viewSpec.disabled,
name,
options,
onOneOfChange,
specProperties,
]);

const toggler = React.useMemo(() => {
if (Layout) {
return (
<div
className={b('toggler', {
radio: !selectToggler,
radio: togglerType === 'radio',
card: togglerType === 'card',
})}
>
<Layout {...props}>{togglerInput}</Layout>
Expand All @@ -122,7 +164,7 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => {
}

return <div>{togglerInput}</div>;
}, [Layout, togglerInput, selectToggler, props]);
}, [Layout, togglerInput, togglerType, props]);

return {oneOfValue, specProperties, toggler, togglerInput};
};
8 changes: 7 additions & 1 deletion src/stories/ObjectMultiOneOf.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ const spec: ObjectSpec = {
},
};

const excludeOptions = ['items', 'viewSpec.type', 'viewSpec.itemLabel', 'viewSpec.table'];
const excludeOptions = [
'items',
'viewSpec.type',
'viewSpec.itemLabel',
'viewSpec.table',
'viewSpec.oneOfParams',
];

const value = {
person: {
Expand Down
8 changes: 7 additions & 1 deletion src/stories/ObjectMultiOneOfFlat.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ const spec: ObjectSpec = {
},
};

const excludeOptions = ['items', 'viewSpec.type', 'viewSpec.itemLabel', 'viewSpec.table'];
const excludeOptions = [
'items',
'viewSpec.type',
'viewSpec.itemLabel',
'viewSpec.table',
'viewSpec.oneOfParams',
];

const value = {
person: {
Expand Down
2 changes: 1 addition & 1 deletion src/stories/components/InputPreview/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ const oneOfParams: ObjectSpec = {
properties: {
toggler: {
type: SpecTypes.String,
enum: ['―', 'radio', 'select'],
enum: ['―', 'radio', 'select', 'card'],
viewSpec: {type: 'select', layout: 'row', layoutTitle: 'Switch type'},
},
},
Expand Down

0 comments on commit caa76bc

Please sign in to comment.