@usefui/components 1.7.1 → 1.7.2
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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +14 -124
- package/dist/index.d.ts +14 -124
- package/dist/index.js +128 -326
- package/dist/index.mjs +127 -318
- package/package.json +3 -3
- package/src/badge/Badge.stories.tsx +32 -0
- package/src/badge/index.tsx +4 -0
- package/src/badge/styles/index.ts +26 -0
- package/src/button/Button.stories.tsx +93 -0
- package/src/button/styles/index.ts +23 -31
- package/src/dialog/index.tsx +17 -20
- package/src/dropdown/Dropdown.stories.tsx +87 -0
- package/src/dropdown/index.tsx +13 -1
- package/src/dropdown/styles/index.ts +14 -6
- package/src/field/styles/index.ts +7 -21
- package/src/index.ts +0 -3
- package/src/message-bubble/MessageBubble.stories.tsx +27 -7
- package/src/message-bubble/index.tsx +6 -2
- package/src/resizable/Resizable.stories.tsx +19 -22
- package/src/resizable/index.tsx +9 -5
- package/src/resizable/styles/index.ts +5 -2
- package/src/__tests__/Tree.test.tsx +0 -275
- package/src/tree/Tree.stories.tsx +0 -141
- package/src/tree/hooks/tree-node-provider.tsx +0 -50
- package/src/tree/hooks/tree-provider.tsx +0 -75
- package/src/tree/index.tsx +0 -231
- package/src/tree/styles/index.ts +0 -23
|
@@ -290,12 +290,8 @@ export const InnerWrapper = styled.div<any>`
|
|
|
290
290
|
display: flex;
|
|
291
291
|
flex-direction: column;
|
|
292
292
|
|
|
293
|
-
right: 0;
|
|
294
|
-
&[data-multiple="true"] {
|
|
295
|
-
right: var(--measurement-small-10) !important;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
293
|
top: var(--measurement-small-10);
|
|
294
|
+
right: var(--measurement-small-10);
|
|
299
295
|
bottom: var(--measurement-small-10);
|
|
300
296
|
|
|
301
297
|
border-left: var(--measurement-small-10) solid var(--font-color-alpha-10);
|
|
@@ -306,7 +302,6 @@ export const InnerWrapper = styled.div<any>`
|
|
|
306
302
|
&[data-error="true"] {
|
|
307
303
|
border-color: var(--alpha-red-10) !important;
|
|
308
304
|
}
|
|
309
|
-
|
|
310
305
|
&[data-shape="round"] {
|
|
311
306
|
border-radius: 0 var(--measurement-large-90) var(--measurement-large-90) 0;
|
|
312
307
|
}
|
|
@@ -332,16 +327,7 @@ export const InnerTrigger = styled.button<any>`
|
|
|
332
327
|
padding: 0 var(--measurement-medium-40);
|
|
333
328
|
|
|
334
329
|
color: var(--font-color-alpha-60);
|
|
335
|
-
|
|
336
|
-
background-color: var(--body-color);
|
|
337
|
-
background: linear-gradient(
|
|
338
|
-
180deg,
|
|
339
|
-
transparent 50%,
|
|
340
|
-
var(--font-color-alpha-10) 100%
|
|
341
|
-
);
|
|
342
|
-
background-size: 100% 200%;
|
|
343
|
-
background-position: 0% 0%;
|
|
344
|
-
backdrop-filter: blur(var(--measurement-medium-10));
|
|
330
|
+
backdrop-filter: blur(var(--measurement-small-60));
|
|
345
331
|
|
|
346
332
|
cursor: pointer;
|
|
347
333
|
transition: all ease-in-out 0.2s;
|
|
@@ -351,7 +337,7 @@ export const InnerTrigger = styled.button<any>`
|
|
|
351
337
|
transition: all ease-in-out 0.2s;
|
|
352
338
|
}
|
|
353
339
|
|
|
354
|
-
::before {
|
|
340
|
+
/* ::before {
|
|
355
341
|
content: "";
|
|
356
342
|
inset: 0;
|
|
357
343
|
|
|
@@ -365,12 +351,12 @@ export const InnerTrigger = styled.button<any>`
|
|
|
365
351
|
|
|
366
352
|
transition: all ease-in-out 0.2s;
|
|
367
353
|
mask-image: linear-gradient(var(--font-color), transparent);
|
|
368
|
-
}
|
|
354
|
+
} */
|
|
369
355
|
|
|
370
356
|
&:hover,
|
|
371
357
|
&:active {
|
|
372
358
|
color: var(--font-color);
|
|
373
|
-
background-position: 0% 50%;
|
|
359
|
+
/* background-position: 0% 50%; */
|
|
374
360
|
|
|
375
361
|
svg {
|
|
376
362
|
opacity: 0.8;
|
|
@@ -390,7 +376,7 @@ export const InnerSegment = styled.span<any>`
|
|
|
390
376
|
text-align: center;
|
|
391
377
|
outline: none;
|
|
392
378
|
color: inherit;
|
|
393
|
-
transition: background-color ease-in-out 0.2s;
|
|
379
|
+
/* transition: background-color ease-in-out 0.2s; */
|
|
394
380
|
|
|
395
381
|
&[data-placeholder="true"] {
|
|
396
382
|
color: var(--font-color-alpha-30);
|
|
@@ -401,7 +387,7 @@ export const InnerSegment = styled.span<any>`
|
|
|
401
387
|
&:active,
|
|
402
388
|
&:focus-within,
|
|
403
389
|
&:has(:active) {
|
|
404
|
-
background-color: var(--font-color-alpha-10);
|
|
390
|
+
/* background-color: var(--font-color-alpha-10); */
|
|
405
391
|
color: var(--font-color);
|
|
406
392
|
}
|
|
407
393
|
}
|
package/src/index.ts
CHANGED
|
@@ -29,7 +29,6 @@ export * from "./text-area";
|
|
|
29
29
|
export * from "./toggle";
|
|
30
30
|
export * from "./toolbar";
|
|
31
31
|
export * from "./tooltip";
|
|
32
|
-
export * from "./tree";
|
|
33
32
|
export * from "./select";
|
|
34
33
|
|
|
35
34
|
export { useAccordion } from "./accordion/hooks";
|
|
@@ -43,6 +42,4 @@ export { useSwitch } from "./switch/hooks";
|
|
|
43
42
|
export { useTabs } from "./tabs/hooks";
|
|
44
43
|
export { useToolbar } from "./toolbar/hooks";
|
|
45
44
|
export { useMessageBubble } from "./message-bubble/hooks";
|
|
46
|
-
export { useTree } from "./tree/hooks/tree-provider";
|
|
47
|
-
export { useTreeNode } from "./tree/hooks/tree-node-provider";
|
|
48
45
|
export { useSelect } from "./select/hooks";
|
|
@@ -76,33 +76,48 @@ export const Conversation: Story = {
|
|
|
76
76
|
{(
|
|
77
77
|
[
|
|
78
78
|
{
|
|
79
|
-
variant: "
|
|
79
|
+
variant: "primary",
|
|
80
80
|
side: "left",
|
|
81
81
|
message: "Hey, how are you doing?",
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
|
-
variant: "
|
|
84
|
+
variant: "meta",
|
|
85
85
|
side: "right",
|
|
86
86
|
message: "All good! What about you?",
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
variant: "
|
|
89
|
+
variant: "primary",
|
|
90
90
|
side: "left",
|
|
91
91
|
message: "Pretty great, thanks for asking",
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
|
-
variant: "
|
|
94
|
+
variant: "meta",
|
|
95
95
|
side: "right",
|
|
96
96
|
message:
|
|
97
97
|
"Hic dolorum esse magnam sint quibusdam porro reprehenderit, enim, repellendus ipsam, iste est! Deserunt ipsam ullam dolores expedita rem, magni iste eveniet.",
|
|
98
98
|
},
|
|
99
|
+
{
|
|
100
|
+
variant: "meta",
|
|
101
|
+
side: "right",
|
|
102
|
+
message: "Hic dolorum esse magnam sint quibusdam.",
|
|
103
|
+
},
|
|
99
104
|
{
|
|
100
105
|
variant: "hint",
|
|
101
106
|
side: "right",
|
|
102
107
|
message: "Hic dolorum esse magnam sint quibusdam.",
|
|
103
108
|
},
|
|
104
109
|
{
|
|
105
|
-
variant: "
|
|
110
|
+
variant: "success",
|
|
111
|
+
side: "right",
|
|
112
|
+
message: "Hic dolorum esse magnam sint quibusdam.",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
variant: "warning",
|
|
116
|
+
side: "right",
|
|
117
|
+
message: "Ipsa nisi fugiat doloribus.",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
variant: "danger",
|
|
106
121
|
side: "right",
|
|
107
122
|
message: "Ipsa nisi fugiat doloribus.",
|
|
108
123
|
},
|
|
@@ -116,7 +131,7 @@ export const Conversation: Story = {
|
|
|
116
131
|
sizing="small"
|
|
117
132
|
alt="foundation-logo"
|
|
118
133
|
src="https://www.untitledui.com/images/avatars/olivia-rhye?fm=webp&q=80"
|
|
119
|
-
shape="smooth"
|
|
134
|
+
// shape="smooth"
|
|
120
135
|
>
|
|
121
136
|
<Avatar.Badge
|
|
122
137
|
alt="foundation-logo"
|
|
@@ -126,7 +141,12 @@ export const Conversation: Story = {
|
|
|
126
141
|
</Field.Meta>
|
|
127
142
|
)}
|
|
128
143
|
|
|
129
|
-
<MessageBubble.Content
|
|
144
|
+
<MessageBubble.Content
|
|
145
|
+
variant={variant}
|
|
146
|
+
className="fs-medium-20"
|
|
147
|
+
shape="round"
|
|
148
|
+
emphasis
|
|
149
|
+
>
|
|
130
150
|
{message}
|
|
131
151
|
</MessageBubble.Content>
|
|
132
152
|
<MessageBubble.Meta createdAt={MOCK_DATE} />
|
|
@@ -40,6 +40,7 @@ export interface IMessageBubbleContentProperties
|
|
|
40
40
|
IComponentSize,
|
|
41
41
|
React.HTMLAttributes<HTMLDivElement> {
|
|
42
42
|
variant?: TComponentVariant | TComponentVariantExtended;
|
|
43
|
+
emphasis?: boolean;
|
|
43
44
|
children: string;
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -99,11 +100,13 @@ MessageBubble.displayName = "MessageBubble";
|
|
|
99
100
|
*
|
|
100
101
|
* @param {IMessageBubbleContentProperties} props - The props for the MessageBubble.Content component.
|
|
101
102
|
* @param {boolean} props.raw - When true, removes default styling for custom layouts.
|
|
103
|
+
* @param {boolean} props.emphasis - Emphasis change the style definition used by the component.
|
|
102
104
|
* @param {ReactNode} props.children - The message text or rich content to render.
|
|
103
105
|
* @returns {ReactElement} The MessageBubble.Content component.
|
|
104
106
|
*/
|
|
105
107
|
const MessageBubbleContent = (props: IMessageBubbleContentProperties) => {
|
|
106
|
-
const { sizing, shape, variant, children, raw, ...restProps } =
|
|
108
|
+
const { emphasis, sizing, shape, variant, children, raw, ...restProps } =
|
|
109
|
+
props;
|
|
107
110
|
const { id, states } = useMessageBubble();
|
|
108
111
|
|
|
109
112
|
return (
|
|
@@ -111,8 +114,9 @@ const MessageBubbleContent = (props: IMessageBubbleContentProperties) => {
|
|
|
111
114
|
data-raw={Boolean(raw)}
|
|
112
115
|
data-side={states?.side}
|
|
113
116
|
variant={variant ?? ComponentVariantEnum.Border}
|
|
114
|
-
shape={shape ?? ComponentShapeEnum.
|
|
117
|
+
shape={shape ?? ComponentShapeEnum.Round}
|
|
115
118
|
sizing={sizing ?? ComponentSizeEnum.Medium}
|
|
119
|
+
emphasis={emphasis}
|
|
116
120
|
aria-label={`message-bubble-content-${id}`}
|
|
117
121
|
{...restProps}
|
|
118
122
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { Page, Resizable } from "..";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -9,31 +9,28 @@ const meta = {
|
|
|
9
9
|
title: "Components/Resizable",
|
|
10
10
|
component: Resizable,
|
|
11
11
|
tags: ["autodocs"],
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
export default meta;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
args: {
|
|
18
|
-
defaultWidth: 30,
|
|
19
|
-
left: (
|
|
20
|
-
<div
|
|
21
|
-
className="h-100 w-100 flex align-center justify-center"
|
|
22
|
-
style={{ borderRight: "1px solid var(--font-color-alpha-10)" }}
|
|
23
|
-
>
|
|
24
|
-
<p className="fs-medium-20">One</p>
|
|
25
|
-
</div>
|
|
26
|
-
),
|
|
27
|
-
right: (
|
|
28
|
-
<div className="h-100 w-100 flex align-center justify-center">
|
|
29
|
-
<p className="fs-medium-20">Two</p>
|
|
30
|
-
</div>
|
|
31
|
-
),
|
|
32
|
-
},
|
|
33
|
-
render: ({ ...args }) => (
|
|
15
|
+
export const Default = {
|
|
16
|
+
render: () => (
|
|
34
17
|
<Page>
|
|
35
18
|
<Page.Content>
|
|
36
|
-
<Resizable
|
|
19
|
+
<Resizable
|
|
20
|
+
defaultWidth={30}
|
|
21
|
+
minWidth={0}
|
|
22
|
+
maxWidth={50}
|
|
23
|
+
left={
|
|
24
|
+
<div className="h-100 w-100 flex align-center justify-center bg-mono-darkest">
|
|
25
|
+
One
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
right={
|
|
29
|
+
<div className="h-100 w-100 flex align-center justify-center">
|
|
30
|
+
Two
|
|
31
|
+
</div>
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
37
34
|
</Page.Content>
|
|
38
35
|
</Page>
|
|
39
36
|
),
|
package/src/resizable/index.tsx
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
|
|
14
14
|
type ResizableEditorProperties = {
|
|
15
15
|
defaultWidth?: number;
|
|
16
|
+
minWidth?: number;
|
|
17
|
+
maxWidth?: number;
|
|
16
18
|
left: React.ReactNode;
|
|
17
19
|
right: React.ReactNode;
|
|
18
20
|
};
|
|
@@ -22,12 +24,16 @@ type ResizableEditorProperties = {
|
|
|
22
24
|
*
|
|
23
25
|
* @param {ResizableEditorProperties} props - The props for the Resizable component.
|
|
24
26
|
* @param {number} props.defaultWidth - The default width of the Resizable left section.
|
|
27
|
+
* @param {number} props.minWidth - The minimum width of the Resizable sections, expressed as a percentage.
|
|
28
|
+
* @param {number} props.maxWidth - The maximum width of the Resizable sections, expressed as a percentage.
|
|
25
29
|
* @param {ReactNode} props.left - The content to be rendered inside the Left panel of the Resizable component.
|
|
26
30
|
* @param {ReactNode} props.right - The content to be rendered inside the Right panel of the Resizable component.
|
|
27
31
|
* @returns {ReactElement} The Resizable component.
|
|
28
32
|
*/
|
|
29
33
|
export const Resizable = ({
|
|
30
34
|
defaultWidth,
|
|
35
|
+
minWidth,
|
|
36
|
+
maxWidth,
|
|
31
37
|
left,
|
|
32
38
|
right,
|
|
33
39
|
}: ResizableEditorProperties) => {
|
|
@@ -47,16 +53,14 @@ export const Resizable = ({
|
|
|
47
53
|
const newLeftWidth =
|
|
48
54
|
((e.clientX - containerRect.left) / containerRect.width) * 100;
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
const threshold = { min: 30, max: 70 };
|
|
52
|
-
|
|
56
|
+
const threshold = { min: minWidth ?? 30, max: maxWidth ?? 70 };
|
|
53
57
|
const constrainedWidth = Math.min(
|
|
54
58
|
Math.max(newLeftWidth, threshold.min),
|
|
55
|
-
threshold.max
|
|
59
|
+
threshold.max,
|
|
56
60
|
);
|
|
57
61
|
setLeftWidth(constrainedWidth);
|
|
58
62
|
},
|
|
59
|
-
[isDragging]
|
|
63
|
+
[isDragging],
|
|
60
64
|
);
|
|
61
65
|
|
|
62
66
|
React.useEffect(() => {
|
|
@@ -5,9 +5,12 @@ import styled from "styled-components";
|
|
|
5
5
|
export const SplitContainer = styled.div`
|
|
6
6
|
position: relative;
|
|
7
7
|
`;
|
|
8
|
-
export const Panel = styled.div<{
|
|
8
|
+
export const Panel = styled.div<{
|
|
9
|
+
width: number;
|
|
10
|
+
}>`
|
|
9
11
|
overflow: hidden;
|
|
10
|
-
width: ${(props) => props.width}
|
|
12
|
+
width: ${(props) => props.width}dvw;
|
|
13
|
+
min-width: var(--measurement-large-60);
|
|
11
14
|
`;
|
|
12
15
|
export const Divider = styled.div<{ $dragging: boolean }>`
|
|
13
16
|
width: var(--measurement-medium-10);
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { test, vi, afterEach, describe, expect } from "vitest";
|
|
4
|
-
import {
|
|
5
|
-
screen,
|
|
6
|
-
render,
|
|
7
|
-
cleanup,
|
|
8
|
-
waitFor,
|
|
9
|
-
fireEvent,
|
|
10
|
-
} from "@testing-library/react";
|
|
11
|
-
import { axe, toHaveNoViolations } from "jest-axe";
|
|
12
|
-
|
|
13
|
-
import { Tree } from "../../src/tree";
|
|
14
|
-
|
|
15
|
-
afterEach(async () => {
|
|
16
|
-
vi.clearAllMocks();
|
|
17
|
-
vi.resetModules();
|
|
18
|
-
cleanup();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
expect.extend(toHaveNoViolations);
|
|
22
|
-
|
|
23
|
-
describe("Tree", () => {
|
|
24
|
-
test("Renders without accessibility violation", async () => {
|
|
25
|
-
const { container } = render(
|
|
26
|
-
<Tree.Root>
|
|
27
|
-
<Tree>
|
|
28
|
-
<Tree.Node nodeId="node-1">
|
|
29
|
-
<Tree.Trigger nodeId="node-1">Node 1</Tree.Trigger>
|
|
30
|
-
<Tree.Content nodeId="node-1" defaultOpen>
|
|
31
|
-
<Tree.Node level={1} nodeId="node-1-child">
|
|
32
|
-
<Tree.Trigger nodeId="node-1-child">Node 1 Child</Tree.Trigger>
|
|
33
|
-
</Tree.Node>
|
|
34
|
-
</Tree.Content>
|
|
35
|
-
</Tree.Node>
|
|
36
|
-
</Tree>
|
|
37
|
-
</Tree.Root>,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const ComponentContainer = await axe(container);
|
|
41
|
-
expect(ComponentContainer).toHaveNoViolations();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// test("Renders with accessibility definition", async () => {
|
|
45
|
-
// render(
|
|
46
|
-
// <Tree.Root>
|
|
47
|
-
// <Tree>
|
|
48
|
-
// <Tree.Node nodeId="node-1">
|
|
49
|
-
// <Tree.Trigger nodeId="node-1">Node 1</Tree.Trigger>
|
|
50
|
-
// <Tree.Content nodeId="node-1">
|
|
51
|
-
// <Tree.Node level={1} nodeId="node-1-child">
|
|
52
|
-
// <Tree.Trigger nodeId="node-1-child">Node 1 Child</Tree.Trigger>
|
|
53
|
-
// </Tree.Node>
|
|
54
|
-
// </Tree.Content>
|
|
55
|
-
// </Tree.Node>
|
|
56
|
-
// </Tree>
|
|
57
|
-
// </Tree.Root>,
|
|
58
|
-
// );
|
|
59
|
-
|
|
60
|
-
// const treeView = screen.getByRole("tree");
|
|
61
|
-
// expect(treeView).toBeDefined();
|
|
62
|
-
|
|
63
|
-
// const treeItems = screen.getAllByRole("treeitem");
|
|
64
|
-
// expect(treeItems.length).toBe(1);
|
|
65
|
-
|
|
66
|
-
// expect(() => screen.getByRole("group")).toThrow();
|
|
67
|
-
|
|
68
|
-
// const trigger = screen.getByLabelText("node-1-action");
|
|
69
|
-
// expect(trigger).toBeDefined();
|
|
70
|
-
// expect(trigger.getAttribute("aria-expanded")).toBe("false");
|
|
71
|
-
// expect(trigger.getAttribute("aria-selected")).toBe("false");
|
|
72
|
-
// expect(trigger.getAttribute("data-state")).toBe("collapsed");
|
|
73
|
-
|
|
74
|
-
// fireEvent.click(trigger);
|
|
75
|
-
// await waitFor(() => {
|
|
76
|
-
// const group = screen.getByRole("group");
|
|
77
|
-
// expect(group).toBeDefined();
|
|
78
|
-
// expect(group.getAttribute("aria-labelledby")).toBeDefined();
|
|
79
|
-
// expect(group.getAttribute("id")).toBeDefined();
|
|
80
|
-
// expect(group.getAttribute("data-nodeid")).toBe("node-1");
|
|
81
|
-
|
|
82
|
-
// expect(trigger.getAttribute("aria-expanded")).toBe("true");
|
|
83
|
-
// expect(trigger.getAttribute("aria-selected")).toBe("true");
|
|
84
|
-
// expect(trigger.getAttribute("data-state")).toBe("expanded");
|
|
85
|
-
|
|
86
|
-
// const childItems = screen.getAllByRole("treeitem");
|
|
87
|
-
// expect(childItems.length).toBe(2);
|
|
88
|
-
// });
|
|
89
|
-
// });
|
|
90
|
-
|
|
91
|
-
test("Renders with correct aria-level on nested nodes", async () => {
|
|
92
|
-
render(
|
|
93
|
-
<Tree.Root>
|
|
94
|
-
<Tree>
|
|
95
|
-
<Tree.Node nodeId="root">
|
|
96
|
-
<Tree.Trigger nodeId="root">Root</Tree.Trigger>
|
|
97
|
-
<Tree.Content nodeId="root" defaultOpen>
|
|
98
|
-
<Tree.Node level={1} nodeId="child">
|
|
99
|
-
<Tree.Trigger nodeId="child">Child</Tree.Trigger>
|
|
100
|
-
<Tree.Content nodeId="child" defaultOpen>
|
|
101
|
-
<Tree.Node level={2} nodeId="grandchild">
|
|
102
|
-
<Tree.Trigger nodeId="grandchild">Grandchild</Tree.Trigger>
|
|
103
|
-
</Tree.Node>
|
|
104
|
-
</Tree.Content>
|
|
105
|
-
</Tree.Node>
|
|
106
|
-
</Tree.Content>
|
|
107
|
-
</Tree.Node>
|
|
108
|
-
</Tree>
|
|
109
|
-
</Tree.Root>,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const treeItems = screen.getAllByRole("treeitem");
|
|
113
|
-
expect((treeItems[0] as HTMLElement).getAttribute("aria-level")).toBe("1");
|
|
114
|
-
expect((treeItems[1] as HTMLElement).getAttribute("aria-level")).toBe("2");
|
|
115
|
-
expect((treeItems[2] as HTMLElement).getAttribute("aria-level")).toBe("3");
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// test("Renders with defaultOpen and expands content on mount", async () => {
|
|
119
|
-
// render(
|
|
120
|
-
// <Tree.Root>
|
|
121
|
-
// <Tree>
|
|
122
|
-
// <Tree.Node nodeId="node-1">
|
|
123
|
-
// <Tree.Trigger nodeId="node-1">Node 1</Tree.Trigger>
|
|
124
|
-
// <Tree.Content nodeId="node-1" defaultOpen>
|
|
125
|
-
// <Tree.Node level={1} nodeId="node-1-child">
|
|
126
|
-
// <Tree.Trigger nodeId="node-1-child">Node 1 Child</Tree.Trigger>
|
|
127
|
-
// </Tree.Node>
|
|
128
|
-
// </Tree.Content>
|
|
129
|
-
// </Tree.Node>
|
|
130
|
-
// </Tree>
|
|
131
|
-
// </Tree.Root>,
|
|
132
|
-
// );
|
|
133
|
-
|
|
134
|
-
// await waitFor(() => {
|
|
135
|
-
// expect(screen.getByRole("group")).toBeDefined();
|
|
136
|
-
// expect(screen.getByText("Node 1 Child")).toBeDefined();
|
|
137
|
-
|
|
138
|
-
// const trigger = screen.getByLabelText("node-1-action");
|
|
139
|
-
// expect(trigger.getAttribute("aria-expanded")).toBe("true");
|
|
140
|
-
// expect(trigger.getAttribute("data-state")).toBe("expanded");
|
|
141
|
-
// });
|
|
142
|
-
// });
|
|
143
|
-
|
|
144
|
-
test("Fires the defined callback and toggles content when trigger is clicked", async () => {
|
|
145
|
-
const onClickCallback = vi.fn();
|
|
146
|
-
|
|
147
|
-
render(
|
|
148
|
-
<Tree.Root>
|
|
149
|
-
<Tree>
|
|
150
|
-
<Tree.Node nodeId="node-1">
|
|
151
|
-
<Tree.Trigger
|
|
152
|
-
nodeId="node-1"
|
|
153
|
-
name="trigger-1"
|
|
154
|
-
onClick={onClickCallback}
|
|
155
|
-
>
|
|
156
|
-
Node 1
|
|
157
|
-
</Tree.Trigger>
|
|
158
|
-
<Tree.Content nodeId="node-1" defaultOpen>
|
|
159
|
-
<Tree.Node level={1} nodeId="node-1-child">
|
|
160
|
-
<Tree.Trigger nodeId="node-1-child">Node 1 Child</Tree.Trigger>
|
|
161
|
-
</Tree.Node>
|
|
162
|
-
</Tree.Content>
|
|
163
|
-
</Tree.Node>
|
|
164
|
-
<Tree.Node nodeId="node-2">
|
|
165
|
-
<Tree.Trigger nodeId="node-2" name="trigger-2">
|
|
166
|
-
Node 2
|
|
167
|
-
</Tree.Trigger>
|
|
168
|
-
<Tree.Content nodeId="node-2">
|
|
169
|
-
<Tree.Node level={1} nodeId="node-2-child">
|
|
170
|
-
<Tree.Trigger nodeId="node-2-child">Node 2 Child</Tree.Trigger>
|
|
171
|
-
</Tree.Node>
|
|
172
|
-
</Tree.Content>
|
|
173
|
-
</Tree.Node>
|
|
174
|
-
</Tree>
|
|
175
|
-
</Tree.Root>,
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
expect(screen.getByText("Node 1 Child")).toBeDefined();
|
|
179
|
-
expect(() => screen.getByText("Node 2 Child")).toThrow();
|
|
180
|
-
|
|
181
|
-
fireEvent.click(screen.getByLabelText("trigger-2-action"));
|
|
182
|
-
await waitFor(() => {
|
|
183
|
-
expect(screen.getByText("Node 2 Child")).toBeDefined();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
fireEvent.click(screen.getByLabelText("trigger-1-action"));
|
|
187
|
-
await waitFor(() => {
|
|
188
|
-
expect(() => screen.getByText("Node 1 Child")).toThrow();
|
|
189
|
-
expect(onClickCallback).toHaveBeenCalledTimes(1);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
fireEvent.click(screen.getByLabelText("trigger-1-action"));
|
|
193
|
-
await waitFor(() => {
|
|
194
|
-
expect(screen.getByText("Node 1 Child")).toBeDefined();
|
|
195
|
-
expect(onClickCallback).toHaveBeenCalledTimes(2);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
fireEvent.click(screen.getByLabelText("trigger-1-action"));
|
|
199
|
-
await waitFor(() => {
|
|
200
|
-
expect(() => screen.getByText("Node 1 Child")).toThrow();
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("Fires onSelectionChange callback with selected node ids", async () => {
|
|
205
|
-
const onSelectionChange = vi.fn();
|
|
206
|
-
|
|
207
|
-
render(
|
|
208
|
-
<Tree.Root onSelectionChange={onSelectionChange}>
|
|
209
|
-
<Tree>
|
|
210
|
-
<Tree.Node nodeId="node-1">
|
|
211
|
-
<Tree.Trigger nodeId="node-1" name="trigger-1">
|
|
212
|
-
Node 1
|
|
213
|
-
</Tree.Trigger>
|
|
214
|
-
</Tree.Node>
|
|
215
|
-
<Tree.Node nodeId="node-2">
|
|
216
|
-
<Tree.Trigger nodeId="node-2" name="trigger-2">
|
|
217
|
-
Node 2
|
|
218
|
-
</Tree.Trigger>
|
|
219
|
-
</Tree.Node>
|
|
220
|
-
</Tree>
|
|
221
|
-
</Tree.Root>,
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
fireEvent.click(screen.getByLabelText("trigger-1-action"));
|
|
225
|
-
await waitFor(() => {
|
|
226
|
-
expect(onSelectionChange).toHaveBeenCalledTimes(1);
|
|
227
|
-
expect(onSelectionChange).toHaveBeenCalledWith(["node-1"]);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
fireEvent.click(screen.getByLabelText("trigger-2-action"));
|
|
231
|
-
await waitFor(() => {
|
|
232
|
-
expect(onSelectionChange).toHaveBeenCalledTimes(2);
|
|
233
|
-
expect(onSelectionChange).toHaveBeenCalledWith(["node-1", "node-2"]);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
fireEvent.click(screen.getByLabelText("trigger-1-action"));
|
|
237
|
-
await waitFor(() => {
|
|
238
|
-
expect(onSelectionChange).toHaveBeenCalledTimes(3);
|
|
239
|
-
expect(onSelectionChange).toHaveBeenCalledWith(["node-2"]);
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test("Renders with defaultExpandedIds and expands matching nodes on mount", async () => {
|
|
244
|
-
render(
|
|
245
|
-
<Tree.Root defaultExpandedIds={["node-1", "node-2"]}>
|
|
246
|
-
<Tree>
|
|
247
|
-
<Tree.Node nodeId="node-1">
|
|
248
|
-
<Tree.Trigger nodeId="node-1">Node 1</Tree.Trigger>
|
|
249
|
-
<Tree.Content nodeId="node-1">
|
|
250
|
-
<Tree.Node level={1} nodeId="node-1-child">
|
|
251
|
-
<Tree.Trigger nodeId="node-1-child">Node 1 Child</Tree.Trigger>
|
|
252
|
-
</Tree.Node>
|
|
253
|
-
</Tree.Content>
|
|
254
|
-
</Tree.Node>
|
|
255
|
-
<Tree.Node nodeId="node-2">
|
|
256
|
-
<Tree.Trigger nodeId="node-2">Node 2</Tree.Trigger>
|
|
257
|
-
<Tree.Content nodeId="node-2">
|
|
258
|
-
<Tree.Node level={1} nodeId="node-2-child">
|
|
259
|
-
<Tree.Trigger nodeId="node-2-child">Node 2 Child</Tree.Trigger>
|
|
260
|
-
</Tree.Node>
|
|
261
|
-
</Tree.Content>
|
|
262
|
-
</Tree.Node>
|
|
263
|
-
</Tree>
|
|
264
|
-
</Tree.Root>,
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
await waitFor(() => {
|
|
268
|
-
expect(screen.getByText("Node 1 Child")).toBeDefined();
|
|
269
|
-
expect(screen.getByText("Node 2 Child")).toBeDefined();
|
|
270
|
-
|
|
271
|
-
const groups = screen.getAllByRole("group");
|
|
272
|
-
expect(groups.length).toBe(2);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
});
|