Skip to content

Commit

Permalink
feat: inlineForm component
Browse files Browse the repository at this point in the history
  • Loading branch information
Katrin-kudryash committed Aug 31, 2023
1 parent c9b36d3 commit b2f911f
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
122 changes: 122 additions & 0 deletions src/components/InlineForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useEffect, useMemo, useReducer, useRef, useState } from 'react';
import styled from 'styled-components';
import { IconQuestionCircleOutline } from '@taskany/icons';

import { KeyCode, useKeyboard } from '../hooks/useKeyboard';
import { useClickOutside } from '../hooks/useClickOutside';
import { nullable } from '../utils';

import { Form } from './Form';
import { Popup } from './Popup';

interface RenderTriggerProps {
onClick: () => void;
}

interface InlineFormProps {
renderTrigger?: (props: RenderTriggerProps) => React.ReactNode;
onSubmit: () => void;
children: React.ReactNode;
tip?: React.ReactNode;
onReset: () => void;
isSubmitted?: boolean;
className?: string;
}

const StyledWrapper = styled.div`
display: contents;
& form {
background-color: transparent;
display: contents;
}
`;

const StyledFormWrapper = styled.div`
display: contents;
position: relative;
`;

const StyledQuestionIcon = styled(IconQuestionCircleOutline)`
margin-left: 4px;
`;

export const InlineForm: React.FC<InlineFormProps> = ({
renderTrigger,
onSubmit,
onReset,
isSubmitted,
children,
tip,
className,
}) => {
const wrapperRef = useRef<HTMLDivElement>(null);
const [visible, toggle] = useReducer((state) => !state, !renderTrigger);
const [hintVisible, toggleHintVisible] = useState(false);
const hintRef = useRef<HTMLAnchorElement>(null);
const trigger = useMemo(() => {
if (typeof renderTrigger === 'function') {
return renderTrigger({ onClick: toggle });
}

return null;
}, [renderTrigger]);

const [onESC] = useKeyboard(
[KeyCode.Escape],
() => {
if (visible) {
toggle();
}
},
{
capture: true,
},
);

useClickOutside(wrapperRef, () => {
if (visible) {
toggle();
}
});

useEffect(() => {
if (isSubmitted) {
toggle();
onReset();
}
}, [onReset, isSubmitted]);

useEffect(() => {
if (!visible) {
onReset();
}
}, [visible, onReset]);

return (
<StyledWrapper ref={wrapperRef} className={className} {...onESC}>
{!visible && trigger}
{visible && (
<Form onSubmit={onSubmit}>
<StyledFormWrapper>
{children}
{nullable(tip, (t: React.ReactNode) => (
<>
<a
ref={hintRef}
onMouseOver={() => toggleHintVisible(true)}
onMouseLeave={() => toggleHintVisible(false)}
>
<StyledQuestionIcon size="s" />
</a>
<Popup reference={hintRef} visible={hintVisible} placement="top-end">
{t}
</Popup>
</>
))}
</StyledFormWrapper>
</Form>
)}
</StyledWrapper>
);
};
1 change: 1 addition & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ export * from './UserGroup';
export * from './Popup';
export * from './ListView';
export * from './ErrorPopup';
export * from './InlineForm';

0 comments on commit b2f911f

Please sign in to comment.