@takaro/lib-components 0.0.15 → 0.0.18

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 (108) hide show
  1. package/Dockerfile.dev +1 -1
  2. package/package.json +5 -7
  3. package/src/components/actions/Button/Button.test.tsx +2 -1
  4. package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +18 -0
  5. package/src/components/actions/Button/style.ts +1 -0
  6. package/src/components/actions/DropdownButton/index.tsx +51 -36
  7. package/src/components/actions/IconButton/IconButton.test.tsx +3 -2
  8. package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +18 -0
  9. package/src/components/actions/IconButton/getIconSize.ts +16 -0
  10. package/src/components/actions/IconButton/index.tsx +2 -16
  11. package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +0 -1
  12. package/src/components/charts/GeoMercator/index.tsx +3 -3
  13. package/src/components/charts/RadialBarChart/index.tsx +1 -1
  14. package/src/components/data/Chip/Chip.test.tsx +3 -2
  15. package/src/components/data/Chip/__snapshots__/Chip.test.tsx.snap +38 -0
  16. package/src/components/data/Console/Console.tsx +1 -7
  17. package/src/components/data/Console/ConsoleLine/index.tsx +1 -1
  18. package/src/components/data/Console/constants.ts +6 -0
  19. package/src/components/data/Table/index.tsx +30 -1
  20. package/src/components/data/Table/subcomponents/Filter/field.tsx +2 -3
  21. package/src/components/data/Table/subcomponents/Filter/index.tsx +1 -11
  22. package/src/components/data/Table/subcomponents/Filter/types.ts +10 -0
  23. package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +0 -1
  24. package/src/components/data/index.ts +0 -3
  25. package/src/components/dialogs/Dialog/DialogBody.tsx +1 -0
  26. package/src/components/feedback/Alert/Alert.test.tsx +2 -1
  27. package/src/components/feedback/Alert/__snapshots__/Alert.test.tsx.snap +44 -0
  28. package/src/components/feedback/IconTooltip/IconTooltip.stories.tsx +22 -0
  29. package/src/components/feedback/IconTooltip/index.tsx +50 -0
  30. package/src/components/feedback/Loaders/Loading.test.tsx +2 -1
  31. package/src/components/feedback/Loaders/Spinner.test.tsx +2 -1
  32. package/src/components/feedback/Loaders/__snapshots__/Loading.test.tsx.snap +141 -0
  33. package/src/components/feedback/Loaders/__snapshots__/Spinner.test.tsx.snap +10 -0
  34. package/src/components/feedback/NetworkDetector/NetworkDetector.test.tsx +2 -1
  35. package/src/components/feedback/NetworkDetector/__snapshots__/NetworkDetector.test.tsx.snap +3 -0
  36. package/src/components/feedback/NotificationBanner/NotificationBanner.test.tsx +2 -1
  37. package/src/components/feedback/NotificationBanner/__snapshots__/NotificationBanner.test.tsx.snap +3 -0
  38. package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +2 -1
  39. package/src/components/feedback/ProgressBar/index.tsx +58 -24
  40. package/src/components/feedback/Skeleton/Skeleton.test.tsx +2 -1
  41. package/src/components/feedback/Skeleton/__snapshots__/Skeleton.test.tsx.snap +9 -0
  42. package/src/components/feedback/Tooltip/TooltipContent.tsx +2 -2
  43. package/src/components/feedback/Tooltip/useTooltip.tsx +3 -0
  44. package/src/components/feedback/index.ts +2 -1
  45. package/src/components/feedback/snacks/Drawer/index.tsx +15 -4
  46. package/src/components/inputs/Date/DateRangePicker/Context.tsx +1 -1
  47. package/src/components/inputs/Date/DateRangePicker/Generic.tsx +2 -1
  48. package/src/components/inputs/Date/DateRangePicker/QuickSelect/index.tsx +1 -17
  49. package/src/components/inputs/Date/subcomponents/RelativePicker/index.tsx +1 -17
  50. package/src/components/inputs/Date/types.ts +14 -0
  51. package/src/components/inputs/DurationField/Generic.tsx +0 -1
  52. package/src/components/inputs/TextField/Controlled.tsx +1 -1
  53. package/src/components/inputs/TextField/Generic.tsx +79 -56
  54. package/src/components/inputs/TextField/TextField.stories.tsx +21 -1
  55. package/src/components/inputs/TextField/style.ts +6 -0
  56. package/src/components/inputs/TextField/util.ts +7 -2
  57. package/src/components/inputs/index.ts +1 -0
  58. package/src/components/inputs/layout/Description.tsx +0 -5
  59. package/src/components/inputs/layout/Label/style.ts +0 -1
  60. package/src/components/inputs/layout/index.ts +3 -1
  61. package/src/components/inputs/layout/setAriaDescribedBy.ts +3 -0
  62. package/src/components/inputs/selects/SelectField/Controlled.tsx +0 -2
  63. package/src/components/inputs/selects/SelectField/Generic/index.tsx +11 -14
  64. package/src/components/inputs/selects/SelectQueryField/Controlled.tsx +2 -2
  65. package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +115 -40
  66. package/src/components/inputs/selects/SelectQueryField/style.ts +0 -1
  67. package/src/components/inputs/selects/SubComponents/Option.tsx +1 -1
  68. package/src/components/inputs/selects/sharedStyle.ts +0 -2
  69. package/src/components/layout/Container/index.ts +1 -1
  70. package/src/components/layout/index.ts +1 -1
  71. package/src/components/navigation/HorizontalNav/HorizontalNav.stories.tsx +6 -22
  72. package/src/components/navigation/HorizontalNav/index.tsx +1 -1
  73. package/src/components/navigation/HorizontalNav/style.ts +28 -3
  74. package/src/components/navigation/Steppers/SlimStepper/Stepper.stories.tsx +2 -1
  75. package/src/components/navigation/Steppers/SlimStepper/index.tsx +4 -4
  76. package/src/components/navigation/Steppers/Stepper/Stepper.stories.tsx +2 -1
  77. package/src/components/navigation/Steppers/Stepper/index.tsx +4 -4
  78. package/src/components/navigation/Steppers/context.tsx +2 -49
  79. package/src/components/navigation/Steppers/provider.tsx +18 -0
  80. package/src/components/navigation/Steppers/useStepper.ts +34 -0
  81. package/src/components/navigation/index.ts +2 -1
  82. package/src/components/other/ActionMenu/index.tsx +20 -11
  83. package/src/components/other/ActionMenu/style.ts +2 -2
  84. package/src/components/other/ClipBoard/ClipBoard.test.tsx +2 -1
  85. package/src/components/other/ClipBoard/__snapshots__/ClipBoard.test.tsx.snap +36 -0
  86. package/src/components/other/Empty/Empty.test.tsx +5 -2
  87. package/src/components/other/Empty/__snapshots__/Empty.test.tsx.snap +21 -0
  88. package/src/components/other/PermissionsGuard/hasPermissionsHelper.ts +18 -0
  89. package/src/components/other/PermissionsGuard/index.tsx +1 -17
  90. package/src/components/other/Plan/Plan.stories.tsx +21 -0
  91. package/src/components/other/Plan/index.tsx +93 -0
  92. package/src/components/other/Plan/style.ts +61 -0
  93. package/src/components/other/Usage/Usage.stories.tsx +21 -0
  94. package/src/components/other/Usage/Usage.tsx +35 -0
  95. package/src/components/other/Usage/UsageCard.stories.tsx +31 -0
  96. package/src/components/other/Usage/UsageCard.tsx +88 -0
  97. package/src/components/other/index.ts +10 -2
  98. package/src/components/visual/Card/index.tsx +11 -8
  99. package/src/components/visual/Divider/Divider.test.tsx +2 -1
  100. package/src/components/visual/Divider/__snapshots__/Divider.test.tsx.snap +13 -0
  101. package/src/components/visual/Divider/index.tsx +9 -6
  102. package/src/errors/errors.ts +1 -1
  103. package/src/helpers/regexprs.ts +2 -1
  104. package/tsconfig.json +0 -5
  105. package/vite.config.mts +17 -0
  106. package/src/components/data/LinkCard/index.tsx +0 -28
  107. package/src/components/feedback/QuestionTooltip/QuestionTooltip.stories.tsx +0 -20
  108. package/src/components/feedback/QuestionTooltip/index.tsx +0 -35
