paris 0.19.0 → 0.20.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 (47) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/package.json +17 -2
  3. package/src/stories/accordion/Accordion.test.tsx +140 -0
  4. package/src/stories/accordionselect/AccordionSelect.test.tsx +252 -0
  5. package/src/stories/avatar/Avatar.test.tsx +77 -0
  6. package/src/stories/button/Button.test.tsx +266 -0
  7. package/src/stories/callout/Callout.test.tsx +79 -0
  8. package/src/stories/card/Card.test.tsx +81 -0
  9. package/src/stories/cardbutton/CardButton.test.tsx +174 -0
  10. package/src/stories/checkbox/Checkbox.test.tsx +531 -0
  11. package/src/stories/combobox/Combobox.test.tsx +164 -0
  12. package/src/stories/dialog/Dialog.module.scss +2 -2
  13. package/src/stories/dialog/Dialog.test.tsx +244 -0
  14. package/src/stories/drawer/Drawer.module.scss +2 -2
  15. package/src/stories/drawer/Drawer.test.tsx +259 -0
  16. package/src/stories/field/Field.test.tsx +146 -0
  17. package/src/stories/icon/Icon.test.tsx +59 -0
  18. package/src/stories/informationaltooltip/InformationalTooltip.test.tsx +178 -0
  19. package/src/stories/input/Input.test.tsx +174 -0
  20. package/src/stories/markdown/Markdown.test.tsx +228 -0
  21. package/src/stories/markdowneditor/FixedToolbar.tsx +44 -14
  22. package/src/stories/markdowneditor/LinkPopover.module.scss +1 -1
  23. package/src/stories/markdowneditor/MarkdownEditor.stories.tsx +4 -1
  24. package/src/stories/markdowneditor/MarkdownEditor.test.tsx +115 -0
  25. package/src/stories/markdowneditor/MarkdownEditor.tsx +11 -1
  26. package/src/stories/markdowneditor/MarkdownEditorContext.tsx +3 -0
  27. package/src/stories/markdowneditor/index.ts +1 -0
  28. package/src/stories/menu/Menu.module.scss +1 -1
  29. package/src/stories/menu/Menu.test.tsx +211 -0
  30. package/src/stories/pagination/usePagination.test.ts +259 -0
  31. package/src/stories/popover/Popover.test.tsx +152 -0
  32. package/src/stories/select/Select.module.scss +2 -1
  33. package/src/stories/select/Select.test.tsx +233 -0
  34. package/src/stories/styledlink/StyledLink.test.tsx +59 -0
  35. package/src/stories/table/Table.test.tsx +156 -0
  36. package/src/stories/tabs/Tabs.module.scss +1 -1
  37. package/src/stories/tabs/Tabs.test.tsx +167 -0
  38. package/src/stories/tag/Tag.test.tsx +90 -0
  39. package/src/stories/text/Text.test.tsx +81 -0
  40. package/src/stories/textarea/TextArea.test.tsx +147 -0
  41. package/src/stories/theme/themes.ts +16 -0
  42. package/src/stories/tilt/Tilt.test.tsx +203 -0
  43. package/src/stories/toast/Toast.test.tsx +86 -0
  44. package/src/stories/utility/Dropdown.module.scss +1 -1
  45. package/src/stories/utility/Utility.test.tsx +96 -0
  46. package/src/test/render.tsx +20 -0
  47. package/src/test/setup.ts +32 -0
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { render, screen } from '../../test/render';
3
+ import { Tag } from './Tag';
4
+
5
+ describe('Tag', () => {
6
+ it('renders children text', () => {
7
+ render(<Tag>Active</Tag>);
8
+ expect(screen.getByText('Active')).toBeInTheDocument();
9
+ });
10
+
11
+ it('renders as a div element', () => {
12
+ render(<Tag>Tag div</Tag>);
13
+ const el = screen.getByText('Tag div').closest('div');
14
+ expect(el).toBeInTheDocument();
15
+ });
16
+
17
+ it('applies the default kind class', () => {
18
+ const { container } = render(<Tag>Default</Tag>);
19
+ const root = container.firstElementChild;
20
+ expect(root?.className).toContain('default');
21
+ });
22
+
23
+ it('applies a custom kind class', () => {
24
+ const { container } = render(<Tag kind="positive">Success</Tag>);
25
+ const root = container.firstElementChild;
26
+ expect(root?.className).toContain('positive');
27
+ });
28
+
29
+ it('applies kind variants', () => {
30
+ const kinds = ['secondary', 'warning', 'negative', 'new', 'void', 'draft'] as const;
31
+ for (const kind of kinds) {
32
+ const { container, unmount } = render(<Tag kind={kind}>{kind}</Tag>);
33
+ const root = container.firstElementChild;
34
+ expect(root?.className).toContain(kind);
35
+ unmount();
36
+ }
37
+ });
38
+
39
+ it('applies the normal size by default', () => {
40
+ const { container } = render(<Tag>Normal</Tag>);
41
+ const root = container.firstElementChild;
42
+ expect(root?.className).toContain('normal');
43
+ });
44
+
45
+ it('applies the compact size', () => {
46
+ const { container } = render(<Tag size="compact">Compact</Tag>);
47
+ const root = container.firstElementChild;
48
+ expect(root?.className).toContain('compact');
49
+ });
50
+
51
+ it('applies rectangle shape by default (children visible)', () => {
52
+ render(<Tag>Rectangle</Tag>);
53
+ const textEl = screen.getByText('Rectangle');
54
+ expect(textEl).toBeVisible();
55
+ });
56
+
57
+ it('applies square shape and hides children visually', () => {
58
+ const { container } = render(<Tag shape="square">Hidden</Tag>);
59
+ const root = container.firstElementChild;
60
+ expect(root?.className).toContain('square');
61
+ });
62
+
63
+ it('applies corner preset classes', () => {
64
+ const { container } = render(<Tag corners="roundedXL">Rounded</Tag>);
65
+ const root = container.firstElementChild;
66
+ expect(root?.className).toContain('roundedXL');
67
+ });
68
+
69
+ it('applies custom border radius for non-preset corners', () => {
70
+ const { container } = render(<Tag corners="8px">Custom radius</Tag>);
71
+ const root = container.firstElementChild as HTMLElement;
72
+ expect(root?.style.borderRadius).toBe('8px');
73
+ });
74
+
75
+ it('sets data-status attribute for colorLevel', () => {
76
+ const { container } = render(
77
+ <Tag kind="positive" colorLevel="strong">
78
+ Strong
79
+ </Tag>,
80
+ );
81
+ const root = container.firstElementChild;
82
+ expect(root?.getAttribute('data-status')).toBe('strong');
83
+ });
84
+
85
+ it('forwards className prop', () => {
86
+ const { container } = render(<Tag className="my-tag">Custom</Tag>);
87
+ const root = container.firstElementChild;
88
+ expect(root?.className).toContain('my-tag');
89
+ });
90
+ });
@@ -0,0 +1,81 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { render, screen } from '../../test/render';
3
+ import { Text } from './Text';
4
+
5
+ describe('Text', () => {
6
+ it('renders children as text', () => {
7
+ render(<Text>Hello World</Text>);
8
+ expect(screen.getByText('Hello World')).toBeInTheDocument();
9
+ });
10
+
11
+ it('renders as a span by default', () => {
12
+ render(<Text>Default span</Text>);
13
+ const el = screen.getByText('Default span');
14
+ expect(el.tagName).toBe('SPAN');
15
+ });
16
+
17
+ it('renders as different elements via the as prop', () => {
18
+ const { unmount } = render(<Text as="h1">Heading</Text>);
19
+ expect(screen.getByText('Heading').tagName).toBe('H1');
20
+ unmount();
21
+
22
+ const { unmount: unmount2 } = render(<Text as="p">Paragraph</Text>);
23
+ expect(screen.getByText('Paragraph').tagName).toBe('P');
24
+ unmount2();
25
+
26
+ render(<Text as="label">Label</Text>);
27
+ expect(screen.getByText('Label').tagName).toBe('LABEL');
28
+ });
29
+
30
+ it('applies the paragraphMedium kind class by default', () => {
31
+ render(<Text>Styled text</Text>);
32
+ const el = screen.getByText('Styled text');
33
+ expect(el.className).toContain('paragraphMedium');
34
+ });
35
+
36
+ it('applies a custom kind class', () => {
37
+ render(<Text kind="headingLarge">Big heading</Text>);
38
+ const el = screen.getByText('Big heading');
39
+ expect(el.className).toContain('headingLarge');
40
+ });
41
+
42
+ it('applies weight class when weight is provided', () => {
43
+ render(<Text weight="bold">Bold text</Text>);
44
+ const el = screen.getByText('Bold text');
45
+ expect(el.className).toContain('weight-bold');
46
+ });
47
+
48
+ it('applies fontStyle class when fontStyle is provided', () => {
49
+ render(<Text fontStyle="italic">Italic text</Text>);
50
+ const el = screen.getByText('Italic text');
51
+ expect(el.className).toContain('fontStyle-italic');
52
+ });
53
+
54
+ it('sets --text-color CSS variable when color is provided', () => {
55
+ render(<Text color="red">Red text</Text>);
56
+ const el = screen.getByText('Red text');
57
+ expect(el.style.getPropertyValue('--text-color')).toBe('red');
58
+ });
59
+
60
+ it('does not set style when no color is provided', () => {
61
+ render(<Text>No color</Text>);
62
+ const el = screen.getByText('No color');
63
+ expect(el.style.getPropertyValue('--text-color')).toBe('');
64
+ });
65
+
66
+ it('forwards className prop', () => {
67
+ render(<Text className="custom-class">Custom</Text>);
68
+ const el = screen.getByText('Custom');
69
+ expect(el.className).toContain('custom-class');
70
+ });
71
+
72
+ it('forwards additional HTML props', () => {
73
+ render(
74
+ <Text data-testid="text-element" id="my-text">
75
+ Props test
76
+ </Text>,
77
+ );
78
+ const el = screen.getByTestId('text-element');
79
+ expect(el.id).toBe('my-text');
80
+ });
81
+ });
@@ -0,0 +1,147 @@
1
+ import { createRef } from 'react';
2
+ import { render, screen } from '../../test/render';
3
+ import { TextArea } from './TextArea';
4
+
5
+ describe('TextArea', () => {
6
+ it('renders with a label', () => {
7
+ render(<TextArea label="Message" />);
8
+ expect(screen.getByLabelText('Message')).toBeInTheDocument();
9
+ });
10
+
11
+ it('renders a textarea element', () => {
12
+ render(<TextArea label="Bio" />);
13
+ const textarea = screen.getByLabelText('Bio');
14
+ expect(textarea.tagName).toBe('TEXTAREA');
15
+ });
16
+
17
+ it('allows typing into the textarea', async () => {
18
+ const { user } = render(<TextArea label="Notes" />);
19
+ const textarea = screen.getByLabelText('Notes');
20
+ await user.type(textarea, 'Hello world');
21
+ expect(textarea).toHaveValue('Hello world');
22
+ });
23
+
24
+ it('displays placeholder text', () => {
25
+ render(<TextArea label="Comment" placeholder="Write a comment..." />);
26
+ expect(screen.getByPlaceholderText('Write a comment...')).toBeInTheDocument();
27
+ });
28
+
29
+ it('defaults to 3 rows', () => {
30
+ render(<TextArea label="Default rows" />);
31
+ expect(screen.getByLabelText('Default rows')).toHaveAttribute('rows', '3');
32
+ });
33
+
34
+ it('accepts a custom rows value', () => {
35
+ render(<TextArea label="Custom rows" rows={6} />);
36
+ expect(screen.getByLabelText('Custom rows')).toHaveAttribute('rows', '6');
37
+ });
38
+
39
+ it('sets data-status to default when no status is provided', () => {
40
+ render(<TextArea label="Default status" />);
41
+ expect(screen.getByLabelText('Default status')).toHaveAttribute('data-status', 'default');
42
+ });
43
+
44
+ it('sets data-status to error', () => {
45
+ render(<TextArea label="Error" status="error" />);
46
+ expect(screen.getByLabelText('Error')).toHaveAttribute('data-status', 'error');
47
+ });
48
+
49
+ it('sets data-status to success', () => {
50
+ render(<TextArea label="Success" status="success" />);
51
+ expect(screen.getByLabelText('Success')).toHaveAttribute('data-status', 'success');
52
+ });
53
+
54
+ it('sets data-status to disabled when disabled', () => {
55
+ render(<TextArea label="Disabled" disabled />);
56
+ const textarea = screen.getByLabelText('Disabled');
57
+ expect(textarea).toHaveAttribute('data-status', 'disabled');
58
+ expect(textarea).toHaveAttribute('aria-disabled', 'true');
59
+ expect(textarea).toHaveAttribute('readonly');
60
+ });
61
+
62
+ it('overrides status with disabled when both are provided', () => {
63
+ render(<TextArea label="Both" status="error" disabled />);
64
+ expect(screen.getByLabelText('Both')).toHaveAttribute('data-status', 'disabled');
65
+ });
66
+
67
+ it('forwards ref to the textarea element', () => {
68
+ const ref = createRef<HTMLTextAreaElement>();
69
+ render(<TextArea label="Ref test" ref={ref} />);
70
+ expect(ref.current).toBeInstanceOf(HTMLTextAreaElement);
71
+ expect(ref.current).toBe(screen.getByLabelText('Ref test'));
72
+ });
73
+
74
+ it('renders a start enhancer', () => {
75
+ render(<TextArea label="With start" startEnhancer={<span data-testid="start-icon">S</span>} />);
76
+ expect(screen.getByTestId('start-icon')).toBeInTheDocument();
77
+ });
78
+
79
+ it('renders an end enhancer', () => {
80
+ render(<TextArea label="With end" endEnhancer={<span data-testid="end-icon">E</span>} />);
81
+ expect(screen.getByTestId('end-icon')).toBeInTheDocument();
82
+ });
83
+
84
+ it('forwards className to the textarea element', () => {
85
+ render(<TextArea label="Classy" className="my-custom-class" />);
86
+ expect(screen.getByLabelText('Classy')).toHaveClass('my-custom-class');
87
+ });
88
+
89
+ it('sets aria-describedby linking to the description', () => {
90
+ render(<TextArea label="Described" description="Helper text" />);
91
+ const textarea = screen.getByLabelText('Described');
92
+ const describedBy = textarea.getAttribute('aria-describedby');
93
+ expect(describedBy).toBeTruthy();
94
+ const descriptionEl = document.getElementById(describedBy!);
95
+ expect(descriptionEl).toBeInTheDocument();
96
+ expect(descriptionEl).toHaveTextContent('Helper text');
97
+ });
98
+
99
+ it('renders description text', () => {
100
+ render(<TextArea label="With desc" description="A helpful note" />);
101
+ expect(screen.getByText('A helpful note')).toBeInTheDocument();
102
+ });
103
+
104
+ it('hides label when hideLabel is true', () => {
105
+ render(<TextArea label="Hidden" hideLabel />);
106
+ expect(screen.getByText('Hidden')).toHaveClass('hidden');
107
+ });
108
+
109
+ it('calls onChange handler', async () => {
110
+ const handleChange = vi.fn();
111
+ const { user } = render(<TextArea label="Change" onChange={handleChange} />);
112
+ await user.type(screen.getByLabelText('Change'), 'x');
113
+ expect(handleChange).toHaveBeenCalled();
114
+ });
115
+
116
+ it('calls onFocus and onBlur handlers', async () => {
117
+ const handleFocus = vi.fn();
118
+ const handleBlur = vi.fn();
119
+ const { user } = render(<TextArea label="Focus" onFocus={handleFocus} onBlur={handleBlur} />);
120
+ await user.click(screen.getByLabelText('Focus'));
121
+ expect(handleFocus).toHaveBeenCalled();
122
+ await user.tab();
123
+ expect(handleBlur).toHaveBeenCalled();
124
+ });
125
+
126
+ it('uses aria-label prop when label is not a string', () => {
127
+ render(<TextArea label={<span>Complex</span>} aria-label="accessible label" />);
128
+ expect(screen.getByRole('textbox', { name: 'accessible label' })).toBeInTheDocument();
129
+ });
130
+
131
+ it('applies container override props', () => {
132
+ render(<TextArea label="Override" overrides={{ container: { 'data-testid': 'wrapper' } }} />);
133
+ expect(screen.getByTestId('wrapper')).toBeInTheDocument();
134
+ });
135
+
136
+ it('spreads additional HTML textarea props', () => {
137
+ render(<TextArea label="Extra" maxLength={500} />);
138
+ expect(screen.getByLabelText('Extra')).toHaveAttribute('maxlength', '500');
139
+ });
140
+
141
+ it('renders a function enhancer', () => {
142
+ render(
143
+ <TextArea label="Fn enhancer" endEnhancer={({ size }) => <span data-testid="fn-enhancer">{size}</span>} />,
144
+ );
145
+ expect(screen.getByTestId('fn-enhancer')).toBeInTheDocument();
146
+ });
147
+ });
@@ -432,6 +432,14 @@ export type Theme = {
432
432
  lg: `${number}px`;
433
433
  xl: `${number}px`;
434
434
  };
