-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ObjectBase): add inline variant #104
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@import '../../../styles/variables.scss'; | ||
|
||
.#{$ns}object-base { | ||
&__content { | ||
&_inline { | ||
display: flex; | ||
|
||
& > .#{$ns}use-search { | ||
width: 150px; | ||
margin-bottom: 0; | ||
margin-right: 8px; | ||
|
||
&:last-child { | ||
margin-right: 0; | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,13 +9,28 @@ import { | |
FieldObjectValue, | ||
FieldValue, | ||
ObjectIndependentInput, | ||
ObjectIndependentInputProps, | ||
ObjectValue, | ||
Spec, | ||
ValidateError, | ||
transformArrIn, | ||
} from '../../../../core'; | ||
import {block, filterPropertiesForObjectInline} from '../../../utils'; | ||
|
||
export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restProps}) => { | ||
import './ObjectBase.scss'; | ||
|
||
const b = block('object-base'); | ||
|
||
export interface ObjectBaseProps extends ObjectIndependentInputProps { | ||
inline?: boolean; | ||
} | ||
|
||
export const ObjectBase: React.FC<ObjectBaseProps> = ({ | ||
inline, | ||
spec, | ||
name, | ||
Layout, | ||
...restProps | ||
}) => { | ||
const addBtn = React.useMemo( | ||
() => ( | ||
<Button | ||
|
@@ -49,18 +64,24 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP | |
); | ||
|
||
const content = React.useMemo(() => { | ||
if (!_.isObjectLike(spec.properties) || !Object.keys(spec.properties || {}).length) { | ||
if ( | ||
!spec.properties || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems this check is not needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is required for typings. Otherwise we have to make type casting |
||
!_.isObjectLike(spec.properties) || | ||
!Object.keys(spec.properties || {}).length | ||
) { | ||
return null; | ||
} | ||
|
||
if (!restProps.input.value) { | ||
if (!inline && !restProps.input.value) { | ||
return addBtn; | ||
} | ||
|
||
const specProperties = {...spec.properties} as Record<string, Spec>; | ||
const specProperties = inline | ||
? filterPropertiesForObjectInline(spec.properties) | ||
: spec.properties; | ||
|
||
return ( | ||
<React.Fragment> | ||
<div className={b('content', {inline})}> | ||
{(spec.viewSpec.order || Object.keys(specProperties)).map((property: string) => | ||
specProperties[property] ? ( | ||
<Controller | ||
|
@@ -73,16 +94,17 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP | |
/> | ||
) : null, | ||
)} | ||
</React.Fragment> | ||
</div> | ||
); | ||
}, [ | ||
spec.properties, | ||
spec.viewSpec.order, | ||
name, | ||
restProps.input.value, | ||
restProps.input.parentOnUnmount, | ||
inline, | ||
addBtn, | ||
name, | ||
parentOnChange, | ||
restProps.input.parentOnUnmount, | ||
]); | ||
|
||
if (!Layout || !content) { | ||
|
@@ -95,3 +117,7 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP | |
</Layout> | ||
); | ||
}; | ||
|
||
export const ObjectInline: ObjectIndependentInput = (props) => { | ||
return <ObjectBase {...props} inline />; | ||
}; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@import '../../../styles/variables.scss'; | ||
|
||
.#{$ns}object-base-view { | ||
&__content { | ||
&_inline { | ||
display: flex; | ||
|
||
& > div { | ||
flex: auto; | ||
margin-right: 8px; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
margin-bottom: 0; | ||
|
||
&:last-child { | ||
margin-right: 0; | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from 'react'; | ||
|
||
import _ from 'lodash'; | ||
|
||
import {ObjectIndependentView, ObjectIndependentViewProps, ViewController} from '../../../../core'; | ||
import {block, filterPropertiesForObjectInline} from '../../../utils'; | ||
|
||
import './ObjectBaseView.scss'; | ||
|
||
const b = block('object-base-view'); | ||
|
||
export interface ObjectBaseViewProps extends ObjectIndependentViewProps { | ||
inline?: boolean; | ||
} | ||
|
||
export const ObjectBaseView: React.FC<ObjectBaseViewProps> = ({ | ||
inline, | ||
spec, | ||
name, | ||
Layout, | ||
...restProps | ||
}) => { | ||
if (!spec.properties || !_.isObjectLike(spec.properties)) { | ||
return null; | ||
} | ||
|
||
const specProperties = inline | ||
? filterPropertiesForObjectInline(spec.properties) | ||
: spec.properties; | ||
|
||
const content = ( | ||
<div className={b('content', {inline})}> | ||
{(spec.viewSpec.order || Object.keys(specProperties)).map((property: string) => | ||
specProperties[property] ? ( | ||
<ViewController | ||
spec={specProperties[property]} | ||
name={`${name ? name + '.' : ''}${property}`} | ||
key={`${name ? name + '.' : ''}${property}`} | ||
/> | ||
) : null, | ||
)} | ||
</div> | ||
); | ||
|
||
if (!Layout) { | ||
return content; | ||
} | ||
|
||
return ( | ||
<Layout spec={spec} name={name} {...restProps}> | ||
{content} | ||
</Layout> | ||
); | ||
}; | ||
|
||
export const ObjectInlineView: ObjectIndependentView = (props) => { | ||
return <ObjectBaseView {...props} inline />; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './ObjectBaseView'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './cn'; | ||
export * from './common'; | ||
export * from './bigIntMath'; | ||
export * from './objectInline'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import {Spec, isNumberSpec, isStringSpec} from '../../core'; | ||
|
||
export const filterPropertiesForObjectInline = (properties: Record<string, Spec>) => { | ||
return Object.fromEntries( | ||
Object.entries(properties).filter( | ||
([, propSpec]) => isStringSpec(propSpec) || isNumberSpec(propSpec), | ||
), | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import React from 'react'; | ||
|
||
import {StoryFn} from '@storybook/react'; | ||
|
||
import {ObjectInline as ObjectInlineBase, ObjectSpec, SpecTypes} from '../lib'; | ||
|
||
import {InputPreview} from './components'; | ||
|
||
export default { | ||
title: 'Object/Inline', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rename it to objectInline - as objectValue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But for |
||
component: ObjectInlineBase, | ||
}; | ||
|
||
const baseSpec: ObjectSpec = { | ||
type: SpecTypes.Object, | ||
properties: { | ||
type: { | ||
type: SpecTypes.String, | ||
enum: ['first', 'second', 'third'], | ||
viewSpec: { | ||
type: 'select', | ||
placeholder: 'Choose type', | ||
layout: 'transparent', | ||
layoutTitle: 'Type', | ||
}, | ||
}, | ||
name: { | ||
type: SpecTypes.String, | ||
viewSpec: { | ||
type: 'base', | ||
placeholder: 'Type your name', | ||
layout: 'transparent', | ||
layoutTitle: 'Name', | ||
}, | ||
}, | ||
}, | ||
viewSpec: { | ||
type: 'inline', | ||
layout: 'row', | ||
layoutTitle: 'Candidate', | ||
}, | ||
}; | ||
|
||
const value = {type: 'first', name: 'Foo'}; | ||
|
||
const excludeOptions = [ | ||
'description', | ||
'viewSpec.type', | ||
'viewSpec.oneOfParams', | ||
'viewSpec.placeholder', | ||
]; | ||
|
||
const template = (spec: ObjectSpec = baseSpec) => { | ||
const Template: StoryFn<typeof ObjectInlineBase> = (__, {viewMode}) => ( | ||
<InputPreview | ||
spec={spec} | ||
value={value} | ||
excludeOptions={excludeOptions} | ||
viewMode={viewMode} | ||
/> | ||
); | ||
|
||
return Template; | ||
}; | ||
|
||
export const Inline = template(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's make the same width for each child input