Skip to content

Commit

Permalink
Things are prettier now
Browse files Browse the repository at this point in the history
  • Loading branch information
henit committed Sep 11, 2023
1 parent e833855 commit 34aaeca
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 58 deletions.
8 changes: 4 additions & 4 deletions packages/dnb-eufemia/src/extensions/forms/Iterate/Array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function ArrayComponent(props: Props) {
(element: unknown) => {
handleChange([...(arrayValue ?? []), element])
},
[arrayValue, handleChange],
[arrayValue, handleChange]
)

return (
Expand All @@ -100,7 +100,7 @@ function ArrayComponent(props: Props) {
elementData.map(
(
{ elementValue, handleElementChange, handleRemoveElement },
elementIndex,
elementIndex
) => {
return (
<IterateElementContext.Provider
Expand All @@ -118,14 +118,14 @@ function ArrayComponent(props: Props) {
? children.map((childElement) =>
typeof childElement === 'function'
? childElement(elementValue, elementIndex)
: childElement,
: childElement
)
: typeof children === 'function'
? children(elementValue, elementIndex)
: children}
</IterateElementContext.Provider>
)
},
}
)
)}
</FlexContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function ArrayPushButton(props: Props) {
<Button
className={classnames(
'dnb-forms-array-push-button',
props.className,
props.className
)}
text={text}
on_click={handleClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function ArrayRemoveElementButton(props: Props) {

if (!iterateElementContext) {
throw new Error(
'ArrayRemoveElementButton must be inside an Iterate.Array component.',
'ArrayRemoveElementButton must be inside an Iterate.Array component.'
)
}

Expand All @@ -54,7 +54,7 @@ function ArrayRemoveElementButton(props: Props) {
<Button
className={classnames(
'dnb-forms-array-remove-element-button',
props.className,
props.className
)}
variant={variant}
size={size}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react'

export interface IterateElementContextState {
index: number;
value: unknown;
path?: string;
handleChange: (path: string, value: unknown) => void;
handleRemove: () => void;
handlePush: (value: unknown) => void;
index: number
value: unknown
path?: string
handleChange: (path: string, value: unknown) => void
handleRemove: () => void
handlePush: (value: unknown) => void
}

const IterateElementContext = React.createContext<IterateElementContextState | undefined>(undefined)
const IterateElementContext = React.createContext<
IterateElementContextState | undefined
>(undefined)

export default IterateElementContext
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Iterate.Array', () => {
render(
<Iterate.Array value={['one', 'two', 'three']} onChange={onChange}>
<Field.String elementPath="/" />
</Iterate.Array>,
</Iterate.Array>
)
const fields = document.querySelectorAll('input')
expect(fields).toHaveLength(3)
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('Iterate.Array', () => {
>
<Field.String elementPath="/foo" />
<Field.String elementPath="/bar" />
</Iterate.Array>,
</Iterate.Array>
)
const fields = document.querySelectorAll('input')
expect(fields).toHaveLength(6)
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('Iterate.Array', () => {
render(
<Iterate.Array value={['first', 'second', 'third']}>
{renderProp}
</Iterate.Array>,
</Iterate.Array>
)

expect(renderProp).toHaveBeenCalledTimes(3)
Expand All @@ -146,7 +146,7 @@ describe('Iterate.Array', () => {
<Field.String elementPath="/" />
{renderProp1}
{renderProp2}
</Iterate.Array>,
</Iterate.Array>
)

expect(renderProp1).toHaveBeenCalledTimes(4)
Expand All @@ -156,7 +156,7 @@ describe('Iterate.Array', () => {
expect(renderProp1).toHaveBeenNthCalledWith(
4,
{ mem: 'D', second: '2nd' },
3,
3
)

expect(renderProp2).toHaveBeenCalledTimes(4)
Expand All @@ -166,7 +166,7 @@ describe('Iterate.Array', () => {
expect(renderProp2).toHaveBeenNthCalledWith(
4,
{ mem: 'D', second: '2nd' },
3,
3
)
})
})
Expand All @@ -190,7 +190,7 @@ describe('Iterate.Array', () => {
<Field.String elementPath="/" />
<Field.String path="/otherValue" />
</Iterate.Array>
</DataContext.Provider>,
</DataContext.Provider>
)

const fields = document.querySelectorAll('input')
Expand Down
12 changes: 5 additions & 7 deletions packages/dnb-eufemia/src/extensions/forms/Iterate/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ArrayComponent from './Array';
import ArrayPushButton from './ArrayPushButton';
import ArrayRemoveElementButton from './ArrayRemoveElementButton';
import IterateElementContext from './IterateElementContext';
import ArrayComponent from './Array'
import ArrayPushButton from './ArrayPushButton'
import ArrayRemoveElementButton from './ArrayRemoveElementButton'
import IterateElementContext from './IterateElementContext'

const Iterate = {
Array: ArrayComponent,
Expand All @@ -11,6 +11,4 @@ const Iterate = {

export default Iterate

export {
IterateElementContext
};
export { IterateElementContext }
55 changes: 35 additions & 20 deletions packages/dnb-eufemia/src/extensions/forms/hooks/useDataValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ interface ReturnAdditional {
handleChange: FieldProps<unknown>['onChange']
}

export default function useDataValue<Props extends Partial<FieldProps<unknown>>>(
props: Props,
): Props & ReturnAdditional {
export default function useDataValue<
Props extends Partial<FieldProps<unknown>>,
>(props: Props): Props & ReturnAdditional {
const {
path,
elementPath,
Expand All @@ -45,8 +45,8 @@ export default function useDataValue<Props extends Partial<FieldProps<unknown>>>
const id = useMemo(() => props.id ?? makeUniqueId(), [props.id])
const dataContext = useContext(DataContext.Context)
const fieldGroupContext = useContext(FieldGroupContext)
const iterateElementContext = useContext(IterateElementContext);
const iterateElementContext = useContext(IterateElementContext)

const {
handlePathChange: dataContextHandlePathChange,
setPathWithError: dataContextSetPathWithError,
Expand All @@ -65,45 +65,58 @@ export default function useDataValue<Props extends Partial<FieldProps<unknown>>>
} = iterateElementContext ?? {}

if (path && path.substring(0, 1) !== '/') {
throw new Error('Invalid path. Data value path JSON Pointers must be from root (starting with a /).')
throw new Error(
'Invalid path. Data value path JSON Pointers must be from root (starting with a /).'
)
}
if (elementPath && elementPath.substring(0, 1) !== '/') {
throw new Error('Invalid elementPath. Element pathJSON Pointers must be from root of iterate element (starting with a /).')
throw new Error(
'Invalid elementPath. Element pathJSON Pointers must be from root of iterate element (starting with a /).'
)
}
if (elementPath && !iterateElementContext) {
throw new Error('elementPath cannot be used when not inside an iterate element context. Wrap the component in an Iterate.Loop.')
throw new Error(
'elementPath cannot be used when not inside an iterate element context. Wrap the component in an Iterate.Loop.'
)
}

const externalValue = useMemo(() => {
if (props.value !== undefined) {
// Value-prop sent directly to the field has highest priority, overriding any surrounding source
return props.value;
return props.value
}

if (inIterate && elementPath) {
// This field is inside an iterate, and has a pointer from the base of the element being iterated
if (elementPath === '/') {
return iterateElementValue;
return iterateElementValue
}

return pointer.has(iterateElementValue, elementPath)
? pointer.get(iterateElementValue, elementPath)
: undefined;
: undefined
}

if (dataContext.data && path) {
// There is a surrounding data context and a path for where in the source to find the data
if (path === '/') {
return dataContext.data;
return dataContext.data
}

return pointer.has(dataContext.data, path)
? pointer.get(dataContext.data, path)
: undefined;
: undefined
}
return undefined;
}, [path, elementPath, inIterate, iterateElementValue, props.value, dataContext.data])

return undefined
}, [
path,
elementPath,
inIterate,
iterateElementValue,
props.value,
dataContext.data,
])

// Hold an internal copy of the input value in case the input component is used uncontrolled,
// and to handle errors in Eufemia on components that does not take updated callback functions into account.
const [value, setValue] = useState(externalValue)
Expand Down Expand Up @@ -267,7 +280,7 @@ export default function useDataValue<Props extends Partial<FieldProps<unknown>>>
const handleChange = useCallback(
(argFromInput) => {
const newValue = fromInput(argFromInput)

if (newValue === value) {
// Avoid triggering a change if the value was not actually changed. This may be caused by rendering components
// calling onChange even if the actual value did not change.
Expand All @@ -287,8 +300,10 @@ export default function useDataValue<Props extends Partial<FieldProps<unknown>>>
dataContextHandlePathChange?.(path, newValue)
}
if (elementPath) {
const iteratValuePath = `/${iterateElementIndex}${(elementPath && elementPath !== '/') ? elementPath : ''}`;
handleIterateElementChange?.(iteratValuePath, newValue);
const iteratValuePath = `/${iterateElementIndex}${
elementPath && elementPath !== '/' ? elementPath : ''
}`
handleIterateElementChange?.(iteratValuePath, newValue)
}
},
[
Expand Down
22 changes: 12 additions & 10 deletions packages/dnb-eufemia/src/extensions/forms/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,17 @@ interface DefaultErrorMessages {
required?: string
}

export interface DataValueReadProps<
Value = unknown,
> {
export interface DataValueReadProps<Value = unknown> {
/** JSON Pointer for where the data for this field is located in the source dataset */
path?: string
/** JSON Pointer for where the data for this field is located in the source iterate loop element */
elementPath?: string;
elementPath?: string
value?: Value
}

export interface DataValueWriteProps<
Value = unknown,
EmptyValue = undefined | string | number
EmptyValue = undefined | string | number,
> {
emptyValue?: EmptyValue
onFocus?: (value: Value | EmptyValue) => void
Expand All @@ -55,7 +53,9 @@ export interface FieldProps<
Value = unknown,
EmptyValue = undefined | string | number,
ErrorMessages extends { required?: string } = DefaultErrorMessages,
> extends ComponentProps, DataValueReadProps<Value>, DataValueWriteProps<Value, EmptyValue> {
> extends ComponentProps,
DataValueReadProps<Value>,
DataValueWriteProps<Value, EmptyValue> {
/** ID added to the actual field component, and linked to the label via for-attribute */
id?: string
layout?: 'horizontal' | 'vertical'
Expand All @@ -75,10 +75,10 @@ export interface FieldProps<
required?: boolean
schema?: JSONSchema7
validator?: (
value: Value | EmptyValue,
value: Value | EmptyValue
) => Error | undefined | Promise<Error | undefined>
onBlurValidator?: (
value: Value | EmptyValue,
value: Value | EmptyValue
) => Error | undefined | Promise<Error | undefined>
/**
* Should error messages based on validation be shown initially (from given value-prop or source data)
Expand Down Expand Up @@ -106,14 +106,16 @@ export interface FieldHelpProps {
}
}

export interface ValueProps<Value> extends ComponentProps, DataValueReadProps<Value> {
export interface ValueProps<Value>
extends ComponentProps,
DataValueReadProps<Value> {
label?: string
/** Should the component render if the value is empty? */
showEmpty?: boolean
/** Text showing in place of the value if no value is given. */
placeholder?: string
/** JSON Pointer for where the data for this field is located in the source iterate loop element */
elementPath?: string;
elementPath?: string
/** For showing the value inline (not as a block element) */
inline?: boolean
// Derivatives
Expand Down

0 comments on commit 34aaeca

Please sign in to comment.