@indico-data/design-system 2.48.0 → 2.50.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.
Files changed (41) hide show
  1. package/lib/components/table/Table.stories.d.ts +1 -0
  2. package/lib/components/table/components/HorizontalStickyHeader.d.ts +10 -0
  3. package/lib/components/table/components/__tests__/HorizontalStickyHeader.test.d.ts +1 -0
  4. package/lib/components/table/components/helpers.d.ts +6 -0
  5. package/lib/components/table/hooks/usePinnedColumnsManager.d.ts +8 -0
  6. package/lib/components/table/sampleData.d.ts +4 -0
  7. package/lib/components/table/types.d.ts +11 -1
  8. package/lib/components/table/utils/processColumns.d.ts +2 -0
  9. package/lib/index.css +188 -89
  10. package/lib/index.d.ts +12 -1
  11. package/lib/index.esm.css +188 -89
  12. package/lib/index.esm.js +238 -2
  13. package/lib/index.esm.js.map +1 -1
  14. package/lib/index.js +238 -2
  15. package/lib/index.js.map +1 -1
  16. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesData.d.ts +7 -0
  17. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesTable.d.ts +1 -0
  18. package/lib/stylesAndAnimations/utilityClasses/UtilityClassesTable.stories.d.ts +6 -0
  19. package/lib/utils/getPreviousHeadersWidth.d.ts +1 -0
  20. package/package.json +1 -1
  21. package/src/components/table/Table.mdx +134 -0
  22. package/src/components/table/Table.stories.tsx +71 -2
  23. package/src/components/table/Table.tsx +16 -1
  24. package/src/components/table/components/HorizontalStickyHeader.tsx +57 -0
  25. package/src/components/table/components/__tests__/HorizontalStickyHeader.test.tsx +104 -0
  26. package/src/components/table/components/helpers.ts +90 -0
  27. package/src/components/table/hooks/usePinnedColumnsManager.ts +146 -0
  28. package/src/components/table/{sampleData.ts → sampleData.tsx} +156 -1
  29. package/src/components/table/styles/Table.scss +32 -15
  30. package/src/components/table/styles/_variables.scss +2 -0
  31. package/src/components/table/types.ts +13 -1
  32. package/src/components/table/utils/processColumns.tsx +35 -0
  33. package/src/setup/setupTests.ts +8 -0
  34. package/src/storybookDocs/Permafrost.mdx +22 -11
  35. package/src/styles/_borders.scss +2 -1
  36. package/src/stylesAndAnimations/borders/BorderColor.tsx +14 -6
  37. package/src/stylesAndAnimations/utilityClasses/UtilityClasses.mdx +24 -0
  38. package/src/stylesAndAnimations/utilityClasses/UtilityClassesData.ts +230 -0
  39. package/src/stylesAndAnimations/utilityClasses/UtilityClassesTable.stories.tsx +13 -0
  40. package/src/stylesAndAnimations/utilityClasses/UtilityClassesTable.tsx +146 -0
  41. package/src/utils/getPreviousHeadersWidth.ts +12 -0
@@ -3,3 +3,11 @@ import { configure } from '@testing-library/react';
3
3
  import './setupIcons';
4
4
 
5
5
  configure({ testIdAttribute: 'data-testid' });
6
+
7
+ class ResizeObserverMock {
8
+ observe() {}
9
+ unobserve() {}
10
+ disconnect() {}
11
+ }
12
+
13
+ global.ResizeObserver = ResizeObserverMock;
@@ -2,13 +2,16 @@ import { Meta } from '@storybook/addon-docs';
2
2
 
3
3
  <Meta title="Getting Started" />
4
4
 
5
- # Permafrost
5
+ # Permafrost
6
+
6
7
  #### Permafrost is the name of our User Interface Design System and Component Library.
8
+
7
9
  Permafrost is utilized in Indico's React projects to ensure a consistent look and feel across our products. It leverages many variables and components that are defined in our design system. We also wrap multiple libraries such as `react-day-picker` or `react-select` to ensure a consistent look and feel.
8
10
 
9
11
  <div style={{ marginBottom: '3rem' }} />
10
12
 
11
13
  ## Installation
