Skip to content

Commit

Permalink
Fix bug that first StackItem has marginBefore when preceding node…
Browse files Browse the repository at this point in the history
… is not JSX.Element (#1120)

* fix(stack): fix bug that first valid element is given marginBefore

* feat(stack): add test code when first child node of stack is not valid

* chore(changest): add changeset

* chore(stack): fix typo in test code
  • Loading branch information
yangwooseong authored Feb 8, 2023
1 parent 1c52fcd commit 70efd99
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/real-vans-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@channel.io/bezier-react": patch
---

Fix bug that first StackItem has marginBefore when the preceding node is not valid element such as null or false
36 changes: 36 additions & 0 deletions packages/bezier-react/src/components/Stack/Stack/Stack.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react'
/* Internal dependencies */
import { css } from 'Foundation'
import { render } from 'Utils/testUtils'
import { StackItem } from 'Components/Stack/StackItem'
import { Stack } from './Stack'

describe('Stack', () => {
Expand Down Expand Up @@ -52,4 +53,39 @@ describe('Stack', () => {
expect(getByTestId('stack')).toHaveStyle({ 'background-color': 'red' })
})
})

it('gives marginBefore attribute to second stackItem if it is given some spacing', () => {
const spacing = 10

const { getByTestId } = render(
<Stack direction="horizontal" spacing={spacing}>
<StackItem testId="one" />
<StackItem testId="two" />
<StackItem testId="three" />
</Stack>,
)

expect(getByTestId('one')).not.toHaveStyle('--margin-before: 10px')
expect(getByTestId('two')).toHaveStyle('--margin-before: 10px')
expect(getByTestId('three')).toHaveStyle('--margin-before: 10px')
})

it('does not give marginBefore attribute to first stackItem if first node is not a valid ReactNode', () => {
const spacing = 10

const { getByTestId } = render(
<Stack direction="horizontal" spacing={spacing}>
{ false }
{ null }
abc
<StackItem testId="one" />
<StackItem testId="two" />
<StackItem testId="three" />
</Stack>,
)

expect(getByTestId('one')).not.toHaveStyle('--margin-before: 10px')
expect(getByTestId('two')).toHaveStyle('--margin-before: 10px')
expect(getByTestId('three')).toHaveStyle('--margin-before: 10px')
})
})
27 changes: 16 additions & 11 deletions packages/bezier-react/src/components/Stack/Stack/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
cloneElement,
forwardRef,
isValidElement,
useRef,
} from 'react'
import type { Ref } from 'react'

Expand Down Expand Up @@ -45,6 +46,8 @@ export const Stack = forwardRef(function Stack(
}: StackProps,
forwardedRef: Ref<HTMLElement>,
) {
const firstValidElementIdx = useRef(-1)

return (
<Styled.Container
ref={forwardedRef}
Expand All @@ -60,24 +63,26 @@ export const Stack = forwardRef(function Stack(
>
{ Children.map(
children,
(element, index) => (
isValidElement(element)
/**
(element, index) => {
if (!isValidElement(element)) { return element }

/**
* NOTE: this assumes that this element is `StackItem`.
*
* Even if the child is not a `StackItem` component,
* it could forward the prop to `StackItem` deeper in the tree,
* or implement a custom behavior compatible with `StackItemProps`.
*/
? cloneElement(element, {
...element.props,
direction,
marginBefore:
if (firstValidElementIdx.current === -1) { firstValidElementIdx.current = index }
return cloneElement(element, {
...element.props,
direction,
marginBefore:
element.props.marginBefore ??
(index > 0 ? spacing : 0),
})
: element
),
(index > firstValidElementIdx.current ? spacing : 0),
})
},

) }
</Styled.Container>
)
Expand Down

0 comments on commit 70efd99

Please sign in to comment.