Skip to content

Commit

Permalink
Components: Fix G2 types (#28571)
Browse files Browse the repository at this point in the history
* fix: Components types

* Fix global process type and refine others
  • Loading branch information
sarayourfriend authored Jan 29, 2021
1 parent 6bfa005 commit d9e7541
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 57 deletions.
12 changes: 9 additions & 3 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 @@ -100,6 +100,7 @@
"@types/classnames": "2.2.10",
"@types/eslint": "6.8.0",
"@types/estree": "0.0.44",
"@types/highlight-words-core": "1.2.0",
"@types/lodash": "4.14.149",
"@types/npm-package-arg": "6.1.0",
"@types/prettier": "1.19.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* External dependencies
*/
import { ContextSystemProvider } from '@wp-g2/components';
import { ContextSystemProvider } from '@wp-g2/context';

/**
* @param {Object} props
* @param {string[]} [props.__unstableNextInclude]
* @param {import('react').ReactNode} props.children
* @param {any} props.value
*/
export function ComponentSystemProvider( {
__unstableNextInclude = [],
children,
Expand Down
20 changes: 18 additions & 2 deletions packages/components/src/__next/context/with-next.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
/**
* External dependencies
*/
import { contextConnect, useContextSystem } from '@wp-g2/components';
import { contextConnect, useContextSystem } from '@wp-g2/context';

/**
* @template {{}} TCurrentProps
* @template {{}} TNextProps
* @param {import('react').ComponentType<TCurrentProps>} CurrentComponent
* @param {import('react').ComponentType<TNextProps>} NextComponent
* @param {string} namespace
* @param {(props: TCurrentProps) => TNextProps} adapter
*/
export function withNext(
CurrentComponent = () => null,
NextComponent = () => null,
namespace = 'Component',
adapter = ( p ) => p
adapter = ( p ) => /** @type {any} */ ( p )
) {
if ( process.env.COMPONENT_SYSTEM_PHASE === 1 ) {
/* eslint-disable jsdoc/no-undefined-types */
/**
* @param {TCurrentProps} props
* @param {import('react').Ref<any>} ref
*/
/* eslint-enable jsdoc/no-undefined-types */
const WrappedComponent = ( props, ref ) => {
// @ts-ignore
const { __unstableVersion, ...otherProps } = useContextSystem(
props,
namespace
);

if ( __unstableVersion === 'next' ) {
// @ts-ignore
const nextProps = adapter( otherProps );
return <NextComponent { ...nextProps } ref={ ref } />;
}
Expand Down
8 changes: 7 additions & 1 deletion packages/components/src/grid/grid-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ const ALIGNMENTS = {
topRight: { alignItems: 'flex-start', justifyContent: 'flex-end' },
};

/* eslint-disable jsdoc/valid-types */
/**
* @param {keyof typeof ALIGNMENTS | undefined} alignment
* @return {{ alignItems?: import('react').CSSProperties['alignItems'], justifyContent?: import('react').CSSProperties['justifyContent']}} CSS props for alignment
*/
export function getAlignmentProps( alignment ) {
const alignmentProps = ALIGNMENTS[ alignment ] || {};
const alignmentProps = alignment ? ALIGNMENTS[ alignment ] : {};

return alignmentProps;
}
/* eslint-enable jsdoc/valid-types */
12 changes: 7 additions & 5 deletions packages/components/src/grid/use-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ export function useGrid( props ) {
...otherProps
} = useContextSystem( props, 'Grid' );

const column = useResponsiveValue( columns );
const row = useResponsiveValue( rows );
const columnsAsArray = Array.isArray( columns ) ? columns : [ columns ];
const column = useResponsiveValue( columnsAsArray );
const rowsAsArray = Array.isArray( rows ) ? rows : [ rows ];
const row = useResponsiveValue( rowsAsArray );

const gridTemplateColumns =
templateColumns || ( !! columns && `repeat(${ column }, 1fr)` );
Expand All @@ -49,12 +51,12 @@ export function useGrid( props ) {
alignItems: align,
display: isInline ? 'inline-grid' : 'grid',
gap,
gridTemplateColumns,
gridTemplateRows,
gridTemplateColumns: gridTemplateColumns || undefined,
gridTemplateRows: gridTemplateRows || undefined,
gridRowGap: rowGap,
gridColumnGap: columnGap,
justifyContent: justify,
verticalAlign: isInline ? 'middle' : null,
verticalAlign: isInline ? 'middle' : undefined,
...alignmentProps,
} );

Expand Down
18 changes: 17 additions & 1 deletion packages/components/src/text/next/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,31 @@ import { text } from '../styles/text-mixins';

const Text = process.env.COMPONENT_SYSTEM_PHASE === 1 ? NextText : undefined;

/**
* @typedef AdaptedTextProps
* @property {keyof JSX.IntrinsicElements} as Styled components `as` prop.
* @property {import('../styles/text-mixins').TextVariant} variant The variant to render.
* @property {import('react').ReactNode} children Children to render.
* @property {string} [className] Classname to render on the element.
*/

/**
* @param {AdaptedTextProps} props
*/
export const adapter = ( { as, variant, ...restProps } ) => ( {
// as has not changed
as,
// luckily `text` just returns an emotion CSS object, so we can pass the styles from that directly to the handy `css` prop
css: text( { variant } ).styles,
// mostly className
// mostly className and children
...restProps,
} );

/* eslint-disable jsdoc/valid-types */
/**
* @param {import('react').ComponentType<AdaptedTextProps>} Current
*/
/* eslint-enable jsdoc/valid-types */
export function withNextComponent( Current ) {
return withNext( Current, Text, 'WPComponentsText', adapter );
}
39 changes: 24 additions & 15 deletions packages/components/src/text/next/text-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import { ui } from '@wp-g2/styles';
import { memoize } from '@wp-g2/utils';
import memoize from 'memize';
import { findAll } from 'highlight-words-core';

/**
Expand All @@ -20,20 +20,38 @@ import { createElement } from '@wordpress/element';
* @typedef Options
* @property {string} [activeClassName=''] Classname for active highlighted areas.
* @property {number} [activeIndex=-1] The index of the active highlighted area.
* @property {import('react').AllHTMLAttributes['style']} [activeStyle] Styles to apply to the active highlighted area.
* @property {import('react').AllHTMLAttributes<HTMLDivElement>['style']} [activeStyle] Styles to apply to the active highlighted area.
* @property {boolean} [autoEscape] Whether to automatically escape text.
* @property {boolean} [caseSensitive=false] Whether to highlight in a case-sensitive manner.
* @property {string} children Children to highlight.
* @property {import('highlight-words-core').FindAllArgs['findChunks']} [findChunks] Custom `findChunks` function to pass to `highlight-words-core`.
* @property {string | Record<string, string>} [highlightClassName=''] Classname to apply to highlighted text or a Record of classnames to apply to given text (which should be the key).
* @property {import('react').AllHTMLAttributes['style']} [highlightStyle={}] Styles to apply to highlighted text.
* @property {string | Record<string, unknown>} [highlightClassName=''] Classname to apply to highlighted text or a Record of classnames to apply to given text (which should be the key).
* @property {import('react').AllHTMLAttributes<HTMLDivElement>['style']} [highlightStyle={}] Styles to apply to highlighted text.
* @property {keyof JSX.IntrinsicElements} [highlightTag='mark'] Tag to use for the highlighted text.
* @property {import('highlight-words-core').FindAllArgs['sanitize']} [sanitize] Custom `santize` function to pass to `highlight-words-core`.
* @property {string[]} [searchWords=[]] Words to search for and highlight.
* @property {string} [unhighlightClassName=''] Classname to apply to unhighlighted text.
* @property {import('react').AllHTMLAttributes['style']} [unhighlightStyle] Style to apply to unhighlighted text.
* @property {import('react').AllHTMLAttributes<HTMLDivElement>['style']} [unhighlightStyle] Style to apply to unhighlighted text.
*/

/**
* Maps props to lowercase names.
*
* @template {Record<string, unknown>} T
* @param {T} object Props to map.
* @return {{[K in keyof T as Lowercase<string & K>]: T[K]}} The mapped props.
*/
/* eslint-enable jsdoc/valid-types */
const lowercaseProps = ( object ) => {
/** @type {any} */
const mapped = {};
for ( const key in object ) {
mapped[ key.toLowerCase() ] = object[ key ];
}
return mapped;
};

const memoizedLowercaseProps = memoize( lowercaseProps );

/**
*
Expand Down Expand Up @@ -73,16 +91,6 @@ export function createHighlighterText( {
let highlightClassNames = '';
let highlightStyles;

const lowercaseProps = ( object ) => {
const mapped = {};
for ( const key in object ) {
mapped[ key.toLowerCase() ] = object[ key ];
}
return mapped;
};

const memoizedLowercaseProps = memoize( lowercaseProps );

const textContent = chunks.map( ( chunk, index ) => {
const text = textToHighlight.substr(
chunk.start,
Expand Down Expand Up @@ -116,6 +124,7 @@ export function createHighlighterText( {
? Object.assign( {}, highlightStyle, activeStyle )
: highlightStyle;

/** @type {Record<string, any>} */
const props = {
...ui.$( 'TextHighlight' ),
children: text,
Expand Down
57 changes: 35 additions & 22 deletions packages/components/src/text/next/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Props as TruncateProps } from '../../truncate/use-truncate';
import type { CSSProperties } from 'react';
import type { CSSProperties, ReactNode } from 'react';

type TextAdjustLineHeightForInnerControls =
| boolean
Expand All @@ -20,7 +20,36 @@ type TextVariant = 'muted';

type TextWeight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;

export type Props = TruncateProps & {
type Highlighted = {
/**
* Letters or words within `Text` can be highlighted using `highlightWords`.
*
* @example
* ```jsx
* import { Text } from `@wp-g2/components`
*
* function Example() {
* return (
* <Text highlightWords={["the"]}>
* Where the north wind meets the sea, there's a river full of memory. Sleep,
* my darling, safe and sound, for in this river all is found. In her waters,
* deep and true, lay the answers and a path for you. Dive down deep into her
* sound, but not too far or you'll be drowned
* </Text>
* )
* }
* ```
*/
highlightWords?: string[];
children: string;
}

type Unhighlighted = {
highlightWords?: undefined;
children: ReactNode;
}

export type Props = TruncateProps & (Highlighted | Unhighlighted) & {
/**
* Adjusts the text alignment.
*
Expand Down Expand Up @@ -77,26 +106,6 @@ export type Props = TruncateProps & {
* Determines if `highlightWords` should be case sensitive.
*/
highlightCaseSensitive?: boolean;
/**
* Letters or words within `Text` can be highlighted using `highlightWords`.
*
* @example
* ```jsx
* import { Text } from `@wp-g2/components`
*
* function Example() {
* return (
* <Text highlightWords={["the"]}>
* Where the north wind meets the sea, there's a river full of memory. Sleep,
* my darling, safe and sound, for in this river all is found. In her waters,
* deep and true, lay the answers and a path for you. Dive down deep into her
* sound, but not too far or you'll be drowned
* </Text>
* )
* }
* ```
*/
highlightWords?: string[];
/**
* Array of search words. String search terms are automatically cast to RegExps unless `highlightEscape` is true.
*/
Expand Down Expand Up @@ -185,4 +194,8 @@ export type Props = TruncateProps & {
* Adjusts font-weight of the text.
*/
weight?: CSSProperties[ 'fontWeight' ] | TextWeight;
/**
* Adjusts letter-spacing of the text.
*/
letterSpacing?: CSSProperties[ 'letterSpacing' ];
};
21 changes: 16 additions & 5 deletions packages/components/src/text/next/use-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function useText( props ) {
display,
highlightEscape = false,
highlightCaseSensitive = false,
highlightWords = [],
highlightWords,
highlightSanitize,
isBlock = false,
letterSpacing,
Expand All @@ -47,15 +47,17 @@ export function useText( props ) {
...otherProps
} = useContextSystem( props, 'Text' );

/** @type {import('react').ReactNode} */
let content = children;
const isHighlighter =
Array.isArray( highlightWords ) && highlightWords.length;
const isHighlighter = Array.isArray( highlightWords );
const isCaption = size === 'caption';

if ( isHighlighter ) {
content = createHighlighterText( {
autoEscape: highlightEscape,
children,
// Disable reason: We need to disable this otherwise it erases the cast
// eslint-disable-next-line object-shorthand
children: /** @type {string} */ ( children ),
caseSensitive: highlightCaseSensitive,
searchWords: highlightWords,
sanitize: highlightSanitize,
Expand All @@ -74,7 +76,9 @@ export function useText( props ) {
color,
display,
fontSize: getFontSize( size ),
fontWeight: weight,
/* eslint-disable jsdoc/valid-types */
fontWeight: /** @type {import('react').CSSProperties['fontWeight']} */ ( weight ),
/* eslint-enable jsdoc/valid-types */
lineHeight,
letterSpacing,
textAlign: align,
Expand Down Expand Up @@ -169,6 +173,13 @@ export function useText( props ) {
};
}

/* eslint-disable jsdoc/valid-types */
/**
* @param {Object} props
* @param {import('./types').Props['adjustLineHeightForInnerControls']} [props.adjustLineHeightForInnerControls]
* @param {import('react').CSSProperties['lineHeight']} [props.lineHeight]
*/
/* eslint-enable jsdoc/valid-types */
function getLineHeight( { adjustLineHeightForInnerControls, lineHeight } ) {
if ( ! isNil( lineHeight ) ) return lineHeight;

Expand Down
Loading

0 comments on commit d9e7541

Please sign in to comment.