@elizaos/client 1.5.5-alpha.10
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/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/assets/empty-module-CLMscLYw.js +1 -0
- package/dist/assets/main-BBZ_3lkn.css +5999 -0
- package/dist/assets/main-C5zNUkXH.js +7 -0
- package/dist/assets/main-Dz64ENQg.js +614 -0
- package/dist/assets/react-vendor-DM5m98rr.js +545 -0
- package/dist/assets/ui-vendor-BQCqNqg0.js +1 -0
- package/dist/elizaos-avatar.png +0 -0
- package/dist/elizaos-icon.png +0 -0
- package/dist/elizaos-logo-light.png +0 -0
- package/dist/elizaos.webp +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/images/agents/agent1.png +0 -0
- package/dist/images/agents/agent2.png +0 -0
- package/dist/images/agents/agent3.png +0 -0
- package/dist/images/agents/agent4.png +0 -0
- package/dist/images/agents/agent5.png +0 -0
- package/dist/index.html +14 -0
- package/index.html +24 -0
- package/package.json +159 -0
- package/postcss.config.js +3 -0
- package/public/elizaos-avatar.png +0 -0
- package/public/elizaos-icon.png +0 -0
- package/public/elizaos-logo-light.png +0 -0
- package/public/elizaos.webp +0 -0
- package/public/favicon.ico +0 -0
- package/public/images/agents/agent1.png +0 -0
- package/public/images/agents/agent2.png +0 -0
- package/public/images/agents/agent3.png +0 -0
- package/public/images/agents/agent4.png +0 -0
- package/public/images/agents/agent5.png +0 -0
- package/src/App.tsx +222 -0
- package/src/components/AgentDetailsPanel.tsx +147 -0
- package/src/components/ChatInputArea.tsx +196 -0
- package/src/components/ChatMessageListComponent.tsx +139 -0
- package/src/components/actionTool.tsx +186 -0
- package/src/components/add-agent-card.tsx +77 -0
- package/src/components/agent-action-viewer.tsx +816 -0
- package/src/components/agent-avatar-stack.tsx +121 -0
- package/src/components/agent-card.cy.tsx +259 -0
- package/src/components/agent-card.tsx +177 -0
- package/src/components/agent-creator.tsx +142 -0
- package/src/components/agent-log-viewer.tsx +645 -0
- package/src/components/agent-memory-edit-overlay.tsx +461 -0
- package/src/components/agent-memory-viewer.tsx +504 -0
- package/src/components/agent-settings.tsx +270 -0
- package/src/components/agent-sidebar.tsx +178 -0
- package/src/components/api-key-dialog.tsx +113 -0
- package/src/components/app-sidebar.tsx +685 -0
- package/src/components/array-input.tsx +116 -0
- package/src/components/audio-recorder.tsx +292 -0
- package/src/components/avatar-panel.tsx +141 -0
- package/src/components/character-form.tsx +1138 -0
- package/src/components/chat.tsx +1813 -0
- package/src/components/combobox.tsx +187 -0
- package/src/components/confirmation-dialog.tsx +59 -0
- package/src/components/connection-error-banner.tsx +101 -0
- package/src/components/connection-status.cy.tsx +73 -0
- package/src/components/connection-status.tsx +155 -0
- package/src/components/copy-button.tsx +35 -0
- package/src/components/delete-button.tsx +24 -0
- package/src/components/env-settings.tsx +261 -0
- package/src/components/group-card.tsx +160 -0
- package/src/components/group-panel.tsx +543 -0
- package/src/components/input-copy.tsx +21 -0
- package/src/components/logs-page.tsx +41 -0
- package/src/components/media-content.tsx +385 -0
- package/src/components/memory-graph.tsx +170 -0
- package/src/components/missing-secrets-dialog.tsx +72 -0
- package/src/components/onboarding-tour.tsx +247 -0
- package/src/components/page-title.tsx +8 -0
- package/src/components/plugins-panel.tsx +383 -0
- package/src/components/profile-card.tsx +66 -0
- package/src/components/profile-overlay.tsx +283 -0
- package/src/components/retry-button.tsx +28 -0
- package/src/components/secret-panel.tsx +1505 -0
- package/src/components/server-management.tsx +264 -0
- package/src/components/split-button.tsx +148 -0
- package/src/components/stop-agent-button.tsx +99 -0
- package/src/components/ui/alert-dialog.cy.tsx +333 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +49 -0
- package/src/components/ui/avatar.cy.tsx +180 -0
- package/src/components/ui/avatar.tsx +57 -0
- package/src/components/ui/badge.cy.tsx +146 -0
- package/src/components/ui/badge.tsx +43 -0
- package/src/components/ui/button.cy.tsx +177 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.cy.tsx +160 -0
- package/src/components/ui/card.tsx +73 -0
- package/src/components/ui/chat/animated-markdown.tsx +59 -0
- package/src/components/ui/chat/chat-bubble.tsx +178 -0
- package/src/components/ui/chat/chat-container.tsx +51 -0
- package/src/components/ui/chat/chat-input.cy.tsx +169 -0
- package/src/components/ui/chat/chat-input.tsx +47 -0
- package/src/components/ui/chat/chat-message-list.tsx +61 -0
- package/src/components/ui/chat/chat-tts-button.tsx +199 -0
- package/src/components/ui/chat/code-block.tsx +79 -0
- package/src/components/ui/chat/expandable-chat.tsx +131 -0
- package/src/components/ui/chat/hooks/useAutoScroll.ts +86 -0
- package/src/components/ui/chat/markdown.tsx +209 -0
- package/src/components/ui/chat/message-loading.tsx +48 -0
- package/src/components/ui/checkbox.cy.tsx +170 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.cy.tsx +283 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.cy.tsx +313 -0
- package/src/components/ui/command.tsx +143 -0
- package/src/components/ui/dialog.cy.tsx +279 -0
- package/src/components/ui/dialog.tsx +104 -0
- package/src/components/ui/dropdown-menu.cy.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +281 -0
- package/src/components/ui/input.cy.tsx +82 -0
- package/src/components/ui/input.tsx +27 -0
- package/src/components/ui/label.cy.tsx +157 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/resizable.tsx +42 -0
- package/src/components/ui/scroll-area.cy.tsx +242 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.cy.tsx +277 -0
- package/src/components/ui/select.tsx +155 -0
- package/src/components/ui/separator.cy.tsx +145 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.cy.tsx +324 -0
- package/src/components/ui/sheet.tsx +119 -0
- package/src/components/ui/sidebar.tsx +734 -0
- package/src/components/ui/skeleton.cy.tsx +149 -0
- package/src/components/ui/skeleton.tsx +17 -0
- package/src/components/ui/split-button.cy.tsx +274 -0
- package/src/components/ui/split-button.tsx +112 -0
- package/src/components/ui/switch.tsx +28 -0
- package/src/components/ui/tabs.cy.tsx +271 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.cy.tsx +136 -0
- package/src/components/ui/textarea.tsx +26 -0
- package/src/components/ui/toast.cy.tsx +209 -0
- package/src/components/ui/toast.tsx +126 -0
- package/src/components/ui/toaster.tsx +29 -0
- package/src/components/ui/tooltip.cy.tsx +244 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/config/agent-templates.ts +349 -0
- package/src/config/voice-models.ts +181 -0
- package/src/constants.ts +23 -0
- package/src/context/AuthContext.tsx +44 -0
- package/src/context/ConnectionContext.tsx +194 -0
- package/src/entry.tsx +9 -0
- package/src/hooks/__tests__/use-agent-tab-state.test.ts +137 -0
- package/src/hooks/__tests__/use-agent-update.test.tsx +250 -0
- package/src/hooks/__tests__/use-character-convert.test.ts +102 -0
- package/src/hooks/__tests__/use-panel-width-state.test.ts +243 -0
- package/src/hooks/__tests__/use-sidebar-state.test.ts +117 -0
- package/src/hooks/use-agent-management.ts +130 -0
- package/src/hooks/use-agent-tab-state.ts +74 -0
- package/src/hooks/use-agent-update.ts +469 -0
- package/src/hooks/use-character-convert.ts +138 -0
- package/src/hooks/use-confirmation.ts +55 -0
- package/src/hooks/use-delete-agent.ts +123 -0
- package/src/hooks/use-dm-channels.ts +198 -0
- package/src/hooks/use-elevenlabs-voices.ts +83 -0
- package/src/hooks/use-file-upload.ts +224 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-onboarding.tsx +49 -0
- package/src/hooks/use-panel-width-state.ts +147 -0
- package/src/hooks/use-partial-update.ts +288 -0
- package/src/hooks/use-plugin-details.ts +462 -0
- package/src/hooks/use-plugins.ts +119 -0
- package/src/hooks/use-query-hooks.ts +1263 -0
- package/src/hooks/use-server-agents.ts +62 -0
- package/src/hooks/use-server-version.tsx +47 -0
- package/src/hooks/use-sidebar-state.ts +50 -0
- package/src/hooks/use-socket-chat.ts +264 -0
- package/src/hooks/use-toast.ts +260 -0
- package/src/hooks/use-version.tsx +64 -0
- package/src/index.css +146 -0
- package/src/lib/api-client-config.ts +53 -0
- package/src/lib/api-type-mappers.ts +196 -0
- package/src/lib/export-utils.ts +123 -0
- package/src/lib/logger.ts +19 -0
- package/src/lib/media-utils.ts +170 -0
- package/src/lib/pca.test.ts +17 -0
- package/src/lib/pca.ts +52 -0
- package/src/lib/socketio-manager.ts +664 -0
- package/src/lib/utils.ts +168 -0
- package/src/main.tsx +16 -0
- package/src/mocks/empty-module.ts +12 -0
- package/src/mocks/node-module.ts +57 -0
- package/src/polyfills.ts +37 -0
- package/src/routes/agent-detail.tsx +30 -0
- package/src/routes/agent-list.tsx +27 -0
- package/src/routes/agent-settings.tsx +48 -0
- package/src/routes/character-detail.tsx +52 -0
- package/src/routes/character-form.tsx +79 -0
- package/src/routes/character-list.tsx +38 -0
- package/src/routes/chat.tsx +128 -0
- package/src/routes/createAgent.tsx +13 -0
- package/src/routes/group-new.tsx +50 -0
- package/src/routes/group.tsx +29 -0
- package/src/routes/home.tsx +218 -0
- package/src/routes/not-found.tsx +71 -0
- package/src/test/setup.ts +154 -0
- package/src/types/crypto-browserify.d.ts +4 -0
- package/src/types/index.ts +13 -0
- package/src/types/rooms.ts +8 -0
- package/src/types.ts +84 -0
- package/src/vite-env.d.ts +40 -0
- package/tailwind.config.ts +90 -0
- package/tsconfig.json +10 -0
- package/vite.config.ts +102 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
4
|
+
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
const Select = SelectPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
const SelectGroup = SelectPrimitive.Group;
|
|
12
|
+
|
|
13
|
+
const SelectValue = SelectPrimitive.Value;
|
|
14
|
+
|
|
15
|
+
const SelectTrigger = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
|
18
|
+
>(({ className, children, ...props }, ref) => (
|
|
19
|
+
<SelectPrimitive.Trigger
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={cn(
|
|
22
|
+
'flex h-12 w-full items-center justify-between whitespace-nowrap rounded border border-input bg-card px-4 py-3 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
<SelectPrimitive.Icon asChild>
|
|
29
|
+
<ChevronDown className="h-4 w-4 opacity-50" />
|
|
30
|
+
</SelectPrimitive.Icon>
|
|
31
|
+
</SelectPrimitive.Trigger>
|
|
32
|
+
));
|
|
33
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
34
|
+
|
|
35
|
+
const SelectScrollUpButton = React.forwardRef<
|
|
36
|
+
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
|
37
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
|
38
|
+
>(({ className, ...props }, ref) => (
|
|
39
|
+
<SelectPrimitive.ScrollUpButton
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
<ChevronUp className="h-4 w-4" />
|
|
45
|
+
</SelectPrimitive.ScrollUpButton>
|
|
46
|
+
));
|
|
47
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
48
|
+
|
|
49
|
+
const SelectScrollDownButton = React.forwardRef<
|
|
50
|
+
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
|
51
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
|
52
|
+
>(({ className, ...props }, ref) => (
|
|
53
|
+
<SelectPrimitive.ScrollDownButton
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
56
|
+
{...props}
|
|
57
|
+
>
|
|
58
|
+
<ChevronDown className="h-4 w-4" />
|
|
59
|
+
</SelectPrimitive.ScrollDownButton>
|
|
60
|
+
));
|
|
61
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
62
|
+
|
|
63
|
+
const SelectContent = React.forwardRef<
|
|
64
|
+
React.ElementRef<typeof SelectPrimitive.Content>,
|
|
65
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
|
66
|
+
>(({ className, children, position = 'popper', ...props }, ref) => (
|
|
67
|
+
<SelectPrimitive.Portal>
|
|
68
|
+
<SelectPrimitive.Content
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn(
|
|
71
|
+
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-xl border border-input bg-card text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
72
|
+
position === 'popper' &&
|
|
73
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
74
|
+
className
|
|
75
|
+
)}
|
|
76
|
+
position={position}
|
|
77
|
+
{...props}
|
|
78
|
+
>
|
|
79
|
+
<SelectScrollUpButton />
|
|
80
|
+
<SelectPrimitive.Viewport
|
|
81
|
+
className={cn(
|
|
82
|
+
'p-2',
|
|
83
|
+
position === 'popper' &&
|
|
84
|
+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
|
|
85
|
+
)}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</SelectPrimitive.Viewport>
|
|
89
|
+
<SelectScrollDownButton />
|
|
90
|
+
</SelectPrimitive.Content>
|
|
91
|
+
</SelectPrimitive.Portal>
|
|
92
|
+
));
|
|
93
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
94
|
+
|
|
95
|
+
const SelectLabel = React.forwardRef<
|
|
96
|
+
React.ElementRef<typeof SelectPrimitive.Label>,
|
|
97
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
|
98
|
+
>(({ className, ...props }, ref) => (
|
|
99
|
+
<SelectPrimitive.Label
|
|
100
|
+
ref={ref}
|
|
101
|
+
className={cn(
|
|
102
|
+
'px-4 py-2 text-xs font-medium text-muted-foreground uppercase tracking-wider',
|
|
103
|
+
className
|
|
104
|
+
)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
));
|
|
108
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
109
|
+
|
|
110
|
+
const SelectItem = React.forwardRef<
|
|
111
|
+
React.ElementRef<typeof SelectPrimitive.Item>,
|
|
112
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
|
113
|
+
>(({ className, children, ...props }, ref) => (
|
|
114
|
+
<SelectPrimitive.Item
|
|
115
|
+
ref={ref}
|
|
116
|
+
className={cn(
|
|
117
|
+
'relative flex w-full cursor-default select-none items-center rounded py-3 pl-4 pr-8 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
118
|
+
className
|
|
119
|
+
)}
|
|
120
|
+
{...props}
|
|
121
|
+
>
|
|
122
|
+
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
123
|
+
<SelectPrimitive.ItemIndicator>
|
|
124
|
+
<Check className="h-4 w-4" />
|
|
125
|
+
</SelectPrimitive.ItemIndicator>
|
|
126
|
+
</span>
|
|
127
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
128
|
+
</SelectPrimitive.Item>
|
|
129
|
+
));
|
|
130
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
131
|
+
|
|
132
|
+
const SelectSeparator = React.forwardRef<
|
|
133
|
+
React.ElementRef<typeof SelectPrimitive.Separator>,
|
|
134
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
|
135
|
+
>(({ className, ...props }, ref) => (
|
|
136
|
+
<SelectPrimitive.Separator
|
|
137
|
+
ref={ref}
|
|
138
|
+
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
|
139
|
+
{...props}
|
|
140
|
+
/>
|
|
141
|
+
));
|
|
142
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
143
|
+
|
|
144
|
+
export {
|
|
145
|
+
Select,
|
|
146
|
+
SelectGroup,
|
|
147
|
+
SelectValue,
|
|
148
|
+
SelectTrigger,
|
|
149
|
+
SelectContent,
|
|
150
|
+
SelectLabel,
|
|
151
|
+
SelectItem,
|
|
152
|
+
SelectSeparator,
|
|
153
|
+
SelectScrollUpButton,
|
|
154
|
+
SelectScrollDownButton,
|
|
155
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
/// <reference path="../../../cypress/support/types.d.ts" />
|
|
3
|
+
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { Separator } from './separator';
|
|
6
|
+
|
|
7
|
+
describe('Separator Component', () => {
|
|
8
|
+
it('renders correctly with default props', () => {
|
|
9
|
+
cy.mount(<Separator />);
|
|
10
|
+
|
|
11
|
+
cy.get('[data-testid="separator"]').should('exist');
|
|
12
|
+
cy.get('[data-testid="separator"]').should('have.attr', 'role', 'none'); // decorative is true by default
|
|
13
|
+
cy.get('[data-testid="separator"]').should('have.class', 'shrink-0');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('Orientation', () => {
|
|
17
|
+
it('renders horizontal separator correctly', () => {
|
|
18
|
+
cy.mount(<Separator orientation="horizontal" />);
|
|
19
|
+
|
|
20
|
+
cy.get('[data-testid="separator"]')
|
|
21
|
+
.should('have.attr', 'data-orientation', 'horizontal')
|
|
22
|
+
.should('have.class', 'h-[1px]')
|
|
23
|
+
.should('have.class', 'w-full');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('renders vertical separator correctly', () => {
|
|
27
|
+
cy.mount(
|
|
28
|
+
<div className="flex h-20">
|
|
29
|
+
<div>Left</div>
|
|
30
|
+
<Separator orientation="vertical" />
|
|
31
|
+
<div>Right</div>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
cy.get('[data-testid="separator"]')
|
|
36
|
+
.should('have.attr', 'data-orientation', 'vertical')
|
|
37
|
+
.should('have.class', 'h-full')
|
|
38
|
+
.should('have.class', 'w-[1px]');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('applies custom className', () => {
|
|
43
|
+
cy.mount(<Separator className="my-custom-separator bg-red-500" />);
|
|
44
|
+
|
|
45
|
+
cy.get('[data-testid="separator"]')
|
|
46
|
+
.should('have.class', 'my-custom-separator')
|
|
47
|
+
.should('have.class', 'bg-red-500');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('decorative prop sets correct aria attributes', () => {
|
|
51
|
+
cy.mount(<Separator decorative />);
|
|
52
|
+
|
|
53
|
+
cy.get('[data-testid="separator"]').should('have.attr', 'role', 'none');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renders in a card layout', () => {
|
|
57
|
+
cy.mount(
|
|
58
|
+
<div className="max-w-sm rounded-lg border p-4">
|
|
59
|
+
<h3 className="font-semibold">Card Title</h3>
|
|
60
|
+
<Separator className="my-2" />
|
|
61
|
+
<p className="text-sm text-gray-600">Card content goes here.</p>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
cy.get('[data-testid="separator"]').should('be.visible');
|
|
66
|
+
cy.get('.my-2').should('exist');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('renders multiple separators in a list', () => {
|
|
70
|
+
cy.mount(
|
|
71
|
+
<ul className="space-y-2">
|
|
72
|
+
<li>Item 1</li>
|
|
73
|
+
<Separator />
|
|
74
|
+
<li>Item 2</li>
|
|
75
|
+
<Separator />
|
|
76
|
+
<li>Item 3</li>
|
|
77
|
+
</ul>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
cy.get('[data-testid="separator"]').should('have.length', 2);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('works with different spacing', () => {
|
|
84
|
+
cy.mount(
|
|
85
|
+
<div>
|
|
86
|
+
<div>Content 1</div>
|
|
87
|
+
<Separator className="my-1" />
|
|
88
|
+
<div>Content 2</div>
|
|
89
|
+
<Separator className="my-4" />
|
|
90
|
+
<div>Content 3</div>
|
|
91
|
+
<Separator className="my-8" />
|
|
92
|
+
<div>Content 4</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
cy.get('[data-testid="separator"]').should('have.length', 3);
|
|
97
|
+
cy.get('.my-1').should('exist');
|
|
98
|
+
cy.get('.my-4').should('exist');
|
|
99
|
+
cy.get('.my-8').should('exist');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('renders in a form layout', () => {
|
|
103
|
+
cy.mount(
|
|
104
|
+
<form className="space-y-4">
|
|
105
|
+
<div>
|
|
106
|
+
<label>Name</label>
|
|
107
|
+
<input type="text" className="w-full border rounded px-2 py-1" />
|
|
108
|
+
</div>
|
|
109
|
+
<Separator />
|
|
110
|
+
<div>
|
|
111
|
+
<label>Email</label>
|
|
112
|
+
<input type="email" className="w-full border rounded px-2 py-1" />
|
|
113
|
+
</div>
|
|
114
|
+
</form>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
cy.get('[data-testid="separator"]').should('exist');
|
|
118
|
+
cy.get('form').find('[data-testid="separator"]').should('have.length', 1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('supports custom styles', () => {
|
|
122
|
+
cy.mount(
|
|
123
|
+
<Separator
|
|
124
|
+
className="bg-gradient-to-r from-transparent via-gray-500 to-transparent"
|
|
125
|
+
style={{ height: '2px' }}
|
|
126
|
+
/>
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
cy.get('[data-testid="separator"]')
|
|
130
|
+
.should('have.class', 'bg-gradient-to-r')
|
|
131
|
+
.should('have.css', 'height', '2px');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('works in dark mode', () => {
|
|
135
|
+
cy.mount(
|
|
136
|
+
<div className="dark bg-gray-900 p-4">
|
|
137
|
+
<div className="text-white">Dark mode content</div>
|
|
138
|
+
<Separator className="my-4 bg-gray-700" />
|
|
139
|
+
<div className="text-white">More content</div>
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
cy.get('[data-testid="separator"]').should('have.class', 'bg-gray-700');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
|
|
6
|
+
interface SeparatorProps extends React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> {
|
|
7
|
+
'data-testid'?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Separator = React.forwardRef<
|
|
11
|
+
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
|
12
|
+
SeparatorProps
|
|
13
|
+
>(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
|
|
14
|
+
<SeparatorPrimitive.Root
|
|
15
|
+
ref={ref}
|
|
16
|
+
decorative={decorative}
|
|
17
|
+
orientation={orientation}
|
|
18
|
+
className={cn(
|
|
19
|
+
'shrink-0 bg-border',
|
|
20
|
+
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
data-testid={props['data-testid'] || 'separator'}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
));
|
|
27
|
+
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
|
28
|
+
|
|
29
|
+
export { Separator };
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
/// <reference path="../../../cypress/support/types.d.ts" />
|
|
3
|
+
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import {
|
|
6
|
+
Sheet,
|
|
7
|
+
SheetClose,
|
|
8
|
+
SheetContent,
|
|
9
|
+
SheetDescription,
|
|
10
|
+
SheetFooter,
|
|
11
|
+
SheetHeader,
|
|
12
|
+
SheetTitle,
|
|
13
|
+
SheetTrigger,
|
|
14
|
+
} from './sheet';
|
|
15
|
+
import { Button } from './button';
|
|
16
|
+
|
|
17
|
+
describe('Sheet Component', () => {
|
|
18
|
+
it('renders basic sheet from right', () => {
|
|
19
|
+
cy.mount(
|
|
20
|
+
<Sheet>
|
|
21
|
+
<SheetTrigger asChild>
|
|
22
|
+
<Button>Open Sheet</Button>
|
|
23
|
+
</SheetTrigger>
|
|
24
|
+
<SheetContent>
|
|
25
|
+
<SheetHeader>
|
|
26
|
+
<SheetTitle>Sheet Title</SheetTitle>
|
|
27
|
+
<SheetDescription>This is a sheet description.</SheetDescription>
|
|
28
|
+
</SheetHeader>
|
|
29
|
+
</SheetContent>
|
|
30
|
+
</Sheet>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
cy.contains('button', 'Open Sheet').should('be.visible');
|
|
34
|
+
cy.contains('Sheet Title').should('not.exist');
|
|
35
|
+
|
|
36
|
+
// Open sheet
|
|
37
|
+
cy.contains('button', 'Open Sheet').click();
|
|
38
|
+
cy.contains('Sheet Title').should('be.visible');
|
|
39
|
+
cy.contains('This is a sheet description.').should('be.visible');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('renders sheet from different sides', () => {
|
|
43
|
+
cy.mount(
|
|
44
|
+
<div className="flex gap-4">
|
|
45
|
+
<Sheet>
|
|
46
|
+
<SheetTrigger>From Top</SheetTrigger>
|
|
47
|
+
<SheetContent side="top">
|
|
48
|
+
<SheetTitle>Top Sheet</SheetTitle>
|
|
49
|
+
</SheetContent>
|
|
50
|
+
</Sheet>
|
|
51
|
+
|
|
52
|
+
<Sheet>
|
|
53
|
+
<SheetTrigger>From Bottom</SheetTrigger>
|
|
54
|
+
<SheetContent side="bottom">
|
|
55
|
+
<SheetTitle>Bottom Sheet</SheetTitle>
|
|
56
|
+
</SheetContent>
|
|
57
|
+
</Sheet>
|
|
58
|
+
|
|
59
|
+
<Sheet>
|
|
60
|
+
<SheetTrigger>From Left</SheetTrigger>
|
|
61
|
+
<SheetContent side="left">
|
|
62
|
+
<SheetTitle>Left Sheet</SheetTitle>
|
|
63
|
+
</SheetContent>
|
|
64
|
+
</Sheet>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Test top sheet
|
|
69
|
+
cy.contains('From Top').click();
|
|
70
|
+
cy.contains('Top Sheet').should('be.visible');
|
|
71
|
+
cy.get('body').type('{esc}');
|
|
72
|
+
|
|
73
|
+
// Test bottom sheet
|
|
74
|
+
cy.contains('From Bottom').click();
|
|
75
|
+
cy.contains('Bottom Sheet').should('be.visible');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('closes sheet when clicking overlay', () => {
|
|
79
|
+
cy.mount(
|
|
80
|
+
<Sheet>
|
|
81
|
+
<SheetTrigger>Open</SheetTrigger>
|
|
82
|
+
<SheetContent>
|
|
83
|
+
<SheetTitle>Click Outside Test</SheetTitle>
|
|
84
|
+
</SheetContent>
|
|
85
|
+
</Sheet>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
cy.contains('Open').click();
|
|
89
|
+
cy.contains('Click Outside Test').should('be.visible');
|
|
90
|
+
|
|
91
|
+
// Use escape key instead of clicking overlay
|
|
92
|
+
cy.get('body').type('{esc}');
|
|
93
|
+
cy.contains('Click Outside Test').should('not.exist');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('renders with footer actions', () => {
|
|
97
|
+
const onSave = cy.stub();
|
|
98
|
+
const onCancel = cy.stub();
|
|
99
|
+
|
|
100
|
+
cy.mount(
|
|
101
|
+
<Sheet>
|
|
102
|
+
<SheetTrigger>Edit Profile</SheetTrigger>
|
|
103
|
+
<SheetContent>
|
|
104
|
+
<SheetHeader>
|
|
105
|
+
<SheetTitle>Edit Profile</SheetTitle>
|
|
106
|
+
<SheetDescription>Make changes to your profile here.</SheetDescription>
|
|
107
|
+
</SheetHeader>
|
|
108
|
+
<div className="py-4">
|
|
109
|
+
<input placeholder="Name" className="w-full p-2 border rounded" />
|
|
110
|
+
</div>
|
|
111
|
+
<SheetFooter>
|
|
112
|
+
<SheetClose asChild>
|
|
113
|
+
<Button variant="outline" onClick={onCancel}>
|
|
114
|
+
Cancel
|
|
115
|
+
</Button>
|
|
116
|
+
</SheetClose>
|
|
117
|
+
<Button onClick={onSave}>Save changes</Button>
|
|
118
|
+
</SheetFooter>
|
|
119
|
+
</SheetContent>
|
|
120
|
+
</Sheet>
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
cy.contains('Edit Profile').click();
|
|
124
|
+
cy.get('input[placeholder="Name"]').should('be.visible');
|
|
125
|
+
|
|
126
|
+
cy.contains('button', 'Save changes').click();
|
|
127
|
+
cy.wrap(onSave).should('have.been.called');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('works as controlled component', () => {
|
|
131
|
+
const TestComponent = () => {
|
|
132
|
+
const [open, setOpen] = React.useState(false);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<>
|
|
136
|
+
<button onClick={() => setOpen(true)}>External Open</button>
|
|
137
|
+
<Sheet open={open} onOpenChange={setOpen}>
|
|
138
|
+
<SheetContent>
|
|
139
|
+
<SheetTitle>Controlled Sheet</SheetTitle>
|
|
140
|
+
<button onClick={() => setOpen(false)}>Close Sheet</button>
|
|
141
|
+
</SheetContent>
|
|
142
|
+
</Sheet>
|
|
143
|
+
</>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
cy.mount(<TestComponent />);
|
|
148
|
+
|
|
149
|
+
cy.contains('Controlled Sheet').should('not.exist');
|
|
150
|
+
cy.contains('External Open').click();
|
|
151
|
+
cy.contains('Controlled Sheet').should('be.visible');
|
|
152
|
+
|
|
153
|
+
cy.contains('button', 'Close Sheet').click();
|
|
154
|
+
cy.contains('Controlled Sheet').should('not.exist');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('handles keyboard navigation', () => {
|
|
158
|
+
cy.mount(
|
|
159
|
+
<Sheet>
|
|
160
|
+
<SheetTrigger>Open</SheetTrigger>
|
|
161
|
+
<SheetContent>
|
|
162
|
+
<SheetTitle>Keyboard Test</SheetTitle>
|
|
163
|
+
<button>First Button</button>
|
|
164
|
+
<button>Second Button</button>
|
|
165
|
+
</SheetContent>
|
|
166
|
+
</Sheet>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
cy.contains('Open').click();
|
|
170
|
+
cy.contains('Keyboard Test').should('be.visible');
|
|
171
|
+
|
|
172
|
+
// ESC key should close
|
|
173
|
+
cy.get('body').type('{esc}');
|
|
174
|
+
cy.contains('Keyboard Test').should('not.exist');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('supports custom className', () => {
|
|
178
|
+
cy.mount(
|
|
179
|
+
<Sheet>
|
|
180
|
+
<SheetTrigger className="custom-trigger">Open</SheetTrigger>
|
|
181
|
+
<SheetContent className="bg-blue-50 custom-content">
|
|
182
|
+
<SheetTitle>Custom Styled Sheet</SheetTitle>
|
|
183
|
+
</SheetContent>
|
|
184
|
+
</Sheet>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
cy.get('.custom-trigger').should('exist');
|
|
188
|
+
cy.contains('Open').click();
|
|
189
|
+
cy.get('.custom-content').should('have.class', 'bg-blue-50');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('renders form inside sheet', () => {
|
|
193
|
+
const onSubmit = cy.stub();
|
|
194
|
+
|
|
195
|
+
cy.mount(
|
|
196
|
+
<Sheet>
|
|
197
|
+
<SheetTrigger>Add Item</SheetTrigger>
|
|
198
|
+
<SheetContent>
|
|
199
|
+
<form
|
|
200
|
+
onSubmit={(e) => {
|
|
201
|
+
e.preventDefault();
|
|
202
|
+
onSubmit('submitted');
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
<SheetHeader>
|
|
206
|
+
<SheetTitle>Add New Item</SheetTitle>
|
|
207
|
+
<SheetDescription>Fill in the details below</SheetDescription>
|
|
208
|
+
</SheetHeader>
|
|
209
|
+
<div className="space-y-4 py-4">
|
|
210
|
+
<input name="title" placeholder="Title" required />
|
|
211
|
+
<textarea name="description" placeholder="Description" />
|
|
212
|
+
</div>
|
|
213
|
+
<SheetFooter>
|
|
214
|
+
<SheetClose asChild>
|
|
215
|
+
<Button type="button" variant="outline">
|
|
216
|
+
Cancel
|
|
217
|
+
</Button>
|
|
218
|
+
</SheetClose>
|
|
219
|
+
<Button type="submit">Add</Button>
|
|
220
|
+
</SheetFooter>
|
|
221
|
+
</form>
|
|
222
|
+
</SheetContent>
|
|
223
|
+
</Sheet>
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
cy.contains('Add Item').click();
|
|
227
|
+
cy.get('input[name="title"]').type('Test Item');
|
|
228
|
+
cy.get('textarea[name="description"]').type('Test Description');
|
|
229
|
+
cy.get('form').submit();
|
|
230
|
+
cy.wrap(onSubmit).should('have.been.calledWith', 'submitted');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('handles long content with scroll', () => {
|
|
234
|
+
cy.mount(
|
|
235
|
+
<Sheet>
|
|
236
|
+
<SheetTrigger>View Content</SheetTrigger>
|
|
237
|
+
<SheetContent className="overflow-y-auto">
|
|
238
|
+
<SheetHeader>
|
|
239
|
+
<SheetTitle>Long Content</SheetTitle>
|
|
240
|
+
</SheetHeader>
|
|
241
|
+
<div className="py-4">
|
|
242
|
+
{Array.from({ length: 50 }, (_, i) => (
|
|
243
|
+
<p key={i} className="py-2">
|
|
244
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
|
|
245
|
+
incididunt ut labore et dolore magna aliqua.
|
|
246
|
+
</p>
|
|
247
|
+
))}
|
|
248
|
+
</div>
|
|
249
|
+
</SheetContent>
|
|
250
|
+
</Sheet>
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
cy.contains('View Content').click();
|
|
254
|
+
cy.get('.overflow-y-auto').should('be.visible');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('renders navigation menu in sheet', () => {
|
|
258
|
+
cy.mount(
|
|
259
|
+
<Sheet>
|
|
260
|
+
<SheetTrigger>Menu</SheetTrigger>
|
|
261
|
+
<SheetContent side="left">
|
|
262
|
+
<SheetHeader>
|
|
263
|
+
<SheetTitle>Navigation</SheetTitle>
|
|
264
|
+
</SheetHeader>
|
|
265
|
+
<nav className="mt-8">
|
|
266
|
+
<ul className="space-y-2">
|
|
267
|
+
<li>
|
|
268
|
+
<a href="#" className="block p-2 hover:bg-gray-100">
|
|
269
|
+
Home
|
|
270
|
+
</a>
|
|
271
|
+
</li>
|
|
272
|
+
<li>
|
|
273
|
+
<a href="#" className="block p-2 hover:bg-gray-100">
|
|
274
|
+
About
|
|
275
|
+
</a>
|
|
276
|
+
</li>
|
|
277
|
+
<li>
|
|
278
|
+
<a href="#" className="block p-2 hover:bg-gray-100">
|
|
279
|
+
Services
|
|
280
|
+
</a>
|
|
281
|
+
</li>
|
|
282
|
+
<li>
|
|
283
|
+
<a href="#" className="block p-2 hover:bg-gray-100">
|
|
284
|
+
Contact
|
|
285
|
+
</a>
|
|
286
|
+
</li>
|
|
287
|
+
</ul>
|
|
288
|
+
</nav>
|
|
289
|
+
</SheetContent>
|
|
290
|
+
</Sheet>
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
cy.contains('Menu').click();
|
|
294
|
+
cy.contains('Navigation').should('be.visible');
|
|
295
|
+
cy.contains('Home').should('be.visible');
|
|
296
|
+
cy.contains('About').should('be.visible');
|
|
297
|
+
cy.contains('Services').should('be.visible');
|
|
298
|
+
cy.contains('Contact').should('be.visible');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('maintains focus management', () => {
|
|
302
|
+
cy.mount(
|
|
303
|
+
<Sheet>
|
|
304
|
+
<SheetTrigger>Open Sheet</SheetTrigger>
|
|
305
|
+
<SheetContent>
|
|
306
|
+
<SheetHeader>
|
|
307
|
+
<SheetTitle>Focus Test</SheetTitle>
|
|
308
|
+
</SheetHeader>
|
|
309
|
+
<div className="space-y-4 py-4">
|
|
310
|
+
<input placeholder="First input" />
|
|
311
|
+
<input placeholder="Second input" />
|
|
312
|
+
<button>Action Button</button>
|
|
313
|
+
</div>
|
|
314
|
+
</SheetContent>
|
|
315
|
+
</Sheet>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
cy.contains('Open Sheet').click();
|
|
319
|
+
|
|
320
|
+
// Focus should be trapped within sheet
|
|
321
|
+
cy.get('input[placeholder="First input"]').focus();
|
|
322
|
+
cy.focused().should('have.attr', 'placeholder', 'First input');
|
|
323
|
+
});
|
|
324
|
+
});
|