Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { TextInput } from "@patternfly/react-core";

export class CSSSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
filterValue: ""
};
}

onFilterChange = (_change, event) => {
this.setState(
{
filterValue: event.target.value
},
() => this.props.getDebouncedFilteredRows(this.state.filterValue)
);
};

render() {
return (
<TextInput
type="text"
aria-label="Filter CSS Variables"
placeholder="Filter CSS Variables"
value={this.state.filterValue}
onChange={this.onFilterChange}
/>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
height: 18px;
width: 18px;
border: 1px solid #72767b;
border-radius: 9px;
}

.ws-td-text {
font-size: 14px;
font-size: 14px !important;
}
Original file line number Diff line number Diff line change
@@ -1,105 +1,226 @@
import React from 'react';
import { TextInput } from '@patternfly/react-core';
import { Table, TableHeader, TableBody, sortable, SortByDirection } from '@patternfly/react-table';
import * as tokensModule from '@patternfly/react-tokens';
import './cssVariables.css';
import React from "react";
import { debounce } from "@patternfly/react-core";
import {
Table,
TableHeader,
TableBody,
sortable,
SortByDirection,
expandable
} from "@patternfly/react-table";
import * as tokensModule from "@patternfly/react-tokens/dist/variables/js";
import global_spacer_md from "@patternfly/react-tokens/dist/js/global_spacer_md";
import LevelUpAltIcon from "@patternfly/react-icons/dist/js/icons/level-up-alt-icon";
import { CSSSearch } from './cssSearch';

import "./cssVariables.css";

const isColorRegex = /^(#|rgb)/;

const mappingAsList = (property, values) => (
<div>
<div
style={{
padding: `4px 0 4px calc(${global_spacer_md.value})`
}}
>
<span style={{ paddingLeft: '16px' }}>
{property}
</span>
</div>
{values.map((entry, index) => (
<div
style={{
padding: `4px 0 4px calc(${global_spacer_md.value} * ${index + 3})`
}}
>
<LevelUpAltIcon style={{ transform: 'rotate(90deg)' }} />
<span style={{ paddingLeft: '16px' }}>
{entry}
</span>
</div>
))}
</div>
);

const flattenList = files => {
let list = [];
files.forEach(file => {
Object.entries(file).forEach(([selector, values]) => {
values.forEach(val => {
list.push({
selector,
property: val.property,
token: val.token,
value: val.value,
values: val.values
});
});
});
});
return list;
};

export class CSSVariables extends React.Component {
constructor(props) {
super(props);
// Ensure array in case of multiple prefixes
this.prefix = typeof props.prefix === 'string'
? [props.prefix]
: props.prefix;
const initialRows = Object.entries(tokensModule)
.filter(([_key, val]) => {
for (let i = 0; i < this.prefix.length; i++) {
if (val.name && val.name.includes(this.prefix[i])) {
return true;
this.prefix =
typeof props.prefix === "string" ? [props.prefix] : props.prefix;
const prefixTokens = this.prefix.map(prefix => prefix.replace("pf-", "").replace(/-+/g, "_"));
const applicableFiles = Object.entries(tokensModule)
.filter(([key, val]) => prefixTokens.includes(key))
.sort(([key1], [key2]) => key1.localeCompare(key2))
.map(([key, val]) => {
if (props.selector) {
return {
[props.selector]: val[props.selector]
}
}
return false
})
.sort(([key1], [key2]) => key1.localeCompare(key2))
.map(([key, val]) => [
val.name,
key,
val.value
]);
return val;
});

this.flatList = flattenList(applicableFiles);

this.columns = [
{ title: 'Variable', transforms: [sortable] },
{ title: 'React Token', transforms: [sortable] },
{ title: 'Value', transforms: [sortable] }
];

...props.hideSelectorColumn ? [] : [{
title: "Selector",
transforms: [sortable],
cellFormatters: [expandable]
}],
{ title: "Variable", transforms: [sortable] },
{ title: "React Token", transforms: [sortable] },
{ title: "Value", transforms: [sortable] }
]

this.state = {
filterValue: '',
rows: initialRows,
searchRE: '',
rows: this.getFilteredRows(),
sortBy: {
index: 0,
direction: 'asc' // a-z
direction: "asc" // a-z
}
};
}

onFilterChange = (_change, event) => {
getFilteredRows = (searchRE) => {
let filteredRows = [];
let rowNumber = -1;
this.flatList.forEach(row => {
const { selector, property, token, value, values} = row;
const passes =
!searchRE ||
searchRE.test(selector) ||
searchRE.test(property) ||
searchRE.test(token) ||
searchRE.test(value) ||
(values && searchRE.test(JSON.stringify(values)));
if (passes) {
const rowKey = `${selector}_${property}`;
const cells = [
...this.props.hideSelectorColumn ? [] : [selector],
property,
token,
<div key={rowKey}>
<div
key={`${rowKey}_1`}
className="pf-l-flex pf-m-space-items-sm"
>
{isColorRegex.test(value) && (
<div
key={`${rowKey}_2`}
className="pf-l-flex pf-m-column pf-m-align-self-center"
>
<span
className="ws-color-box"
style={{ backgroundColor: value }}
/>
</div>
)}
<div
key={`${rowKey}_3`}
className="pf-l-flex pf-m-column pf-m-align-self-center ws-td-text"
>
{value}
</div>
</div>
</div>
];
filteredRows.push({
isOpen: values ? false : undefined,
cells
});
rowNumber += 1;
if (values) {
filteredRows.push({
parent: rowNumber,
fullWidth: true,
cells: [
{
title: mappingAsList(property, values)
}
]
});
rowNumber += 1;
}
}
});
return filteredRows;
};

onCollapse = (event, rowKey, isOpen) => {
const { rows } = this.state;
rows[rowKey].isOpen = isOpen;
this.setState({
filterValue: event.target.value
rows
});
}
};

getDebouncedFilteredRows = debounce(value => {
const searchRE = new RegExp(value, "i");
this.setState({
searchRE,
rows: this.getFilteredRows(searchRE)
});
}, 500);

onSort = (_event, index, direction) => {
const sortedRows = this.state.rows
.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0));
this.flatList = this.flatList.sort((a, b) => {
const indexToColMap = {
'1': 'selector',
'2': 'property',
'3': 'token',
'4': 'value'
};
const column = indexToColMap[index];
if (direction === SortByDirection.asc) {
return a[column] < b[column] ? -1 : a[column] > b[column] ? 1 : 0;
} else {
return a[column] > b[column] ? -1 : a[column] < b[column] ? 1 : 0;
}
});
this.setState({
sortBy: {
index,
direction
},
rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
rows: this.getFilteredRows(this.state.searchRE)
});
}
};

render() {
const searchRE = new RegExp(this.state.filterValue, 'i');
const filteredRows = this.state.rows
.filter(c => searchRE.test(c[0]) || searchRE.test(c[1]) || searchRE.test(c[2]));
return (
<React.Fragment>
<TextInput
type="text"
aria-label="Filter CSS Variables"
placeholder="Filter CSS Variables"
value={this.state.filterValue}
onChange={this.onFilterChange}
/>
<CSSSearch getDebouncedFilteredRows={this.getDebouncedFilteredRows} />
<Table
variant="compact"
aria-label={`CSS Variables for prefixes ${this.prefix.join(' ')}`}
aria-label={`CSS Variables for prefixes ${this.prefix.join(" ")}`}
sortBy={this.state.sortBy}
onSort={this.onSort}
cells={this.columns}
rows={filteredRows.map(row => ({
cells: [
row[0],
row[1],
<div key={row[2]}>
<div key={`${row[2]}1`} className="pf-l-flex pf-m-space-items-sm">
{isColorRegex.test(row[2]) && (
<div key={`${row[2]}2`} className="pf-l-flex pf-m-column pf-m-align-self-center">
<span className="ws-color-box" style={{ backgroundColor: row[2] }} />
</div>
)}
<div key={`${row[2]}3`} className="pf-l-flex pf-m-column pf-m-align-self-center ws-td-text">
{row[2]}
</div>
</div>
</div>
]
}))}
rows={this.state.rows}
onCollapse={this.onCollapse}
gridBreakPoint="grid-lg"
>
<TableHeader />
<TableBody />
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby-theme-patternfly-org/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './autoLinkHeader/autoLinkHeader';
export * from './banner/banner';
export * from './commonComponents/commonComponents';
export * from './cssVariables/cssVariables';
export * from './cssVariables/cssSearch';
export * from './example/example';
export * from './footer/footer';
export * from './gdprBanner/gdprBanner';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const PropsTable = props => {
aria-label={props.caption}
cells={columns}
caption={props.caption}
gridBreakPoint="grid-lg"
rows={props.rows
.filter(row => !row.hide)
.map((row, idx) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,13 @@ PatternFly 4 styles provide a default starting point. You can use the variable s

## Global CSS variables

<CSSVariables prefix="global" />
<CSSVariables prefix="patternfly_variables" selector=":root" hideSelectorColumn />

## Chart CSS variables

<CSSVariables prefix="patternfly_charts" hideSelectorColumn />

## Font type CSS variables

<CSSVariables prefix="patternfly_variables" selector=".pf-m-redhat-font" />