14
+
12
15
  Indico serves Permafrost as a package on npm. In order to take advantage of it in your project, you can install it by adding the following to your `package.json`:
13
16
 
14
17
  ```json
@@ -16,16 +19,17 @@ Indico serves Permafrost as a package on npm. In order to take advantage of it i
16
19
  "@indico-data/permafrost": "latest" // or the specific version you want
17
20
  }
18
21
  ```
19
- After adding the package, import the CSS file to apply Permafrost’s styles to the components.
22
+
23
+ After adding the package, import the CSS file to apply Permafrost's styles to the components.
20
24
 
21
25
  ```css
22
- @import "@indico-data/permafrost/dist/index.css";
26
+ @import '@indico-data/permafrost/dist/index.css';
23
27
  ```
24
28
 
25
-
26
29
  ## Usage
27
30
 
28
31
  ### Overriding Variables
32
+
29
33
  You are able to override any of the variables in the design system. We currently support `light` and `dark` themes. If you would like to override a variable in the dark theme, try this approach:
30
34
 
31
35
  ```css
@@ -37,7 +41,8 @@ You are able to override any of the variables in the design system. We currently
37
41
  This pattern applies to all of our variables which you can find in the CSS variables directory in the project.
38
42
 
39
43
  ### Theming
40
- In order to switch between the light and dark themes, you can simply add the `data-theme` attribute to the `html` element. *Note* If no theme is provided, it will default to `:root` which is the dark theme.
44
+
45
+ In order to switch between the light and dark themes, you can simply add the `data-theme` attribute to the `html` element. _Note_ If no theme is provided, it will default to `:root` which is the dark theme.
41
46
 
42
47
  ```html
43
48
  <html data-theme="light">
@@ -47,18 +52,22 @@ In order to switch between the light and dark themes, you can simply add the `da
47
52
 
48
53
  In the example above, it will leverage the `light` theme to render our styles with the `light mode` variables. It is important to note that while Permafrost natively supports `light` and `dark` values for data-theme, these can be extended and even overridden by your project to support additional themes.
49
54
 
50
-
51
55
  ### Importing Components
56
+
52
57
  Using components from Permafrost is as simple as importing them from the package and using them in your project.
53
58
 
54
59
  ```tsx
55
- import {Icon} from '@indico-data/design-system';
60
+ import { Icon } from '@indico-data/design-system';
56
61
 
57
-
58
- <Icon name="indico-o" />
62
+ <Icon name="indico-o" />;
59
63
  ```
60
64
 
65
+ ### Utility Classes
66
+
67
+ Utility classes are pre-defined CSS classes that provide quick and easy styling options for common design patterns. They help maintain consistency and speed up development by offering ready-to-use styles for margins, typography, and more. For a complete list of available utility classes and their usage, see our [Utility Classes documentation](/docs/utility-classes-overview--docs).
68
+
61
69
  ### CSS Only
70
+
62
71
  We have tried to provide as much support as possible for those who wish to implement Permafrost without using our React components. This is where the CSS only approach comes in. We have wrapped the components in a way that allows you to use the same styles with a different library. In order to use the CSS only approach, you can import the css file that sets the styles for the components.
63
72
 
64
73
  You can do this by going into the project and running the following command:
@@ -70,11 +79,13 @@ yarn build
70
79
  This will create an `index.css` file in the `dist` directory that you can then copy and import into your project.
71
80
 
72
81
  #### SASS
82
+
73
83
  If you prefer to use SASS, you can copy the entire `/styles` directory and import the `index.scss` file into your project.
74
84
 
75
85
  **Note:** This will only give you the styling of our design system, none of the interactivity.
76
86
 
77
87
  ### CSS Only Usage
88
+
78
89
  If you wish to do the CSS only approach, you can do so by applying the CSS classes to your components. For example, if you have an input you wish to have styled with our design system, you can do the following:
79
90
 
80
91
  ```tsx
@@ -83,10 +94,10 @@ If you wish to do the CSS only approach, you can do so by applying the CSS class
83
94
 
84
95
  We are as generic as possible with our CSS classes, so you can easily override them if needed.
85
96
 
86
-
87
97
  ## Testing
