Add event handler props for components.tags/0.3.0
@@ -48,7 +48,7 @@ describe('on unknown kinds', () => { | |||
it('should render null', () => { | |||
fc.assert( | |||
fc.property(fc.string().filter(s => !['button', 'a'].includes(s)), (element) => { | |||
fc.property(fc.string().filter((s) => !['button', 'a'].includes(s)), (element) => { | |||
const wrapper = Enzyme.shallow(<Button element={element as ButtonElement} />) | |||
expect(wrapper.isEmptyRender()).toBe(true) | |||
@@ -156,6 +156,18 @@ const propTypes = { | |||
* Does the button display a border? | |||
*/ | |||
border: PropTypes.bool, | |||
/** | |||
* Event handler triggered when the component is clicked. | |||
*/ | |||
onClick: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component receives focus. | |||
*/ | |||
onFocus: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -173,7 +185,9 @@ const Button = React.forwardRef<HTMLAnchorElement | HTMLButtonElement | HTMLSpan | |||
rel, | |||
type = 'button', | |||
border = false, | |||
...etcProps | |||
onClick, | |||
onFocus, | |||
onBlur, | |||
}, | |||
ref, | |||
) => { | |||
@@ -184,12 +198,7 @@ const Button = React.forwardRef<HTMLAnchorElement | HTMLButtonElement | HTMLSpan | |||
} | |||
const buttonContent = ( | |||
<React.Fragment> | |||
{ | |||
border | |||
&& ( | |||
<Border /> | |||
) | |||
} | |||
{border && <Border />} | |||
{stringify(children)} | |||
</React.Fragment> | |||
) | |||
@@ -197,26 +206,36 @@ const Button = React.forwardRef<HTMLAnchorElement | HTMLButtonElement | HTMLSpan | |||
switch (element) { | |||
case 'button': | |||
return ( | |||
<Base {...etcProps} type={type!} ref={ref as React.Ref<HTMLButtonElement>} disabled={disabled!} style={commonButtonStyles}> | |||
<Base | |||
onClick={onClick as React.EventHandler<React.SyntheticEvent>} | |||
type={type!} | |||
ref={ref as React.Ref<HTMLButtonElement>} | |||
disabled={disabled!} | |||
style={commonButtonStyles} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
> | |||
{buttonContent} | |||
</Base> | |||
) | |||
case 'a': | |||
if (disabled) { | |||
return ( | |||
<DisabledLinkBase {...etcProps} ref={ref as React.Ref<HTMLSpanElement>} style={commonButtonStyles}> | |||
<DisabledLinkBase ref={ref as React.Ref<HTMLSpanElement>} style={commonButtonStyles}> | |||
{buttonContent} | |||
</DisabledLinkBase> | |||
) | |||
} | |||
return ( | |||
<LinkBase | |||
{...etcProps} | |||
onClick={onClick as React.EventHandler<React.SyntheticEvent>} | |||
href={href!} | |||
target={target!} | |||
rel={rel!} | |||
ref={ref as React.Ref<HTMLAnchorElement>} | |||
style={commonButtonStyles} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
> | |||
{buttonContent} | |||
</LinkBase> | |||
@@ -123,6 +123,18 @@ const propTypes = { | |||
* Name of the form field associated with this component. | |||
*/ | |||
name: PropTypes.string, | |||
/** | |||
* Event handler triggered when the component is toggled. | |||
*/ | |||
onChange: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component receives focus. | |||
*/ | |||
onFocus: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -133,10 +145,17 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
* @see {@link RadioButton} for a similar component on selecting a single value among very few choices. | |||
* @type {React.ComponentType<{readonly label?: string} & React.ClassAttributes<unknown>>} | |||
*/ | |||
const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', name, }, ref) => ( | |||
const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', name, onChange, onFocus, onBlur }, ref) => ( | |||
<Base> | |||
<CaptureArea> | |||
<Input ref={ref} type="checkbox" name={name!} /> | |||
<Input | |||
ref={ref} | |||
type="checkbox" | |||
name={name!} | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
/> | |||
<IndicatorWrapper> | |||
<Border /> | |||
<Indicator> | |||
@@ -43,12 +43,7 @@ const propTypes = { | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
const Icon: React.FC<Props> = ({ | |||
name, | |||
weight = '0.125rem', | |||
size = '1.5rem', | |||
label = name, | |||
}) => { | |||
const Icon: React.FC<Props> = ({ name, weight = '0.125rem', size = '1.5rem', label = name }) => { | |||
const iconName = pascalCase(name, { transform: pascalCaseTransformMerge }) | |||
const { [iconName as keyof typeof FeatherIcon]: TheIcon = null } = FeatherIcon | |||
const { magnitude: sizeValue, unit: sizeUnit } = splitValueAndUnit(size) | |||
@@ -121,6 +121,18 @@ const propTypes = { | |||
* Short textual description indicating the nature of the component's value. | |||
*/ | |||
label: PropTypes.any, | |||
/** | |||
* Event handler triggered when the component is selected. | |||
*/ | |||
onChange: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component receives focus. | |||
*/ | |||
onFocus: PropTypes.func, | |||
/** | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -132,13 +144,17 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
* @type {React.ComponentType<{readonly label?: string, readonly name?: string} & React.ClassAttributes<unknown>>} | |||
*/ | |||
const RadioButton = React.forwardRef<HTMLInputElement, Props>( | |||
( | |||
{ label = '', name, }, | |||
ref | |||
) => ( | |||
({ label = '', name, onChange, onFocus, onBlur }, ref) => ( | |||
<Base> | |||
<CaptureArea> | |||
<Input ref={ref} name={name} type="radio" /> | |||
<Input | |||
ref={ref} | |||
name={name} | |||
type="radio" | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
/> | |||
<IndicatorWrapper> | |||
<Border /> | |||
<Indicator /> | |||
@@ -149,7 +165,7 @@ const RadioButton = React.forwardRef<HTMLInputElement, Props>( | |||
</Label> | |||
</CaptureArea> | |||
</Base> | |||
) | |||
), | |||
) | |||
RadioButton.propTypes = propTypes | |||
@@ -242,12 +242,7 @@ const Select = React.forwardRef<HTMLSelectElement, Props>( | |||
opacity: disabled ? 0.5 : undefined, | |||
}} | |||
> | |||
{ | |||
border | |||
&& ( | |||
<Border /> | |||
) | |||
} | |||
{border && <Border />} | |||
<CaptureArea> | |||
<LabelWrapper | |||
style={{ | |||
@@ -204,6 +204,10 @@ const propTypes = { | |||
* Is the component active? | |||
*/ | |||
disabled: PropTypes.bool, | |||
/** | |||
* Event handler triggered when the component changes value. | |||
*/ | |||
onChange: PropTypes.func, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -226,6 +230,7 @@ const Slider: React.FC<Props> = ({ | |||
label = '', | |||
length = '16rem', | |||
disabled = false, | |||
onChange, | |||
}) => { | |||
const [isClient, setIsClient] = React.useState(false) | |||
@@ -295,6 +300,7 @@ const Slider: React.FC<Props> = ({ | |||
padding: orientation === 'horizontal' ? '0.875rem 0.75rem' : '0.75rem 0.875rem', | |||
cursor: disabled ? 'not-allowed' : undefined, | |||
}} | |||
onChange={onChange!} | |||
> | |||
<Track> | |||
<Highlight | |||
@@ -361,6 +367,7 @@ const Slider: React.FC<Props> = ({ | |||
width: length!, | |||
}} | |||
disabled={disabled!} | |||
onChange={onChange!} | |||
type="range" | |||
/> | |||
</ClickArea> | |||
@@ -70,7 +70,7 @@ describe.each` | |||
multiline | tag | |||
${false} | ${'input'} | |||
${true} | ${'textarea'} | |||
`('on multiline (multiline=$multiline)', ({ tag: rawTag, multiline: rawMultiline, }) => { | |||
`('on multiline (multiline=$multiline)', ({ tag: rawTag, multiline: rawMultiline }) => { | |||
const tag = rawTag as string | |||
const multiline = rawMultiline as boolean | |||
@@ -279,12 +279,7 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
opacity: disabled ? 0.5 : undefined, | |||
}} | |||
> | |||
{ | |||
border | |||
&& ( | |||
<Border /> | |||
) | |||
} | |||
{border && <Border />} | |||
<CaptureArea> | |||
<LabelWrapper | |||
style={{ | |||
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "@tesseract-design/react-common", | |||
"version": "0.1.1", | |||
"version": "0.2.0", | |||
"description": "Common front-end components for Web using the Tesseract design system, written in React.", | |||
"directories": { | |||
"lib": "dist" | |||
@@ -37,7 +37,15 @@ | |||
"rollup-plugin-terser": "5.3.0", | |||
"ts-jest": "^26.1.3", | |||
"tslib": "^2.0.0", | |||
"typescript": "^3.9.7" | |||
"typescript": "^3.9.7", | |||
"@reach/slider": "^0.10.5", | |||
"docz": "^2.3.1", | |||
"pascal-case": "3.1.1", | |||
"prop-types": "15.7.2", | |||
"react": "16.13.1", | |||
"react-dom": "16.13.1", | |||
"react-feather": "2.0.3", | |||
"styled-components": "5.1.0" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c", | |||
@@ -46,7 +54,7 @@ | |||
"generate": "plop", | |||
"docs": "docz" | |||
}, | |||
"dependencies": { | |||
"peerDependencies": { | |||
"@reach/slider": "^0.10.5", | |||
"docz": "^2.3.1", | |||
"pascal-case": "3.1.1", | |||