@centreon/ui 26.12.2 → 26.12.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "26.12.2",
3
+ "version": "26.12.3",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -10,7 +10,6 @@ import {
10
10
 
11
11
  import { useCallback, useState } from 'react';
12
12
  import { useTranslation } from 'react-i18next';
13
- import { makeStyles } from 'tss-react/mui';
14
13
 
15
14
  import type { Group } from './Inputs/models';
16
15
 
@@ -23,22 +22,6 @@ interface Props {
23
22
  isCollapsible: boolean;
24
23
  }
25
24
 
26
- const useStyles = makeStyles()((theme) => ({
27
- expandCollapseIcon: {
28
- justifySelf: 'flex-end'
29
- },
30
- groupTitleContainer: {
31
- alignItems: 'center',
32
- columnGap: theme.spacing(1),
33
- display: 'flex',
34
- flexDirection: 'row'
35
- },
36
- title: {},
37
- tooltip: {
38
- maxWidth: theme.spacing(60)
39
- }
40
- }));
41
-
42
25
  const CollapsibleGroup = ({
43
26
  children,
44
27
  isCollapsible,
@@ -47,7 +30,6 @@ const CollapsibleGroup = ({
47
30
  defaultIsOpen = false,
48
31
  className
49
32
  }: Props): JSX.Element => {
50
- const { classes, cx } = useStyles();
51
33
  const { t } = useTranslation();
52
34
 
53
35
  const [isOpen, setIsOpen] = useState(isCollapsible && defaultIsOpen);
@@ -56,7 +38,7 @@ const CollapsibleGroup = ({
56
38
  setIsOpen((currentIsOpen) => !currentIsOpen);
57
39
  };
58
40
 
59
- const containerClassName = className || '';
41
+ const containerClassName = `flex items-center gap-x-2 ${className || ''}`;
60
42
 
61
43
  const CollapseIcon = isOpen ? ExpandLess : ExpandMore;
62
44
  const ContainerComponent = useCallback(
@@ -66,7 +48,7 @@ const CollapsibleGroup = ({
66
48
  isCollapsible ? (
67
49
  <ListItemButton
68
50
  aria-label={group?.name}
69
- className={`${cx(classes.groupTitleContainer, containerClassName)} bg-background-listing-header`}
51
+ className={`${containerClassName} bg-background-listing-header rounded-lg`}
70
52
  dense
71
53
  disableGutters
72
54
  disableRipple
@@ -75,18 +57,9 @@ const CollapsibleGroup = ({
75
57
  {containerComponentChildren}
76
58
  </ListItemButton>
77
59
  ) : (
78
- <Box className={cx(classes.groupTitleContainer, containerClassName)}>
79
- {containerComponentChildren}
80
- </Box>
60
+ <Box className={containerClassName}>{containerComponentChildren}</Box>
81
61
  ),
82
- [
83
- isCollapsible,
84
- classes.groupTitleContainer,
85
- containerClassName,
86
- cx,
87
- group?.name,
88
- toggle
89
- ]
62
+ [isCollapsible, containerClassName, group?.name, toggle]
90
63
  );
91
64
 
92
65
  return (
@@ -100,7 +73,7 @@ const CollapsibleGroup = ({
100
73
  data-testid={`${group?.name}-header`}
101
74
  >
102
75
  <Typography
103
- className="groupText scroll-m-12 snap-start"
76
+ className="groupText scroll-m-12 snap-start text-base font-medium"
104
77
  variant="h6"
105
78
  {...group?.titleAttributes}
106
79
  data-section-group-form-id={group?.name}
@@ -110,7 +83,7 @@ const CollapsibleGroup = ({
110
83
  {group?.EndIcon && (
111
84
  <Tooltip
112
85
  classes={{
113
- tooltip: classes.tooltip
86
+ tooltip: 'max-w-120'
114
87
  }}
115
88
  placement="top"
116
89
  title={group?.TooltipContent ? <group.TooltipContent /> : ''}
@@ -1,15 +1,19 @@
1
1
  import { Typography } from '@mui/material';
2
2
 
3
+ import { ThemeMode, userAtom } from '@centreon/ui-context';
4
+
3
5
  import { faker } from '@faker-js/faker';
4
6
  import { rs } from '@rstest/core';
5
7
  import { render } from '@test-setup/render';
6
8
  import { screen, waitFor, within } from '@testing-library/react';
7
9
  import userEvent from '@testing-library/user-event';
8
10
  import { useFormikContext } from 'formik';
11
+ import { createStore, Provider } from 'jotai';
9
12
  import { object } from 'yup';
10
13
 
11
14
  import type { SelectEntry } from '..';
12
15
  import { Button } from '../components';
16
+ import ThemeProvider from '../ThemeProvider';
13
17
  import { Form } from './Form';
14
18
  import { type InputProps, InputType } from './Inputs/models';
15
19
 
@@ -443,3 +447,107 @@ describe('Form with sections', () => {
443
447
  );
444
448
  });
445
449
  });
450
+
451
+ // The theme mode comes from the user atom, and the Tailwind tokens from the
452
+ // `dark` class on the document.
453
+ const initializeFormTitles = (themeMode: ThemeMode): void => {
454
+ const store = createStore();
455
+ store.set(userAtom, { ...store.get(userAtom), themeMode });
456
+
457
+ document.documentElement.classList.toggle(
458
+ 'dark',
459
+ themeMode === ThemeMode.dark
460
+ );
461
+
462
+ render(
463
+ <Provider store={store}>
464
+ <ThemeProvider>
465
+ <Form
466
+ areGroupsOpen
467
+ groups={[{ name: 'Titles section', order: 1 }]}
468
+ initialValues={{ gridField: '', topLevelField: '' }}
469
+ inputs={[
470
+ {
471
+ additionalLabel: 'Top level block title',
472
+ fieldName: 'topLevelField',
473
+ group: 'Titles section',
474
+ label: 'Top level field',
475
+ type: InputType.Text
476
+ },
477
+ {
478
+ fieldName: '',
479
+ grid: {
480
+ columns: [
481
+ {
482
+ additionalLabel: 'Grid block title',
483
+ fieldName: 'gridField',
484
+ label: 'Grid field',
485
+ type: InputType.Text
486
+ }
487
+ ]
488
+ },
489
+ group: 'Titles section',
490
+ label: 'Grid',
491
+ type: InputType.Grid
492
+ }
493
+ ]}
494
+ isCollapsible
495
+ submit={rs.fn()}
496
+ validationSchema={object()}
497
+ />
498
+ </ThemeProvider>
499
+ </Provider>
500
+ );
501
+ };
502
+
503
+ const textPrimaryColor = {
504
+ [ThemeMode.dark]: 'rgb(255, 255, 255)',
505
+ [ThemeMode.light]: 'rgb(0, 0, 0)'
506
+ };
507
+
508
+ [ThemeMode.light, ThemeMode.dark].forEach((themeMode) => {
509
+ describe(`Form titles in ${themeMode} mode`, () => {
510
+ beforeEach(() => {
511
+ expect.hasAssertions();
512
+ });
513
+ beforeEach(() => initializeFormTitles(themeMode));
514
+
515
+ afterEach(() => {
516
+ document.documentElement.classList.remove('dark');
517
+ });
518
+
519
+ it('displays the section title in 16px medium on a 24px line', async () => {
520
+ const title = await screen.findByText('Titles section');
521
+
522
+ expect(title).toHaveStyle({
523
+ fontSize: '16px',
524
+ fontWeight: '500',
525
+ lineHeight: '24px'
526
+ });
527
+ });
528
+
529
+ it('rounds the collapsible section header with an 8px radius', async () => {
530
+ expect(await screen.findByLabelText('Titles section')).toHaveStyle({
531
+ borderRadius: '8px'
532
+ });
533
+ });
534
+
535
+ it('displays the grid block title in 16px bold with the text colour', async () => {
536
+ expect(await screen.findByText('Grid block title')).toHaveStyle({
537
+ color: textPrimaryColor[themeMode],
538
+ fontSize: '16px',
539
+ fontWeight: '700',
540
+ lineHeight: '24px'
541
+ });
542
+ });
543
+
544
+ it('displays the top level block title like the grid block title', async () => {
545
+ expect(await screen.findByText('Top level block title')).toHaveStyle({
546
+ color: textPrimaryColor[themeMode],
547
+ fontSize: '16px',
548
+ fontWeight: '700',
549
+ lineHeight: '24px'
550
+ });
551
+ });
552
+ });
553
+ });
@@ -45,8 +45,7 @@ const Grid = ({
45
45
  <Box key={key as string} sx={{ width: '100%' }}>
46
46
  {field.additionalLabel && (
47
47
  <Typography
48
- className={field?.additionalLabelClassName}
49
- sx={{ color: 'primary.main', marginBottom: 0.5 }}
48
+ className={`mb-1 text-base font-bold text-text-primary ${field?.additionalLabelClassName || ''}`}
50
49
  variant="h6"
51
50
  >
52
51
  {field.additionalLabel}
@@ -26,7 +26,6 @@ import {
26
26
  toPairs
27
27
  } from 'ramda';
28
28
  import { Fragment, useMemo } from 'react';
29
- import { makeStyles } from 'tss-react/mui';
30
29
 
31
30
  import { GroupDirection } from '..';
32
31
  import CollapsibleGroup from '../CollapsibleGroup';
@@ -104,42 +103,6 @@ export const getInput = cond<
104
103
  [T, always(TextInput)]
105
104
  ]);
106
105
 
107
- interface StylesProps {
108
- groupDirection?: GroupDirection;
109
- }
110
-
111
- const useStyles = makeStyles<StylesProps>()((theme, { groupDirection }) => ({
112
- additionalLabel: {
113
- marginBottom: theme.spacing(0.5)
114
- },
115
- buttons: {
116
- columnGap: theme.spacing(2),
117
- display: 'flex',
118
- flexDirection: 'row',
119
- justifyContent: 'flex-end'
120
- },
121
- divider: {
122
- margin: equals(groupDirection, GroupDirection.Horizontal)
123
- ? theme.spacing(0, 2)
124
- : theme.spacing(2, 0)
125
- },
126
- groups: {
127
- display: 'flex',
128
- flexDirection: equals(groupDirection, GroupDirection.Horizontal)
129
- ? 'row'
130
- : 'column'
131
- },
132
- inputs: {
133
- display: 'flex',
134
- flexDirection: 'column',
135
- margin: theme.spacing(2, 0),
136
- rowGap: theme.spacing(2)
137
- },
138
- inputWrapper: {
139
- width: '100%'
140
- }
141
- }));
142
-
143
106
  interface Props {
144
107
  areGroupsOpen?: boolean;
145
108
  groupDirection?: GroupDirection;
@@ -161,7 +124,7 @@ const Inputs = ({
161
124
  areGroupsOpen,
162
125
  inputsClassName
163
126
  }: Props): JSX.Element => {
164
- const { classes, cx } = useStyles({ groupDirection });
127
+ const isHorizontal = equals(groupDirection, GroupDirection.Horizontal);
165
128
  const formikContext = useFormikContext<FormikValues>();
166
129
 
167
130
  const groupsName = pluck('name', groups);
@@ -217,7 +180,7 @@ const Inputs = ({
217
180
  ) as Array<[string | null, Array<InputProps>]>;
218
181
 
219
182
  return (
220
- <div className={classes.groups}>
183
+ <div className={`flex ${isHorizontal ? 'flex-row' : 'flex-col'}`}>
221
184
  {normalizedInputsByGroup.map(([groupName, groupedInputs], index) => {
222
185
  const hasGroupTitle = not(isNil(groupName));
223
186
 
@@ -238,7 +201,9 @@ const Inputs = ({
238
201
  hasGroupTitle={hasGroupTitle}
239
202
  isCollapsible={isCollapsible}
240
203
  >
241
- <div className={cx(classes.inputs, inputsClassName)}>
204
+ <div
205
+ className={`flex flex-col my-4 gap-y-4 ${inputsClassName || ''}`}
206
+ >
242
207
  {groupedInputs.map((inputProps) => {
243
208
  const key =
244
209
  isNotNil(inputProps.label) || isNotEmpty(inputProps.label)
@@ -257,14 +222,11 @@ const Inputs = ({
257
222
  const Input = getInput(inputProps.type);
258
223
 
259
224
  return (
260
- <div className={classes.inputWrapper} key={key as string}>
225
+ <div className="w-full" key={key as string}>
261
226
  {inputProps.additionalLabel && (
262
227
  <Typography
263
- className={cx(
264
- classes.additionalLabel,
265
- inputProps?.additionalLabelClassName
266
- )}
267
- variant="body1"
228
+ className={`mb-1 text-base font-bold text-text-primary ${inputProps?.additionalLabelClassName || ''}`}
229
+ variant="h6"
268
230
  >
269
231
  {inputProps.additionalLabel}
270
232
  </Typography>
@@ -282,13 +244,9 @@ const Inputs = ({
282
244
  hasGroupTitle &&
283
245
  not(equals(lastGroup, groupName as string)) && (
284
246
  <Divider
285
- className={classes.divider}
247
+ className={isHorizontal ? 'my-0 mx-4' : 'my-4 mx-0'}
286
248
  flexItem
287
- orientation={
288
- equals(groupDirection, GroupDirection.Horizontal)
289
- ? 'vertical'
290
- : 'horizontal'
291
- }
249
+ orientation={isHorizontal ? 'vertical' : 'horizontal'}
292
250
  />
293
251
  )}
294
252
  </Fragment>