98
+
88
99
  All of our components have been tested with React Testing Library. You can view the tests for each component by looking in the `__tests__` directory in each component. To run them, you can simply run the following command:
89
100
 
90
101
  ```bash
91
102
  yarn jest
92
- ```
103
+ ```
@@ -3,7 +3,8 @@ $values: var(--pf-border-thin), var(--pf-border-sm), var(--pf-border-md), var(--
3
3
  var(--pf-border-xl);
4
4
  $directions: ('t', top), ('b', bottom), ('l', left), ('r', right);
5
5
  $styles: dashed, dotted, double, solid;
6
- $color-names: 'primary', 'secondary', 'gray', 'steel', 'green', 'orange', 'red';
6
+ $color-names: 'primary', 'secondary', 'tertiary', 'gray', 'red', 'orange', 'yellow', 'green',
7
+ 'purple';
7
8
  $color-grades: '100', '200', '300', '400', '500', '600', '700', '800', '900';
8
9
  $radiusSizes: 0, sm, lg, md, xl, pill, circle, shaped;
9
10
  $radiusValues: var(--pf-rounded-0), var(--pf-rounded-sm), var(--pf-rounded-md), var(--pf-rounded-lg),
@@ -18,12 +18,12 @@ export const BorderColor = () => {
18
18
  <p className="text-align--center">border-secondary</p>
19
19
  </div>
20
20
  <div>
21
- <div className="sb__square bg-gray-800 border border-lg border-gray"></div>
22
- <p className="text-align--center">border-gray</p>
21
+ <div className="sb__square bg-gray-800 border border-lg border-tertiary"></div>
22
+ <p className="text-align--center">border-tertiary</p>
23
23
  </div>
24
24
  <div>
25
- <div className="sb__square bg-gray-800 border border-lg border-green"></div>
26
- <p className="text-align--center">border-green</p>
25
+ <div className="sb__square bg-gray-800 border border-lg border-gray"></div>
26
+ <p className="text-align--center">border-gray</p>
27
27
  </div>
28
28
  <div>
29
29
  <div className="sb__square bg-gray-800 border border-lg border-red"></div>
@@ -34,8 +34,16 @@ export const BorderColor = () => {
34
34
  <p className="text-align--center">border-orange</p>
35
35
  </div>
36
36
  <div>
37
- <div className="sb__square bg-gray-800 border border-lg border-steel"></div>
38
- <p className="text-align--center">border-steel</p>
37
+ <div className="sb__square bg-gray-800 border border-lg border-yellow"></div>
38
+ <p className="text-align--center">border-yellow</p>
39
+ </div>
40
+ <div>
41
+ <div className="sb__square bg-gray-800 border border-lg border-green"></div>
42
+ <p className="text-align--center">border-green</p>
43
+ </div>
44
+ <div>
45
+ <div className="sb__square bg-gray-800 border border-lg border-purple"></div>
46
+ <p className="text-align--center">border-purple</p>
39
47
  </div>
40
48
  </div>
41
49
  );
@@ -0,0 +1,24 @@
1
+ import { Meta, Canvas } from '@storybook/blocks';
2
+ import * as UtilityClassesStories from './UtilityClassesTable.stories';
3
+
4
+ <Meta title="Utility Classes/Overview" />
5
+
6
+ # Utility Classes Overview
7
+
8
+ Utility classes are designed to provide quick and easy styling options for common design patterns. They help maintain consistency and speed up development by offering predefined styles for borders, colors, typography, and more.
9
+
10
+ ## Example Usage
11
+
12
+ Here's a brief example of how you can use utility classes in your project:
13
+
14
+ ```tsx
15
+ <div className="mb-4 text-uppercase">
16
+ This will have a bottom margin of 16px and the text will be uppercase
17
+ </div>
18
+ ```
19
+
20
+ **Note:** If you find yourself adding more than a few utility classes to a single element and it starts resembling Tailwind, consider using CSS (styled-components, SCSS, etc.) and leverage the design system variables directly.
21
+
22
+ ## Utility Classes
23
+
24
+ <Canvas of={UtilityClassesStories.Default} />
@@ -0,0 +1,230 @@
1
+ export type UtilityClassData = {
2
+ className: string;
3
+ css: string;
4
+ category: string;
5
+ resolvedCss?: string;
6
+ };
7
+
8
+ export const utilityClassesData: UtilityClassData[] = [
9
+ // Border Utilities
10
+ {
11
+ className: 'border-primary',
12
+ css: 'border-color: var(--pf-primary-color);',
13
+ category: 'Border',
14
+ },
15
+ {
16
+ className: 'border-secondary',
17
+ css: 'border-color: var(--pf-secondary-color);',
18
+ category: 'Border',
19
+ },
20
+ {
21
+ className: 'border-tertiary',
22
+ css: 'border-color: var(--pf-tertiary-color);',
23
+ category: 'Border',
24
+ },
25
+ { className: 'border-gray', css: 'border-color: var(--pf-gray-color);', category: 'Border' },
26
+ { className: 'border-red', css: 'border-color: var(--pf-red-color);', category: 'Border' },
27
+ { className: 'border-orange', css: 'border-color: var(--pf-orange-color);', category: 'Border' },
28
+ { className: 'border-yellow', css: 'border-color: var(--pf-yellow-color);', category: 'Border' },
29
+ { className: 'border-green', css: 'border-color: var(--pf-green-color);', category: 'Border' },
30
+ { className: 'border-purple', css: 'border-color: var(--pf-purple-color);', category: 'Border' },
31
+ { className: 'border-thin', css: 'border-width: var(--pf-border-thin);', category: 'Border' },
32
+ { className: 'border-sm', css: 'border-width: var(--pf-border-sm);', category: 'Border' },
33
+ { className: 'border-md', css: 'border-width: var(--pf-border-md);', category: 'Border' },
34
+ { className: 'border-lg', css: 'border-width: var(--pf-border-lg);', category: 'Border' },
35
+ { className: 'border-xl', css: 'border-width: var(--pf-border-xl);', category: 'Border' },
36
+ { className: 'border-dashed', css: 'border-style: dashed;', category: 'Border' },
37
+ { className: 'border-dotted', css: 'border-style: dotted;', category: 'Border' },
38
+ { className: 'border-double', css: 'border-style: double;', category: 'Border' },
39
+ { className: 'border-solid', css: 'border-style: solid;', category: 'Border' },
40
+ { className: 'rounded', css: 'border-radius: var(--pf-rounded);', category: 'Border' },
41
+ { className: 'rounded-0', css: 'border-radius: var(--pf-rounded-0);', category: 'Border' },
42
+ { className: 'rounded-sm', css: 'border-radius: var(--pf-rounded-sm);', category: 'Border' },
43
+ { className: 'rounded-md', css: 'border-radius: var(--pf-rounded-md);', category: 'Border' },
44
+ { className: 'rounded-lg', css: 'border-radius: var(--pf-rounded-lg);', category: 'Border' },
45
+ { className: 'rounded-xl', css: 'border-radius: var(--pf-rounded-xl);', category: 'Border' },
46
+ { className: 'rounded-pill', css: 'border-radius: var(--pf-rounded-pill);', category: 'Border' },
47
+ {
48
+ className: 'rounded-circle',
49
+ css: 'border-radius: var(--pf-rounded-circle);',
50
+ category: 'Border',
51
+ },
52
+ {
53
+ className: 'rounded-shaped',
54
+ css: 'border-radius: var(--pf-rounded-shaped);',
55
+ category: 'Border',
56
+ },
57
+
58
+ // Color Utilities
59
+ { className: 'color-primary', css: 'color: var(--pf-primary-color);', category: 'Color' },
60
+ { className: 'color-secondary', css: 'color: var(--pf-secondary-color);', category: 'Color' },
61
+ { className: 'color-tertiary', css: 'color: var(--pf-tertiary-color);', category: 'Color' },
62
+ { className: 'color-gray', css: 'color: var(--pf-gray-color);', category: 'Color' },
63
+ { className: 'color-red', css: 'color: var(--pf-red-color);', category: 'Color' },
64
+ { className: 'color-orange', css: 'color: var(--pf-orange-color);', category: 'Color' },
65
+ { className: 'color-yellow', css: 'color: var(--pf-yellow-color);', category: 'Color' },
66
+ { className: 'color-green', css: 'color: var(--pf-green-color);', category: 'Color' },
67
+ { className: 'color-purple', css: 'color: var(--pf-purple-color);', category: 'Color' },
68
+ { className: 'color-success', css: 'color: var(--pf-success-color);', category: 'Color' },
69
+ { className: 'color-info', css: 'color: var(--pf-info-color);', category: 'Color' },
70
+ { className: 'color-neutral', css: 'color: var(--pf-neutral-color);', category: 'Color' },
71
+ { className: 'color-warning', css: 'color: var(--pf-warning-color);', category: 'Color' },
72
+ { className: 'color-error', css: 'color: var(--pf-error-color);', category: 'Color' },
73
+ { className: 'color-brand', css: 'color: var(--pf-brand-color);', category: 'Color' },
74
+
75
+ // Typography Utilities
76
+ {
77
+ className: 'text-h1',
78
+ css: 'font-size: var(--pf-font-size-h1); font-weight: var(--pf-font-weight-bold);',
79
+ category: 'Typography',
80
+ },
81
+ {
82
+ className: 'text-h2',
83
+ css: 'font-size: var(--pf-font-size-h2); font-weight: var(--pf-font-weight-bold);',
84
+ category: 'Typography',
85
+ },
86
+ {
87
+ className: 'text-h3',
88
+ css: 'font-size: var(--pf-font-size-h3); font-weight: var(--pf-font-weight-bold);',
89
+ category: 'Typography',
90
+ },
91
+ {
92
+ className: 'text-h4',
93
+ css: 'font-size: var(--pf-font-size-h4); font-weight: var(--pf-font-weight-bold);',
94
+ category: 'Typography',
95
+ },
96
+ {
97
+ className: 'text-h5',
98
+ css: 'font-size: var(--pf-font-size-h5); font-weight: var(--pf-font-weight-bold);',
99
+ category: 'Typography',
100
+ },
101
+ { className: 'text-body', css: 'font-size: var(--pf-font-size-body);', category: 'Typography' },
102
+ {
103
+ className: 'text-body-2',
104
+ css: 'font-size: var(--pf-font-size-body2);',
105
+ category: 'Typography',
106
+ },
107
+ {
108
+ className: 'subtitle',
109
+ css: 'font-size: var(--pf-font-size-subtitle);',
110
+ category: 'Typography',
111
+ },
112
+ {
113
+ className: 'subtitle-2',
114
+ css: 'font-size: var(--pf-font-size-subtitle2);',
115
+ category: 'Typography',
116
+ },
117
+ {
118
+ className: 'text-caption',
119
+ css: 'font-size: var(--pf-font-size-caption);',
120
+ category: 'Typography',
121
+ },
122
+ {
123
+ className: 'text-overline',
124
+ css: 'font-size: var(--pf-font-size-overline); text-transform: uppercase;',
125
+ category: 'Typography',
126
+ },
127
+ { className: 'text-capitalize', css: 'text-transform: capitalize;', category: 'Typography' },
128
+ { className: 'text-uppercase', css: 'text-transform: uppercase;', category: 'Typography' },
129
+ { className: 'text-lowercase', css: 'text-transform: lowercase;', category: 'Typography' },
130
+ { className: 'text-decoration--none', css: 'text-decoration: none;', category: 'Typography' },
131
+ {
132
+ className: 'text-decoration--underline',
133
+ css: 'text-decoration: underline;',
134
+ category: 'Typography',
135
+ },
136
+ {
137
+ className: 'text-decoration--line-through',
138
+ css: 'text-decoration: line-through;',
139
+ category: 'Typography',
140
+ },
141
+ {
142
+ className: 'text-decoration--overline',
143
+ css: 'text-decoration: overline;',
144
+ category: 'Typography',
145
+ },
146
+ {
147
+ className: 'text-weight--thin',
148
+ css: 'font-weight: var(--pf-font-weight-thin);',
149
+ category: 'Typography',
150
+ },
151
+ {
152
+ className: 'text-weight--light',
153
+ css: 'font-weight: var(--pf-font-weight-light);',
154
+ category: 'Typography',
155
+ },
156
+ {
157
+ className: 'text-weight--regular',
158
+ css: 'font-weight: var(--pf-font-weight-regular);',
159
+ category: 'Typography',
160
+ },
161
+ {
162
+ className: 'text-weight--medium',
163
+ css: 'font-weight: var(--pf-font-weight-medium);',
164
+ category: 'Typography',
165
+ },
166
+ {
167
+ className: 'text-weight--bold',
168
+ css: 'font-weight: var(--pf-font-weight-bold);',
169
+ category: 'Typography',
170
+ },
171
+ {
172
+ className: 'text-weight--heavy',
173
+ css: 'font-weight: var(--pf-font-weight-heavy);',
174
+ category: 'Typography',
175
+ },
176
+ { className: 'text-align--left', css: 'text-align: left;', category: 'Typography' },
177
+ { className: 'text-align--center', css: 'text-align: center;', category: 'Typography' },
178
+ { className: 'text-align--right', css: 'text-align: right;', category: 'Typography' },
179
+ { className: 'text-opacity--0', css: 'opacity: 0;', category: 'Typography' },
180
+ { className: 'text-opacity--50', css: 'opacity: 0.5;', category: 'Typography' },
181
+ { className: 'text-opacity--100', css: 'opacity: 1;', category: 'Typography' },
182
+ { className: 'text-break--word', css: 'overflow-wrap: break-word;', category: 'Typography' },
183
+
184
+ // Sizing Utilities
185
+ { className: 'ma-auto', css: 'margin: auto;', category: 'Sizing' },
186
+ { className: 'ma-0', css: 'margin: var(--pf-margin-0);', category: 'Sizing' },
187
+ { className: 'ma-1', css: 'margin: var(--pf-margin-1);', category: 'Sizing' },
188
+ { className: 'ma-2', css: 'margin: var(--pf-margin-2);', category: 'Sizing' },
189
+ { className: 'ma-3', css: 'margin: var(--pf-margin-3);', category: 'Sizing' },
190
+ { className: 'ma-4', css: 'margin: var(--pf-margin-4);', category: 'Sizing' },
191
+ { className: 'ma-5', css: 'margin: var(--pf-margin-5);', category: 'Sizing' },
192
+ { className: 'ma-6', css: 'margin: var(--pf-margin-6);', category: 'Sizing' },
193
+ { className: 'ma-7', css: 'margin: var(--pf-margin-7);', category: 'Sizing' },
194
+ { className: 'ma-8', css: 'margin: var(--pf-margin-8);', category: 'Sizing' },
195
+ { className: 'ma-9', css: 'margin: var(--pf-margin-9);', category: 'Sizing' },
196
+ { className: 'ma-10', css: 'margin: var(--pf-margin-10);', category: 'Sizing' },
197
+ { className: 'ma-11', css: 'margin: var(--pf-margin-11);', category: 'Sizing' },
198
+ { className: 'ma-12', css: 'margin: var(--pf-margin-12);', category: 'Sizing' },
199
+ { className: 'ma-13', css: 'margin: var(--pf-margin-13);', category: 'Sizing' },
200
+ { className: 'ma-14', css: 'margin: var(--pf-margin-14);', category: 'Sizing' },
201
+ { className: 'ma-15', css: 'margin: var(--pf-margin-15);', category: 'Sizing' },
202
+ { className: 'ma-16', css: 'margin: var(--pf-margin-16);', category: 'Sizing' },
203
+ { className: 'pa-0', css: 'padding: var(--pf-padding-0);', category: 'Sizing' },
204
+ { className: 'pa-1', css: 'padding: var(--pf-padding-1);', category: 'Sizing' },
205
+ { className: 'pa-2', css: 'padding: var(--pf-padding-2);', category: 'Sizing' },
206
+ { className: 'pa-3', css: 'padding: var(--pf-padding-3);', category: 'Sizing' },
207
+ { className: 'pa-4', css: 'padding: var(--pf-padding-4);', category: 'Sizing' },
208
+ { className: 'pa-5', css: 'padding: var(--pf-padding-5);', category: 'Sizing' },
209
+ { className: 'pa-6', css: 'padding: var(--pf-padding-6);', category: 'Sizing' },
210
+ { className: 'pa-7', css: 'padding: var(--pf-padding-7);', category: 'Sizing' },
211
+ { className: 'pa-8', css: 'padding: var(--pf-padding-8);', category: 'Sizing' },
212
+ { className: 'pa-9', css: 'padding: var(--pf-padding-9);', category: 'Sizing' },
213
+ { className: 'pa-10', css: 'padding: var(--pf-padding-10);', category: 'Sizing' },
214
+ { className: 'pa-11', css: 'padding: var(--pf-padding-11);', category: 'Sizing' },
215
+ { className: 'pa-12', css: 'padding: var(--pf-padding-12);', category: 'Sizing' },
216
+ { className: 'pa-13', css: 'padding: var(--pf-padding-13);', category: 'Sizing' },
217
+ { className: 'pa-14', css: 'padding: var(--pf-padding-14);', category: 'Sizing' },
218
+ { className: 'pa-15', css: 'padding: var(--pf-padding-15);', category: 'Sizing' },
219
+ { className: 'pa-16', css: 'padding: var(--pf-padding-16);', category: 'Sizing' },
220
+
221
+ // Icon Sizes
222
+ { className: 'icon-xs', css: 'font-size: var(--pf-icon-size-xs);', category: 'Icon' },
223
+ { className: 'icon-sm', css: 'font-size: var(--pf-icon-size-sm);', category: 'Icon' },
224
+ { className: 'icon-md', css: 'font-size: var(--pf-icon-size-md);', category: 'Icon' },
225
+ { className: 'icon-lg', css: 'font-size: var(--pf-icon-size-lg);', category: 'Icon' },
226
+ { className: 'icon-xl', css: 'font-size: var(--pf-icon-size-xl);', category: 'Icon' },
227
+
228
+ // Drop Shadows
229
+ { className: 'dropshadow', css: 'box-shadow: var(--pf-dropshadow);', category: 'Effect' },
230
+ ];
@@ -0,0 +1,13 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { UtilityClassesTable } from './UtilityClassesTable';
3
+
4
+ const meta: Meta<typeof UtilityClassesTable> = {
5
+ title: 'remove/Utility Classes/Table',
6
+ component: UtilityClassesTable,
7
+ };
8
+
9
+ export default meta;
10
+
11
+ type Story = StoryObj<typeof UtilityClassesTable>;
12
+
13
+ export const Default: Story = {};
@@ -0,0 +1,146 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Table, Select, Input, Container, Row, Col } from '@/components';
3
+ import { MultiValue, SingleValue, ActionMeta } from 'react-select';
4
+ import { UtilityClassData, utilityClassesData } from './UtilityClassesData';
5
+
6
+ const categories = Array.from(new Set(utilityClassesData.map((item) => item.category)));
7
+
8
+ // Resolve CSS variables using getComputedStyle
9
+ const resolveCssVariables = (css: string): string => {
10
+ const tempElement = document.createElement('div');
11
+ document.body.appendChild(tempElement);
12
+ const style = getComputedStyle(tempElement);
13
+
14
+ const resolvedCss = css.replace(/var\((--pf-[\w-]+)\)/g, (_, variable) => {
15
+ return style.getPropertyValue(variable).trim() || variable;
16
+ });
17
+
18
+ document.body.removeChild(tempElement);
19
+ return resolvedCss;
20
+ };
21
+
22
+ const formatCss = (css: string): string => {
23
+ return css
24
+ .split(';')
25
+ .filter(Boolean)
26
+ .map((line) => line.trim() + ';')
27
+ .join('\n');
28
+ };
29
+
30
+ export const UtilityClassesTable = () => {
31
+ const [classNameSearch, setClassNameSearch] = useState('');
32
+ const [cssSearch, setCssSearch] = useState('');
33
+ const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
34
+ const [rowData, setRowData] = useState<UtilityClassData[]>([]);
35
+
36
+ useEffect(() => {
37
+ const resolved = utilityClassesData.map((item) => ({
38
+ ...item,
39
+ resolvedCss: resolveCssVariables(item.css),
40
+ }));
41
+ setRowData(resolved);
42
+ }, []);
43
+
44
+ const handleCategoryChange = (
45
+ newValue:
46
+ | MultiValue<{ value: string; label: string }>
47
+ | SingleValue<{ value: string; label: string }>,
48
+ ) => {
49
+ setSelectedCategories(Array.isArray(newValue) ? newValue.map((option) => option.value) : []);
50
+ };
51
+
52
+ const filteredData = rowData.filter(
53
+ (item) =>
54
+ (selectedCategories.length === 0 || selectedCategories.includes(item.category)) &&
55
+ item.className.toLowerCase().includes(classNameSearch.toLowerCase()) &&
56
+ (item.css.toLowerCase().includes(cssSearch.toLowerCase()) ||
57
+ item.resolvedCss?.toLowerCase().includes(cssSearch.toLowerCase())),
58
+ );
59
+
60
+ return (
61
+ <Container>
62
+ <Row className="mb-4">
63
+ <Col sm={4}>
64
+ <Input
65
+ id="classNameSearch"
66
+ name="classNameSearch"
67
+ label="Class Name"
68
+ value={classNameSearch}
69
+ onChange={(e) => setClassNameSearch(e.target.value)}
70
+ />
71
+ </Col>
72
+ <Col sm={4}>
73
+ <Input
74
+ id="cssSearch"
75
+ name="cssSearch"
76
+ label="CSS"
77
+ value={cssSearch}
78
+ onChange={(e) => setCssSearch(e.target.value)}
79
+ />
80
+ </Col>
81
+ <Col sm={4}>
82
+ <div className="form-control">
83
+ <div data-testid={`category-label`} className={`form-label mb-2`}>
84
+ <label htmlFor={`categoryFilter`}>Category</label>
85
+ </div>
86
+ <Select
87
+ id="categoryFilter"
88
+ name="categoryFilter"
89
+ options={categories.map((category) => ({ value: category, label: category }))}
90
+ onChange={handleCategoryChange}
91
+ value={categories
92
+ .filter((category) => selectedCategories.includes(category))
93
+ .map((category) => ({ value: category, label: category }))}
94
+ placeholder=""
95
+ isMulti
96
+ isClearable
97
+ />
98
+ </div>
99
+ </Col>
100
+ </Row>
101
+
102
+ <Table
103
+ columns={[
104
+ { name: 'Class Name', selector: (row) => row.className, sortable: true, width: '225px' },
105
+ {
106
+ name: 'CSS Applied',
107
+ selector: (row) => formatCss(row.css),
108
+ sortable: true,
109
+ cell: (row) => (
110
+ <pre
111
+ style={{
112
+ fontFamily: 'monospace',
113
+ whiteSpace: 'pre-wrap',
114
+ fontSize: '12px',
115
+ }}
116
+ >
117
+ {formatCss(row.css)}
118
+ </pre>
119
+ ),
120
+ },
121
+ {
122
+ name: 'Resolved CSS',
123
+ selector: (row) => formatCss(row.resolvedCss || ''),
124
+ sortable: true,
125
+ cell: (row) => (
126
+ <pre
127
+ style={{
128
+ fontFamily: 'monospace',
129
+ whiteSpace: 'pre-wrap',
130
+ fontSize: '12px',
131
+ }}
132
+ >
133
+ {formatCss(row.resolvedCss || '')}
134
+ </pre>
135
+ ),
136
+ },
137
+ { name: 'Category', selector: (row) => row.category, sortable: true, width: '114px' },
138
+ ]}
139
+ data={filteredData}
140
+ dense
141
+ noDataComponent="-- No Classes Found --"
142
+ pagination={false}
143
+ />
144
+ </Container>
145
+ );
146
+ };
@@ -0,0 +1,12 @@
1
+ export const getPreviousHeadersWidth = (position: number): number => {
2
+ // Get headers with positions less than current position
3
+ const previousHeaders = Array.from({ length: position }, (_, i) =>
4
+ document.querySelector(`[data-column-id="sticky-column-${i}"]`),
5
+ ).filter((header): header is HTMLElement => header !== null);
6
+
7
+ // Sum up widths of previous headers
8
+ return previousHeaders.reduce((acc, header) => {
9
+ const width = header.offsetWidth;
10
+ return acc + width;
11
+ }, 0);
12
+ };