package/Dockerfile.dev CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20.18.0-alpine AS build
1
+ FROM node:22.11.0-alpine AS build
2
2
 
3
3
  ENV NODE_ENV=development
4
4
  WORKDIR /app
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takaro/lib-components",
3
- "version": "0.0.15",
3
+ "version": "0.0.18",
4
4
  "private": false,
5
5
  "description": "Takaro UI is a simple and customizable component library to build React apps faster within the Takaro eco system",
6
6
  "license": "AGPL-3.0-or-later",
@@ -9,10 +9,8 @@
9
9
  "scripts": {
10
10
  "build": "storybook build -c ../../.storybook",
11
11
  "start:dev": "NODE_OPTIONS='' storybook dev -c ../../.storybook -p 13002",
12
- "_test": "jest",
13
12
  "test:unit": "CI=true vitest",
14
- "test:watch": "jest --watch",
15
- "test:update": "jest --updateSnapshot"
13
+ "test:snapshot": "vitest -u"
16
14
  },
17
15
  "devDependencies": {
18
16
  "@hookform/devtools": "4.3.1",
@@ -31,9 +29,9 @@
31
29
  "@rjsf/core": "5.20.0",
32
30
  "@rjsf/utils": "5.20.0",
33
31
  "@rjsf/validator-ajv8": "5.20.0",
34
- "@sentry/react": "8.32.0",
32
+ "@sentry/react": "8.53.0",
35
33
  "@tanstack/react-table": "8.20.5",
36
- "@tanstack/react-router": "1.58.15",
34
+ "@tanstack/react-router": "1.102.1",
37
35
  "@types/luxon": "3.4.2",
38
36
  "@visx/axis": "3.10.1",
39
37
  "@visx/brush": "3.10.4",
@@ -51,7 +49,7 @@
51
49
  "@visx/shape": "3.5.0",
52
50
  "@visx/tooltip": "3.3.0",
53
51
  "@visx/vendor": "3.5.0",
54
- "@visx/zoom": "^3.3.0",
52
+ "@visx/zoom": "3.3.0",
55
53
  "framer-motion": "11.9.0",
56
54
  "luxon": "3.5.0",
57
55
  "notistack": "3.0.1",
@@ -1,5 +1,6 @@
1
1
  import { Button } from '.';
2
- import { render } from 'test-utils';
2
+ import { expect, it } from 'vitest';
3
+ import { render } from '../../../test/testUtils';
3
4
 
4
5
  it('Should render <Button/>', () => {
5
6
  const { container } = render(<Button text="button text" />);
@@ -0,0 +1,18 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Should render <Button/> 1`] = `
4
+ <div>
5
+ <button
6
+ class="sc-jlGgGc iqEzFy"
7
+ color="primary"
8
+ tabindex="0"
9
+ type="button"
10
+ >
11
+
12
+ <span>
13
+ button text
14
+ </span>
15
+
16
+ </button>
17
+ </div>
18
+ `;
@@ -34,6 +34,7 @@ export const Default = styled.button<{
34
34
  span {
35
35
  font-size: 1.25rem;
36
36
  font-weight: 600;
37
+ white-space: nowrap;
37
38
  color: ${({ theme, color }) => {
38
39
  switch (color) {
39
40
  case 'white':
@@ -1,9 +1,11 @@
1
- import { FC, useState, useEffect, ReactElement, useRef } from 'react';
1
+ import { useState, useEffect, ReactElement, useRef, forwardRef } from 'react';
2
2
  import { useOutsideAlerter } from '../../../hooks';
3
3
  import { MdChevronRight as ArrowIcon } from 'react-icons/md';
4
4
  import { ActionMenu } from '../../../components';
5
5
  import { styled } from '../../../styled';
6
- import { useFloating } from '@floating-ui/react';
6
+ import { useFloating, useMergeRefs } from '@floating-ui/react';
7
+ import { shade } from 'polished';
8
+ import { ButtonColor } from '../Button/style';
7
9
 
8
10
  const Arrow = styled(ArrowIcon)`
9
11
  transform: rotate(90deg);
@@ -12,7 +14,7 @@ const Arrow = styled(ArrowIcon)`
12
14
 
13
15
  const Wrapper = styled.div``;
14
16
 
15
- const DropdownActionContainer = styled.div<{ isVisible: boolean }>`
17
+ const DropdownActionContainer = styled.div<{ color: ButtonColor }>`
16
18
  font-weight: 500;
17
19
  display: flex;
18
20
  align-items: center;
@@ -20,94 +22,107 @@ const DropdownActionContainer = styled.div<{ isVisible: boolean }>`
20
22
  justify-content: center;
21
23
  cursor: pointer;
22
24
  width: 3.2rem;
23
- border: .1rem solid ${({ theme, isVisible }) => (isVisible ? theme.colors.primary : theme.colors.backgroundAccent)}};
25
+
26
+ background: ${({ theme, color }) => shade(0.5, theme.colors[color])};
27
+ border: .1rem solid ${({ theme, color }) => theme.colors[color === 'background' ? 'backgroundAccent' : color]}};
24
28
  border-top-right-radius: ${({ theme }) => theme.borderRadius.small}};
