@patternfly/design-tokens 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ .ws-token-swatch {
2
+ height: 1em;
3
+ display: inline-block;
4
+ aspect-ratio: 1 / 1;
5
+ border-radius: 50%;
6
+ border: var(--pf-t--global--border--width--regular) solid var(--pf-t--global--background--color--inverse--default);
7
+ box-shadow: var(--pf-t--global--box-shadow--sm);
8
+ }
9
+
10
+ @media (min-width: 1200px) {
11
+ .tokens-table-outer-wrapper {
12
+ width: calc(92vw - var(--pf-v6-c-page__sidebar--Width));
13
+ max-width: calc(92vw - var(--pf-v6-c-page__sidebar--Width));
14
+ }
15
+ }
@@ -1,10 +1,5 @@
1
- import React from "react";
2
- import {
3
- SearchInput,
4
- Toolbar,
5
- ToolbarItem,
6
- ToolbarContent,
7
- } from "@patternfly/react-core";
1
+ import React from 'react';
2
+ import { Flex, FlexItem, Grid, GridItem, Title, capitalize } from '@patternfly/react-core';
8
3
  import {
9
4
  Table,
10
5
  Thead,
@@ -14,130 +9,238 @@ import {
14
9
  Td,
15
10
  ExpandableRowContent,
16
11
  OuterScrollContainer,
17
- InnerScrollContainer,
18
- } from "@patternfly/react-table";
12
+ InnerScrollContainer
13
+ } from '@patternfly/react-table';
14
+ import { TokensToolbar } from './tokensToolbar';
15
+ import './tokensTable.css';
19
16
 
20
17
  // eslint-disable-next-line camelcase
21
- import global_spacer_md from "@patternfly/react-tokens/dist/esm/global_spacer_md";
22
- import LevelUpAltIcon from "@patternfly/react-icons/dist/esm/icons/level-up-alt-icon";
23
-
24
- import * as scssAsJson from "../scssAsJson";
18
+ import global_spacer_md from '@patternfly/react-tokens/dist/esm/global_spacer_md';
19
+ import LevelUpAltIcon from '@patternfly/react-icons/dist/esm/icons/level-up-alt-icon';
25
20
 