435
+ layers: {
436
+ below: number;
437
+ sticky: number;
438
+ dropdown: number;
439
+ overlay: number;
440
+ popover: number;
441
+ menu: number;
442
+ };
435
443
  };
436
444
  tokens: TokensT;
437
445
  utils: {
@@ -1054,6 +1062,14 @@ export const LightTheme: Theme = {
1054
1062
  lg: '768px',
1055
1063
  xl: '1024px',
1056
1064
  },
1065
+ layers: {
1066
+ below: -1,
1067
+ sticky: 100,
1068
+ dropdown: 200,
1069
+ overlay: 300,
1070
+ popover: 400,
1071
+ menu: 500,
1072
+ },
1057
1073
  },
1058
1074
  tokens: T,
1059
1075
  utils: {
@@ -0,0 +1,203 @@
1
+ import { fireEvent } from '@testing-library/react';
2
+ import { render, screen } from '../../test/render';
3
+ import { Tilt } from './Tilt';
4
+
5
+ describe('Tilt', () => {
6
+ it('renders children', () => {
7
+ render(
8
+ <Tilt>
9
+ <div data-testid="child">Content</div>
10
+ </Tilt>,
11
+ );
12
+ expect(screen.getByTestId('child')).toBeInTheDocument();
13
+ });
14
+
15
+ it('renders multiple children', () => {
16
+ render(
17
+ <Tilt>
18
+ <div data-testid="child-1">First</div>
19
+ <div data-testid="child-2">Second</div>
20
+ </Tilt>,
21
+ );
22
+ expect(screen.getByTestId('child-1')).toBeInTheDocument();
23
+ expect(screen.getByTestId('child-2')).toBeInTheDocument();
24
+ });
25
+
26
+ describe('className forwarding', () => {
27
+ it('forwards custom className', () => {
28
+ const { container } = render(<Tilt className="custom-class">Content</Tilt>);
29
+ expect(container.firstElementChild).toHaveClass('custom-class');
30
+ });
31
+
32
+ it('preserves container class when custom className is added', () => {
33
+ const { container } = render(<Tilt className="custom-class">Content</Tilt>);
34
+ expect(container.firstElementChild).toHaveClass('container');
35
+ expect(container.firstElementChild).toHaveClass('custom-class');
36
+ });
37
+ });
38
+
39
+ describe('style forwarding', () => {
40
+ it('applies custom styles', () => {
41
+ const { container } = render(<Tilt style={{ backgroundColor: 'red' }}>Content</Tilt>);
42
+ const el = container.firstElementChild as HTMLElement;
43
+ expect(el.style.backgroundColor).toBe('red');
44
+ });
45
+ });
46
+
47
+ describe('transform', () => {
48
+ it('applies initial transform with default perspective and scale', () => {
49
+ const { container } = render(<Tilt>Content</Tilt>);
50
+ const el = container.firstElementChild as HTMLElement;
51
+ expect(el.style.transform).toContain('perspective(1000px)');
52
+ expect(el.style.transform).toContain('rotateX(0deg)');
53
+ expect(el.style.transform).toContain('rotateY(0deg)');
54
+ expect(el.style.transform).toContain('scale3d(1,1,1)');
55
+ });
56
+
57
+ it('applies custom perspective', () => {
58
+ const { container } = render(<Tilt perspective={500}>Content</Tilt>);
59
+ const el = container.firstElementChild as HTMLElement;
60
+ expect(el.style.transform).toContain('perspective(500px)');
61
+ });
62
+ });
63
+
64
+ describe('glare', () => {
65
+ it('renders glare overlay by default', () => {
66
+ const { container } = render(<Tilt>Content</Tilt>);
67
+ const glareWrapper = container.querySelector('.glareWrapper');
68
+ expect(glareWrapper).toBeInTheDocument();
69
+ });
70
+
71
+ it('does not render glare when glareEnable is false', () => {
72
+ const { container } = render(<Tilt glareEnable={false}>Content</Tilt>);
73
+ const glareWrapper = container.querySelector('.glareWrapper');
74
+ expect(glareWrapper).not.toBeInTheDocument();
75
+ });
76
+
77
+ it('does not render glare when tilt is disabled', () => {
78
+ const { container } = render(<Tilt disableTilt>Content</Tilt>);
79
+ const glareWrapper = container.querySelector('.glareWrapper');
80
+ expect(glareWrapper).not.toBeInTheDocument();
81
+ });
82
+ });
83
+
84
+ describe('disableTilt', () => {
85
+ it('uses scale of 1 when tilt is disabled', () => {
86
+ const { container } = render(<Tilt disableTilt>Content</Tilt>);
87
+ const el = container.firstElementChild as HTMLElement;
88
+ expect(el.style.transform).toContain('scale3d(1,1,1)');
89
+ });
90
+ });
91
+
92
+ describe('mouse events', () => {
93
+ it('calls onEnter on mouse enter', () => {
94
+ const onEnter = vi.fn();
95
+ const { container } = render(<Tilt onEnter={onEnter}>Content</Tilt>);
96
+ fireEvent.mouseEnter(container.firstElementChild!);
97
+ expect(onEnter).toHaveBeenCalledTimes(1);
98
+ expect(onEnter).toHaveBeenCalledWith(expect.objectContaining({ event: expect.anything() }));
99
+ });
100
+
101
+ it('calls onLeave on mouse leave', () => {
102
+ const onLeave = vi.fn();
103
+ const { container } = render(<Tilt onLeave={onLeave}>Content</Tilt>);
104
+ const el = container.firstElementChild!;
105
+ fireEvent.mouseEnter(el);
106
+ fireEvent.mouseLeave(el);
107
+ expect(onLeave).toHaveBeenCalledTimes(1);
108
+ });
109
+
110
+ it('calls onMove on mouse move', () => {
111
+ const onMove = vi.fn();
112
+ const { container } = render(<Tilt onMove={onMove}>Content</Tilt>);
113
+ const el = container.firstElementChild!;
114
+ fireEvent.mouseEnter(el);
115
+ fireEvent.mouseMove(el, { pageX: 50, pageY: 50 });
116
+ expect(onMove).toHaveBeenCalled();
117
+ });
118
+
119
+ it('resets transform on mouse leave when reset is true', () => {
120
+ const { container } = render(<Tilt reset>Content</Tilt>);
121
+ const el = container.firstElementChild as HTMLElement;
122
+ fireEvent.mouseEnter(el);
123
+ fireEvent.mouseLeave(el);
124
+ expect(el.style.transform).toContain('rotateX(0deg)');
125
+ expect(el.style.transform).toContain('rotateY(0deg)');
126
+ });
127
+ });
128
+
129
+ describe('touch events', () => {
130
+ it('calls onEnter on touch start', () => {
131
+ const onEnter = vi.fn();
132
+ const { container } = render(<Tilt onEnter={onEnter}>Content</Tilt>);
133
+ fireEvent.touchStart(container.firstElementChild!, {
134
+ touches: [{ pageX: 50, pageY: 50 }],
135
+ });
136
+ expect(onEnter).toHaveBeenCalledTimes(1);
137
+ });
138
+
139
+ it('calls onLeave on touch end', () => {
140
+ const onLeave = vi.fn();
141
+ const { container } = render(<Tilt onLeave={onLeave}>Content</Tilt>);
142
+ const el = container.firstElementChild!;
143
+ fireEvent.touchStart(el, { touches: [{ pageX: 50, pageY: 50 }] });
144
+ fireEvent.touchEnd(el);
145
+ expect(onLeave).toHaveBeenCalledTimes(1);
146
+ });
147
+ });
148
+
149
+ describe('manual tilt angles', () => {
150
+ it('applies manual tilt angle X', () => {
151
+ const { container } = render(<Tilt tiltAngleXManual={10}>Content</Tilt>);
152
+ const el = container.firstElementChild as HTMLElement;
153
+ expect(el.style.transform).toContain('rotateX(10deg)');
154
+ });
155
+
156
+ it('applies manual tilt angle Y', () => {
157
+ const { container } = render(<Tilt tiltAngleYManual={15}>Content</Tilt>);
158
+ const el = container.firstElementChild as HTMLElement;
159
+ expect(el.style.transform).toContain('rotateY(15deg)');
160
+ });
161
+
162
+ it('applies transition when manual angles are set', () => {
163
+ const { container } = render(
164
+ <Tilt tiltAngleXManual={10} transitionSpeed={300}>
165
+ Content
166
+ </Tilt>,
167
+ );
168
+ const el = container.firstElementChild as HTMLElement;
169
+ expect(el.style.transition).toContain('300ms');
170
+ });
171
+ });
172
+
173
+ describe('transition', () => {
174
+ it('applies transition on mouse enter', () => {
175
+ const { container } = render(<Tilt transitionSpeed={500}>Content</Tilt>);
176
+ const el = container.firstElementChild as HTMLElement;
177
+ fireEvent.mouseEnter(el);
178
+ expect(el.style.transition).toContain('500ms');
179
+ });
180
+
181
+ it('applies custom easing function', () => {
182
+ const { container } = render(<Tilt transitionEasing="ease-in-out">Content</Tilt>);
183
+ const el = container.firstElementChild as HTMLElement;
184
+ fireEvent.mouseEnter(el);
185
+ expect(el.style.transition).toContain('ease-in-out');
186
+ });
187
+ });
188
+
189
+ describe('glare border radius', () => {
190
+ it('uses custom glareBorderRadius when provided', () => {
191
+ const { container } = render(<Tilt glareBorderRadius="10px">Content</Tilt>);
192
+ const glareWrapper = container.querySelector('.glareWrapper') as HTMLElement;
193
+ expect(glareWrapper.style.borderRadius).toBe('10px');
194
+ });
195
+
196
+ it('derives glare border radius from style.borderRadius', () => {
197
+ const { container } = render(<Tilt style={{ borderRadius: '20px' }}>Content</Tilt>);
198
+ const glareWrapper = container.querySelector('.glareWrapper') as HTMLElement;
199
+ // jsdom may simplify calc(20px - 1px) to calc(19px)
200
+ expect(glareWrapper.style.borderRadius).toMatch(/calc\((?:20px - 1px|19px)\)/);
201
+ });
202
+ });
203
+ });
@@ -0,0 +1,86 @@
1
+ import { act, render, screen, waitFor } from '../../test/render';
2
+ import { Toast, toast } from './Toast';
3
+
4
+ describe('Toast', () => {
5
+ it('renders the Toaster container without crashing', () => {
6
+ const { container } = render(<Toast />);
7
+ expect(container).toBeInTheDocument();
8
+ });
9
+
10
+ it('displays a toast message when toast() is called', async () => {
11
+ render(<Toast />);
12
+
13
+ act(() => {
14
+ toast('Hello from Paris');
15
+ });
16
+
17
+ await waitFor(() => {
18
+ expect(screen.getByText('Hello from Paris')).toBeInTheDocument();
19
+ });
20
+ });
21
+
22
+ it('displays a success toast', async () => {
23
+ render(<Toast />);
24
+
25
+ act(() => {
26
+ toast.success('Operation succeeded');
27
+ });
28
+
29
+ await waitFor(() => {
30
+ expect(screen.getByText('Operation succeeded')).toBeInTheDocument();
31
+ });
32
+ });
33
+
34
+ it('displays an error toast', async () => {
35
+ render(<Toast />);
36
+
37
+ act(() => {
38
+ toast.error('Something went wrong');
39
+ });
40
+
41
+ await waitFor(() => {
42
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument();
43
+ });
44
+ });
45
+
46
+ it('displays a loading toast', async () => {
47
+ render(<Toast />);
48
+
49
+ act(() => {
50
+ toast.loading('Please wait...');
51
+ });
52
+
53
+ await waitFor(() => {
54
+ expect(screen.getByText('Please wait...')).toBeInTheDocument();
55
+ });
56
+ });
57
+
58
+ it('displays a custom JSX toast', async () => {
59
+ render(<Toast />);
60
+
61
+ act(() => {
62
+ toast(<span data-testid="custom-toast">Custom content</span>);
63
+ });
64
+
65
+ await waitFor(() => {
66
+ expect(screen.getByTestId('custom-toast')).toBeInTheDocument();
67
+ });
68
+ });
69
+
70
+ it('applies toast styling className', async () => {
71
+ render(<Toast />);
72
+
73
+ act(() => {
74
+ toast('Styled toast');
75
+ });
76
+
77
+ await waitFor(() => {
78
+ const toastEl = screen.getByText('Styled toast').closest('[class*="toast"]');
79
+ expect(toastEl).toBeInTheDocument();
80
+ });
81
+ });
82
+
83
+ it('passes additional Toaster props through', () => {
84
+ render(<Toast position="bottom-left" />);
85
+ });
86
+ });
@@ -1,6 +1,6 @@
1
1
  .transitionContainer {
2
2
  position: relative;
3
- z-index: 10;
3
+ z-index: var(--pte-new-layers-dropdown);
4
4
  }
5
5
 
6
6
  .transition {