Skip to content

Commit

Permalink
Squash update/type-more-components
Browse files Browse the repository at this point in the history
  • Loading branch information
sirreal committed Oct 16, 2020
1 parent 78095ef commit c74a29f
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 50 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"@types/requestidlecallback": "0.3.1",
"@types/semver": "7.2.0",
"@types/sprintf-js": "1.1.2",
"@types/tinycolor2": "1.4.2",
"@types/uuid": "7.0.2",
"@types/webpack": "4.41.16",
"@types/webpack-sources": "0.1.7",
Expand Down
30 changes: 30 additions & 0 deletions packages/components/src/base-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ import {
StyledHelp,
} from './styles/base-control-styles';

/**
* @typedef Props
* @property {string} id The id of the element to which labels and help text are being generated.
* That element should be passed as a child.
* @property {import('react').ReactNode} help If this property is added, a help text will be
* generated using help property as the content.
* @property {import('react').ReactNode} label If this property is added, a label will be generated
* using label property as the content.
* @property {boolean} [hideLabelFromVision] If true, the label will only be visible to screen readers.
* @property {string} [className] The class that will be added with "components-base-control" to the
* classes of the wrapper div. If no className is passed only
* components-base-control is used.
* @property {import('react').ReactNode} [children] The content to be displayed within
* the BaseControl.
*/