26
- export const TokensTable = () => {
27
- const scssVariables = Object.keys(scssAsJson);
28
- const [searchValue, setSearchValue] = React.useState('');
29
- const [expandedTokens, setExpandedTokens] = React.useState([]);
30
- const setExpanded = (tokenName, isExpanding = true) =>
31
- setExpandedTokens((prevExpanded) => {
32
- const otherExpandedTokens = prevExpanded.filter((n) => n !== tokenName);
33
- return isExpanding ? [...otherExpandedTokens, tokenName] : otherExpandedTokens;
34
- });
35
- const isTokenExpanded = (tokenName) => expandedTokens.includes(tokenName);
36
-
37
- const showTokenChain = (tokenName) => {
38
- let tokenChain = [];
39
- let tokenValue = scssAsJson[tokenName];
21
+ // Used to combine data grouped by theme under each token name
22
+ const deepMerge = (target, source) => {
23
+ for (const key in source) {
24
+ if (source[key] instanceof Object && key in target) {
25
+ Object.assign(source[key], deepMerge(target[key], source[key]));
26
+ }
27
+ }
28
+ return Object.assign(target || {}, source);
29
+ };
40
30
 
41
- while (tokenValue !== undefined) {
42
- tokenChain = [...tokenChain, tokenValue]
43
- tokenValue = scssAsJson[tokenValue];
31
+ const getTokenChain = (themeTokenData) => {
32
+ let tokenChain = [];
33
+ let referenceToken = themeTokenData?.references?.[0];
34
+ while (referenceToken && referenceToken !== undefined) {
35
+ tokenChain = [...tokenChain, referenceToken.name];
36
+ if (referenceToken?.references?.[0]) {
37
+ referenceToken = referenceToken?.references?.[0];
38
+ } else {
39
+ tokenChain.push(referenceToken.value);
40
+ break;
44
41
  }
42
+ }
43
+ return tokenChain;
44
+ };
45
45
 
46
- return (
47
- <div>
46
+ const showTokenChain = (themeTokenData) => {
47
+ const tokenChain = getTokenChain(themeTokenData);
48
+ return (
49
+ <div>
50
+ {tokenChain.map((nextValue, index) => (
48
51
  <div
49
- className="ws-css-property"
52
+ key={`${index}`}
50
53
  style={{
51
- padding: `4px 0 4px calc(${global_spacer_md.value} * ${3})`
52
- }}>
54
+ padding: `4px 0 4px calc(${global_spacer_md.value} * ${index})`
55
+ }}
56
+ >
53
57
  <LevelUpAltIcon style={{ transform: 'rotate(90deg)' }} />
54
- <span style={{ paddingLeft: '16px' }}>
55
- {tokenName}
56
- </span>
58
+ <span style={{ paddingInlineStart: global_spacer_md.value }}>{nextValue}</span>
57
59
  </div>
58
- {tokenChain.map((nextValue, index) => (
59
- <div
60
- key={index}
61
- style={{
62
- padding: `4px 0 4px calc(${global_spacer_md.value} * ${index + 4})`
63
- }}
64
- >
65
- <LevelUpAltIcon style={{ transform: 'rotate(90deg)' }} />
66
- <span style={{ paddingLeft: '16px' }}>
67
- {nextValue}
68
- </span>
69
- </div>
70
- ))}
71
- </div>
60
+ ))}
61
+ </div>
62
+ );
63
+ };
64
+
65
+ const isSearchMatch = (searchValue, tokenName, tokenData) => {
66
+ // match all tokens if no search term
67
+ if (searchValue === '') {
68
+ return true;
69
+ }
70
+ // match search term to token name, value, and description
71
+ searchValue = searchValue.toLowerCase();
72
+ return (
73
+ tokenName.toLowerCase().includes(searchValue) ||
74
+ Object.entries(tokenData).some(
75
+ ([_themeName, themeData]) =>
76
+ themeData?.value?.toString().toLowerCase().includes(searchValue) ||
77
+ themeData?.description?.toLowerCase().includes(searchValue)
72
78
  )
73
- };
79
+ );
80
+ };
81
+
82
+ export const TokensTable = ({ tokenJson, formatThemeText = capitalize }) => {
83
+ // parse tokens from json, convert from modules, merge into single allTokens obj
84
+ const themesArr = Object.keys(tokenJson);
85
+ const themesObj = themesArr.reduce((acc, cur) => {
86
+ acc[cur] = JSON.parse(JSON.stringify(tokenJson[cur]));
87
+ return acc;
88
+ }, {});
89
+ const allTokens = deepMerge(...Object.values(themesObj));
90
+ // remove default property which is duplicate of other fields
91
+ delete allTokens.default;
92
+
93
+ // state variables
94
+ const [searchValue, setSearchValue] = React.useState('');
95
+ const [expandedTokens, setExpandedTokens] = React.useState([]);
96
+ const [selectedCategories, setSelectedCategories] = React.useState([]);
97
+
98
+ // helper funcs
99
+ const isTokenExpanded = (tokenName) => expandedTokens.includes(tokenName);
100
+ const isSelectedCategory = (categoryName) =>
101
+ selectedCategories.length === 0 || selectedCategories.includes(categoryName);
102
+ const setExpanded = (tokenName, isExpanding = true) =>
103
+ setExpandedTokens((prevExpanded) => {
104
+ const otherExpandedTokens = prevExpanded.filter((n) => n !== tokenName);
105
+ return isExpanding ? [...otherExpandedTokens, tokenName] : otherExpandedTokens;
106
+ });
74
107
 
75
108
  return (
76
109
  <React.Fragment>
77
- <Toolbar id="filter-toolbar">
78
- <ToolbarContent>
79
- <ToolbarItem variant="search-filter">
80
- <SearchInput
81
- aria-label="Search all tokens"
82
- placeholder="Search all tokens"
83
- value={searchValue}
84
- onChange={(_event, value) => setSearchValue(value)}
85
- onClear={() => setSearchValue("")}
86
- />
87
- </ToolbarItem>
88
- </ToolbarContent>
89
- </Toolbar>
90
- <OuterScrollContainer>
110
+ <TokensToolbar
111
+ searchValue={searchValue}
112
+ setSearchValue={setSearchValue}
113
+ selectedCategories={selectedCategories}
114
+ setSelectedCategories={setSelectedCategories}
115
+ />
116
+ <OuterScrollContainer className="tokens-table-outer-wrapper">
91
117
  <InnerScrollContainer>
92
- <Table variant="compact">
93
- <Thead>
94
- <Th></Th>
95
- <Th>Name</Th>
96
- <Th>Value</Th>
97
- </Thead>
98
- {scssVariables.map((tokenName, rowIndex) => {
99
- if (tokenName === 'default') {
100
- return undefined
101
- } else if (searchValue !== '' && !tokenName.includes(searchValue)) {
102
- return undefined
118
+ {
119
+ // Create new Table for each tokens layer [base, chart, palette, semantic]
120
+ Object.entries(allTokens).map(([layerName, layerDataObj], _rowIndex) => {
121
+ // save if semantic layer - used for custom styling due to description field
122
+ const isSemanticLayer = layerName === 'semantic';
123
+
124
+ // Create array of all tokens/nested tokens in layer, filtered by selectedCategories
125
+ let layerTokens = [];
126
+ if (!['base', 'semantic'].includes(layerName) && isSelectedCategory(layerName)) {
127
+ layerTokens = Object.entries(layerDataObj);
103
128
  } else {
104
- const isResolved = scssAsJson[scssAsJson[tokenName]] === undefined;
105
- return (
106
- <Tbody key={`row-${tokenName}`} isExpanded={isTokenExpanded(tokenName)}>
107
- <Tr>
108
- <Td
109
- expand={
110
- !isResolved
111
- ? {
112
- rowIndex,
113
- isExpanded: isTokenExpanded(tokenName),
114
- onToggle: () =>
115
- setExpanded(tokenName, !isTokenExpanded(tokenName)),
116
- expandId: `${tokenName}-expandable-toggle`,
117
- }
118
- : undefined
119
- }
120
- />
121
- <Td>{tokenName}</Td>
122
- <Td>{scssAsJson[scssAsJson[tokenName]] === undefined && scssAsJson[tokenName]}</Td>
123
- </Tr>
124
- {!isResolved && (
125
- <Tr isExpanded={isTokenExpanded(tokenName)}>
126
- <Td />
127
- <Td noPadding dataLabel="Details" colSpan={2}>
128
- <ExpandableRowContent>
129
- {showTokenChain(scssAsJson[tokenName])}
130
- </ExpandableRowContent>
131
- </Td>
132
- </Tr>
133
- )}
134
- </Tbody>
135
- )
129
+ // base/semantic combine subcategory tokens into flattened arr
130
+ for (var subLayer in layerDataObj) {
131
+ isSelectedCategory(subLayer) && layerTokens.push(...Object.entries(layerDataObj[subLayer]));
132
+ }
136
133
  }
137
- })}
138
- </Table>
134
+ // finally filter all tokens based on search term
135
+ const filteredTokens = layerTokens.filter(([tokenName, tokenData]) =>
136
+ isSearchMatch(searchValue, tokenName, tokenData)
137
+ );
138
+
139
+ return (
140
+ <>
141
+ <Title headingLevel="h2" id={`${layerName}-table`} className="pf-v6-u-mt-xl">
142
+ {formatThemeText(layerName)} tokens
143
+ </Title>
144
+ <Table variant="compact" style={{ marginBlockEnd: `var(--pf-t--global--spacer--xl)` }}>
145
+ <Thead>
146
+ <Tr>
147
+ {/* Only semantic tokens have description, adjust columns accordingly */}
148
+ <Th width={5}></Th>
149
+ <Th width={isSemanticLayer ? 60 : 80}>Name</Th>
150
+ <Th width={isSemanticLayer ? 10 : 15}>Value</Th>
151
+ {isSemanticLayer && <Th width={25}>Description</Th>}
152
+ </Tr>
153
+ </Thead>
154
+
155
+ {/* Loop through row for each token in current layer */}
156
+ {filteredTokens.map(([tokenName, tokenData], rowIndex) => {
157
+ const tokenThemesArr = Object.entries(tokenData);
158
+ const hasReferences = tokenThemesArr.some(([_themeName, themeToken]) =>
159
+ themeToken.hasOwnProperty('references')
160
+ );
161
+ const tokenDescription = tokenThemesArr[0][1].description;
162
+
163
+ return (
164
+ <Tbody key={`row-${tokenName}`} isExpanded={isTokenExpanded(tokenName)}>
165
+ <Tr>
166
+ {/* Expandable row icon */}
167
+ <Td
168
+ expand={
169
+ hasReferences
170
+ ? {
171
+ rowIndex,
172
+ isExpanded: isTokenExpanded(tokenName),
173
+ onToggle: () => setExpanded(tokenName, !isTokenExpanded(tokenName)),
174
+ expandId: `${tokenName}-expandable-toggle`
175
+ }
176
+ : undefined
177
+ }
178
+ />
179
+ <Td>
180
+ <code>{tokenName}</code>
181
+ </Td>
182
+ {/* Token values for each theme */}
183
+ <Td>
184
+ {tokenThemesArr.map(([themeName, themeToken]) => {
185
+ const isColor = /^(#|rgb)/.test(themeToken.value);
186
+ return (
187
+ <Flex
188
+ justifyContent={{ default: 'justify-content-space-between' }}
189
+ flexWrap={{ default: 'nowrap' }}
190
+ key={`${themeName}-${tokenName}`}
191
+ >
192
+ <FlexItem>{formatThemeText(themeName)}:</FlexItem>
193
+ {isColor ? (
194
+ <FlexItem
195
+ key={`${themeName}_${tokenName}_swatch`}
196
+ className="pf-v6-l-flex pf-m-column pf-m-align-self-center"
197
+ >
198
+ <span
199
+ className="ws-token-swatch"
200
+ style={{ backgroundColor: themeToken.value }}
201
+ />
202
+ </FlexItem>
203
+ ) : (
204
+ <div className="pf-v6-l-flex pf-m-column pf-m-align-self-center">
205
+ {themeToken.value}
206
+ </div>
207
+ )}
208
+ </Flex>
209
+ );
210
+ })}
211
+ </Td>
212
+ {/* Description - only for semantic tokens */}
213
+ {isSemanticLayer && <Td>{tokenDescription}</Td>}
214
+ </Tr>
215
+
216
+ {/* Expandable token chain */}
217
+ {hasReferences && isTokenExpanded(tokenName) && (
218
+ <Tr isExpanded>
219
+ <Td />
220
+ <Td colSpan={3}>
221
+ <ExpandableRowContent>
222
+ <Grid hasGutter>
223
+ {tokenThemesArr.map(([themeName, themeToken]) => (
224
+ <>
225
+ <GridItem span={2}>{formatThemeText(themeName)}:</GridItem>
226
+ <GridItem span={10}>{showTokenChain(themeToken)}</GridItem>
227
+ </>
228
+ ))}
229
+ </Grid>
230
+ </ExpandableRowContent>
231
+ </Td>
232
+ </Tr>
233
+ )}
234
+ </Tbody>
235
+ );
236
+ })}
237
+ </Table>
238
+ </>
239
+ );
240
+ })
241
+ }
139
242
  </InnerScrollContainer>
140
243
  </OuterScrollContainer>
141
244
  </React.Fragment>
142
- )
245
+ );
143
246
  };
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import {
3
+ MenuToggle,
4
+ SearchInput,
5
+ Select,
6
+ SelectList,
7
+ SelectOption,
8
+ Toolbar,
9
+ ToolbarItem,
10
+ ToolbarContent
11
+ } from '@patternfly/react-core';
12
+ import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
13
+
14
+ export const TokensToolbar = ({ selectedCategories, setSelectedCategories, searchValue, setSearchValue }) => {
15
+ const [isSelectOpen, setIsSelectOpen] = React.useState(false);
16
+
17
+ return (
18
+ <Toolbar id="filter-toolbar">
19
+ <ToolbarContent>
20
+ <ToolbarItem variant="search-filter">
21
+ <SearchInput
22
+ aria-label="Search all tokens"
23
+ placeholder="Search all tokens"
24
+ value={searchValue}
25
+ onChange={(_event, value) => setSearchValue(value)}
26
+ onClear={() => setSearchValue('')}
27
+ />
28
+ </ToolbarItem>
29
+ <ToolbarItem>
30
+ <Select
31
+ id="select-tokens-category"
32
+ aria-label="Select Input"
33
+ role="menu"
34
+ toggle={(toggleRef) => (
35
+ <MenuToggle
36
+ icon={<FilterIcon />}
37
+ ref={toggleRef}
38
+ onClick={() => setIsSelectOpen(!isSelectOpen)}
39
+ isExpanded={isSelectOpen}
40
+ >
41
+ Category
42
+ </MenuToggle>
43
+ )}
44
+ isOpen={isSelectOpen}
45
+ onOpenChange={(isOpen) => setIsSelectOpen(isOpen)}
46
+ onSelect={(_e, category) => {
47
+ if (selectedCategories.includes(category)) {
48
+ setSelectedCategories(selectedCategories.filter((cat) => cat !== category));
49
+ } else {
50
+ setSelectedCategories([...selectedCategories, category]);
51
+ }
52
+ setIsSelectOpen(!isSelectOpen);
53
+ }}
54
+ >
55
+ <SelectList>
56
+ <SelectOption hasCheckbox key={0} value="colors" isSelected={selectedCategories.includes('colors')}>
57
+ Colors
58
+ </SelectOption>
59
+ <SelectOption hasCheckbox key={1} value="dimension" isSelected={selectedCategories.includes('dimension')}>
60
+ Dimension
61
+ </SelectOption>
62
+ <SelectOption hasCheckbox key={2} value="motion" isSelected={selectedCategories.includes('motion')}>
63
+ Motion
64
+ </SelectOption>
65
+ <SelectOption hasCheckbox key={3} value="palette" isSelected={selectedCategories.includes('palette')}>
66
+ Palette
67
+ </SelectOption>
68
+ <SelectOption hasCheckbox key={4} value="chart" isSelected={selectedCategories.includes('chart')}>
69
+ Chart
70
+ </SelectOption>
71
+ </SelectList>
72
+ </Select>
73
+ </ToolbarItem>
74
+ </ToolbarContent>
75
+ </Toolbar>
76
+ );
77
+ };
@@ -1,11 +1,14 @@
1
1
  import React from 'react';
2
2
  import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
3
+ import * as defaultTokens from '../../../content/./token-layers-default.json';
4
+ import * as darkTokens from '../../../content/./token-layers-dark.json';
3
5
  import { TokensTable } from '../../../content/./tokensTable.js';
4
6
  const pageData = {
5
7
  "id": "All PatternFly tokens",
6
8
  "section": "tokens",
7
9
  "subsection": "",
8
10
  "deprecated": false,
11
+ "template": false,
9
12
  "beta": false,
10
13
  "demo": false,
11
14
  "newImplementationLink": false,
@@ -16,16 +19,18 @@ const pageData = {
16
19
  "relPath": "packages/module/patternfly-docs/content/all-patternfly-tokens.md"
17
20
  };
18
21
  pageData.liveContext = {
22
+ defaultTokens,
23
+ darkTokens,
19
24
  TokensTable
20
25
  };
21
- pageData.relativeImports = "import { TokensTable } from 'content/./tokensTable.js';"
26
+ pageData.relativeImports = "import * as defaultTokens from 'content/./token-layers-default.json';,import * as darkTokens from 'content/./token-layers-dark.json';,import { TokensTable } from 'content/./tokensTable.js';"
22
27
  pageData.examples = {
23
28
 
24
29
  };
25
30
 
26
31
  const Component = () => (
27
32
  <React.Fragment>
28
- <TokensTable/>
33
+ <TokensTable tokenJson={{default: defaultTokens, dark: darkTokens}}/>
29
34
  </React.Fragment>
30
35
  );
31
36
  Component.displayName = 'TokensAllPatternflyTokensTokensDocs';
@@ -106,20 +106,6 @@
106
106
  }
107
107
  },
108
108
  "font": {
109
- "family": {
110
- "100": {
111
- "type": "string",
112
- "value": "Red Hat Text VF"
113
- },
114
- "200": {
115
- "type": "string",
116
- "value": "Red Hat Display VF"
117
- },
118
- "300": {
119
- "type": "string",
120
- "value": "Red Hat Mono VF"
121
- }
122
- },
123
109
  "weight": {
124
110
  "100": {
125
111
  "type": "number",
@@ -181,6 +167,20 @@
181
167
  "type": "number",
182
168
  "value": 36
183
169
  }
170
+ },
171
+ "family": {
172
+ "100": {
173
+ "type": "string",
174
+ "value": "\"Red Hat Text\", \"RedHatText\", \"Noto Sans Arabic\", \"Noto Sans Hebrew\", \"Noto Sans JP\", \"Noto Sans KR\", \"Noto Sans Malayalam\", \"Noto Sans SC\", \"Noto Sans TC\", \"Noto Sans Thai\", Helvetica, Arial, sans-serif"
175
+ },
176
+ "200": {
177
+ "type": "string",
178
+ "value": "\"Red Hat Display\", \"RedHatDisplay\", \"Noto Sans Arabic\", \"Noto Sans Hebrew\", \"Noto Sans JP\", \"Noto Sans KR\", \"Noto Sans Malayalam\", \"Noto Sans SC\", \"Noto Sans TC\", \"Noto Sans Thai\", Helvetica, Arial, sans-serif"
179
+ },
180
+ "300": {
181
+ "type": "string",
182
+ "value": "\"Red Hat Mono\", \"RedHatMono\", \"Courier New\", Courier, monospace"
183
+ }
184
184
  }
185
185
  },
186
186
  "z-index": {
@@ -328,6 +328,28 @@
328
328
  "type": "number",
329
329
  "value": 1450
330
330
  }
331
+ },
332
+ "text-decoration": {
333
+ "line": {
334
+ "100": {
335
+ "type": "string",
336
+ "value": "none"
337
+ },
338
+ "200": {
339
+ "type": "string",
340
+ "value": "underline"
341
+ }
342
+ },
343
+ "style": {
344
+ "100": {
345
+ "type": "string",
346
+ "value": "solid"
347
+ },
348
+ "200": {
349
+ "type": "string",
350
+ "value": "dashed"
351
+ }
352
+ }
331
353
  }
332
354
  }
333
355
  }