@echothink-ui/motion 0.1.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.
- package/README.md +5 -0
- package/dist/components/AgentThinkingAnimation.d.ts +2 -0
- package/dist/components/AttentionPulse.d.ts +2 -0
- package/dist/components/DAGStatusTransition.d.ts +2 -0
- package/dist/components/DocumentLockPulse.d.ts +2 -0
- package/dist/components/PipelineFlowAnimation.d.ts +2 -0
- package/dist/components/ProgressTransition.d.ts +2 -0
- package/dist/components/SkeletonLoadingPattern.d.ts +2 -0
- package/dist/components/StatusChangeAnimation.d.ts +2 -0
- package/dist/components/StepCompletionAnimation.d.ts +2 -0
- package/dist/components/StreamingText.d.ts +2 -0
- package/dist/components/SyncProgressAnimation.d.ts +2 -0
- package/dist/components/motionUtils.d.ts +5 -0
- package/dist/components/types.d.ts +82 -0
- package/dist/index.cjs +2381 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2333 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/src/components/AgentThinkingAnimation.tsx +59 -0
- package/src/components/AttentionPulse.tsx +57 -0
- package/src/components/DAGStatusTransition.tsx +292 -0
- package/src/components/DocumentLockPulse.tsx +72 -0
- package/src/components/PipelineFlowAnimation.tsx +243 -0
- package/src/components/ProgressTransition.tsx +51 -0
- package/src/components/SkeletonLoadingPattern.tsx +248 -0
- package/src/components/StatusChangeAnimation.test.tsx +20 -0
- package/src/components/StatusChangeAnimation.tsx +89 -0
- package/src/components/StepCompletionAnimation.tsx +75 -0
- package/src/components/StreamingText.tsx +77 -0
- package/src/components/SyncProgressAnimation.test.tsx +49 -0
- package/src/components/SyncProgressAnimation.tsx +256 -0
- package/src/components/motionUtils.tsx +942 -0
- package/src/components/types.ts +111 -0
- package/src/index.test.tsx +97 -0
- package/src/index.tsx +44 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
import type { EthOperationalStatus, EthSeverity, SurfaceComponentProps } from "@echothink-ui/core";
|
|
3
|
+
|
|
4
|
+
export interface ProgressTransitionProps
|
|
5
|
+
extends Omit<React.HTMLAttributes<HTMLElement>, "children"> {
|
|
6
|
+
from?: number;
|
|
7
|
+
to: number;
|
|
8
|
+
durationMs?: number;
|
|
9
|
+
children?: (currentValue: number) => React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface MotionFlowNode {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
status: EthOperationalStatus;
|
|
16
|
+
x?: number;
|
|
17
|
+
y?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MotionFlowEdge {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
active?: boolean;
|
|
24
|
+
status?: EthOperationalStatus;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PipelineFlowAnimationProps extends React.HTMLAttributes<HTMLElement> {
|
|
28
|
+
nodes: MotionFlowNode[];
|
|
29
|
+
edges: MotionFlowEdge[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface DAGStatusTransitionProps extends React.HTMLAttributes<HTMLElement> {
|
|
33
|
+
nodes: MotionFlowNode[];
|
|
34
|
+
previousNodes?: MotionFlowNode[];
|
|
35
|
+
edges?: MotionFlowEdge[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface AgentThinkingAnimationProps extends React.HTMLAttributes<HTMLElement> {
|
|
39
|
+
label?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type SyncProgressAnimationStatus =
|
|
43
|
+
| "syncing"
|
|
44
|
+
| "synced"
|
|
45
|
+
| "paused"
|
|
46
|
+
| "stale"
|
|
47
|
+
| "failed"
|
|
48
|
+
| "error";
|
|
49
|
+
|
|
50
|
+
export interface SyncProgressAnimationProps extends React.HTMLAttributes<HTMLElement> {
|
|
51
|
+
completed?: number;
|
|
52
|
+
description?: React.ReactNode;
|
|
53
|
+
label?: React.ReactNode;
|
|
54
|
+
progress?: number;
|
|
55
|
+
rate?: React.ReactNode;
|
|
56
|
+
remaining?: React.ReactNode;
|
|
57
|
+
source?: React.ReactNode;
|
|
58
|
+
stage?: React.ReactNode;
|
|
59
|
+
status?: SyncProgressAnimationStatus;
|
|
60
|
+
target?: React.ReactNode;
|
|
61
|
+
total?: number;
|
|
62
|
+
variant?: "compact" | "detailed";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type SkeletonLoadingPatternVariant = "article" | "card" | "list" | "table";
|
|
66
|
+
|
|
67
|
+
export interface SkeletonLoadingPatternProps extends React.HTMLAttributes<HTMLElement> {
|
|
68
|
+
columns?: number;
|
|
69
|
+
label?: string;
|
|
70
|
+
lines?: number;
|
|
71
|
+
rows?: number;
|
|
72
|
+
variant?: SkeletonLoadingPatternVariant;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface AttentionPulseProps extends React.HTMLAttributes<HTMLElement> {
|
|
76
|
+
severity?: EthSeverity;
|
|
77
|
+
maxRepeats?: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface DocumentLockPulseProps extends React.HTMLAttributes<HTMLElement> {
|
|
81
|
+
lockedBy?: React.ReactNode;
|
|
82
|
+
active?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface StreamingTextProps
|
|
86
|
+
extends Omit<React.HTMLAttributes<HTMLElement>, "children" | "onDone"> {
|
|
87
|
+
text: string;
|
|
88
|
+
intervalMs?: number;
|
|
89
|
+
onDone?: () => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type StepCompletionState = "completed" | "current" | "pending";
|
|
93
|
+
|
|
94
|
+
export interface StepCompletionAnimationProps extends React.HTMLAttributes<HTMLElement> {
|
|
95
|
+
completed?: boolean;
|
|
96
|
+
description?: React.ReactNode;
|
|
97
|
+
label?: React.ReactNode;
|
|
98
|
+
state?: StepCompletionState;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface StatusChangeAnimationProps extends React.HTMLAttributes<HTMLElement> {
|
|
102
|
+
status: EthOperationalStatus;
|
|
103
|
+
previousStatus?: EthOperationalStatus;
|
|
104
|
+
label?: React.ReactNode;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type {
|
|
108
|
+
SurfaceComponentProps,
|
|
109
|
+
EthOperationalStatus,
|
|
110
|
+
EthSeverity
|
|
111
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { act, render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { SkeletonLoadingPattern, StepCompletionAnimation, StreamingText } from "./index";
|
|
4
|
+
|
|
5
|
+
describe("@echothink-ui/motion SkeletonLoadingPattern", () => {
|
|
6
|
+
it("renders a labelled article skeleton by default", () => {
|
|
7
|
+
render(<SkeletonLoadingPattern label="Loading request summary" lines={4} />);
|
|
8
|
+
|
|
9
|
+
const status = screen.getByRole("status", { name: "Loading request summary" });
|
|
10
|
+
|
|
11
|
+
expect(status.getAttribute("data-pattern")).toBe("article");
|
|
12
|
+
expect(status.querySelectorAll('[data-skeleton-segment="text-line"]')).toHaveLength(4);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("renders table and list patterns for repeated loading surfaces", () => {
|
|
16
|
+
const { rerender } = render(
|
|
17
|
+
<SkeletonLoadingPattern columns={4} label="Loading audit table" rows={3} variant="table" />
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const table = screen.getByRole("status", { name: "Loading audit table" });
|
|
21
|
+
expect(table.getAttribute("data-pattern")).toBe("table");
|
|
22
|
+
expect(table.querySelectorAll('[data-skeleton-row="table"]')).toHaveLength(3);
|
|
23
|
+
expect(table.querySelectorAll("[data-skeleton-cell]")).toHaveLength(12);
|
|
24
|
+
|
|
25
|
+
rerender(<SkeletonLoadingPattern label="Loading review queue" rows={3} variant="list" />);
|
|
26
|
+
|
|
27
|
+
const list = screen.getByRole("status", { name: "Loading review queue" });
|
|
28
|
+
expect(list.getAttribute("data-pattern")).toBe("list");
|
|
29
|
+
expect(list.querySelectorAll('[data-skeleton-row="list"]')).toHaveLength(3);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("@echothink-ui/motion StepCompletionAnimation", () => {
|
|
34
|
+
it("renders a completed step with semantic completion text and marker", () => {
|
|
35
|
+
render(<StepCompletionAnimation label="Plan approved" />);
|
|
36
|
+
|
|
37
|
+
const status = screen.getByRole("status");
|
|
38
|
+
|
|
39
|
+
expect(status.getAttribute("data-state")).toBe("completed");
|
|
40
|
+
expect(screen.getByText("Plan approved")).toBeTruthy();
|
|
41
|
+
expect(screen.getByText("Completed")).toBeTruthy();
|
|
42
|
+
expect(status.querySelector(".eth-motion-step-completion__check")).toBeTruthy();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("renders current and pending states without marking them complete", () => {
|
|
46
|
+
const { rerender } = render(
|
|
47
|
+
<StepCompletionAnimation
|
|
48
|
+
description="Waiting on compliance reviewer"
|
|
49
|
+
label="Review gate"
|
|
50
|
+
state="current"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(screen.getByRole("status").getAttribute("data-state")).toBe("current");
|
|
55
|
+
expect(screen.getByText("In progress")).toBeTruthy();
|
|
56
|
+
expect(screen.getByText("Waiting on compliance reviewer")).toBeTruthy();
|
|
57
|
+
|
|
58
|
+
rerender(<StepCompletionAnimation completed={false} label="Publish" />);
|
|
59
|
+
|
|
60
|
+
expect(screen.getByRole("status").getAttribute("data-state")).toBe("pending");
|
|
61
|
+
expect(screen.getByText("Pending")).toBeTruthy();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("@echothink-ui/motion StreamingText", () => {
|
|
66
|
+
it("marks active streaming text as busy until the reveal completes", () => {
|
|
67
|
+
vi.useFakeTimers();
|
|
68
|
+
try {
|
|
69
|
+
const onDone = vi.fn();
|
|
70
|
+
|
|
71
|
+
render(
|
|
72
|
+
<StreamingText
|
|
73
|
+
aria-label="Draft stream"
|
|
74
|
+
intervalMs={10}
|
|
75
|
+
onDone={onDone}
|
|
76
|
+
text="Draft ready"
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const status = screen.getByRole("status", { name: "Draft stream" });
|
|
81
|
+
expect(status.getAttribute("aria-busy")).toBe("true");
|
|
82
|
+
expect(status.getAttribute("data-streaming")).toBe("true");
|
|
83
|
+
expect(status.textContent).toBe("");
|
|
84
|
+
|
|
85
|
+
act(() => {
|
|
86
|
+
vi.advanceTimersByTime(110);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(status.textContent).toBe("Draft ready");
|
|
90
|
+
expect(status.getAttribute("aria-busy")).toBe("false");
|
|
91
|
+
expect(status.getAttribute("data-streaming")).toBe("false");
|
|
92
|
+
expect(onDone).toHaveBeenCalledTimes(1);
|
|
93
|
+
} finally {
|
|
94
|
+
vi.useRealTimers();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
AgentThinkingAnimationProps,
|
|
3
|
+
AttentionPulseProps,
|
|
4
|
+
DAGStatusTransitionProps,
|
|
5
|
+
DocumentLockPulseProps,
|
|
6
|
+
MotionFlowEdge,
|
|
7
|
+
MotionFlowNode,
|
|
8
|
+
PipelineFlowAnimationProps,
|
|
9
|
+
ProgressTransitionProps,
|
|
10
|
+
SkeletonLoadingPatternVariant,
|
|
11
|
+
SkeletonLoadingPatternProps,
|
|
12
|
+
StatusChangeAnimationProps,
|
|
13
|
+
StepCompletionAnimationProps,
|
|
14
|
+
StepCompletionState,
|
|
15
|
+
StreamingTextProps,
|
|
16
|
+
SyncProgressAnimationProps,
|
|
17
|
+
SyncProgressAnimationStatus
|
|
18
|
+
} from "./components/types";
|
|
19
|
+
export { AgentThinkingAnimation } from "./components/AgentThinkingAnimation";
|
|
20
|
+
export { AttentionPulse } from "./components/AttentionPulse";
|
|
21
|
+
export { DAGStatusTransition } from "./components/DAGStatusTransition";
|
|
22
|
+
export { DocumentLockPulse } from "./components/DocumentLockPulse";
|
|
23
|
+
export { PipelineFlowAnimation } from "./components/PipelineFlowAnimation";
|
|
24
|
+
export { ProgressTransition } from "./components/ProgressTransition";
|
|
25
|
+
export { SkeletonLoadingPattern } from "./components/SkeletonLoadingPattern";
|
|
26
|
+
export { StatusChangeAnimation } from "./components/StatusChangeAnimation";
|
|
27
|
+
export { StepCompletionAnimation } from "./components/StepCompletionAnimation";
|
|
28
|
+
export { StreamingText } from "./components/StreamingText";
|
|
29
|
+
export { SyncProgressAnimation } from "./components/SyncProgressAnimation";
|
|
30
|
+
|
|
31
|
+
export const MotionComponentNames = [
|
|
32
|
+
"ProgressTransition",
|
|
33
|
+
"PipelineFlowAnimation",
|
|
34
|
+
"DAGStatusTransition",
|
|
35
|
+
"AgentThinkingAnimation",
|
|
36
|
+
"SyncProgressAnimation",
|
|
37
|
+
"SkeletonLoadingPattern",
|
|
38
|
+
"AttentionPulse",
|
|
39
|
+
"DocumentLockPulse",
|
|
40
|
+
"StreamingText",
|
|
41
|
+
"StepCompletionAnimation",
|
|
42
|
+
"StatusChangeAnimation"
|
|
43
|
+
] as const;
|
|
44
|
+
export type MotionComponentName = (typeof MotionComponentNames)[number];
|