/**
* @param {Props} props
* @return {JSX.Element} Element
*/
function BaseControl( {
id,
label,
Expand Down Expand Up @@ -64,6 +84,16 @@ function BaseControl( {
);
}

/**
* @typedef VisualLabelProps
* @property {string} [className] Class name
* @property {import('react').ReactNode} [children] Children
*/

/**
* @param {VisualLabelProps} Props
* @return {JSX.Element} Element
*/
BaseControl.VisualLabel = ( { className, children } ) => {
className = classnames( 'components-base-control__label', className );
return <span className={ className }>{ children }</span>;
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/utils/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function rgba( hexValue = '', alpha = 1 ) {
/**
* Retrieves a color from the color palette.
*
* @param {string} value The value to retrieve.
* @param {import('lodash').PropertyPath} value The value to retrieve.
* @return {string} The color (or fallback, if not found).
*
* @example
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/utils/font-values.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const HELP_TEXT = {
fontSize: '12px',
};

/**
* @template {string} T
* @type {Record<T, import('react').CSSProperties>}
*/
export default {
default: DEFAULT,
helpText: HELP_TEXT,
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/utils/font.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { get } from 'lodash';
*/
import FONT from './font-values';

/**
* @param {import('lodash').PropertyPath} value
* @return {string} Style value
*/
export function font( value ) {
return get( FONT, value, '' );
}
21 changes: 16 additions & 5 deletions packages/components/src/utils/hooks/use-controlled-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { useEffect, useState } from '@wordpress/element';
*/
import { isValueDefined, getDefinedValue } from '../values';

/**
* @template T
* @typedef Options
* @property {T | undefined} initial Initial value
* @property {T | ""} fallback Fallback value
*/

/** @type {Readonly<{ initial: undefined, fallback: '' }>} */
const defaultOptions = {
initial: undefined,
/**
Expand All @@ -33,12 +41,12 @@ const defaultOptions = {
* Unlike the basic useState hook, useControlledState's state can
* be updated if a new incoming prop value is changed.
*
* @param {any} currentState The current value.
* @param {Object} options Additional options for the hook.
* @param {any} options.initial The initial state.
* @param {any} options.fallback The state to use when no state is defined.
* @template T
*
* @param {T | undefined} currentState The current value.
* @param {Options<T>} [options=defaultOptions] Additional options for the hook.
*
* @return {[*, Function]} The controlled value and the value setter.
* @return {[T | "", (nextState: T) => void]} The controlled value and the value setter.
*/
function useControlledState( currentState, options = defaultOptions ) {
const { initial, fallback } = { ...defaultOptions, ...options };
Expand All @@ -60,11 +68,14 @@ function useControlledState( currentState, options = defaultOptions ) {
fallback
);

/* eslint-disable jsdoc/no-undefined-types */
/** @type {(nextState: T) => void} */
const setState = ( nextState ) => {
if ( ! hasCurrentState ) {
setInternalState( nextState );
}
};
/* eslint-enable jsdoc/no-undefined-types */

return [ state, setState ];
}
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/utils/hooks/use-jump-step.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function useJumpStep( {
const [ isShiftKey, setIsShiftKey ] = useState( false );

useEffect( () => {
/** @type {(event: KeyboardEvent)=>void} */
const handleShiftKeyToggle = ( event ) => {
setIsShiftKey( event.shiftKey );
};
Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/utils/hooks/use-update-effect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
*/
import { useRef, useEffect } from '@wordpress/element';

/*
/**
* A `React.useEffect` that will not run on the first render.
* Source:
* https://github.com/reakit/reakit/blob/master/packages/reakit-utils/src/useUpdateEffect.ts
*
* @param {()=>void} effect
* @param {import('react').DependencyList} deps
*/
function useUpdateEffect( effect, deps ) {
const mounted = useRef( false );
Expand Down
33 changes: 18 additions & 15 deletions packages/components/src/utils/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { clamp } from 'lodash';
/**
* Parses and retrieves a number value.
*
* @param {any} value The incoming value.
* @param {unknown} value The incoming value.
*
* @return {number} The parsed number value.
*/
Expand All @@ -19,26 +19,34 @@ export function getNumber( value ) {
/**
* Safely adds 2 values.
*
* @param {number|string} args Values to add together.
* @param {Array<number|string>} args Values to add together.
*
* @return {number} The sum of values.
*/
export function add( ...args ) {
return args.reduce( ( sum, arg ) => sum + getNumber( arg ), 0 );
return args.reduce(
/** @type {(sum:number, arg: number|string) => number} */
( sum, arg ) => sum + getNumber( arg ),
0
);
}

/**
* Safely subtracts 2 values.
*
* @param {number|string} args Values to subtract together.
* @param {Array<number|string>} args Values to subtract together.
*
* @return {number} The difference of the 2 values.
* @return {number} The difference of the values.
*/
export function subtract( ...args ) {
return args.reduce( ( diff, arg, index ) => {
const value = getNumber( arg );
return index === 0 ? value : diff - value;
} );
return args.reduce(
/** @type {(diff:number, arg: number|string, index:number) => number} */
( diff, arg, index ) => {
const value = getNumber( arg );
return index === 0 ? value : diff - value;
},
0
);
}

/**
Expand Down Expand Up @@ -84,12 +92,7 @@ export function roundClamp(
* Clamps a value based on a min/max range with rounding.
* Returns a string.
*
* @param {any} args Arguments for roundClamp().
* @property {number} value The value.
* @property {number} min The minimum range.
* @property {number} max The maximum range.
* @property {number} step A multiplier for the value.
*
* @param {Parameters<typeof roundClamp>} args Arguments for roundClamp().
* @return {string} The rounded and clamped value.
*/
export function roundClampString( ...args ) {
Expand Down
10 changes: 6 additions & 4 deletions packages/components/src/utils/rtl.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ function getConvertedKey( key ) {
/**
* An incredibly basic ltr -> rtl converter for style properties
*
* @param {Object} ltrStyles
* @param {import('react').CSSProperties} ltrStyles
*
* @return {Object} Converted ltr -> rtl styles
* @return {import('react').CSSProperties} Converted ltr -> rtl styles
*/
export const convertLTRToRTL = ( ltrStyles = {} ) => {
return mapKeys( ltrStyles, ( _value, key ) => getConvertedKey( key ) );
Expand All @@ -76,8 +76,8 @@ export const convertLTRToRTL = ( ltrStyles = {} ) => {
/**
* A higher-order function that create an incredibly basic ltr -> rtl style converter for CSS objects.
*
* @param {Object} ltrStyles Ltr styles. Converts and renders from ltr -> rtl styles, if applicable.
* @param {null|Object} rtlStyles Rtl styles. Renders if provided.
* @param {import('react').CSSProperties} ltrStyles Ltr styles. Converts and renders from ltr -> rtl styles, if applicable.
* @param {import('react').CSSProperties} [rtlStyles] Rtl styles. Renders if provided.
*
* @return {Function} A function to output CSS styles for Emotion's renderer
*/
Expand All @@ -86,9 +86,11 @@ export function rtl( ltrStyles = {}, rtlStyles ) {
const isRTL = getRTL();

if ( rtlStyles ) {
// @ts-ignore: `css` types are wrong, it can accept an object: https://emotion.sh/docs/object-styles#with-css
return isRTL ? css( rtlStyles ) : css( ltrStyles );
}

// @ts-ignore: `css` types are wrong, it can accept an object: https://emotion.sh/docs/object-styles#with-css
return isRTL ? css( convertLTRToRTL( ltrStyles ) ) : css( ltrStyles );
};
}
2 changes: 1 addition & 1 deletion packages/components/src/utils/space.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const SPACE_GRID_BASE = 8;
/**
* Creates a spacing CSS value (px) based on grid system values.
*
* @param {number} value Multiplier against the grid base value (8)
* @param {number} [value=1] Multiplier against the grid base value (8)
* @return {string} The spacing value (px).
*/
export function space( value = 1 ) {
Expand Down
26 changes: 18 additions & 8 deletions packages/components/src/utils/values.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
/* eslint-disable jsdoc/valid-types */
/**
* Determines if a value is null or undefined.
*
* @param {any} value The value to check.
* @return {boolean} Whether value is null or undefined.
* @template T
*
* @param {T | null | undefined} value The value to check.
* @return {value is T} Whether value is not null or undefined.
*/
export function isValueDefined( value ) {
return value !== undefined && value !== null;
}
/* eslint-enable jsdoc/valid-types */

/* eslint-disable jsdoc/valid-types */
/**
* Determines if a value is empty, null, or undefined.
*
* @param {any} value The value to check.
* @return {boolean} Whether value is empty.
* @template T
*
* @param {T | "" | null | undefined} value The value to check.
* @return {value is T} Whether value is empty.
*/
export function isValueEmpty( value ) {
const isEmptyString = value === '';

return ! isValueDefined( value ) || isEmptyString;
}
/* eslint-enable jsdoc/valid-types */

/**
* Attempts to get a defined/non-null value from a collection of arguments.
* Get the first defined/non-null value from an array.
*
* @template T
*
* @param {Array<any>} values Values to derive from.
* @param {any} fallbackValue Fallback value if there are no defined values.
* @return {any} A defined value or the fallback value.
* @param {Array<T | null | undefined>} values Values to derive from.
* @param {T} fallbackValue Fallback value if there are no defined values.
* @return {T} A defined value or the fallback value.
*/
export function getDefinedValue( values = [], fallbackValue ) {
return values.find( isValueDefined ) ?? fallbackValue;
Expand Down
18 changes: 15 additions & 3 deletions packages/components/src/visually-hidden/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ import classnames from 'classnames';
*/
import { renderAsRenderProps } from './utils';

/**
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
* @typedef OwnProps
* @property {T} [as='div'] Component to render, e.g. `"div"` or `MyComponent`.
*/

/**
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
* @typedef {OwnProps<T> & import('react').ComponentProps<T>} Props
*/

/**
* VisuallyHidden component to render text out non-visually
* for use in devices such as a screen reader.
*
* @param {Object} props Component props.
* @param {string|WPComponent} [props.as="div"] A tag or component to render.
* @param {string} [props.className] Class to set on the container.
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
*
* @param {Props<T>} props
* @return {JSX.Element} Element
*/
function VisuallyHidden( { as = 'div', className, ...props } ) {
return renderAsRenderProps( {
Expand Down
15 changes: 12 additions & 3 deletions packages/components/src/visually-hidden/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
/**
* Utility Functions
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
* @typedef OwnProps
* @property {T} [as='div'] Component to render
* @property {import('react').ReactNode | ((props: import('react').ComponentProps<T>) => JSX.Element) } [children] Children or render props function
*/

/**
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
* @typedef {OwnProps<T> & import('react').ComponentProps<T>} Props
*/

/**
Expand All @@ -9,8 +17,9 @@
*
* See VisuallyHidden hidden for example.
*
* @param {string|WPComponent} as A tag or component to render.
* @return {WPComponent} The rendered component.
* @template {keyof JSX.IntrinsicElements | import('react').JSXElementConstructor<any>} T
* @param {Props<T>} props
* @return {JSX.Element} The rendered element.
*/
function renderAsRenderProps( { as: Component = 'div', ...props } ) {
if ( typeof props.children === 'function' ) {
Expand Down
Loading

0 comments on commit c74a29f

Please sign in to comment.