diff --git a/front/src/components/table/EditableCell.tsx b/front/src/components/table/EditableCell.tsx deleted file mode 100644 index 6771d6b1b2..0000000000 --- a/front/src/components/table/EditableCell.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import styled from '@emotion/styled'; -import { ChangeEvent, useRef, useState } from 'react'; - -type OwnProps = { - content: string; - changeHandler: (updated: string) => void; -}; - -const StyledEditable = styled.div` - position: relative; - box-sizing: border-box; - height: 32px; - display: flex; - align-items: center; - width: 100%; - - :hover::before { - display: block; - } - - ::before { - content: ''; - position: absolute; - top: -1px; - left: -1px; - width: calc(100% + 2px); - height: calc(100% + 2px); - border: 1px solid ${(props) => props.theme.text20}; - box-sizing: border-box; - border-radius: 4px; - pointer-events: none; - display: none; - } - - &:has(input:focus-within)::before { - content: ''; - position: absolute; - top: -1px; - left: -1px; - width: calc(100% + 2px); - height: calc(100% + 2px); - border: 1px solid ${(props) => props.theme.text20}; - border-radius: 4px; - pointer-events: none; - display: block; - z-index: 1; - box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09); - } -`; - -const StyledInplaceInput = styled.input` - width: 100%; - border: none; - outline: none; -`; - -const Container = styled.div` - width: 100%; - padding-left: ${(props) => props.theme.spacing(2)}; - padding-right: ${(props) => props.theme.spacing(2)}; -`; - -function EditableCell({ content, changeHandler }: OwnProps) { - const inputRef = useRef(null); - const [inputValue, setInputValue] = useState(content); - - return ( - { - inputRef.current?.focus(); - }} - > - - ) => { - setInputValue(event.target.value); - changeHandler(event.target.value); - }} - /> - - - ); -} - -export default EditableCell; diff --git a/front/src/components/table/__stories__/EditableCell.stories.tsx b/front/src/components/table/__stories__/EditableCell.stories.tsx deleted file mode 100644 index c9e51ca60b..0000000000 --- a/front/src/components/table/__stories__/EditableCell.stories.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import EditableCell from '../EditableCell'; -import { ThemeProvider } from '@emotion/react'; -import { lightTheme } from '../../../layout/styles/themes'; -import { StoryFn } from '@storybook/react'; - -const component = { - title: 'EditableCell', - component: EditableCell, -}; - -type OwnProps = { - content: string; - changeHandler: (updated: string) => void; -}; - -export default component; - -const Template: StoryFn = (args: OwnProps) => { - return ( - -
- -
-
- ); -}; - -export const EditableCellStory = Template.bind({}); -EditableCellStory.args = { - content: 'Test string', -}; diff --git a/front/src/components/table/editable-cell/EditableCellWrapper.tsx b/front/src/components/table/editable-cell/EditableCellWrapper.tsx new file mode 100644 index 0000000000..1f506c5373 --- /dev/null +++ b/front/src/components/table/editable-cell/EditableCellWrapper.tsx @@ -0,0 +1,71 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import { ReactElement, useRef, useState } from 'react'; +import { useOutsideAlerter } from '../../../hooks/useOutsideAlerter'; +import { ThemeType } from '../../../layout/styles/themes'; + +type OwnProps = { + children: ReactElement; + onEditModeChange: (isEditMode: boolean) => void; +}; + +const StyledWrapper = styled.div` + position: relative; + box-sizing: border-box; + height: 32px; + display: flex; + align-items: center; + width: 100%; +`; + +type styledEditModeWrapperProps = { + isEditMode: boolean; +}; + +const styledEditModeWrapper = (theme: ThemeType) => + css` + position: absolute; + width: 260px; + height: 100%; + + display: flex; + padding-left: ${theme.spacing(2)}; + padding-right: ${theme.spacing(2)}; + background: ${theme.primaryBackground}; + border: 1px solid ${theme.primaryBorder}; + box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.16); + z-index: 1; + border-radius: 4px; + backdrop-filter: blur(20px); + `; + +const Container = styled.div` + width: 100%; + padding-left: ${(props) => props.theme.spacing(2)}; + padding-right: ${(props) => props.theme.spacing(2)}; + ${(props) => props.isEditMode && styledEditModeWrapper(props.theme)} +`; + +function EditableCellWrapper({ children, onEditModeChange }: OwnProps) { + const [isEditMode, setIsEditMode] = useState(false); + + const wrapperRef = useRef(null); + useOutsideAlerter(wrapperRef, () => { + setIsEditMode(false); + onEditModeChange(false); + }); + + return ( + { + setIsEditMode(true); + onEditModeChange(true); + }} + > + {children} + + ); +} + +export default EditableCellWrapper; diff --git a/front/src/components/table/editable-cell/EditableText.tsx b/front/src/components/table/editable-cell/EditableText.tsx new file mode 100644 index 0000000000..4dac72758a --- /dev/null +++ b/front/src/components/table/editable-cell/EditableText.tsx @@ -0,0 +1,55 @@ +import styled from '@emotion/styled'; +import { ChangeEvent, useRef, useState } from 'react'; +import EditableCellWrapper from './EditableCellWrapper'; + +type OwnProps = { + placeholder?: string; + content: string; + changeHandler: (updated: string) => void; +}; + +type StyledEditModeProps = { + isEditMode: boolean; +}; + +const StyledInplaceInput = styled.input` + width: 100%; + border: none; + outline: none; + + &::placeholder { + font-weight: ${(props) => (props.isEditMode ? 'bold' : 'normal')}; + color: ${(props) => + props.isEditMode ? props.theme.text20 : 'transparent'}; + } +`; + +function EditableCell({ content, placeholder, changeHandler }: OwnProps) { + const inputRef = useRef(null); + const [inputValue, setInputValue] = useState(content); + const [isEditMode, setIsEditMode] = useState(false); + + const onEditModeChange = (isEditMode: boolean) => { + setIsEditMode(isEditMode); + if (isEditMode) { + inputRef.current?.focus(); + } + }; + + return ( + + ) => { + setInputValue(event.target.value); + changeHandler(event.target.value); + }} + /> + + ); +} + +export default EditableCell; diff --git a/front/src/components/table/editable-cell/__stories__/EditableText.stories.tsx b/front/src/components/table/editable-cell/__stories__/EditableText.stories.tsx new file mode 100644 index 0000000000..a526b4cc54 --- /dev/null +++ b/front/src/components/table/editable-cell/__stories__/EditableText.stories.tsx @@ -0,0 +1,35 @@ +import EditableText from '../EditableText'; +import { ThemeProvider } from '@emotion/react'; +import { lightTheme } from '../../../../layout/styles/themes'; +import { StoryFn } from '@storybook/react'; + +const component = { + title: 'EditableText', + component: EditableText, +}; + +type OwnProps = { + content: string; + changeHandler: (updated: string) => void; +}; + +export default component; + +const Template: StoryFn = (args: OwnProps) => { + return ( + +
+ +
+
+ ); +}; + +export const EditableTextStory = Template.bind({}); +EditableTextStory.args = { + placeholder: 'Test placeholder', + content: 'Test string', + changeHandler: () => { + console.log('changed'); + }, +}; diff --git a/front/src/components/table/__tests__/EditableCell.test.tsx b/front/src/components/table/editable-cell/__tests__/EditableText.test.tsx similarity index 64% rename from front/src/components/table/__tests__/EditableCell.test.tsx rename to front/src/components/table/editable-cell/__tests__/EditableText.test.tsx index eb48568f1b..eeab931a20 100644 --- a/front/src/components/table/__tests__/EditableCell.test.tsx +++ b/front/src/components/table/editable-cell/__tests__/EditableText.test.tsx @@ -1,14 +1,22 @@ import { fireEvent, render } from '@testing-library/react'; -import { EditableCellStory } from '../__stories__/EditableCell.stories'; +import { EditableTextStory } from '../__stories__/EditableText.stories'; it('Checks the EditableCell editing event bubbles up', async () => { const func = jest.fn(() => null); const { getByTestId } = render( - , + , ); const parent = getByTestId('content-editable-parent'); + + const wrapper = parent.querySelector('div'); + + if (!wrapper) { + throw new Error('Editable input not found'); + } + fireEvent.click(wrapper); + const editableInput = parent.querySelector('input'); if (!editableInput) { diff --git a/front/src/pages/companies/companies-table.tsx b/front/src/pages/companies/companies-table.tsx index c5d2d41815..70fe26d750 100644 --- a/front/src/pages/companies/companies-table.tsx +++ b/front/src/pages/companies/companies-table.tsx @@ -5,7 +5,7 @@ import ColumnHead from '../../components/table/ColumnHead'; import HorizontalyAlignedContainer from '../../layout/containers/HorizontalyAlignedContainer'; import Checkbox from '../../components/form/Checkbox'; import CompanyChip from '../../components/chips/CompanyChip'; -import EditableCell from '../../components/table/EditableCell'; +import EditableText from '../../components/table/editable-cell/EditableText'; import PipeChip from '../../components/chips/PipeChip'; import { FaRegBuilding, @@ -53,7 +53,7 @@ export const companiesColumns = [ columnHelper.accessor('employees', { header: () => } />, cell: (props) => ( - { const company = props.row.original; @@ -66,7 +66,7 @@ export const companiesColumns = [ columnHelper.accessor('domain_name', { header: () => } />, cell: (props) => ( - { const company = props.row.original; @@ -79,7 +79,7 @@ export const companiesColumns = [ columnHelper.accessor('address', { header: () => } />, cell: (props) => ( - { const company = props.row.original; diff --git a/front/src/pages/people/people-table.tsx b/front/src/pages/people/people-table.tsx index 767e0c8f14..7f5a622651 100644 --- a/front/src/pages/people/people-table.tsx +++ b/front/src/pages/people/people-table.tsx @@ -19,7 +19,7 @@ import CompanyChip from '../../components/chips/CompanyChip'; import PersonChip from '../../components/chips/PersonChip'; import { GraphqlQueryPerson, Person } from '../../interfaces/person.interface'; import PipeChip from '../../components/chips/PipeChip'; -import EditableCell from '../../components/table/EditableCell'; +import EditableText from '../../components/table/editable-cell/EditableText'; import { OrderByFields, updatePerson } from '../../services/people'; import { FilterType, @@ -152,7 +152,8 @@ export const peopleColumns = [ columnHelper.accessor('email', { header: () => } />, cell: (props) => ( - { const person = props.row.original;