-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement SensitiveTextControl component and use it for API keys so t…
…hat the text is not visible by default.
- Loading branch information
1 parent
32bbab6
commit 6222797
Showing
5 changed files
with
189 additions
and
2 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,96 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import clsx from 'clsx'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { BaseControl } from '@wordpress/components'; | ||
import { useInstanceId } from '@wordpress/compose'; | ||
import { forwardRef, useState } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import InputVisibleButton from './input-invisible-button.js'; | ||
import './style.scss'; | ||
|
||
/** | ||
* Renders a modified version of TextControl, which shows a button to toggle visibility of the input text. | ||
* | ||
* By default, the input text is hidden, i.e. the input type is forced to 'password'. | ||
* | ||
* The code is almost entirely copied from the original TextControl component implementation. | ||
* | ||
* @since n.e.x.t | ||
* | ||
* @param {Object} props Component props. These are identical to the props of the SensitiveTextControl component, with the | ||
* addition of 'buttonShowLabel' and 'buttonHideLabel'. | ||
* @param {Object} ref Reference to the component. | ||
* @return {Component} The component to be rendered. | ||
*/ | ||
function UnforwardedSensitiveTextControl( props, ref ) { | ||
const { | ||
__nextHasNoMarginBottom, | ||
__next40pxDefaultSize = false, | ||
label, | ||
hideLabelFromVision, | ||
value, | ||
help, | ||
id: idProp, | ||
className, | ||
onChange, | ||
type = 'text', | ||
buttonShowLabel, | ||
buttonHideLabel, | ||
...additionalProps | ||
} = props; | ||
const id = useInstanceId( | ||
SensitiveTextControl, | ||
'inspector-text-control', | ||
idProp | ||
); | ||
const onChangeValue = ( event ) => onChange( event.target.value ); | ||
|
||
const [ visible, setVisible ] = useState( false ); | ||
|
||
return ( | ||
<BaseControl | ||
__nextHasNoMarginBottom={ __nextHasNoMarginBottom } | ||
__associatedWPComponentName="SensitiveTextControl" | ||
label={ label } | ||
hideLabelFromVision={ hideLabelFromVision } | ||
id={ id } | ||
help={ help } | ||
className={ className } | ||
> | ||
<div className="ai-services-sensitive-text-control-container"> | ||
<input | ||
className={ clsx( 'components-text-control__input', { | ||
'is-next-40px-default-size': __next40pxDefaultSize, | ||
} ) } | ||
type={ visible ? type : 'password' } | ||
id={ id } | ||
value={ value } | ||
onChange={ onChangeValue } | ||
aria-describedby={ !! help ? id + '__help' : undefined } | ||
ref={ ref } | ||
{ ...additionalProps } | ||
/> | ||
<InputVisibleButton | ||
visible={ visible } | ||
setVisible={ setVisible } | ||
showLabel={ buttonShowLabel } | ||
hideLabel={ buttonHideLabel } | ||
/> | ||
</div> | ||
</BaseControl> | ||
); | ||
} | ||
|
||
export const SensitiveTextControl = forwardRef( | ||
UnforwardedSensitiveTextControl | ||
); | ||
|
||
export default SensitiveTextControl; |
54 changes: 54 additions & 0 deletions
54
src/components/SensitiveTextControl/input-invisible-button.js
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,54 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import PropTypes from 'prop-types'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Button, Dashicon } from '@wordpress/components'; | ||
import { _x } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Renders a wrapper for the actions within the header of the application. | ||
* | ||
* Any children passed to this component will be rendered inside the header actions area. | ||
* | ||
* @since n.e.x.t | ||
* | ||
* @param {Object} props Component props. | ||
* @param {boolean} props.visible Whether the input is visible. | ||
* @param {Function} props.setVisible Function to toggle the input visibility. Must accept a boolean. | ||
* @param {string} props.showLabel Label for the show action. | ||
* @param {string} props.hideLabel Label for the hide action. | ||
* @return {Component} The component to be rendered. | ||
*/ | ||
function InputVisibleButton( { visible, setVisible, showLabel, hideLabel } ) { | ||
return ( | ||
<Button | ||
variant="secondary" | ||
className="ai-services-input-visible-button" | ||
onClick={ () => setVisible( ! visible ) } | ||
ariaLabel={ visible ? hideLabel : showLabel } | ||
> | ||
<Dashicon | ||
icon={ visible ? 'hidden' : 'visibility' } | ||
aria-hidden="true" | ||
/> | ||
<span className="text"> | ||
{ visible | ||
? _x( 'Hide', 'action', 'ai-services' ) | ||
: _x( 'Show', 'action', 'ai-services' ) } | ||
</span> | ||
</Button> | ||
); | ||
} | ||
|
||
InputVisibleButton.propTypes = { | ||
visible: PropTypes.bool.isRequired, | ||
setVisible: PropTypes.func.isRequired, | ||
showLabel: PropTypes.string, | ||
hideLabel: PropTypes.string, | ||
}; | ||
|
||
export default InputVisibleButton; |
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 @@ | ||
.ai-services-sensitive-text-control-container { | ||
display: flex; | ||
|
||
.ai-services-input-visible-button { | ||
margin-left: 4px; | ||
|
||
.dashicons { | ||
margin-right: 4px; | ||
} | ||
} | ||
|
||
.components-text-control__input { | ||
min-height: 36px; // Same as button. | ||
} | ||
|
||
@media (max-width: 782px) { | ||
|
||
.components-text-control__input { | ||
min-height: 40px; // Same as button. | ||
} | ||
|
||
.ai-services-input-visible-button { | ||
min-height: 40px; // Same as input. | ||
} | ||
} | ||
} |
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