@epicbagel/saas-kit 1.20.0 → 1.22.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 +39 -0
- package/dist/primitives/agent-audio-visualizer-bar.d.cts +2 -2
- package/dist/primitives/agent-audio-visualizer-bar.d.ts +2 -2
- package/dist/primitives/alert.d.cts +1 -1
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/attachment.d.cts +1 -1
- package/dist/primitives/attachment.d.ts +1 -1
- package/dist/primitives/badge.d.cts +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/bubble.d.cts +1 -1
- package/dist/primitives/bubble.d.ts +1 -1
- package/dist/primitives/button.d.cts +2 -2
- package/dist/primitives/button.d.ts +2 -2
- package/dist/primitives/item.d.cts +2 -2
- package/dist/primitives/item.d.ts +2 -2
- package/dist/primitives/section-header.d.cts +1 -1
- package/dist/primitives/section-header.d.ts +1 -1
- package/dist/primitives/toggle-group.d.cts +2 -2
- package/dist/primitives/toggle-group.d.ts +2 -2
- package/dist/primitives/toggle.d.cts +2 -2
- package/dist/primitives/toggle.d.ts +2 -2
- package/dist/primitives/workflow-assistant.cjs +170 -0
- package/dist/primitives/workflow-assistant.d.cts +43 -0
- package/dist/primitives/workflow-assistant.d.ts +43 -0
- package/dist/primitives/workflow-assistant.js +170 -0
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -60,6 +60,45 @@ does not import a voice provider. Stop and release audio tracks before setting
|
|
|
60
60
|
}} />
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
## Workflow assistant
|
|
64
|
+
|
|
65
|
+
`primitives/workflow-assistant` exports `WorkflowAssistant`, a controlled
|
|
66
|
+
conversation panel beside a working list. It uses `ChatThread`, `ChatInput`
|
|
67
|
+
and the same `voiceSession` contract as Chat. The panel is non-modal: it
|
|
68
|
+
leaves the page interactive, does not trap focus, and keeps the current
|
|
69
|
+
`context` visible in its header. On short screens the panel can scroll while
|
|
70
|
+
the header stays reachable.
|
|
71
|
+
|
|
72
|
+
Opening the launcher starts an inactive voice session. Minimizing preserves
|
|
73
|
+
the session, transcript and host-owned draft; the minimized launcher reports
|
|
74
|
+
the current voice state and keeps End available. `disabled`, `pending` or
|
|
75
|
+
`voiceSession.disabled` prevent a new call but never prevent reopening or
|
|
76
|
+
ending an active call. Activation moves keyboard focus to the panel heading;
|
|
77
|
+
minimizing returns it to the launcher. A host-driven open or scope update
|
|
78
|
+
does not move focus away from the page.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { WorkflowAssistant } from "@epicbagel/saas-kit/primitives/workflow-assistant";
|
|
82
|
+
|
|
83
|
+
<WorkflowAssistant
|
|
84
|
+
open={open} onOpenChange={setOpen}
|
|
85
|
+
expanded={expanded} onExpandedChange={setExpanded}
|
|
86
|
+
title="Voice review" context={`Current list · ${items.length} items`}
|
|
87
|
+
messages={messages} value={draft} onChange={setDraft} onSend={sendRequest}
|
|
88
|
+
pending={pending} error={error}
|
|
89
|
+
voiceSession={{ state, muted, onMutedChange: setMuted,
|
|
90
|
+
onStart: startVoice, onEnd: endVoice }}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The host owns authorization, list scope, messages, draft clearing, audio and
|
|
95
|
+
connection cleanup. When scope changes, the host must cancel or replace any
|
|
96
|
+
session that still refers to the previous list. Omit `voiceSession` for a
|
|
97
|
+
text-only conversation, omit `onExpandedChange` to hide the expand control,
|
|
98
|
+
and use `besideCornerAction` to leave space for an existing corner action.
|
|
99
|
+
Override panel actions with `labels`; minimized session status and End also
|
|
100
|
+
honor `voiceSession.labels`.
|
|
101
|
+
|
|
63
102
|
## API dictation
|
|
64
103
|
|
|
65
104
|
Wrap the application in `DictationProvider` to use an authenticated transcription
|
|
@@ -11,10 +11,10 @@ import { AgentVisualizerState } from '../hooks/use-agent-audio-visualizer-bar.cj
|
|
|
11
11
|
*/
|
|
12
12
|
declare function normalizeVolumeBands(bands: number[], count: number): number[];
|
|
13
13
|
declare const AgentAudioVisualizerBarElementVariants: (props?: ({
|
|
14
|
-
size?: "
|
|
14
|
+
size?: "icon" | "md" | "sm" | "lg" | "xl" | null | undefined;
|
|
15
15
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
16
16
|
declare const AgentAudioVisualizerBarVariants: (props?: ({
|
|
17
|
-
size?: "
|
|
17
|
+
size?: "icon" | "md" | "sm" | "lg" | "xl" | null | undefined;
|
|
18
18
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
19
19
|
/**
|
|
20
20
|
* Props for the AgentAudioVisualizerBar component.
|
|
@@ -11,10 +11,10 @@ import { AgentVisualizerState } from '../hooks/use-agent-audio-visualizer-bar.js
|
|
|
11
11
|
*/
|
|
12
12
|
declare function normalizeVolumeBands(bands: number[], count: number): number[];
|
|
13
13
|
declare const AgentAudioVisualizerBarElementVariants: (props?: ({
|
|
14
|
-
size?: "
|
|
14
|
+
size?: "icon" | "md" | "sm" | "lg" | "xl" | null | undefined;
|
|
15
15
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
16
16
|
declare const AgentAudioVisualizerBarVariants: (props?: ({
|
|
17
|
-
size?: "
|
|
17
|
+
size?: "icon" | "md" | "sm" | "lg" | "xl" | null | undefined;
|
|
18
18
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
19
19
|
/**
|
|
20
20
|
* Props for the AgentAudioVisualizerBar component.
|
|
@@ -4,7 +4,7 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const alertVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "success" | "default" | "destructive" | "warning" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface AlertProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {
|
|
10
10
|
marginBottom?: "none" | "md";
|
|
@@ -4,7 +4,7 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const alertVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "success" | "default" | "destructive" | "warning" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface AlertProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {
|
|
10
10
|
marginBottom?: "none" | "md";
|
|
@@ -12,7 +12,7 @@ declare function Attachment({ className, state, size, orientation, ...props }: R
|
|
|
12
12
|
state?: "idle" | "uploading" | "processing" | "error" | "done";
|
|
13
13
|
}): react_jsx_runtime.JSX.Element;
|
|
14
14
|
declare const attachmentMediaVariants: (props?: ({
|
|
15
|
-
variant?: "
|
|
15
|
+
variant?: "icon" | "image" | null | undefined;
|
|
16
16
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
17
17
|
declare function AttachmentMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>): react_jsx_runtime.JSX.Element;
|
|
18
18
|
declare function AttachmentContent({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
@@ -12,7 +12,7 @@ declare function Attachment({ className, state, size, orientation, ...props }: R
|
|
|
12
12
|
state?: "idle" | "uploading" | "processing" | "error" | "done";
|
|
13
13
|
}): react_jsx_runtime.JSX.Element;
|
|
14
14
|
declare const attachmentMediaVariants: (props?: ({
|
|
15
|
-
variant?: "
|
|
15
|
+
variant?: "icon" | "image" | null | undefined;
|
|
16
16
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
17
17
|
declare function AttachmentMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>): react_jsx_runtime.JSX.Element;
|
|
18
18
|
declare function AttachmentContent({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
@@ -4,7 +4,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
4
4
|
import { ElementType } from 'react';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "error" | "success" | "default" | "secondary" | "destructive" | "outline" | "warning" | "info" | "neutral" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
10
10
|
weight?: "normal" | "semibold" | "bold";
|
|
@@ -4,7 +4,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
4
4
|
import { ElementType } from 'react';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "error" | "success" | "default" | "secondary" | "destructive" | "outline" | "warning" | "info" | "neutral" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
10
10
|
weight?: "normal" | "semibold" | "bold";
|
|
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare function BubbleGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
7
7
|
declare const bubbleVariants: (props?: ({
|
|
8
|
-
variant?: "
|
|
8
|
+
variant?: "muted" | "default" | "secondary" | "destructive" | "outline" | "ghost" | "tinted" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare function Bubble({ variant, align, className, ...props }: React.ComponentProps<"div"> & VariantProps<typeof bubbleVariants> & {
|
|
11
11
|
align?: "start" | "end";
|
|
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare function BubbleGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
7
7
|
declare const bubbleVariants: (props?: ({
|
|
8
|
-
variant?: "
|
|
8
|
+
variant?: "muted" | "default" | "secondary" | "destructive" | "outline" | "ghost" | "tinted" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare function Bubble({ variant, align, className, ...props }: React.ComponentProps<"div"> & VariantProps<typeof bubbleVariants> & {
|
|
11
11
|
align?: "start" | "end";
|
|
@@ -5,12 +5,12 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const buttonVariants: (props?: ({
|
|
7
7
|
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "outline-muted" | "ghost" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
|
|
8
|
-
size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon
|
|
8
|
+
size?: "filter" | "status" | "icon" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | "tone" | null | undefined;
|
|
9
9
|
width?: "auto" | "full" | "responsive" | null | undefined;
|
|
10
10
|
align?: "center" | "start" | null | undefined;
|
|
11
11
|
shrink?: boolean | null | undefined;
|
|
12
12
|
shape?: "circle" | "default" | "pill" | null | undefined;
|
|
13
|
-
ring?: "
|
|
13
|
+
ring?: "surface" | "none" | null | undefined;
|
|
14
14
|
grow?: boolean | null | undefined;
|
|
15
15
|
minWidth?: "auto" | "zero" | null | undefined;
|
|
16
16
|
textAlign?: "center" | "start" | null | undefined;
|
|
@@ -5,12 +5,12 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const buttonVariants: (props?: ({
|
|
7
7
|
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "outline-muted" | "ghost" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
|
|
8
|
-
size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon
|
|
8
|
+
size?: "filter" | "status" | "icon" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | "tone" | null | undefined;
|
|
9
9
|
width?: "auto" | "full" | "responsive" | null | undefined;
|
|
10
10
|
align?: "center" | "start" | null | undefined;
|
|
11
11
|
shrink?: boolean | null | undefined;
|
|
12
12
|
shape?: "circle" | "default" | "pill" | null | undefined;
|
|
13
|
-
ring?: "
|
|
13
|
+
ring?: "surface" | "none" | null | undefined;
|
|
14
14
|
grow?: boolean | null | undefined;
|
|
15
15
|
minWidth?: "auto" | "zero" | null | undefined;
|
|
16
16
|
textAlign?: "center" | "start" | null | undefined;
|
|
@@ -8,14 +8,14 @@ import '@radix-ui/react-separator';
|
|
|
8
8
|
declare function ItemGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
9
9
|
declare function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>): react_jsx_runtime.JSX.Element;
|
|
10
10
|
declare const itemVariants: (props?: ({
|
|
11
|
-
variant?: "
|
|
11
|
+
variant?: "muted" | "default" | "outline" | null | undefined;
|
|
12
12
|
size?: "xs" | "sm" | "default" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
14
14
|
declare function Item({ className, variant, size, asChild, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemVariants> & {
|
|
15
15
|
asChild?: boolean;
|
|
16
16
|
}): react_jsx_runtime.JSX.Element;
|
|
17
17
|
declare const itemMediaVariants: (props?: ({
|
|
18
|
-
variant?: "
|
|
18
|
+
variant?: "icon" | "image" | "default" | null | undefined;
|
|
19
19
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
20
20
|
declare function ItemMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>): react_jsx_runtime.JSX.Element;
|
|
21
21
|
declare function ItemContent({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
@@ -8,14 +8,14 @@ import '@radix-ui/react-separator';
|
|
|
8
8
|
declare function ItemGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
9
9
|
declare function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>): react_jsx_runtime.JSX.Element;
|
|
10
10
|
declare const itemVariants: (props?: ({
|
|
11
|
-
variant?: "
|
|
11
|
+
variant?: "muted" | "default" | "outline" | null | undefined;
|
|
12
12
|
size?: "xs" | "sm" | "default" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
14
14
|
declare function Item({ className, variant, size, asChild, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemVariants> & {
|
|
15
15
|
asChild?: boolean;
|
|
16
16
|
}): react_jsx_runtime.JSX.Element;
|
|
17
17
|
declare const itemMediaVariants: (props?: ({
|
|
18
|
-
variant?: "
|
|
18
|
+
variant?: "icon" | "image" | "default" | null | undefined;
|
|
19
19
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
20
20
|
declare function ItemMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>): react_jsx_runtime.JSX.Element;
|
|
21
21
|
declare function ItemContent({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
|
|
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const sectionHeaderVariants: (props?: ({
|
|
7
7
|
variant?: "muted" | "plain" | null | undefined;
|
|
8
|
-
spacing?: "
|
|
8
|
+
spacing?: "tight" | "loose" | "none" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLHeadingElement>, "children">, VariantProps<typeof sectionHeaderVariants> {
|
|
11
11
|
/** Pre-rendered icon node. Sized to match the header text. */
|
|
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const sectionHeaderVariants: (props?: ({
|
|
7
7
|
variant?: "muted" | "plain" | null | undefined;
|
|
8
|
-
spacing?: "
|
|
8
|
+
spacing?: "tight" | "loose" | "none" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLHeadingElement>, "children">, VariantProps<typeof sectionHeaderVariants> {
|
|
11
11
|
/** Pre-rendered icon node. Sized to match the header text. */
|
|
@@ -5,11 +5,11 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const ToggleGroup: React.ForwardRefExoticComponent<((Omit<ToggleGroupPrimitive.ToggleGroupSingleProps & React.RefAttributes<HTMLDivElement>, "ref"> | Omit<ToggleGroupPrimitive.ToggleGroupMultipleProps & React.RefAttributes<HTMLDivElement>, "ref">) & VariantProps<(props?: ({
|
|
7
7
|
variant?: "default" | "outline" | null | undefined;
|
|
8
|
-
size?: "
|
|
8
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string>) & React.RefAttributes<HTMLDivElement>>;
|
|
10
10
|
declare const ToggleGroupItem: React.ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
|
|
11
11
|
variant?: "default" | "outline" | null | undefined;
|
|
12
|
-
size?: "
|
|
12
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
14
14
|
grow?: boolean;
|
|
15
15
|
textSize?: "inherit" | "xs";
|
|
@@ -5,11 +5,11 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
5
5
|
|
|
6
6
|
declare const ToggleGroup: React.ForwardRefExoticComponent<((Omit<ToggleGroupPrimitive.ToggleGroupSingleProps & React.RefAttributes<HTMLDivElement>, "ref"> | Omit<ToggleGroupPrimitive.ToggleGroupMultipleProps & React.RefAttributes<HTMLDivElement>, "ref">) & VariantProps<(props?: ({
|
|
7
7
|
variant?: "default" | "outline" | null | undefined;
|
|
8
|
-
size?: "
|
|
8
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string>) & React.RefAttributes<HTMLDivElement>>;
|
|
10
10
|
declare const ToggleGroupItem: React.ForwardRefExoticComponent<Omit<ToggleGroupPrimitive.ToggleGroupItemProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
|
|
11
11
|
variant?: "default" | "outline" | null | undefined;
|
|
12
|
-
size?: "
|
|
12
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & {
|
|
14
14
|
grow?: boolean;
|
|
15
15
|
textSize?: "inherit" | "xs";
|
|
@@ -5,11 +5,11 @@ import * as React from 'react';
|
|
|
5
5
|
|
|
6
6
|
declare const toggleVariants: (props?: ({
|
|
7
7
|
variant?: "default" | "outline" | null | undefined;
|
|
8
|
-
size?: "
|
|
8
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare const Toggle: React.ForwardRefExoticComponent<Omit<TogglePrimitive.ToggleProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
|
|
11
11
|
variant?: "default" | "outline" | null | undefined;
|
|
12
|
-
size?: "
|
|
12
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLButtonElement>>;
|
|
14
14
|
|
|
15
15
|
export { Toggle, toggleVariants };
|
|
@@ -5,11 +5,11 @@ import * as React from 'react';
|
|
|
5
5
|
|
|
6
6
|
declare const toggleVariants: (props?: ({
|
|
7
7
|
variant?: "default" | "outline" | null | undefined;
|
|
8
|
-
size?: "
|
|
8
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare const Toggle: React.ForwardRefExoticComponent<Omit<TogglePrimitive.ToggleProps & React.RefAttributes<HTMLButtonElement>, "ref"> & VariantProps<(props?: ({
|
|
11
11
|
variant?: "default" | "outline" | null | undefined;
|
|
12
|
-
size?: "
|
|
12
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-lg" | "avatar" | "chip" | null | undefined;
|
|
13
13
|
} & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLButtonElement>>;
|
|
14
14
|
|
|
15
15
|
export { Toggle, toggleVariants };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
var _chunkYMI3X2YLcjs = require('../chunk-YMI3X2YL.cjs');
|
|
6
|
+
require('../chunk-NKWHDI4C.cjs');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunkJDEXZGIYcjs = require('../chunk-JDEXZGIY.cjs');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
|
|
13
|
+
require('../chunk-2BSFYU22.cjs');
|
|
14
|
+
|
|
15
|
+
// src/primitives/workflow-assistant.tsx
|
|
16
|
+
var _react = require('react');
|
|
17
|
+
var _lucidereact = require('lucide-react');
|
|
18
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
19
|
+
var SESSION_LABELS = {
|
|
20
|
+
disconnected: "Voice chat",
|
|
21
|
+
connecting: "Connecting\u2026",
|
|
22
|
+
listening: "Listening\u2026",
|
|
23
|
+
thinking: "Thinking\u2026",
|
|
24
|
+
speaking: "Speaking",
|
|
25
|
+
reconnecting: "Reconnecting\u2026",
|
|
26
|
+
error: "Voice chat unavailable"
|
|
27
|
+
};
|
|
28
|
+
var WorkflowAssistant = _react.forwardRef.call(void 0, function WorkflowAssistant2({
|
|
29
|
+
open,
|
|
30
|
+
onOpenChange,
|
|
31
|
+
expanded = false,
|
|
32
|
+
onExpandedChange,
|
|
33
|
+
title = "Voice review",
|
|
34
|
+
context,
|
|
35
|
+
description,
|
|
36
|
+
summaries,
|
|
37
|
+
voiceSession,
|
|
38
|
+
pending,
|
|
39
|
+
disabled,
|
|
40
|
+
error,
|
|
41
|
+
besideCornerAction = false,
|
|
42
|
+
labels,
|
|
43
|
+
className
|
|
44
|
+
}, ref) {
|
|
45
|
+
const titleId = _react.useId.call(void 0, );
|
|
46
|
+
const statusId = _react.useId.call(void 0, );
|
|
47
|
+
const launcher = _react.useRef.call(void 0, null);
|
|
48
|
+
const heading = _react.useRef.call(void 0, null);
|
|
49
|
+
const moveFocus = _react.useRef.call(void 0, false);
|
|
50
|
+
_react.useEffect.call(void 0, () => {
|
|
51
|
+
if (!moveFocus.current) return;
|
|
52
|
+
moveFocus.current = false;
|
|
53
|
+
_optionalChain([(open ? heading.current : launcher.current), 'optionalAccess', _ => _.focus, 'call', _2 => _2()]);
|
|
54
|
+
}, [open]);
|
|
55
|
+
const toggle = (next) => {
|
|
56
|
+
moveFocus.current = true;
|
|
57
|
+
onOpenChange(next);
|
|
58
|
+
};
|
|
59
|
+
const startDisabled = pending || disabled || voiceSession.disabled;
|
|
60
|
+
const active = voiceSession.state !== "disconnected" && voiceSession.state !== "error";
|
|
61
|
+
const status = voiceSession.muted && voiceSession.state === "listening" ? _nullishCoalesce(_optionalChain([voiceSession, 'access', _3 => _3.labels, 'optionalAccess', _4 => _4.muted]), () => ( "Microphone muted")) : _nullishCoalesce(_optionalChain([voiceSession, 'access', _5 => _5.labels, 'optionalAccess', _6 => _6[voiceSession.state]]), () => ( SESSION_LABELS[voiceSession.state]));
|
|
62
|
+
const unavailable = voiceSession.state === "error" && voiceSession.disabled;
|
|
63
|
+
if (!open) return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
64
|
+
"aside",
|
|
65
|
+
{
|
|
66
|
+
ref,
|
|
67
|
+
"data-slot": "workflow-assistant-launcher",
|
|
68
|
+
"aria-label": title,
|
|
69
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "fixed bottom-[calc(1.5rem+env(safe-area-inset-bottom))] z-40 flex max-w-[calc(100vw-9rem)] items-center gap-1", besideCornerAction ? "right-32 md:right-36" : "right-6 md:right-8", className),
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
72
|
+
_chunkJDEXZGIYcjs.Button,
|
|
73
|
+
{
|
|
74
|
+
ref: launcher,
|
|
75
|
+
type: "button",
|
|
76
|
+
shape: "pill",
|
|
77
|
+
className: "min-h-12 min-w-12 max-w-full gap-2 shadow-lg",
|
|
78
|
+
disabled: startDisabled && !active && !unavailable,
|
|
79
|
+
"aria-label": active ? title : unavailable ? "Voice review unavailable" : _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _7 => _7.start]), () => ( "Start voice review")),
|
|
80
|
+
"aria-expanded": false,
|
|
81
|
+
"aria-describedby": active ? statusId : void 0,
|
|
82
|
+
onClick: () => {
|
|
83
|
+
toggle(true);
|
|
84
|
+
if (!active && !startDisabled) voiceSession.onStart();
|
|
85
|
+
},
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.AudioLines, { "aria-hidden": "true", className: "shrink-0" }),
|
|
88
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { id: statusId, role: active ? "status" : void 0, className: "truncate", children: active ? status : unavailable ? "Voice unavailable" : title })
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
active && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
93
|
+
_chunkJDEXZGIYcjs.Button,
|
|
94
|
+
{
|
|
95
|
+
type: "button",
|
|
96
|
+
variant: "outline",
|
|
97
|
+
shape: "circle",
|
|
98
|
+
size: "icon",
|
|
99
|
+
className: "min-h-12 min-w-12 bg-background shadow-lg",
|
|
100
|
+
onClick: () => {
|
|
101
|
+
_optionalChain([launcher, 'access', _8 => _8.current, 'optionalAccess', _9 => _9.focus, 'call', _10 => _10()]);
|
|
102
|
+
voiceSession.onEnd();
|
|
103
|
+
},
|
|
104
|
+
"aria-label": _nullishCoalesce(_nullishCoalesce(_optionalChain([labels, 'optionalAccess', _11 => _11.end]), () => ( _optionalChain([voiceSession, 'access', _12 => _12.labels, 'optionalAccess', _13 => _13.end]))), () => ( "End voice chat")),
|
|
105
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Square, { "aria-hidden": "true" })
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
112
|
+
"aside",
|
|
113
|
+
{
|
|
114
|
+
ref,
|
|
115
|
+
"data-slot": "workflow-assistant",
|
|
116
|
+
"aria-labelledby": titleId,
|
|
117
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
118
|
+
"fixed inset-x-2 bottom-[calc(1rem+env(safe-area-inset-bottom))] z-40 flex min-h-0 flex-col overflow-y-auto overscroll-contain rounded-2xl border bg-background shadow-xl sm:inset-x-auto sm:right-6 sm:w-[28rem] md:right-8",
|
|
119
|
+
expanded ? "h-[calc(100dvh-6rem)]" : "max-h-[min(36rem,70dvh)]",
|
|
120
|
+
className
|
|
121
|
+
),
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "sticky top-0 z-10 flex shrink-0 items-start gap-2 border-b bg-background p-3", children: [
|
|
124
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1", children: [
|
|
125
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { ref: heading, tabIndex: -1, id: titleId, className: "text-sm font-semibold", children: title }),
|
|
126
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { title: context, className: "mt-1 truncate text-xs text-muted-foreground", children: context })
|
|
127
|
+
] }),
|
|
128
|
+
onExpandedChange && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
129
|
+
_chunkJDEXZGIYcjs.Button,
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
variant: "ghost",
|
|
133
|
+
size: "icon",
|
|
134
|
+
"aria-label": expanded ? _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _14 => _14.collapse]), () => ( "Reduce panel")) : _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _15 => _15.expand]), () => ( "Expand panel")),
|
|
135
|
+
onClick: () => onExpandedChange(!expanded),
|
|
136
|
+
children: expanded ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Minimize2, { "aria-hidden": "true" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Maximize2, { "aria-hidden": "true" })
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "ghost", size: "icon", "aria-label": _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _16 => _16.minimize]), () => ( "Minimize voice review")), onClick: () => toggle(false), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronDown, { "aria-hidden": "true" }) })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "shrink-0", "data-slot": "workflow-assistant-voice", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
142
|
+
_chunkYMI3X2YLcjs.VoiceSessionControls,
|
|
143
|
+
{
|
|
144
|
+
...voiceSession,
|
|
145
|
+
disabled: Boolean(startDisabled),
|
|
146
|
+
size: "hero",
|
|
147
|
+
onEnd: () => {
|
|
148
|
+
_optionalChain([heading, 'access', _17 => _17.current, 'optionalAccess', _18 => _18.focus, 'call', _19 => _19()]);
|
|
149
|
+
voiceSession.onEnd();
|
|
150
|
+
},
|
|
151
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, !active && "justify-center px-4 py-6 text-center")
|
|
152
|
+
}
|
|
153
|
+
) }),
|
|
154
|
+
description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "shrink-0 px-4 py-3 text-sm text-muted-foreground", children: description }),
|
|
155
|
+
error && (voiceSession.state !== "error" || error !== voiceSession.error) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "shrink-0 px-4 py-2 text-sm text-destructive", children: error }),
|
|
156
|
+
pending && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "status", className: "shrink-0 px-4 py-2 text-sm text-muted-foreground", children: "Applying your instructions\u2026" }),
|
|
157
|
+
summaries.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { "aria-label": "Action summaries", className: "min-h-20 flex-1 overflow-y-auto border-t px-4 py-3", children: [
|
|
158
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "mb-3 text-xs font-medium text-muted-foreground", children: "Action summaries" }),
|
|
159
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ol", { className: "space-y-3", "aria-live": "polite", "aria-relevant": "additions", children: [...summaries].reverse().map((summary) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "space-y-1 border-b pb-3 last:border-0 last:pb-0", children: [
|
|
160
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-xs text-muted-foreground", children: summary.context }),
|
|
161
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "whitespace-pre-wrap break-words text-sm", children: summary.body })
|
|
162
|
+
] }, summary.id)) })
|
|
163
|
+
] })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
exports.WorkflowAssistant = WorkflowAssistant;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { VoiceSessionControlsProps } from './voice-session-controls.cjs';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
interface WorkflowSummary {
|
|
7
|
+
id: string;
|
|
8
|
+
/** Scope at the time of the action, which may differ from the current list. */
|
|
9
|
+
context: string;
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
interface WorkflowAssistantProps {
|
|
13
|
+
open: boolean;
|
|
14
|
+
onOpenChange: (open: boolean) => void;
|
|
15
|
+
expanded?: boolean;
|
|
16
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
17
|
+
title?: string;
|
|
18
|
+
/** Current host-owned scope. Keep it visible while the summaries scroll. */
|
|
19
|
+
context: string;
|
|
20
|
+
description?: ReactNode;
|
|
21
|
+
/** Saved action receipts and clarification questions, newest last. Read-only. */
|
|
22
|
+
summaries: WorkflowSummary[];
|
|
23
|
+
/** Minimizing preserves this host-owned session; only End calls onEnd. */
|
|
24
|
+
voiceSession: VoiceSessionControlsProps;
|
|
25
|
+
pending?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
error?: string | null;
|
|
28
|
+
/** Leave room for an existing corner action such as New. */
|
|
29
|
+
besideCornerAction?: boolean;
|
|
30
|
+
labels?: {
|
|
31
|
+
start?: string;
|
|
32
|
+
minimize?: string;
|
|
33
|
+
expand?: string;
|
|
34
|
+
collapse?: string;
|
|
35
|
+
end?: string;
|
|
36
|
+
};
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Voice-only workflow controls: the underlying list stays usable.
|
|
40
|
+
* The host owns scope, authorization, persistence and the voice connection. */
|
|
41
|
+
declare const WorkflowAssistant: React.ForwardRefExoticComponent<WorkflowAssistantProps & React.RefAttributes<HTMLElement>>;
|
|
42
|
+
|
|
43
|
+
export { WorkflowAssistant, type WorkflowAssistantProps, type WorkflowSummary };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { VoiceSessionControlsProps } from './voice-session-controls.js';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
interface WorkflowSummary {
|
|
7
|
+
id: string;
|
|
8
|
+
/** Scope at the time of the action, which may differ from the current list. */
|
|
9
|
+
context: string;
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
interface WorkflowAssistantProps {
|
|
13
|
+
open: boolean;
|
|
14
|
+
onOpenChange: (open: boolean) => void;
|
|
15
|
+
expanded?: boolean;
|
|
16
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
17
|
+
title?: string;
|
|
18
|
+
/** Current host-owned scope. Keep it visible while the summaries scroll. */
|
|
19
|
+
context: string;
|
|
20
|
+
description?: ReactNode;
|
|
21
|
+
/** Saved action receipts and clarification questions, newest last. Read-only. */
|
|
22
|
+
summaries: WorkflowSummary[];
|
|
23
|
+
/** Minimizing preserves this host-owned session; only End calls onEnd. */
|
|
24
|
+
voiceSession: VoiceSessionControlsProps;
|
|
25
|
+
pending?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
error?: string | null;
|
|
28
|
+
/** Leave room for an existing corner action such as New. */
|
|
29
|
+
besideCornerAction?: boolean;
|
|
30
|
+
labels?: {
|
|
31
|
+
start?: string;
|
|
32
|
+
minimize?: string;
|
|
33
|
+
expand?: string;
|
|
34
|
+
collapse?: string;
|
|
35
|
+
end?: string;
|
|
36
|
+
};
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Voice-only workflow controls: the underlying list stays usable.
|
|
40
|
+
* The host owns scope, authorization, persistence and the voice connection. */
|
|
41
|
+
declare const WorkflowAssistant: React.ForwardRefExoticComponent<WorkflowAssistantProps & React.RefAttributes<HTMLElement>>;
|
|
42
|
+
|
|
43
|
+
export { WorkflowAssistant, type WorkflowAssistantProps, type WorkflowSummary };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import {
|
|
4
|
+
VoiceSessionControls
|
|
5
|
+
} from "../chunk-KF4X37DP.js";
|
|
6
|
+
import "../chunk-5OF6D3GH.js";
|
|
7
|
+
import {
|
|
8
|
+
Button
|
|
9
|
+
} from "../chunk-W326GKML.js";
|
|
10
|
+
import {
|
|
11
|
+
cn
|
|
12
|
+
} from "../chunk-G6SRSWXB.js";
|
|
13
|
+
import "../chunk-GJ7S3L6R.js";
|
|
14
|
+
|
|
15
|
+
// src/primitives/workflow-assistant.tsx
|
|
16
|
+
import { forwardRef, useEffect, useId, useRef } from "react";
|
|
17
|
+
import { AudioLines, ChevronDown, Maximize2, Minimize2, Square } from "lucide-react";
|
|
18
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
var SESSION_LABELS = {
|
|
20
|
+
disconnected: "Voice chat",
|
|
21
|
+
connecting: "Connecting\u2026",
|
|
22
|
+
listening: "Listening\u2026",
|
|
23
|
+
thinking: "Thinking\u2026",
|
|
24
|
+
speaking: "Speaking",
|
|
25
|
+
reconnecting: "Reconnecting\u2026",
|
|
26
|
+
error: "Voice chat unavailable"
|
|
27
|
+
};
|
|
28
|
+
var WorkflowAssistant = forwardRef(function WorkflowAssistant2({
|
|
29
|
+
open,
|
|
30
|
+
onOpenChange,
|
|
31
|
+
expanded = false,
|
|
32
|
+
onExpandedChange,
|
|
33
|
+
title = "Voice review",
|
|
34
|
+
context,
|
|
35
|
+
description,
|
|
36
|
+
summaries,
|
|
37
|
+
voiceSession,
|
|
38
|
+
pending,
|
|
39
|
+
disabled,
|
|
40
|
+
error,
|
|
41
|
+
besideCornerAction = false,
|
|
42
|
+
labels,
|
|
43
|
+
className
|
|
44
|
+
}, ref) {
|
|
45
|
+
const titleId = useId();
|
|
46
|
+
const statusId = useId();
|
|
47
|
+
const launcher = useRef(null);
|
|
48
|
+
const heading = useRef(null);
|
|
49
|
+
const moveFocus = useRef(false);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!moveFocus.current) return;
|
|
52
|
+
moveFocus.current = false;
|
|
53
|
+
(open ? heading.current : launcher.current)?.focus();
|
|
54
|
+
}, [open]);
|
|
55
|
+
const toggle = (next) => {
|
|
56
|
+
moveFocus.current = true;
|
|
57
|
+
onOpenChange(next);
|
|
58
|
+
};
|
|
59
|
+
const startDisabled = pending || disabled || voiceSession.disabled;
|
|
60
|
+
const active = voiceSession.state !== "disconnected" && voiceSession.state !== "error";
|
|
61
|
+
const status = voiceSession.muted && voiceSession.state === "listening" ? voiceSession.labels?.muted ?? "Microphone muted" : voiceSession.labels?.[voiceSession.state] ?? SESSION_LABELS[voiceSession.state];
|
|
62
|
+
const unavailable = voiceSession.state === "error" && voiceSession.disabled;
|
|
63
|
+
if (!open) return /* @__PURE__ */ jsxs(
|
|
64
|
+
"aside",
|
|
65
|
+
{
|
|
66
|
+
ref,
|
|
67
|
+
"data-slot": "workflow-assistant-launcher",
|
|
68
|
+
"aria-label": title,
|
|
69
|
+
className: cn("fixed bottom-[calc(1.5rem+env(safe-area-inset-bottom))] z-40 flex max-w-[calc(100vw-9rem)] items-center gap-1", besideCornerAction ? "right-32 md:right-36" : "right-6 md:right-8", className),
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ jsxs(
|
|
72
|
+
Button,
|
|
73
|
+
{
|
|
74
|
+
ref: launcher,
|
|
75
|
+
type: "button",
|
|
76
|
+
shape: "pill",
|
|
77
|
+
className: "min-h-12 min-w-12 max-w-full gap-2 shadow-lg",
|
|
78
|
+
disabled: startDisabled && !active && !unavailable,
|
|
79
|
+
"aria-label": active ? title : unavailable ? "Voice review unavailable" : labels?.start ?? "Start voice review",
|
|
80
|
+
"aria-expanded": false,
|
|
81
|
+
"aria-describedby": active ? statusId : void 0,
|
|
82
|
+
onClick: () => {
|
|
83
|
+
toggle(true);
|
|
84
|
+
if (!active && !startDisabled) voiceSession.onStart();
|
|
85
|
+
},
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx(AudioLines, { "aria-hidden": "true", className: "shrink-0" }),
|
|
88
|
+
/* @__PURE__ */ jsx("span", { id: statusId, role: active ? "status" : void 0, className: "truncate", children: active ? status : unavailable ? "Voice unavailable" : title })
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
active && /* @__PURE__ */ jsx(
|
|
93
|
+
Button,
|
|
94
|
+
{
|
|
95
|
+
type: "button",
|
|
96
|
+
variant: "outline",
|
|
97
|
+
shape: "circle",
|
|
98
|
+
size: "icon",
|
|
99
|
+
className: "min-h-12 min-w-12 bg-background shadow-lg",
|
|
100
|
+
onClick: () => {
|
|
101
|
+
launcher.current?.focus();
|
|
102
|
+
voiceSession.onEnd();
|
|
103
|
+
},
|
|
104
|
+
"aria-label": labels?.end ?? voiceSession.labels?.end ?? "End voice chat",
|
|
105
|
+
children: /* @__PURE__ */ jsx(Square, { "aria-hidden": "true" })
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
return /* @__PURE__ */ jsxs(
|
|
112
|
+
"aside",
|
|
113
|
+
{
|
|
114
|
+
ref,
|
|
115
|
+
"data-slot": "workflow-assistant",
|
|
116
|
+
"aria-labelledby": titleId,
|
|
117
|
+
className: cn(
|
|
118
|
+
"fixed inset-x-2 bottom-[calc(1rem+env(safe-area-inset-bottom))] z-40 flex min-h-0 flex-col overflow-y-auto overscroll-contain rounded-2xl border bg-background shadow-xl sm:inset-x-auto sm:right-6 sm:w-[28rem] md:right-8",
|
|
119
|
+
expanded ? "h-[calc(100dvh-6rem)]" : "max-h-[min(36rem,70dvh)]",
|
|
120
|
+
className
|
|
121
|
+
),
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-10 flex shrink-0 items-start gap-2 border-b bg-background p-3", children: [
|
|
124
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
125
|
+
/* @__PURE__ */ jsx("h2", { ref: heading, tabIndex: -1, id: titleId, className: "text-sm font-semibold", children: title }),
|
|
126
|
+
/* @__PURE__ */ jsx("p", { title: context, className: "mt-1 truncate text-xs text-muted-foreground", children: context })
|
|
127
|
+
] }),
|
|
128
|
+
onExpandedChange && /* @__PURE__ */ jsx(
|
|
129
|
+
Button,
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
variant: "ghost",
|
|
133
|
+
size: "icon",
|
|
134
|
+
"aria-label": expanded ? labels?.collapse ?? "Reduce panel" : labels?.expand ?? "Expand panel",
|
|
135
|
+
onClick: () => onExpandedChange(!expanded),
|
|
136
|
+
children: expanded ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": "true" })
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": labels?.minimize ?? "Minimize voice review", onClick: () => toggle(false), children: /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0", "data-slot": "workflow-assistant-voice", children: /* @__PURE__ */ jsx(
|
|
142
|
+
VoiceSessionControls,
|
|
143
|
+
{
|
|
144
|
+
...voiceSession,
|
|
145
|
+
disabled: Boolean(startDisabled),
|
|
146
|
+
size: "hero",
|
|
147
|
+
onEnd: () => {
|
|
148
|
+
heading.current?.focus();
|
|
149
|
+
voiceSession.onEnd();
|
|
150
|
+
},
|
|
151
|
+
className: cn(!active && "justify-center px-4 py-6 text-center")
|
|
152
|
+
}
|
|
153
|
+
) }),
|
|
154
|
+
description && /* @__PURE__ */ jsx("div", { className: "shrink-0 px-4 py-3 text-sm text-muted-foreground", children: description }),
|
|
155
|
+
error && (voiceSession.state !== "error" || error !== voiceSession.error) && /* @__PURE__ */ jsx("p", { role: "alert", className: "shrink-0 px-4 py-2 text-sm text-destructive", children: error }),
|
|
156
|
+
pending && /* @__PURE__ */ jsx("p", { role: "status", className: "shrink-0 px-4 py-2 text-sm text-muted-foreground", children: "Applying your instructions\u2026" }),
|
|
157
|
+
summaries.length > 0 && /* @__PURE__ */ jsxs("section", { "aria-label": "Action summaries", className: "min-h-20 flex-1 overflow-y-auto border-t px-4 py-3", children: [
|
|
158
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-xs font-medium text-muted-foreground", children: "Action summaries" }),
|
|
159
|
+
/* @__PURE__ */ jsx("ol", { className: "space-y-3", "aria-live": "polite", "aria-relevant": "additions", children: [...summaries].reverse().map((summary) => /* @__PURE__ */ jsxs("li", { className: "space-y-1 border-b pb-3 last:border-0 last:pb-0", children: [
|
|
160
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: summary.context }),
|
|
161
|
+
/* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words text-sm", children: summary.body })
|
|
162
|
+
] }, summary.id)) })
|
|
163
|
+
] })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
export {
|
|
169
|
+
WorkflowAssistant
|
|
170
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epicbagel/saas-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -1290,6 +1290,16 @@
|
|
|
1290
1290
|
"default": "./dist/primitives/voice-session-controls.cjs"
|
|
1291
1291
|
}
|
|
1292
1292
|
},
|
|
1293
|
+
"./primitives/workflow-assistant": {
|
|
1294
|
+
"import": {
|
|
1295
|
+
"types": "./dist/primitives/workflow-assistant.d.ts",
|
|
1296
|
+
"default": "./dist/primitives/workflow-assistant.js"
|
|
1297
|
+
},
|
|
1298
|
+
"require": {
|
|
1299
|
+
"types": "./dist/primitives/workflow-assistant.d.cts",
|
|
1300
|
+
"default": "./dist/primitives/workflow-assistant.cjs"
|
|
1301
|
+
}
|
|
1302
|
+
},
|
|
1293
1303
|
"./hooks/use-agent-audio-visualizer-bar": {
|
|
1294
1304
|
"import": {
|
|
1295
1305
|
"types": "./dist/hooks/use-agent-audio-visualizer-bar.d.ts",
|