From 8b2caed4162957418778ef30ea3c3601ca9dd8fd Mon Sep 17 00:00:00 2001 From: zallen <47335686+redallen@users.noreply.github.com> Date: Fri, 30 Oct 2020 15:07:00 -0400 Subject: [PATCH] Fix circular deps (#5086) * add rollup to react-table * fix circular deps in react-core * fix circular deps in react-table * fix circular deps in react-charts * add check to react-datetime * move to types and enums * revert most table changes * fix table build * revert fixing charts circular dependencies --- package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-core/rollup.config.js | 35 ++------ .../ApplicationLauncherSeparator.tsx | 2 +- .../src/components/Select/Select.tsx | 2 +- .../src/components/Select/favorites.ts | 81 +++++++++++++++++++ .../src/components/Tabs/TabContent.tsx | 2 +- .../react-core/src/components/Tabs/Tabs.tsx | 12 +-- .../src/components/Tabs/TabsContext.ts | 12 +++ .../react-core/src/components/Tabs/index.ts | 1 + packages/react-core/src/helpers/util.ts | 81 ------------------- packages/react-datetime/package.json | 1 + packages/react-datetime/rollup.config.js | 7 ++ packages/react-table/package.json | 1 + packages/react-table/rollup.config.js | 7 ++ .../src/components/Table/SelectColumn.tsx | 6 +- .../src/components/Table/SortColumn.tsx | 6 +- .../src/components/Table/Table.tsx | 12 +-- .../src/components/Table/TableContext.ts | 9 +++ .../Table/utils/decorators/selectable.tsx | 4 +- .../Table/utils/decorators/sortable.tsx | 4 +- packages/rollup.base.js | 56 +++++++++++++ 22 files changed, 203 insertions(+), 142 deletions(-) create mode 100644 packages/react-core/src/components/Select/favorites.ts create mode 100644 packages/react-core/src/components/Tabs/TabsContext.ts create mode 100644 packages/react-datetime/rollup.config.js create mode 100644 packages/react-table/rollup.config.js create mode 100644 packages/react-table/src/components/Table/TableContext.ts create mode 100644 packages/rollup.base.js diff --git a/package.json b/package.json index 2ff77a1ffe2..90f94fb2ba3 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "build:integration": "lerna run build:demo-app --stream", "build:docs": "yarn workspace @patternfly/react-docs build:docs", "build:generate": "lerna run generate --parallel --stream", - "build:umd": "yarn workspace @patternfly/react-core build:umd", + "build:umd": "lerna run build:umd --parallel --stream", "clean": "yarn clean:build && lerna run clean --parallel", "clean:build": "rimraf .cache .eslintcache coverage", "generate": "yarn plop", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index d233b1d016b..19a223f8a50 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -29,8 +29,8 @@ }, "homepage": "https://github.com/patternfly/patternfly-react#readme", "scripts": { - "clean": "rimraf dist", "build:umd": "rollup -c && rollup -c --environment IS_PRODUCTION", + "clean": "rimraf dist", "generate": "node scripts/copyStyles.js", "gen:tests": "yo tsx-docgen" }, diff --git a/packages/react-core/rollup.config.js b/packages/react-core/rollup.config.js index 67204136aeb..1f8aeb25ac0 100644 --- a/packages/react-core/rollup.config.js +++ b/packages/react-core/rollup.config.js @@ -1,30 +1,7 @@ -import resolve from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import scss from 'rollup-plugin-scss'; -import replace from '@rollup/plugin-replace'; -import { terser } from 'rollup-plugin-terser'; +const { name } = require('./package.json'); +const baseConfig = require('../rollup.base'); -const isProduction = process.env.IS_PRODUCTION; - -module.exports = { - input: 'dist/esm/index.js', - output: { - file: `dist/umd/react-core${isProduction ? '.min' : ''}.js`, - format: 'umd', - name: 'PatternFlyReact', - globals: { - react: 'React', - 'react-dom': 'ReactDOM' - } - }, - external: ['react', 'react-dom'], - plugins: [ - replace({ - 'process.env.NODE_ENV': `'${isProduction ? 'production' : 'development'}'` - }), - resolve(), - commonjs(), - scss(), - isProduction && terser() - ] -}; +module.exports = baseConfig({ + packageName: name.replace('@patternfly/', ''), + name: 'PatternFlyReact' +}); diff --git a/packages/react-core/src/components/ApplicationLauncher/ApplicationLauncherSeparator.tsx b/packages/react-core/src/components/ApplicationLauncher/ApplicationLauncherSeparator.tsx index 0df6a5da45e..59ca4ac3aba 100644 --- a/packages/react-core/src/components/ApplicationLauncher/ApplicationLauncherSeparator.tsx +++ b/packages/react-core/src/components/ApplicationLauncher/ApplicationLauncherSeparator.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DropdownSeparator, SeparatorProps } from '../Dropdown'; +import { DropdownSeparator, SeparatorProps } from '../Dropdown/DropdownSeparator'; export const ApplicationLauncherSeparator: React.FunctionComponent = ({ // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/packages/react-core/src/components/Select/Select.tsx b/packages/react-core/src/components/Select/Select.tsx index 48277daf058..54ddc519225 100644 --- a/packages/react-core/src/components/Select/Select.tsx +++ b/packages/react-core/src/components/Select/Select.tsx @@ -22,7 +22,7 @@ import { } from '../../helpers'; import { Divider } from '../Divider'; import { ToggleMenuBaseProps, Popper } from '../../helpers/Popper/Popper'; -import { createRenderableFavorites, extendItemsWithFavorite } from '../../helpers/util'; +import { createRenderableFavorites, extendItemsWithFavorite } from './favorites'; // seed for the aria-labelledby ID let currentId = 0; diff --git a/packages/react-core/src/components/Select/favorites.ts b/packages/react-core/src/components/Select/favorites.ts new file mode 100644 index 00000000000..419fb7650a0 --- /dev/null +++ b/packages/react-core/src/components/Select/favorites.ts @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { ApplicationLauncherSeparator } from '../ApplicationLauncher/ApplicationLauncherSeparator'; +import { Divider } from '../Divider/Divider'; + +/** + * This function is a helper for creating an array of renderable favorite items for the Application launcher or Select + * + * @param {object} items The items rendered in Select or Application aLauncher + * @param {boolean} isGrouped Flag indicating if items are grouped + * @param {any[]} favorites Array of ids of favorited items + * @param {boolean} isEnterTriggersArrowDown Flag indicating if we should add isEnterTriggersArrowDown to favorited item + */ +export const createRenderableFavorites = ( + items: object, + isGrouped: boolean, + favorites: any[], + isEnterTriggersArrowDown?: boolean +) => { + if (isGrouped) { + const favoriteItems: React.ReactNode[] = []; + (items as React.ReactElement[]).forEach(group => { + if (favorites.length > 0) { + return ( + group.props.children && + (group.props.children as React.ReactElement[]) + .filter(item => favorites.includes(item.props.id)) + .map(item => { + if (isEnterTriggersArrowDown) { + return favoriteItems.push( + React.cloneElement(item, { + isFavorite: true, + enterTriggersArrowDown: isEnterTriggersArrowDown, + id: `favorite-${item.props.id}` + }) + ); + } else { + return favoriteItems.push( + React.cloneElement(item, { isFavorite: true, id: `favorite-${item.props.id}` }) + ); + } + }) + ); + } + }); + return favoriteItems; + } + return (items as React.ReactElement[]) + .filter(item => favorites.includes(item.props.id)) + .map(item => React.cloneElement(item, { isFavorite: true, enterTriggersArrowDown: isEnterTriggersArrowDown })); +}; + +/** + * This function is a helper for extending the array of renderable favorite with the select/application launcher items to render in the Application launcher or Select + * + * @param {object} items The items rendered in Select or Application aLauncher + * @param {boolean} isGrouped Flag indicating if items are grouped + * @param {any[]} favorites Array of ids of favorited items + */ +export const extendItemsWithFavorite = (items: object, isGrouped: boolean, favorites: any[]) => { + if (isGrouped) { + return (items as React.ReactElement[]).map(group => + React.cloneElement(group, { + children: React.Children.map(group.props.children as React.ReactElement[], item => { + if (item.type === ApplicationLauncherSeparator || item.type === Divider) { + return item; + } + return React.cloneElement(item, { + isFavorite: favorites.some( + favoriteId => favoriteId === item.props.id || `favorite-${favoriteId}` === item.props.id + ) + }); + }) + }) + ); + } + return (items as React.ReactElement[]).map(item => + React.cloneElement(item, { + isFavorite: favorites.some(favoriteId => favoriteId === item.props.id) + }) + ); +}; diff --git a/packages/react-core/src/components/Tabs/TabContent.tsx b/packages/react-core/src/components/Tabs/TabContent.tsx index 2645e4a8367..18ca06978f8 100644 --- a/packages/react-core/src/components/Tabs/TabContent.tsx +++ b/packages/react-core/src/components/Tabs/TabContent.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/TabContent/tab-content'; import { css } from '@patternfly/react-styles'; import { getOUIAProps, OUIAProps } from '../../helpers'; -import { TabsContextConsumer, TabsContextProps } from './Tabs'; +import { TabsContextConsumer, TabsContextProps } from './TabsContext'; export interface TabContentProps extends Omit, 'ref'>, OUIAProps { /** content rendered inside the tab content area if used outside Tabs component */ diff --git a/packages/react-core/src/components/Tabs/Tabs.tsx b/packages/react-core/src/components/Tabs/Tabs.tsx index 928219ccc1b..d2967ab63e9 100644 --- a/packages/react-core/src/components/Tabs/Tabs.tsx +++ b/packages/react-core/src/components/Tabs/Tabs.tsx @@ -9,6 +9,7 @@ import { getUniqueId, isElementInView, formatBreakpointMods } from '../../helper import { TabButton } from './TabButton'; import { TabContent } from './TabContent'; import { TabProps } from './Tab'; +import { TabsContextProvider } from './TabsContext'; import { getOUIAProps, OUIAProps, getDefaultOUIAId } from '../../helpers'; export enum TabsComponent { @@ -60,17 +61,6 @@ export interface TabsProps extends Omit({ - variant: 'default' -}); - -export const TabsContextProvider = TabsContext.Provider; -export const TabsContextConsumer = TabsContext.Consumer; - const variantStyle = { default: '', light300: styles.modifiers.colorSchemeLight_300 diff --git a/packages/react-core/src/components/Tabs/TabsContext.ts b/packages/react-core/src/components/Tabs/TabsContext.ts new file mode 100644 index 00000000000..714efcf446a --- /dev/null +++ b/packages/react-core/src/components/Tabs/TabsContext.ts @@ -0,0 +1,12 @@ +import * as React from 'react'; + +export interface TabsContextProps { + variant: 'default' | 'light300'; +} + +const TabsContext = React.createContext({ + variant: 'default' +}); + +export const TabsContextProvider = TabsContext.Provider; +export const TabsContextConsumer = TabsContext.Consumer; diff --git a/packages/react-core/src/components/Tabs/index.ts b/packages/react-core/src/components/Tabs/index.ts index cf91a986bd6..b5930447d95 100644 --- a/packages/react-core/src/components/Tabs/index.ts +++ b/packages/react-core/src/components/Tabs/index.ts @@ -1,5 +1,6 @@ export * from './Tab'; export * from './Tabs'; export * from './TabContent'; +export * from './TabsContext'; export * from './TabTitleText'; export * from './TabTitleIcon'; diff --git a/packages/react-core/src/helpers/util.ts b/packages/react-core/src/helpers/util.ts index a8c487c62ac..b5f1ed0b0f4 100644 --- a/packages/react-core/src/helpers/util.ts +++ b/packages/react-core/src/helpers/util.ts @@ -1,8 +1,5 @@ import * as ReactDOM from 'react-dom'; import { SIDE } from './constants'; -import * as React from 'react'; -import { ApplicationLauncherSeparator } from '../components/ApplicationLauncher/ApplicationLauncherSeparator'; -import { Divider } from '../components/Divider/Divider'; /** * @param {string} input - String to capitalize first letter @@ -277,84 +274,6 @@ export const toCamel = (s: string) => s.replace(/([-_][a-z])/gi, camelize); */ export const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); -/** - * This function is a helper for creating an array of renderable favorite items for the Application launcher or Select - * - * @param {object} items The items rendered in Select or Application aLauncher - * @param {boolean} isGrouped Flag indicating if items are grouped - * @param {any[]} favorites Array of ids of favorited items - * @param {boolean} isEnterTriggersArrowDown Flag indicating if we should add isEnterTriggersArrowDown to favorited item - */ -export const createRenderableFavorites = ( - items: object, - isGrouped: boolean, - favorites: any[], - isEnterTriggersArrowDown?: boolean -) => { - if (isGrouped) { - const favoriteItems: React.ReactNode[] = []; - (items as React.ReactElement[]).forEach(group => { - if (favorites.length > 0) { - return ( - group.props.children && - (group.props.children as React.ReactElement[]) - .filter(item => favorites.includes(item.props.id)) - .map(item => { - if (isEnterTriggersArrowDown) { - return favoriteItems.push( - React.cloneElement(item, { - isFavorite: true, - enterTriggersArrowDown: isEnterTriggersArrowDown, - id: `favorite-${item.props.id}` - }) - ); - } else { - return favoriteItems.push( - React.cloneElement(item, { isFavorite: true, id: `favorite-${item.props.id}` }) - ); - } - }) - ); - } - }); - return favoriteItems; - } - return (items as React.ReactElement[]) - .filter(item => favorites.includes(item.props.id)) - .map(item => React.cloneElement(item, { isFavorite: true, enterTriggersArrowDown: isEnterTriggersArrowDown })); -}; - -/** - * This function is a helper for extending the array of renderable favorite with the select/application launcher items to render in the Application launcher or Select - * - * @param {object} items The items rendered in Select or Application aLauncher - * @param {boolean} isGrouped Flag indicating if items are grouped - * @param {any[]} favorites Array of ids of favorited items - */ -export const extendItemsWithFavorite = (items: object, isGrouped: boolean, favorites: any[]) => { - if (isGrouped) { - return (items as React.ReactElement[]).map(group => - React.cloneElement(group, { - children: React.Children.map(group.props.children as React.ReactElement[], item => { - if (item.type === ApplicationLauncherSeparator || item.type === Divider) { - return item; - } - return React.cloneElement(item, { - isFavorite: favorites.some( - favoriteId => favoriteId === item.props.id || `favorite-${favoriteId}` === item.props.id - ) - }); - }) - }) - ); - } - return (items as React.ReactElement[]).map(item => - React.cloneElement(item, { - isFavorite: favorites.some(favoriteId => favoriteId === item.props.id) - }) - ); -}; - /** * Calculate the width of the text * Example: diff --git a/packages/react-datetime/package.json b/packages/react-datetime/package.json index 5951de3ab69..73c669f2948 100644 --- a/packages/react-datetime/package.json +++ b/packages/react-datetime/package.json @@ -31,6 +31,7 @@ }, "homepage": "https://github.com/patternfly/patternfly-react/tree/master/packages/react-datetime#readme", "scripts": { + "build:umd": "rollup -c && rollup -c --environment IS_PRODUCTION", "clean": "rimraf dist" }, "dependencies": { diff --git a/packages/react-datetime/rollup.config.js b/packages/react-datetime/rollup.config.js new file mode 100644 index 00000000000..6b5ae0a2912 --- /dev/null +++ b/packages/react-datetime/rollup.config.js @@ -0,0 +1,7 @@ +const { name } = require('./package.json'); +const baseConfig = require('../rollup.base'); + +module.exports = baseConfig({ + packageName: name.replace('@patternfly/', ''), + name: 'PatternFlyDateTime' +}); diff --git a/packages/react-table/package.json b/packages/react-table/package.json index 861b943c48a..92003e269da 100644 --- a/packages/react-table/package.json +++ b/packages/react-table/package.json @@ -27,6 +27,7 @@ }, "homepage": "https://github.com/patternfly/patternfly-react/tree/master/packages/react-table#readme", "scripts": { + "build:umd": "rollup -c && rollup -c --environment IS_PRODUCTION", "clean": "rimraf dist" }, "dependencies": { diff --git a/packages/react-table/rollup.config.js b/packages/react-table/rollup.config.js new file mode 100644 index 00000000000..afe67e0e28e --- /dev/null +++ b/packages/react-table/rollup.config.js @@ -0,0 +1,7 @@ +const { name } = require('./package.json'); +const baseConfig = require('../rollup.base'); + +module.exports = baseConfig({ + packageName: name.replace('@patternfly/', ''), + name: 'PatternFlyTable' +}); diff --git a/packages/react-table/src/components/Table/SelectColumn.tsx b/packages/react-table/src/components/Table/SelectColumn.tsx index cd45dab3cc5..736b76c0ad1 100644 --- a/packages/react-table/src/components/Table/SelectColumn.tsx +++ b/packages/react-table/src/components/Table/SelectColumn.tsx @@ -1,5 +1,9 @@ import * as React from 'react'; -import { RowSelectVariant } from './Table'; + +export enum RowSelectVariant { + radio = 'radio', + checkbox = 'checkbox' +} export interface SelectColumnProps { name?: string; diff --git a/packages/react-table/src/components/Table/SortColumn.tsx b/packages/react-table/src/components/Table/SortColumn.tsx index bd7e560cb60..4cf1428c208 100644 --- a/packages/react-table/src/components/Table/SortColumn.tsx +++ b/packages/react-table/src/components/Table/SortColumn.tsx @@ -4,9 +4,13 @@ import LongArrowAltDownIcon from '@patternfly/react-icons/dist/js/icons/long-arr import ArrowsAltVIcon from '@patternfly/react-icons/dist/js/icons/arrows-alt-v-icon'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Table/table'; -import { SortByDirection } from './Table'; import { TableText } from './TableText'; +export enum SortByDirection { + asc = 'asc', + desc = 'desc' +} + export interface SortColumnProps extends React.ButtonHTMLAttributes { children?: React.ReactNode; className?: string; diff --git a/packages/react-table/src/components/Table/Table.tsx b/packages/react-table/src/components/Table/Table.tsx index 7ec91642329..0ce023e0226 100644 --- a/packages/react-table/src/components/Table/Table.tsx +++ b/packages/react-table/src/components/Table/Table.tsx @@ -17,6 +17,8 @@ import { BodyWrapper } from './BodyWrapper'; import { toCamel } from './utils'; import { calculateColumns } from './utils/headerUtils'; import { formatterValueType, ColumnType, RowType, RowKeyType, ColumnsType } from './base'; +import { RowSelectVariant } from './SelectColumn'; +import { SortByDirection } from './SortColumn'; export enum TableGridBreakpoint { none = '', @@ -33,11 +35,6 @@ export enum TableVariant { export type RowEditType = 'save' | 'cancel' | 'edit'; -export enum RowSelectVariant { - radio = 'radio', - checkbox = 'checkbox' -} - export interface RowErrors { [name: string]: string[]; } @@ -78,11 +75,6 @@ export type OnRowEdit = ( validationErrors?: RowErrors ) => void; -export enum SortByDirection { - asc = 'asc', - desc = 'desc' -} - // Todo: Update type with next breaking change release // export type IHeaderRow = ColumnType; diff --git a/packages/react-table/src/components/Table/TableContext.ts b/packages/react-table/src/components/Table/TableContext.ts new file mode 100644 index 00000000000..7296cfac94f --- /dev/null +++ b/packages/react-table/src/components/Table/TableContext.ts @@ -0,0 +1,9 @@ +import * as React from 'react'; +import { IHeaderRow, IRow } from './Table'; +import { ColumnsType } from './base'; + +export const TableContext = React.createContext({ + headerData: null as ColumnsType, + headerRows: null as IHeaderRow[], + rows: [] as (IRow | string[])[] +}); diff --git a/packages/react-table/src/components/Table/utils/decorators/selectable.tsx b/packages/react-table/src/components/Table/utils/decorators/selectable.tsx index a4329d4c212..2094420ceb3 100644 --- a/packages/react-table/src/components/Table/utils/decorators/selectable.tsx +++ b/packages/react-table/src/components/Table/utils/decorators/selectable.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Table/table'; -import { IExtra, IFormatterValueType, ITransform, RowSelectVariant } from '../../Table'; -import { SelectColumn } from '../../SelectColumn'; +import { IExtra, IFormatterValueType, ITransform } from '../../Table'; +import { SelectColumn, RowSelectVariant } from '../../SelectColumn'; import checkStyles from '@patternfly/react-styles/css/components/Check/check'; export const selectable: ITransform = ( diff --git a/packages/react-table/src/components/Table/utils/decorators/sortable.tsx b/packages/react-table/src/components/Table/utils/decorators/sortable.tsx index 5f4173f5339..8add015e582 100644 --- a/packages/react-table/src/components/Table/utils/decorators/sortable.tsx +++ b/packages/react-table/src/components/Table/utils/decorators/sortable.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Table/table'; -import { SortByDirection, IExtra, IFormatterValueType, ITransform } from '../../Table'; -import { SortColumn } from '../../SortColumn'; +import { IExtra, IFormatterValueType, ITransform } from '../../Table'; +import { SortColumn, SortByDirection } from '../../SortColumn'; export const sortable: ITransform = (label: IFormatterValueType, { columnIndex, column, property }: IExtra) => { const { diff --git a/packages/rollup.base.js b/packages/rollup.base.js new file mode 100644 index 00000000000..a654bf1cf87 --- /dev/null +++ b/packages/rollup.base.js @@ -0,0 +1,56 @@ +const resolve = require('@rollup/plugin-node-resolve'); +const commonjs = require('@rollup/plugin-commonjs'); +const scss = require('rollup-plugin-scss'); +const replace = require('@rollup/plugin-replace'); +const { terser } = require('rollup-plugin-terser'); + +const isProduction = process.env.IS_PRODUCTION; +let exitCode = 0; + +function circularFailPlugin() { + return { + name: 'circluarFailPlugin', + buildEnd() { + if (exitCode !== 0) { + process.exit(exitCode); + } + } + }; +} + +module.exports = ({ packageName, name }) => ({ + input: 'dist/esm/index.js', + output: { + file: `dist/umd/${packageName}${isProduction ? '.min' : ''}.js`, + format: 'umd', + name, + globals: { + react: 'React', + 'react-dom': 'ReactDOM' + } + }, + external: ['react', 'react-dom'], + plugins: [ + replace({ + 'process.env.NODE_ENV': `'${isProduction ? 'production' : 'development'}'` + }), + resolve(), + commonjs(), + scss(), + isProduction && terser(), + circularFailPlugin() + ], + onwarn(warning) { + if (warning.code === 'CIRCULAR_DEPENDENCY') { + const split = warning.message.split(':'); + if (warning.message.includes('d3-interpolate')) { + // eslint-disable-next-line no-console + console.error(`\x1b[33m(!) ${split[0]}:\x1b[0m${split[1]}`); + } else { + // eslint-disable-next-line no-console + console.error(`\x1b[31m(!) ${split[0]}:\x1b[0m${split[1]}`); + exitCode = 1; + } + } + } +});