25
29
  border-bottom-right-radius: ${({ theme }) => theme.borderRadius.small}};
26
-
27
30
 
28
- &:hover {
29
- border-color:${({ theme }) => theme.colors.primary};
30
- svg {
31
- fill: ${({ theme }) => theme.colors.primary};
32
- }
31
+ svg {
32
+ fill: ${({ theme }) => theme.colors.text};
33
33
  }
34
34
  &:active {
35
35
  background-color: transparent;
36
36
  }
37
37
  `;
38
38
 
39
- const CurrentAction = styled.div`
39
+ const CurrentAction = styled.div<{ color: ButtonColor }>`
40
40
  padding: ${({ theme }) => `${theme.spacing['0_5']} ${theme.spacing[1]}`};
41
41
  font-weight: 500;
42
42
  cursor: pointer;
43
43
  min-width: 10rem;
44
44
  height: 100%;
45
45
  color: ${({ theme }) => theme.colors.text};
46
- border-top: 0.1rem solid ${({ theme }) => theme.colors.backgroundAccent};
47
- border-left: 0.1rem solid ${({ theme }) => theme.colors.backgroundAccent};
48
- border-bottom: 0.1rem solid ${({ theme }) => theme.colors.backgroundAccent};
46
+ width: calc(100% - 3.2rem);
47
+ white-space: nowrap;
48
+
49
+ background: ${({ theme, color }) => shade(0.5, theme.colors[color])};
50
+ border-top: 0.1rem solid ${({ theme, color }) => theme.colors[color === 'background' ? 'backgroundAccent' : color]};
51
+ border-left: 0.1rem solid ${({ theme, color }) => theme.colors[color === 'background' ? 'backgroundAccent' : color]};
52
+ border-bottom: 0.1rem solid ${({ theme, color }) => theme.colors[color === 'background' ? 'backgroundAccent' : color]};
49
53
  border-top-left-radius: ${({ theme }) => theme.borderRadius.small};
50
54
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius.small};
51
55
 
52
56
  text-align: center;
53
- &:hover {
54
- color: ${({ theme }) => theme.colors.primary};
55
- border-color: ${({ theme }) => theme.colors.primary};
56
- }
57
57
  &:active {
58
58
  background-color: transparent;
59
59
  }
60
60
  `;
61
61
 
62
- const Container = styled.div`
62
+ const Container = styled.div<{ fullWidth: boolean }>`
63
63
  display: flex;
64
64
  align-items: center;
65
65
  flex-wrap: wrap;
66
66
  border-radius: ${({ theme }) => theme.borderRadius.large};
67
- width: max-content;
68
-
69
- &:hover ${DropdownActionContainer} {
70
- border-left-color: ${({ theme }) => theme.colors.primary};
71
- }
67
+ width: ${({ fullWidth }) => (fullWidth ? '100%' : 'max-content')};
72
68
  `;
73
69
 
74
70
  export interface DropdownButtonProps {
75
71
  children: ReactElement[];
72
+ color?: ButtonColor;
73
+ onSelectedChanged?: (index: number) => void;
74
+ fullWidth?: boolean;
76
75
  }
77
76
 
78
- export const DropdownButton: FC<DropdownButtonProps> = ({ children }) => {
79
- const [visible, setVisible] = useState<boolean>(false);
77
+ export const DropdownButton = forwardRef<HTMLDivElement, DropdownButtonProps>(function Dropdown(
78
+ { children, color = 'primary', onSelectedChanged, fullWidth = false },
79
+ propRef,
80
+ ) {
81
+ const [listVisible, setListVisible] = useState<boolean>(false);
80
82
  const [selected, setSelected] = useState<number>(0);
81
83
  const { x, y, refs, strategy } = useFloating();
82
84
 
83
85
  const parentRef = useRef<HTMLDivElement>(null);
86
+ const ref = useMergeRefs([propRef, parentRef]);
84
87
 
85
88
  useOutsideAlerter(parentRef, () => {
86
- setVisible(false);
89
+ setListVisible(false);
87
90
  });
88
91
 
89
92
  useEffect(() => {
90
- setVisible(false);
93
+ if (onSelectedChanged) {
94
+ onSelectedChanged(selected);
95
+ }
96
+ setListVisible(false);
91
97
  }, [selected]);
92
98
 
93
99
  const handleSelectedActionClicked = () => {
94
- setVisible(false);
100
+ setListVisible(false);
95
101
  children[selected].props.onClick();
96
102
  };
97
103
 
104
+ // TODO: this element does not handle the case where there are no children/actions
105
+
98
106
  return (
99
- <Wrapper ref={parentRef}>
100
- <Container ref={refs.setReference}>
101
- <CurrentAction onClick={handleSelectedActionClicked}>{children[selected].props.text}</CurrentAction>
102
- <DropdownActionContainer onClick={() => setVisible(!visible)} isVisible={visible}>
107
+ <Wrapper ref={ref}>
108
+ <Container ref={refs.setReference} fullWidth={fullWidth}>
109
+ <CurrentAction color={color} onClick={handleSelectedActionClicked} role="button">
110
+ {children[selected].props.text}
111
+ </CurrentAction>
112
+ <DropdownActionContainer role="button" color={color} onClick={() => setListVisible(!listVisible)}>
103
113
  <Arrow size={20} />
104
114
  </DropdownActionContainer>
105
- {visible && (
106
- <ActionMenu selectedState={[selected, setSelected]} attributes={{ x, y, strategy }} ref={refs.setFloating}>
115
+ {listVisible && (
116
+ <ActionMenu
117
+ selected={selected}
118
+ setSelected={(s) => setSelected(s)}
119
+ attributes={{ x, y, strategy }}
120
+ ref={refs.setFloating}
121
+ >
107
122
  {children}
108
123
  </ActionMenu>
109
124
  )}
110
125
  </Container>
111
126
  </Wrapper>
112
127
  );
113
- };
128
+ });
@@ -1,7 +1,8 @@
1
1
  import { IconButton } from '.';
2
- import { render } from 'test-utils';
2
+ import { render } from '../../../test/testUtils';
3
+ import { it, expect } from 'vitest';
3
4
 
4
5
  it('Should render <IconButton />', () => {
5
- const { container } = render(<IconButton icon={<div>icon</div>} />);
6
+ const { container } = render(<IconButton icon={<div>icon</div>} ariaLabel="test" />);
6
7
  expect(container).toMatchSnapshot();
7
8
  });
@@ -0,0 +1,18 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Should render <IconButton /> 1`] = `
4
+ <div>
5
+ <button
6
+ aria-label="test"
7
+ class="sc-lmUcrn bKlaHv"
8
+ color="primary"
9
+ type="button"
10
+ >
11
+ <div
12
+ size="18"
13
+ >
14
+ icon
15
+ </div>
16
+ </button>
17
+ </div>
18
+ `;
@@ -0,0 +1,16 @@
1
+ import { Size } from '../../../styled/types';
2
+
3
+ export const getIconSize = (size: Size) => {
4
+ switch (size) {
5
+ case 'tiny':
6
+ return 15;
7
+ case 'small':
8
+ return 16;
9
+ case 'medium':
10
+ return 18;
11
+ case 'large':
12
+ return 20;
13
+ case 'huge':
14
+ return 24;
15
+ }
16
+ };
@@ -2,6 +2,7 @@ import { cloneElement, forwardRef, ReactElement } from 'react';
2
2
  import { Color, Size } from '../../../styled/types';
