-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* components: Add `BaseField` * Give better tests and fix types * Remove unnecessary eslint disable * Remove isFocused prop * Rename error to include a verb * Fix admin colors * Remove unused manual focus styles * Fix README for removed/updated props * Remove component and update tests * Update packages/components/src/base-field/hook.js Co-authored-by: Marco Ciampini <marco.ciampo@gmail.com> * Fully remove isClickable Co-authored-by: Marco Ciampini <marco.ciampo@gmail.com>
- Loading branch information
1 parent
af89254
commit 8f29773
Showing
10 changed files
with
479 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
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,67 @@ | ||
# BaseField | ||
|
||
<div class="callout callout-alert"> | ||
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes. | ||
</div> | ||
|
||
`BaseField` is an internal (i.e., not exported in the `index.js`) primitive component used for building more complex fields like `TextField`. It provides error handling and focus styles for field components. It does _not_ handle layout of the component aside from wrapping the field in a `Flex` wrapper. | ||
|
||
## Usage | ||
|
||
`BaseField` is primarily used as a hook rather than a component: | ||
|
||
```js | ||
function useExampleField( props ) { | ||
const { | ||
as = 'input', | ||
...baseProps, | ||
} = useBaseField( props ); | ||
|
||
const inputProps = { | ||
as, | ||
// more cool stuff here | ||
} | ||
|
||
return { inputProps, ...baseProps }; | ||
} | ||
|
||
function ExampleField( props, forwardRef ) { | ||
const { | ||
preFix, | ||
affix, | ||
disabled, | ||
inputProps, | ||
...baseProps | ||
} = useExampleField( props ); | ||
|
||
return ( | ||
<View { ...baseProps } disabled={ disabled }> | ||
{preFix} | ||
<View | ||
autocomplete="off" | ||
{ ...inputProps } | ||
disabled={ disabled } | ||
/> | ||
{affix} | ||
</View> | ||
); | ||
} | ||
``` | ||
|
||
## Props | ||
|
||
### `hasError`: `boolean` | ||
|
||
Renders an error style around the component. | ||
|
||
### `disabled`: `boolean` | ||
|
||
Whether the field is disabled. | ||
|
||
### `isInline`: `boolean` | ||
|
||
Renders a component that can be inlined in some text. | ||
|
||
### `isSubtle`: `boolean` | ||
|
||
Renders a subtle variant of the component. |
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,64 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { cx } from 'emotion'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useMemo } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { useContextSystem } from '../ui/context'; | ||
import { useControlGroupContext } from '../ui/control-group'; | ||
import { useFlex } from '../flex'; | ||
import * as styles from './styles'; | ||
|
||
/** | ||
* @typedef OwnProps | ||
* @property {boolean} [hasError=false] Renders an error. | ||
* @property {boolean} [disabled] Whether the field is disabled. | ||
* @property {boolean} [isInline=false] Renders as an inline element (layout). | ||
* @property {boolean} [isSubtle=false] Renders a subtle variant. | ||
*/ | ||
|
||
/** @typedef {import('../flex/types').FlexProps & OwnProps} Props */ | ||
|
||
/** | ||
* @param {import('../ui/context').PolymorphicComponentProps<Props, 'div'>} props | ||
*/ | ||
export function useBaseField( props ) { | ||
const { | ||
className, | ||
hasError = false, | ||
isInline = false, | ||
isSubtle = false, | ||
// extract these because useFlex doesn't accept it | ||
defaultValue, | ||
disabled, | ||
...flexProps | ||
} = useContextSystem( props, 'BaseField' ); | ||
|
||
const { styles: controlGroupStyles } = useControlGroupContext(); | ||
|
||
const classes = useMemo( | ||
() => | ||
cx( | ||
styles.BaseField, | ||
controlGroupStyles, | ||
isSubtle && styles.subtle, | ||
hasError && styles.error, | ||
isInline && styles.inline, | ||
className | ||
), | ||
[ className, controlGroupStyles, hasError, isInline, isSubtle ] | ||
); | ||
|
||
return { | ||
...useFlex( { ...flexProps, className: classes } ), | ||
disabled, | ||
defaultValue, | ||
}; | ||
} |
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 @@ | ||
export { useBaseField } from './hook'; |
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,86 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { css } from 'emotion'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { CONFIG, COLORS, reduceMotion } from '../utils'; | ||
import { safariOnly } from '../utils/browsers'; | ||
|
||
export const BaseField = css` | ||
background: ${ CONFIG.controlBackgroundColor }; | ||
border-radius: ${ CONFIG.controlBorderRadius }; | ||
border: 1px solid; | ||
border-color: ${ CONFIG.controlBorderColor }; | ||
box-shadow: ${ CONFIG.controlBoxShadow }; | ||
display: flex; | ||
flex: 1; | ||
font-size: ${ CONFIG.fontSize }; | ||
outline: none; | ||
padding: 0 8px; | ||
position: relative; | ||
transition: border-color ${ CONFIG.transitionDurationFastest } ease; | ||
${ reduceMotion( 'transition' ) } | ||
width: 100%; | ||
&[disabled] { | ||
opacity: 0.6; | ||
} | ||
&:hover { | ||
border-color: ${ CONFIG.controlBorderColorHover }; | ||
} | ||
&:focus, | ||
&[data-focused='true'] { | ||
border-color: ${ COLORS.admin.theme }; | ||
box-shadow: ${ CONFIG.controlBoxShadowFocus }; | ||
} | ||
`; | ||
|
||
export const subtle = css` | ||
background-color: transparent; | ||
&:hover, | ||
&:active, | ||
&:focus, | ||
&[data-focused='true'] { | ||
background: ${ CONFIG.controlBackgroundColor }; | ||
} | ||
`; | ||
|
||
export const error = css` | ||
border-color: ${ CONFIG.controlDestructiveBorderColor }; | ||
&:hover, | ||
&:active { | ||
border-color: ${ CONFIG.controlDestructiveBorderColor }; | ||
} | ||
&:focus, | ||
&[data-focused='true'] { | ||
border-color: ${ CONFIG.controlDestructiveBorderColor }; | ||
box-shadow: 0 0 0, 0.5px, ${ CONFIG.controlDestructiveBorderColor }; | ||
} | ||
`; | ||
|
||
export const errorFocus = css` | ||
border-color: ${ CONFIG.controlDestructiveBorderColor }; | ||
box-shadow: 0 0 0, 0.5px, ${ CONFIG.controlDestructiveBorderColor }; | ||
&:hover { | ||
border-color: ${ CONFIG.controlDestructiveBorderColor }; | ||
} | ||
`; | ||
|
||
export const inline = css` | ||
display: inline-flex; | ||
vertical-align: baseline; | ||
width: auto; | ||
${ safariOnly` | ||
vertical-align: middle; | ||
` } | ||
`; |
143 changes: 143 additions & 0 deletions
143
packages/components/src/base-field/test/__snapshots__/index.js.snap
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,143 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`base field props should render error styles 1`] = ` | ||
Snapshot Diff: | ||
- Received styles | ||
+ Base styles | ||
@@ -12,11 +12,11 @@ | ||
"-webkit-justify-content": "space-between", | ||
"-webkit-transition": "border-color 100ms ease", | ||
"align-items": "center", | ||
"background": "#fff", | ||
"border": "1px solid", | ||
- "border-color": "#d94f4f", | ||
+ "border-color": "#757575", | ||
"border-radius": "2px", | ||
"box-shadow": "transparent", | ||
"display": "flex", | ||
"flex": "1", | ||
"flex-direction": "row", | ||
`; | ||
|
||
exports[`base field props should render inline styles 1`] = ` | ||
Snapshot Diff: | ||
- Received styles | ||
+ Base styles | ||
@@ -15,18 +15,17 @@ | ||
"background": "#fff", | ||
"border": "1px solid", | ||
"border-color": "#757575", | ||
"border-radius": "2px", | ||
"box-shadow": "transparent", | ||
- "display": "inline-flex", | ||
+ "display": "flex", | ||
"flex": "1", | ||
"flex-direction": "row", | ||
"font-size": "13px", | ||
"justify-content": "space-between", | ||
"outline": "none", | ||
"padding": "0 8px", | ||
"position": "relative", | ||
"transition": "border-color 100ms ease", | ||
- "vertical-align": "baseline", | ||
- "width": "auto", | ||
+ "width": "100%", | ||
}, | ||
] | ||
`; | ||
|
||
exports[`base field props should render subtle styles 1`] = ` | ||
Snapshot Diff: | ||
- Received styles | ||
+ Base styles | ||
@@ -11,11 +11,10 @@ | ||
"-webkit-flex-direction": "row", | ||
"-webkit-justify-content": "space-between", | ||
"-webkit-transition": "border-color 100ms ease", | ||
"align-items": "center", | ||
"background": "#fff", | ||
- "background-color": "transparent", | ||
"border": "1px solid", | ||
"border-color": "#757575", | ||
"border-radius": "2px", | ||
"box-shadow": "transparent", | ||
"display": "flex", | ||
`; | ||
|
||
exports[`base field should render correctly 1`] = ` | ||
.emotion-0 { | ||
display: -webkit-box; | ||
display: -webkit-flex; | ||
display: -ms-flexbox; | ||
display: flex; | ||
-webkit-align-items: center; | ||
-webkit-box-align: center; | ||
-ms-flex-align: center; | ||
align-items: center; | ||
-webkit-flex-direction: row; | ||
-ms-flex-direction: row; | ||
flex-direction: row; | ||
-webkit-box-pack: justify; | ||
-webkit-justify-content: space-between; | ||
-ms-flex-pack: justify; | ||
justify-content: space-between; | ||
width: 100%; | ||
background: #fff; | ||
border-radius: 2px; | ||
border: 1px solid; | ||
border-color: #757575; | ||
box-shadow: transparent; | ||
display: -webkit-box; | ||
display: -webkit-flex; | ||
display: -ms-flexbox; | ||
display: flex; | ||
-webkit-flex: 1; | ||
-ms-flex: 1; | ||
flex: 1; | ||
font-size: 13px; | ||
outline: none; | ||
padding: 0 8px; | ||
position: relative; | ||
-webkit-transition: border-color 100ms ease; | ||
transition: border-color 100ms ease; | ||
width: 100%; | ||
} | ||
.emotion-0 > * + *:not(marquee) { | ||
margin-left: calc(4px * 2); | ||
} | ||
.emotion-0 > * { | ||
min-width: 0; | ||
} | ||
@media ( prefers-reduced-motion:reduce ) { | ||
.emotion-0 { | ||
-webkit-transition-duration: 0ms; | ||
transition-duration: 0ms; | ||
} | ||
} | ||
.emotion-0[disabled] { | ||
opacity: 0.6; | ||
} | ||
.emotion-0:hover { | ||
border-color: #757575; | ||
} | ||
.emotion-0:focus, | ||
.emotion-0[data-focused='true'] { | ||
border-color: var( --wp-admin-theme-color,#00669b); | ||
box-shadow: 0 0 0,0.5px,[object Object]; | ||
} | ||
<div | ||
class="components-flex components-base-field emotion-0 emotion-1 emotion-2" | ||
data-wp-c16t="true" | ||
data-wp-component="BaseField" | ||
/> | ||
`; |
Oops, something went wrong.