Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f28608e
commit 8db47d3
Showing
13 changed files
with
424 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import propBasedCssClassService from '@base/services/prop-based-css-class/prop-based-css-class'; | ||
|
||
const _public = {}; | ||
|
||
_public.buildCssClasses = ({ required, blocked, element } = {}) => { | ||
const baseCssClass = getBaseCssClass(); | ||
const cssClasses = [baseCssClass, buildRequiredCssClass(required, element, baseCssClass)]; | ||
propBasedCssClassService.handleBooleanProp( | ||
{ blocked }, | ||
isValidBooleanProp, | ||
cssClasses, | ||
baseCssClass | ||
); | ||
return cssClasses.join(' ').replace(/\s+/g, ' ').trim(); | ||
}; | ||
|
||
function getBaseCssClass(){ | ||
return 't-field'; | ||
} | ||
|
||
function isValidBooleanProp(propName){ | ||
return ['blocked'].includes(propName); | ||
} | ||
|
||
function buildRequiredCssClass(required, element, baseCssClass){ | ||
return shouldAppendRequiredCssClass(required, element) ? `${baseCssClass}-required` : ''; | ||
} | ||
|
||
function shouldAppendRequiredCssClass(required, element){ | ||
if(required) | ||
return true; | ||
if(required === undefined) | ||
return containsRequiredFormControl(element); | ||
} | ||
|
||
function containsRequiredFormControl(element){ | ||
return element && !!element.querySelector('[required]'); | ||
} | ||
|
||
export default _public; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import fieldService from './field'; | ||
|
||
describe('Field Service', () => { | ||
it('should build css classes', () => { | ||
expect(fieldService.buildCssClasses()).toEqual('t-field'); | ||
}); | ||
|
||
it('should append required modifier css class if field contains a required form control', () => { | ||
const fieldEl = document.createElement('div'); | ||
const inputEl = document.createElement('input'); | ||
inputEl.setAttribute('required',''); | ||
fieldEl.appendChild(inputEl); | ||
expect(fieldService.buildCssClasses({ element: fieldEl }).includes('t-field-required')).toEqual(true); | ||
}); | ||
|
||
it('should optionally append required modifier css class programmatically', () => { | ||
const cssClasses = fieldService.buildCssClasses({ required: true }); | ||
expect(cssClasses).toEqual('t-field t-field-required'); | ||
}); | ||
|
||
it('should optionally not append required modifier css class programmatically', () => { | ||
const cssClasses = fieldService.buildCssClasses({ required: false }); | ||
expect(cssClasses).toEqual('t-field'); | ||
}); | ||
|
||
it('should append blocked modifier css class if it has been given as true', () => { | ||
const cssClasses = fieldService.buildCssClasses({ blocked: true }); | ||
expect(cssClasses).toEqual('t-field t-field-blocked'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
.t-field | ||
display inline-block | ||
&.t-field-blocked | ||
display block | ||
&.t-field-required | ||
.t-field-label | ||
&:after | ||
content '*' | ||
position absolute | ||
top 0 | ||
right -8px | ||
color var(--t-color-red) | ||
|
||
.t-field-label | ||
position relative | ||
color var(--t-color-grey-dark) | ||
font-size var(--t-font-size-xxs) | ||
font-weight bold | ||
& + .t-field-content | ||
margin-top 5px |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
module.exports = { | ||
name: 'Field', | ||
description: 'Container for form controls like input, select or textarea.', | ||
properties: [ | ||
{ | ||
name: 'label', | ||
type: 'String', | ||
values: 'Any', | ||
required: true | ||
}, | ||
{ | ||
name: 'required', | ||
type: 'Boolean', | ||
values: 'true, false' | ||
}, | ||
{ | ||
name: 'blocked', | ||
type: 'Boolean', | ||
values: 'true, false' | ||
} | ||
], | ||
examples: [ | ||
{ | ||
title: 'Default Field', | ||
controller: function(){ | ||
const { Field, Input } = taslonicReact; | ||
|
||
return function(){ | ||
return ( | ||
<Field label="Name"> | ||
<Input /> | ||
</Field> | ||
); | ||
} | ||
} | ||
}, | ||
{ | ||
title: 'Required Field', | ||
description: 'If you pass a required form control to the field, it will automatically show an asterisk mark.', | ||
controller: function(){ | ||
const { Field, Input } = taslonicReact; | ||
|
||
return function(){ | ||
return ( | ||
<Field label="Name"> | ||
<Input required /> | ||
</Field> | ||
); | ||
} | ||
} | ||
}, | ||
{ | ||
title: 'Dynamic Required Field', | ||
description: 'You can optionally control the asterisk mark visibility regardless of the form control passed to the field.', | ||
controller: function(){ | ||
const { useState } = React; | ||
const { Field, Input, Row, Col, Button } = taslonicReact; | ||
|
||
return function(){ | ||
const [required, setRequired] = useState(true); | ||
|
||
return ( | ||
<> | ||
<Row> | ||
<Col> | ||
<Field label="Name" required={required}> | ||
<Input required={required} /> | ||
</Field> | ||
</Col> | ||
</Row> | ||
<Row> | ||
<Col> | ||
<Button onClick={() => setRequired(!required)}> | ||
Toggle Required | ||
</Button> | ||
</Col> | ||
</Row> | ||
</> | ||
); | ||
} | ||
} | ||
}, | ||
{ | ||
title: 'Blocked Field', | ||
description: 'Blocked fields behave like a block.', | ||
controller: function(){ | ||
const { useState } = React; | ||
const { Field, Input, Row, Col } = taslonicReact; | ||
|
||
return function(){ | ||
const [required, setRequired] = useState(true); | ||
|
||
return ( | ||
<Row> | ||
<Col md="6"> | ||
<Field label="First Name" blocked> | ||
<Input blocked /> | ||
</Field> | ||
</Col> | ||
<Col md="6"> | ||
<Field label="Last Name" blocked> | ||
<Input blocked /> | ||
</Field> | ||
</Col> | ||
</Row> | ||
); | ||
} | ||
} | ||
} | ||
] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React, { useState, useEffect, useRef } from 'react'; | ||
import fieldService from '@base/services/field/field'; | ||
|
||
export const Field = ({ label, required, blocked, children }) => { | ||
const [cssClasses, setCssClasses] = useState(''); | ||
const fieldElement = useRef(); | ||
|
||
useEffect(() => { | ||
setCssClasses(buildCssClasses(required, blocked, fieldElement.current)); | ||
}, [required, blocked, fieldElement, setCssClasses]); | ||
|
||
return ( | ||
<span ref={fieldElement} className={cssClasses}> | ||
<label className="t-field-label"> | ||
{ label } | ||
</label> | ||
<div className="t-field-content"> | ||
{children} | ||
</div> | ||
</span> | ||
); | ||
}; | ||
|
||
function buildCssClasses(required, blocked, element){ | ||
return fieldService.buildCssClasses({ required, blocked, element }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from 'react'; | ||
import { mount } from 'enzyme'; | ||
import testingService from '@react/services/testing/testing'; | ||
import { Field } from './field'; | ||
|
||
describe('Field', () => { | ||
function mountComponent({ label, required, blocked } = {}, content = <input />){ | ||
return mount( | ||
<Field label={ label } required={ required } blocked={ blocked }> | ||
{ content } | ||
</Field> | ||
); | ||
} | ||
|
||
it('should have base css class', () => { | ||
const wrapper = mountComponent(); | ||
expect(testingService.getRootElProp(wrapper, 'className')).toEqual('t-field'); | ||
}); | ||
|
||
it('should render a label', () => { | ||
const label = 'Email'; | ||
const wrapper = mountComponent({ label }); | ||
expect(wrapper.find('label').text()).toEqual(label); | ||
}); | ||
|
||
it('should contain required css class if required prop has been given as true', () => { | ||
const wrapper = mountComponent({ required: true }); | ||
expect(testingService.getRootElProp(wrapper, 'className').includes('t-field-required')).toEqual(true); | ||
}); | ||
|
||
it('should contain required css class if no required prop has been passed but content is required', () => { | ||
const wrapper = mountComponent({}, <input type="text" required />); | ||
expect(testingService.getRootElProp(wrapper, 'className').includes('t-field-required')).toEqual(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
module.exports = { | ||
name: 'Field', | ||
description: 'Container for form controls like input, select or textarea.', | ||
properties: [ | ||
{ | ||
name: 'label', | ||
type: 'String', | ||
values: 'Any', | ||
required: true | ||
}, | ||
{ | ||
name: 'required', | ||
type: 'Boolean', | ||
values: 'true, false' | ||
}, | ||
{ | ||
name: 'blocked', | ||
type: 'Boolean', | ||
values: 'true, false' | ||
} | ||
], | ||
examples: [ | ||
{ | ||
title: 'Default Field', | ||
template: ` | ||
<t-field label="Name"> | ||
<t-input /> | ||
</t-field> | ||
` | ||
}, | ||
{ | ||
title: 'Required Field', | ||
description: 'If you pass a required form control to the field, it will automatically show an asterisk mark.', | ||
template: ` | ||
<t-field label="Name"> | ||
<t-input required /> | ||
</t-field> | ||
` | ||
}, | ||
{ | ||
title: 'Dynamic Required Field', | ||
description: 'You can optionally control the asterisk mark visibility regardless of the form control passed to the field.', | ||
controller: { | ||
data(){ | ||
return { | ||
required: true | ||
}; | ||
}, | ||
methods: { | ||
toggleRequired(){ | ||
this.required = !this.required; | ||
} | ||
} | ||
}, | ||
template: ` | ||
<div> | ||
<t-row> | ||
<t-col> | ||
<t-field label="Name" :required="required"> | ||
<t-input :required="required" /> | ||
</t-field> | ||
</t-col> | ||
</t-row> | ||
<t-row> | ||
<t-col> | ||
<t-button @click="toggleRequired"> | ||
Toggle Required | ||
</t-button> | ||
</t-col> | ||
</t-row> | ||
</div> | ||
` | ||
}, | ||
{ | ||
title: 'Blocked Field', | ||
description: 'Blocked fields behave like a block.', | ||
template: ` | ||
<t-row> | ||
<t-col md="6"> | ||
<t-field label="First Name" blocked> | ||
<t-input blocked /> | ||
</t-field> | ||
</t-col> | ||
<t-col md="6"> | ||
<t-field label="Last Name" blocked> | ||
<t-input blocked /> | ||
</t-field> | ||
</t-col> | ||
</t-row> | ||
` | ||
} | ||
] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<span :class="classes"> | ||
<label class="t-field-label"> | ||
{{ label }} | ||
</label> | ||
<div class="t-field-content"> | ||
<slot></slot> | ||
</div> | ||
</span> |
Oops, something went wrong.