Skip to content

Commit

Permalink
fix(extendPropsWithContext): [internal] rewrite to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Sep 16, 2022
1 parent 99629c4 commit a27bcf7
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 54 deletions.
7 changes: 4 additions & 3 deletions packages/dnb-eufemia/src/components/badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { createSkeletonClass } from '../skeleton/SkeletonHelper'
import Context from '../../shared/Context'
import { ISpacingProps } from '../../shared/interfaces'
import { SkeletonShow } from '../skeleton/Skeleton'
import { extendPropsWithContext } from '../../shared/component-helper'
import { usePropsWithContext } from '../../shared/component-helper'
import { warn } from '../../shared/component-helper'

export interface BadgeProps {
Expand Down Expand Up @@ -78,9 +78,10 @@ export const defaultProps = {
function Badge(localProps: BadgeAndISpacingProps) {
// Every component should have a context
const context = React.useContext(Context)

// Extract additional props from global context
const { children, ...props } = extendPropsWithContext(
{ ...defaultProps, ...localProps },
const { children, ...props } = usePropsWithContext(
localProps,
defaultProps,
context?.Badge
)
Expand Down
5 changes: 1 addition & 4 deletions packages/dnb-eufemia/src/components/info-card/InfoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ const InfoCard = (localProps: InfoCardProps & ISpacingProps) => {
closeButtonAttributes,
acceptButtonAttributes,
...props
} = usePropsWithContext(
{ ...defaultProps, ...localProps },
{ skeleton: context?.skeleton }
)
} = usePropsWithContext(localProps, { skeleton: context?.skeleton })

const skeletonClasses = createSkeletonClass('shape', skeleton, context)
const spacingClasses = createSpacingClasses(props)
Expand Down
16 changes: 0 additions & 16 deletions packages/dnb-eufemia/src/shared/__tests__/component-helper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { registerElement } from '../custom-element'
import {
isTrue,
extend,
extendPropsWithContext,
defineNavigator,
validateDOMAttributes,
processChildren,
Expand Down Expand Up @@ -338,21 +337,6 @@ describe('"extend" should', () => {
})
})

describe('"extendPropsWithContext" should', () => {
it('extend prop from other context object', () => {
expect(
extendPropsWithContext(
{ key: { x: 'y' }, foo: null }, // given props
{ key: { x: 'y' }, foo: null }, // default props
{ key: 'I can’t replace You', foo: 'bar' }
)
).toEqual({
key: { x: 'y' },
foo: 'bar', // because the prop was null, we get bar
})
})
})

describe('"isTrue" should', () => {
it('return true if we provide true as boolean', () => {
expect(isTrue(true)).toBe(true)
Expand Down
33 changes: 2 additions & 31 deletions packages/dnb-eufemia/src/shared/component-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import {
import { getPreviousSibling } from './helpers/getPreviousSibling'
import { init } from './Eufemia'

export { usePropsWithContext } from './hooks/usePropsWithContext'
export { InteractionInvalidation } from './helpers/InteractionInvalidation'
export { extendPropsWithContext } from './helpers/extendPropsWithContext'
export { registerElement } from './custom-element'

export { getPreviousSibling, warn }
Expand Down Expand Up @@ -277,37 +279,6 @@ export const extend = (...objects) => {
}, first)
}

// extends props from a given context
// but give the context second priority only
export const extendPropsWithContext = (
props,
defaults = {},
...contexts
) => {
const context = contexts.reduce((acc, cur) => {
if (cur) {
acc = { ...acc, ...cur }
}
return acc
}, {})

return {
...props,
...Object.entries(context).reduce((acc, [key, value]) => {
if (
// check if a prop of the same name exists
typeof props[key] !== 'undefined' &&
// and if it was NOT defined as a component prop, because its still the same as the defaults
props[key] === defaults[key]
) {
// then we use the context value
acc[key] = value
}
return acc
}, {}),
}
}

// check if value is "truthy"
export const isTrue = (value) => {
if (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { extendPropsWithContext } from '../extendPropsWithContext'

describe('"extendPropsWithContext" should', () => {
it('extend prop from other context object', () => {
expect(
extendPropsWithContext(
{ key: { x: 'y' }, foo: null }, // given props
{ key: { x: 'y' }, foo: null }, // default props
{ key: 'I can’t replace You', foo: 'bar' }
)
).toEqual({
key: { x: 'y' },
foo: 'bar', // because the prop was null, we get bar
})
})
})
40 changes: 40 additions & 0 deletions packages/dnb-eufemia/src/shared/helpers/extendPropsWithContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export type DefaultsProps = Record<string, unknown>
export type Contexts = Array<Record<string, unknown>>

/**
* Extends props from a given context
* but give the context second priority only
*
* @param props object of component properties
* @param defaults object of potential default values
* @param contexts the rest of all context to merge
* @returns merged properties
*/
export function extendPropsWithContext<Props>(
props: Props,
defaults: DefaultsProps = {},
...contexts: Contexts
) {
const context = contexts.reduce((acc, cur) => {
if (cur) {
acc = { ...acc, ...cur }
}
return acc
}, {})

return {
...props,
...Object.entries(context).reduce((acc, [key, value]) => {
if (
// check if a prop of the same name exists
typeof props[key] !== 'undefined' &&
// and if it was NOT defined as a component prop, because its still the same as the defaults
props[key] === defaults[key]
) {
// then we use the context value
acc[key] = value
}
return acc
}, {}),
}
}

0 comments on commit a27bcf7

Please sign in to comment.