Skip to content

Commit

Permalink
Fix [FormChipCell] issues with labels (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
Taras-Hlukhovetskyi authored Mar 18, 2024
1 parent b921821 commit 1bd565b
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/lib/components/FormChipCell/FormChip/FormChip.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const FormChip = React.forwardRef(
}, [chipIndex, setChipsSizes])

return (
<div onClick={(event) => handleToEditMode(event, chipIndex)} ref={chipRef}>
<div onClick={(event) => handleToEditMode(event, chipIndex, keyName)} ref={chipRef}>
<NewChipForm
chip={chip}
chipIndex={chipIndex}
Expand Down
64 changes: 49 additions & 15 deletions src/lib/components/FormChipCell/FormChipCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ const FormChipCell = ({
return {
chipIndex: lastChipSelected ? null : prevState.chipIndex + 1,
isEdit: !lastChipSelected,
isKeyFocused: true,
isKeyFocused: !lastChipSelected,
isValueFocused: false,
isNewChip: false
}
Expand All @@ -189,25 +189,29 @@ const FormChipCell = ({
}

setEditConfig((prevState) => {
const isPrevChipIndexExists = prevState.chipIndex - 1 < 0
const firstChipIsSelected = prevState.chipIndex === 0

isChipNotEmpty &&
isPrevChipIndexExists &&
onExitEditModeCallback &&
onExitEditModeCallback()
isChipNotEmpty && firstChipIsSelected && onExitEditModeCallback && onExitEditModeCallback()

return {
chipIndex: isPrevChipIndexExists ? null : prevState.chipIndex - 1,
isEdit: !isPrevChipIndexExists,
isKeyFocused: isPrevChipIndexExists,
isValueFocused: !isPrevChipIndexExists,
chipIndex: firstChipIsSelected ? null : prevState.chipIndex - 1,
isEdit: !firstChipIsSelected,
isKeyFocused: false,
isValueFocused: !firstChipIsSelected,
isNewChip: false
}
})
}

checkChipsList(get(formState.values, name))
event && event.preventDefault()

if (
(editConfig.chipIndex > 0 && editConfig.chipIndex < fields.value.length - 1) ||
(fields.value.length > 1 && editConfig.chipIndex === 0 && nameEvent !== TAB_SHIFT) ||
(fields.value.length > 1 && editConfig.chipIndex === fields.value.length - 1 && nameEvent !== TAB)
) {
event && event.preventDefault()
}
},
[
editConfig.chipIndex,
Expand All @@ -220,16 +224,46 @@ const FormChipCell = ({
)

const handleToEditMode = useCallback(
(event, index) => {
(event, chipIndex, keyName) => {
if (isEditable) {
const { clientX: pointerCoordinateX, clientY: pointerCoordinateY } = event
let isKeyClicked = false
const isClickedInsideInputElement = (pointerCoordinateX, pointerCoordinateY, inputElement) => {
if (inputElement) {
const {
top: topPosition,
left: leftPosition,
right: rightPosition,
bottom: bottomPosition
} = inputElement.getBoundingClientRect()
if (pointerCoordinateX > rightPosition || pointerCoordinateX < leftPosition)
return false
if (pointerCoordinateY > bottomPosition || pointerCoordinateY < topPosition)
return false

return true
}
}
event.stopPropagation()

if (event.target.nodeName !== 'INPUT') {
if (event.target.firstElementChild) {
isKeyClicked = isClickedInsideInputElement(
pointerCoordinateX,
pointerCoordinateY,
event.target.firstElementChild
)
}
} else {
isKeyClicked = event.target.name === keyName
}

setEditConfig((preState) => ({
...preState,
chipIndex: index,
chipIndex,
isEdit: true,
isKeyFocused: true,
isValueFocused: false
isKeyFocused: isKeyClicked,
isValueFocused: !isKeyClicked
}))
}

Expand Down
73 changes: 42 additions & 31 deletions src/lib/components/FormChipCell/NewChipForm/NewChipForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ such restriction.
import React, { useState, useCallback, useEffect, useLayoutEffect, useMemo } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { isEmpty, get } from 'lodash'
import { isEmpty, get, isNil } from 'lodash'

import NewChipInput from '../NewChipInput/NewChipInput'
import OptionsMenu from '../../../elements/OptionsMenu/OptionsMenu'
import ValidationTemplate from '../../../elements/ValidationTemplate/ValidationTemplate'

import { CHIP_OPTIONS } from '../../../types'
import { BACKSPACE, CLICK, DELETE, TAB, TAB_SHIFT } from '../../../constants'
import { CLICK, TAB, TAB_SHIFT } from '../../../constants'
import { getTextWidth } from '../formChipCell.util'

import { ReactComponent as Close } from '../../../images/close.svg'

Expand Down Expand Up @@ -95,6 +96,11 @@ const NewChipForm = React.forwardRef(
'item_edited_invalid'
)

const closeButtonClass = classnames(
'edit-chip__icon-close',
(editConfig.chipIndex === chipIndex || !isEditable) && 'edit-chip__icon-close_hidden'
)

useLayoutEffect(() => {
if (!chipData.keyFieldWidth && !chipData.valueFieldWidth) {
const currentWidthKeyInput = refInputKey.current.scrollWidth + 1
Expand Down Expand Up @@ -187,33 +193,24 @@ const NewChipForm = React.forwardRef(

const focusChip = useCallback(
(event) => {
event.stopPropagation()

if (editConfig.chipIndex === chipIndex && isEditable) {
if (!event.shiftKey && event.key === TAB && editConfig.isValueFocused) {
onChange(event, TAB)
return onChange(event, TAB)
} else if (event.shiftKey && event.key === TAB && editConfig.isKeyFocused) {
onChange(event, TAB_SHIFT)
}

if (event.key === BACKSPACE || event.key === DELETE) {
setChipData((prevState) => ({
...prevState,
keyFieldWidth: editConfig.isKeyFocused ? minWidthInput : prevState.keyFieldWidth,
valueFieldWidth: editConfig.isValueFocused
? minWidthValueInput
: prevState.valueFieldWidth
}))
return onChange(event, TAB_SHIFT)
}
}
event.stopPropagation()
},
[editConfig, onChange, chipIndex, isEditable]
)

const handleOnFocus = useCallback(
(event) => {
const isKeyFocused = event.target.name === keyName

if (editConfig.chipIndex === chipIndex) {
if (event.target.name === keyName) {
if (isKeyFocused) {
refInputKey.current.selectionStart = refInputKey.current.selectionEnd

setEditConfig((prevConfig) => ({
Expand All @@ -232,6 +229,18 @@ const NewChipForm = React.forwardRef(
}

event && event.stopPropagation()
} else if (isNil(editConfig.chipIndex)) {
if (isKeyFocused) {
refInputKey.current.selectionStart = refInputKey.current.selectionEnd
} else {
refInputValue.current.selectionStart = refInputValue.current.selectionEnd
}
setEditConfig({
chipIndex,
isEdit: true,
isKeyFocused: isKeyFocused,
isValueFocused: !isKeyFocused
})
}
},
[keyName, refInputKey, refInputValue, setEditConfig, editConfig.chipIndex, chipIndex]
Expand All @@ -241,7 +250,7 @@ const NewChipForm = React.forwardRef(
(event) => {
event.preventDefault()
if (event.target.name === keyName) {
const currentWidthKeyInput = refInputKey.current.scrollWidth
const currentWidthKeyInput = getTextWidth(refInputKey.current)

setChipData((prevState) => ({
...prevState,
Expand All @@ -256,7 +265,7 @@ const NewChipForm = React.forwardRef(
: minWidthInput
}))
} else {
const currentWidthValueInput = refInputValue.current.scrollWidth
const currentWidthValueInput = getTextWidth(refInputValue.current)

setChipData((prevState) => ({
...prevState,
Expand All @@ -275,7 +284,7 @@ const NewChipForm = React.forwardRef(
[maxWidthInput, refInputKey, refInputValue, keyName]
)

useEffect(() => {
useLayoutEffect(() => {
if (editConfig.chipIndex === chipIndex) {
setSelectedInput(
editConfig.isKeyFocused ? 'key' : editConfig.isValueFocused ? 'value' : null
Expand Down Expand Up @@ -325,7 +334,9 @@ const NewChipForm = React.forwardRef(
>
<NewChipInput
className={labelKeyClassName}
disabled={!isEditable || (editConfig.chipIndex && editConfig.chipIndex !== chipIndex)}
disabled={
!isEditable || (!isNil(editConfig.chipIndex) && editConfig.chipIndex !== chipIndex)
}
name={keyName}
onChange={handleOnChange}
onFocus={handleOnFocus}
Expand All @@ -337,7 +348,9 @@ const NewChipForm = React.forwardRef(
{!chipData.isKeyOnly && (
<NewChipInput
className={labelValueClassName}
disabled={!isEditable || (editConfig.chipIndex && editConfig.chipIndex !== chipIndex)}
disabled={
!isEditable || (!isNil(editConfig.chipIndex) && editConfig.chipIndex !== chipIndex)
}
name={valueName}
onChange={handleOnChange}
onFocus={handleOnFocus}
Expand All @@ -347,19 +360,17 @@ const NewChipForm = React.forwardRef(
/>
)}

{editConfig.chipIndex !== chipIndex && isEditable && (
<button
className="edit-chip__icon-close"
onClick={(event) => handleRemoveChip(event, chipIndex)}
>
<Close />
</button>
)}
<button
className={closeButtonClass}
onClick={(event) => handleRemoveChip(event, chipIndex)}
>
<Close />
</button>

{(editConfig.isKeyFocused ? !isEmpty(chipData.key) : !isEmpty(chipData.value)) &&
editConfig.chipIndex === chipIndex &&
!isEmpty(get(meta, ['error', editConfig.chipIndex, selectedInput], [])) && (
<OptionsMenu show={showValidationRules} ref={ref}>
<OptionsMenu show={showValidationRules} ref={refInputContainer}>
{getValidationRules()}
</OptionsMenu>
)}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/components/FormChipCell/NewChipForm/newChipForm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
background-color: transparent;
border: none;

&[disabled] {
pointer-events: none;
}

&.item_edited {
&_invalid {
color: $amaranth;
Expand Down Expand Up @@ -58,6 +62,10 @@
align-items: center;
justify-content: center;

&_hidden {
visibility: hidden;
}

svg {
transform: scale(0.7);
}
Expand Down
31 changes: 31 additions & 0 deletions src/lib/components/FormChipCell/formChipCell.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,34 @@ under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
export const uniquenessError = { name: 'uniqueness', label: 'Key must be unique' }

export const getTextWidth = (elementWithText) => {
if (!elementWithText) {
return 0
}
const hiddenElementId = 'chips-hidden-element'
let hiddenElement = document.getElementById(hiddenElementId)

if (!hiddenElement) {
hiddenElement = document.createElement('span')
const styles = {
position: 'absolute',
left: '-10000px',
top: "auto",
visibility: 'hidden'
}

for (const [styleName, styleValue] of Object.entries(styles)) {
hiddenElement.style[styleName ] = styleValue;
}

hiddenElement.style.font = window.getComputedStyle(elementWithText).font
hiddenElement.id = hiddenElementId
hiddenElement.tabIndex = -1
document.body.append(hiddenElement)
}

hiddenElement.textContent = elementWithText.value

return hiddenElement.offsetWidth ?? 0
}
18 changes: 4 additions & 14 deletions src/lib/components/FormSelect/FormSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
import React, { useState, useEffect, useCallback, useMemo, useRef, useLayoutEffect } from 'react'
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { Field, useField } from 'react-final-form'
Expand Down Expand Up @@ -54,13 +54,12 @@ const FormSelect = ({
const [isInvalid, setIsInvalid] = useState(false)
const [isConfirmDialogOpen, setConfirmDialogOpen] = useState(false)
const [isOpen, setIsOpen] = useState(false)
const [position, setPosition] = useState('bottom-right')
const [searchValue, setSearchValue] = useState('')
const optionsListRef = useRef()
const popUpRef = useRef()
const selectRef = useRef()
const searchRef = useRef()
const { width: selectWidth, left: selectLeft } = selectRef?.current?.getBoundingClientRect() || {}
const { width: selectWidth } = selectRef?.current?.getBoundingClientRect() || {}

const selectWrapperClassNames = classNames(
'form-field__wrapper',
Expand Down Expand Up @@ -162,16 +161,6 @@ const FormSelect = ({
[closeMenu]
)

useLayoutEffect(() => {
if (popUpRef?.current) {
const { width } = popUpRef.current.getBoundingClientRect()

selectLeft + width > window.innerWidth
? setPosition('bottom-left')
: setPosition('bottom-right')
}
}, [isOpen, selectLeft])

useEffect(() => {
if (isOpen) {
window.addEventListener('scroll', handleScroll, true)
Expand Down Expand Up @@ -345,7 +334,8 @@ const FormSelect = ({
ref={popUpRef}
customPosition={{
element: selectRef,
position
position: 'bottom-right',
autoHorizontalPosition: true
}}
style={{
maxWidth: `${selectWidth < 500 ? 500 : selectWidth}px`,
Expand Down
Loading

0 comments on commit 1bd565b

Please sign in to comment.