Skip to content

Commit

Permalink
front: ui-core input tooltip status messages
Browse files Browse the repository at this point in the history
Signed-off-by: Egor Berezovskiy <[email protected]>
  • Loading branch information
Wadjetz committed Jan 3, 2025
1 parent 435e11a commit 33e1e38
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 8 deletions.
4 changes: 4 additions & 0 deletions ui-core/src/components/inputs/FieldWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type FieldWrapperProps = {
small?: boolean;
children?: React.ReactNode;
className?: string;
onCloseStatusMessage?: () => void;
};

const FieldWrapper = ({
Expand All @@ -31,6 +32,7 @@ const FieldWrapper = ({
small = false,
className,
children,
onCloseStatusMessage,
}: FieldWrapperProps) => {
const statusClassname = statusWithMessage ? { [statusWithMessage.status]: true } : {};

Expand Down Expand Up @@ -65,8 +67,10 @@ const FieldWrapper = ({
{/* STATUS MESSAGE */}
{statusWithMessage && (
<StatusMessage
small={small}
statusWithMessage={statusWithMessage}
showIcon={statusIconPosition === 'before-status-message'}
onClose={onCloseStatusMessage}
/>
)}
</div>
Expand Down
3 changes: 3 additions & 0 deletions ui-core/src/components/inputs/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
withIcons = [],
onKeyUp,
onBlur,
onCloseStatusMessage,
...rest
},
ref
Expand All @@ -86,7 +87,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
disabled={disabled}
required={required}
small={small}
statusIconPosition={statusWithMessage?.tooltip ? 'before-status-message' : undefined}
className={cx('input-field-wrapper', inputFieldWrapperClassname)}
onCloseStatusMessage={onCloseStatusMessage}
>
<div
className={cx('input-wrapper', {
Expand Down
2 changes: 1 addition & 1 deletion ui-core/src/components/inputs/InputStatusIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const InputStatusIcon = ({ status, small, className }: InputStatusIconProps) =>
return (
<span className={cx('status-icon', className, status)}>
{status === 'loading' && <Gear size={size} />}
{status === 'info' && <Info size={size} />}
{status === 'info' && <Info variant="fill" size={size} />}
{status === 'success' && <CheckCircle variant="fill" size={size} />}
{status === 'warning' && <Alert variant="fill" size={size} />}
{status === 'error' && <Blocked variant="fill" size={size} />}
Expand Down
23 changes: 20 additions & 3 deletions ui-core/src/components/inputs/StatusMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react';

import { X } from '@osrd-project/ui-icons';
import cx from 'classnames';

import InputStatusIcon from './InputStatusIcon';

export type Status = 'success' | 'info' | 'error' | 'warning' | 'loading';
export type TooltipType = 'left' | 'right';

export type StatusWithMessage = {
tooltip?: TooltipType;
status: Status;
message?: string;
};
Expand All @@ -15,16 +18,30 @@ export type StatusMessageProps = {
statusWithMessage: StatusWithMessage;
showIcon?: boolean;
small?: boolean;
onClose?: () => void;
};

const StatusMessage = ({ statusWithMessage, showIcon, small }: StatusMessageProps) => {
const { status, message } = statusWithMessage;
const StatusMessage = ({ statusWithMessage, showIcon, small, onClose }: StatusMessageProps) => {
const { tooltip, status, message } = statusWithMessage;
if (message === undefined) return null;

return (
<div className="status-message-wrapper">
<div
className={cx({
'status-message-wrapper': !tooltip,
'status-message-wrapper-tooltip': tooltip,
'tooltip-left': tooltip === 'left',
'tooltip-right': tooltip === 'right',
[status]: status,
})}
>
{showIcon && <InputStatusIcon status={status} small={small} />}
<span className={cx('status-message', { [status]: status })}>{message}</span>
{status === 'info' && (
<button className="status-close" onClick={onClose}>
<X size="sm" />
</button>
)}
</div>
);
};
Expand Down
77 changes: 76 additions & 1 deletion ui-core/src/stories/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import React, { useState } from 'react';

import { ChevronDown, X } from '@osrd-project/ui-icons';
import type { Meta, StoryObj } from '@storybook/react';
import '@osrd-project/ui-core/dist/theme.css';

import Input from '../components/inputs/Input';
import { type StatusWithMessage } from '../components/inputs/StatusMessage';

const meta: Meta<typeof Input> = {
component: Input,
Expand Down Expand Up @@ -173,6 +174,80 @@ export const ErrorInput: Story = {
},
};

export const TooltipErrorInput: Story = {
args: {
label: 'Name',
type: 'text',
required: true,
value: 'Michel Sardou',
statusWithMessage: {
tooltip: 'right',
status: 'error',
message: '“Michel Sardou” can’t be used',
},
},
};

export const TooltipInfoInput: Story = {
args: {
label: 'Name',
type: 'text',
required: true,
value: 'Michel Sardou',
},
decorators: [
function Component(Story, ctx) {
const [status, setStatus] = useState<StatusWithMessage | undefined>({
tooltip: 'right',
status: 'info',
message: '“Michel Sardou” can’t be used',
});
return (
<Story
args={{
...ctx.args,
statusWithMessage: status,
onCloseStatusMessage: () => setStatus(undefined),
}}
/>
);
},
],
};

export const TwoTooltipErrorInput: Story = {
decorators: [
(Story) => (
<div style={{ display: 'flex', flexDirection: 'row', gap: '20px' }}>
<Story
args={{
label: 'Name',
type: 'text',
value: 'Michel Sardou',
statusWithMessage: {
tooltip: 'left',
status: 'error',
message: 'Michel Sardou can’t be used',
},
}}
/>
<Story
args={{
label: 'Name',
type: 'text',
value: 'Jean-Michel Halleurt',
statusWithMessage: {
tooltip: 'right',
status: 'error',
message: 'Jean-Michel Halleurt can’t be used',
},
}}
/>
</div>
),
],
};

export const ErrorWithoutMessageInput: Story = {
args: {
label: 'Name',
Expand Down
14 changes: 11 additions & 3 deletions ui-core/src/styles/inputs/fieldWrapper.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
.feed-back {
--input-wrapper-padding: 3px;
--field-wrapper-padding-bottom: 16px;
--status-message-wrapper-tooltip--offset: 4px;

border-radius: 0.5rem;
position: relative;
padding: 0.625rem 0.813rem 1rem 1rem;

&.info {
&.success:not(:has(.status-message-wrapper-tooltip)) {
@apply bg-success-5;
}

&.info:not(:has(.status-message-wrapper-tooltip)) {
@apply bg-info-5;
}

&.warning {
&.warning:not(:has(.status-message-wrapper-tooltip)) {
@apply bg-warning-5;
}

&.error {
&.error:not(:has(.status-message-wrapper-tooltip)) {
@apply bg-error-5;
}

Expand Down
81 changes: 81 additions & 0 deletions ui-core/src/styles/inputs/statusMessage.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,84 @@
}
}
}

.status-message-wrapper-tooltip {
position: absolute;
display: flex;
align-items: center;
width: 320px;
top: calc(
100% - var(--input-wrapper-padding) - var(--field-wrapper-padding-bottom) -
var(--status-message-wrapper-tooltip--offset)
);
gap: 12px;
border-radius: 8px;
box-shadow:
0 10px 20px 0 rgba(0, 0, 0, 0.2),
0 1px 0 rgba(255, 255, 255, 0.6) inset;
padding-inline: 12px;
z-index: 10;

.status-close {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 8px;
right: 8px;
color: theme('colors.info.30');
&:hover {
color: theme('colors.info.80');
}
}

&.loading {
background-color: theme('colors.white.25');
}

&.success {
background-color: theme('colors.success.5');
}

&.error {
background-color: theme('colors.error.5');
}

&.info {
background-color: theme('colors.info.5');
padding-inline: 12px 32px;
}

&.warning {
background-color: theme('colors.warning.5');
}

&.tooltip-left {
left: 8px;
}

&.tooltip-right {
right: 8px;
}

.status-message {
font-weight: 600;
padding-block: 6px 10px;

&.success {
color: theme('colors.success.60');
}

&.error {
color: theme('colors.error.60');
}

&.info {
color: theme('colors.info.60');
}

&.warning {
color: theme('colors.warning.60');
}
}
}

0 comments on commit 33e1e38

Please sign in to comment.