3
3
  import { Badge } from '../../../components';
4
4
  import { Default } from './style';
5
+ import { getIconSize } from './getIconSize';
5
6
 
6
7
  export interface IconButtonProps {
7
8
  size?: Size;
@@ -14,28 +15,13 @@ export interface IconButtonProps {
14
15
  badge?: string;
15
16
  }
16
17
 
17
- const getSize = (size: Size) => {
18
- switch (size) {
19
- case 'tiny':
20
- return 15;
21
- case 'small':
22
- return 16;
23
- case 'medium':
24
- return 18;
25
- case 'large':
26
- return 20;
27
- case 'huge':
28
- return 24;
29
- }
30
- };
31
-
32
18
  export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(
33
19
  { icon, color = 'primary', size = 'medium', disabled, onClick = () => {}, ariaLabel, badge },
34
20
  ref,
35
21
  ) {
36
22
  return (
37
23
  <Default type="button" color={color} onClick={onClick} ref={ref} disabled={disabled} aria-label={ariaLabel}>
38
- {cloneElement(icon, { size: getSize(size) })}
24
+ {cloneElement(icon, { size: getIconSize(size) })}
39
25
  {badge && <Badge>{badge}</Badge>}
40
26
  </Default>
41
27
  );
@@ -47,7 +47,6 @@ export const ToggleButtonGroup: FC<ToggleButtonGroupProps> & SubComponents = ({
47
47
  const m = new Map<string, boolean>();
48
48
  Children.forEach(children, (child) => {
49
49
  if (isValidElement(child)) {
50
- console.log(child.props.value, defaultValue);
51
50
  if (child.props.value === defaultValue) {
52
51
  m.set(child.props.value, true);
53
52
  } else {
@@ -84,9 +84,9 @@ const Chart = <T,>({
84
84
  const theme = useTheme();
85
85
  const { hideTooltip, showTooltip, tooltipData, tooltipLeft = 0, tooltipTop = 0 } = useTooltip<T>();
86
86
 
87
- const centerX = width / 2 + 50;
88
- const centerY = height / 2 + 150;
89
- const scale = (width / 1000) * 100;
87
+ const centerX = width / 2;
88
+ const centerY = height / 2;
89
+ const scale = Math.min(width, height) * 0.25;
90
90
 
91
91
  const colorScale = scaleLinear({
92
92
  domain: [Math.min(...data.map((d) => yAccessor(d))), Math.max(...data.map((d) => yAccessor(d)))],
@@ -12,7 +12,7 @@ import { useTooltip, useTooltipInPortal } from '@visx/tooltip';
12
12
  import localPoint from '@visx/event/lib/localPointGeneric';
13
13
  import { useGradients } from '../useGradients';
14
14
 
15
- export const defaultMargin = { top: 10, right: 0, bottom: 25, left: 40 };
15
+ const defaultMargin = { top: 10, right: 0, bottom: 25, left: 40 };
16
16
  export interface RadialBarChartProps<T> {
17
17
  name: string;
18
18
  data: T[];
@@ -1,7 +1,8 @@
1
1
  import { Chip } from '.';
2
- import { render } from 'test-utils';
2
+ import { render } from '../../../test/testUtils';
3
+ import { expect, it } from 'vitest';
3
4
 
4
5
  it('Should render <Chip/>', () => {
5
- const { container } = render(<Chip label="chip label" />);
6
+ const { container } = render(<Chip variant="outline" label="chip label" />);
6
7
  expect(container).toMatchSnapshot();
7
8
  });
@@ -0,0 +1,38 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Should render <Chip/> 1`] = `
4
+ <div>
5
+ <div
6
+ style="padding: .5rem; max-width: 100%;"
7
+ >
8
+ <div
9
+ style="display: flex; align-items: center; gap: .5rem;"
10
+ >
11
+ <strong
12
+ style="font-size: 1rem;"
13
+ >
14
+ Something went wrong!
15
+ </strong>
16
+ <button
17
+ style="appearance: none; font-size: .6em; border: 1px solid currentcolor; padding: .1rem .2rem; font-weight: bold; border-radius: .25rem;"
18
+ >
19
+ Hide Error
20
+ </button>
21
+ </div>
22
+ <div
23
+ style="height: .25rem;"
24
+ />
25
+ <div>
26
+ <pre
27
+ style="font-size: .7em; border: 1px solid red; border-radius: .25rem; padding: .3rem; color: red; overflow: auto;"
28
+ >
29
+ <code>
30
+ Passed an incorrect argument to a color function, please pass a string representation of a color.
31
+
32
+
33
+ </code>
34
+ </pre>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ `;
@@ -8,13 +8,7 @@ import { useConsoleLiveModeScrolling } from './useConsoleLiveMode';
8
8
  import Autosizer from 'react-virtualized-auto-sizer';
9
9
  import { AiOutlineDelete as ClearIcon } from 'react-icons/ai';
10
10
  import { Button } from '../../../components';
11
-
12
- const DEFAULT_LINE_HEIGHT = 25;
13
- export const GUTTER_SIZE = 10;
14
- /* TODO: this does not work with the scrollitemto because it has no knowledge of the padding.
15
- * https://gist.github.com/ValentinJS/4f3738ed426cac183e8446c869b162dd might be an option.
16
- */
17
- export const LIST_PADDING_SIZE = 0;
11
+ import { GUTTER_SIZE, LIST_PADDING_SIZE, DEFAULT_LINE_HEIGHT } from './constants';
18
12
 
19
13
  interface RowState {
20
14
  height: number;
@@ -20,7 +20,7 @@ import {
20
20
  ExpandIconContainer,
21
21
  } from './style';
22
22
  import { Message, MessageType } from '../MessageModel';
23
- import { GUTTER_SIZE, LIST_PADDING_SIZE } from '../Console';
23
+ import { GUTTER_SIZE, LIST_PADDING_SIZE } from '../constants';
24
24
 
25
25
  const COLLAPSED_LENGTH = 125;
26
26
 
@@ -0,0 +1,6 @@
1
+ export const DEFAULT_LINE_HEIGHT = 25;
2
+ export const GUTTER_SIZE = 10;
3
+ /* TODO: this does not work with the scrollitemto because it has no knowledge of the padding.
4
+ * https://gist.github.com/ValentinJS/4f3738ed426cac183e8446c869b162dd might be an option.
5
+ */
6
+ export const LIST_PADDING_SIZE = 0;
@@ -28,6 +28,7 @@ import {
28
28
  AiOutlinePicRight as TightDensityIcon,
29
29
  AiOutlineRight as ExpandIcon,
30
30
  AiOutlineUp as CollapseIcon,
31
+ AiOutlineSearch as SearchIcon,
31
32
  } from 'react-icons/ai';
32
33
  import { ColumnHeader } from './subcomponents/ColumnHeader';
33
34
  import { ColumnVisibility } from './subcomponents/ColumnVisibility';
@@ -37,7 +38,8 @@ import { PageSizeSelect } from './subcomponents/Pagination/PageSizeSelect';
37
38
 
38
39
  import { ColumnFilter, PageOptions } from '../../../hooks/useTableActions';
39
40
  import { GenericCheckBox as CheckBox } from '../../inputs/CheckBox/Generic';
40
- import { useLocalStorage } from '../../../hooks';
41
+ import { useDebounce, useLocalStorage } from '../../../hooks';
42
+ import { UnControlledTextField } from '../../../components';
41
43
 
42
44
  export interface TableProps<DataType extends object> {
43
45
  id: string;
@@ -58,6 +60,10 @@ export interface TableProps<DataType extends object> {
58
60
  /// Renders actions that are only visible when one or more rows are selected.
59
61
  renderRowSelectionActions?: () => JSX.Element;
60
62
 
63
+ /// When callback is assigned, an input field will appear in the toolbar.
64
+ onSearchInputChanged?: (input: string) => void;
65
+ searchInputPlaceholder?: string;
66
+
61
67
  title?: string;
62
68
 
63
69
  rowSelection?: {
@@ -95,6 +101,8 @@ export function Table<DataType extends object>({
95
101
  rowSelection,
96
102
  columnSearch,
97
103
  renderDetailPanel,
104
+ onSearchInputChanged,
105
+ searchInputPlaceholder = 'Search...',
98
106
  renderToolbar,
99
107
  canExpand = () => false,
100
108
  renderRowSelectionActions,
@@ -127,6 +135,15 @@ export function Table<DataType extends object>({
127
135
 
128
136
  const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({});
129
137
  const { storedValue: density, setValue: setDensity } = useLocalStorage<Density>(`table-density-${id}`, 'tight');
138
+ const [searchInput, setSearchInput] = useState<string>('');
139
+ const debouncedValue = useDebounce(searchInput, 350);
140
+
141
+ useEffect(() => {
142
+ if (onSearchInputChanged) {
143
+ onSearchInputChanged(debouncedValue);
144
+ table.resetPagination();
145
+ }
146
+ }, [debouncedValue]);
130
147
 
131
148
  // Might because potentially none fullfil the canExpand condtion.
132
149
  const rowsMightExpand = renderDetailPanel ? true : false;
@@ -245,6 +262,18 @@ export function Table<DataType extends object>({
245
262
  {hasRowSelection && renderRowSelectionActions && renderRowSelectionActions()}
246
263
  </Flex>
247
264
  <Flex>
265
+ {onSearchInputChanged && (
266
+ <UnControlledTextField
267
+ name="search-input"
268
+ value={searchInput}
269
+ placeholder={searchInputPlaceholder}
270
+ id={id + '-search-input'}
271
+ hasDescription={false}
272
+ hasError={false}
273
+ icon={<SearchIcon />}
274
+ onChange={(e) => setSearchInput(e.currentTarget.value)}
275
+ />
276
+ )}
248
277
  {renderToolbar && renderToolbar()}
249
278
  {!isLoading && <Filter table={table} />}
250
279
  <ColumnVisibility
@@ -1,9 +1,10 @@
1
1
  import { Control, UseFormSetValue, useWatch } from 'react-hook-form';
2
2
  import { SelectField, TextField } from '../../../../../components';
3
- import { Operators, FilterInputType, IFormInputs } from '.';
3
+ import { IFormInputs } from '.';
4
4
  import { Column } from '@tanstack/react-table';
5
5
  import { useLayoutEffect } from 'react';
6
6
  import { camelCaseToSpaces } from '../../../../../helpers';
7
+ import { FilterInputType, Operators } from './types';
7
8
 
8
9
  interface FilterFieldProps<DataType> {
9
10
  index: number;
@@ -70,7 +71,6 @@ export function FilterRow<DataType extends object>({
70
71
  control={control}
71
72
  name={`filters.${index}.column`}
72
73
  label="Column"
73
- inPortal
74
74
  render={(selectedItems) => {
75
75
  if (selectedItems.length === 0) {
76
76
  return 'Select a column';
@@ -95,7 +95,6 @@ export function FilterRow<DataType extends object>({
95
95
  control={control}
96
96
  name={`filters.${index}.operator`}
97
97
  label="Condition"
98
- inPortal
99
98
  render={() => {
100
99
  const operator = currentOperator?.toString();
101
100
 
@@ -7,17 +7,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
7
7
  import { useCallback, useEffect, useMemo, useState } from 'react';
8
8
  import { ButtonContainer, Container, FilterActions, FilterContainer } from './style';
9
9
  import { FilterRow } from './field';
10
-
11
- export enum Operators {
12
- is = 'is',
13
- contains = 'contains',
14
- }
15
-
16
- export enum FilterInputType {
17
- string = 'string',
18
- uuid = 'uuid',
19
- datetime = 'datetime',
20
- }
10
+ import { Operators, FilterInputType } from './types';
21
11
 
22
12
  export interface IFormInputs {
23
13
  filters: {
@@ -0,0 +1,10 @@
1
+ export enum Operators {
2
+ is = 'is',
3
+ contains = 'contains',
4
+ }
5
+
6
+ export enum FilterInputType {
7
+ string = 'string',
8
+ uuid = 'uuid',
9
+ datetime = 'datetime',
10
+ }
@@ -14,7 +14,6 @@ export const PageSizeSelect: FC<PageSizeSelectProps> = ({ onPageSizeChange, page
14
14
  id="page-size"
15
15
  multiple={false}
16
16
  name="pageSize"
17
- inPortal={true}
18
17
  value={pageSize.toString() || '10'}
19
18
  onChange={onPageSizeChange}
20
19
  render={(selectedItems) => {
@@ -18,9 +18,6 @@ export { Drawer, DrawerSkeleton } from './Drawer';
18
18
  export { Stats } from './Stats';
19
19
  export type { StatsProps } from './Stats/';
20
20
 
21
- export { LinkCard } from './LinkCard';
22
- export type { LinkCardProps } from './LinkCard';
23
-
24
21
  export { DateFormatter } from './DateFormatter';
25
22
  export type { DateFormatterProps } from './DateFormatter';
26
23
 
@@ -7,6 +7,7 @@ const Container = styled.div<{ size: Size }>`
7
7
  flex-flow: column nowrap;
8
8
  align-items: center;
9
9
  width: 100%;
10
+ min-width: 350px;
10
11
  margin: 0 auto;
11
12
  padding: ${({ theme }) => theme.spacing[4]};
12
13
 
@@ -1,5 +1,6 @@
1
1
  import { Alert } from '.';
2
- import { render } from 'test-utils';
2
+ import { render } from '../../../test/testUtils';
3
+ import { expect, it } from 'vitest';
3
4
 
4
5
  it('Should render <Alert/>', () => {
5
6
  const { container } = render(<Alert text="Alert text" title="Alert title" variant="info" />);