@vvedantb/ui 0.3.2 → 0.4.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +66 -19
  2. package/app/README.md +8 -8
  3. package/package.json +5 -30
  4. package/src/composer/Composer.tsx +1 -0
  5. package/src/composer/index.ts +1 -0
  6. package/src/composer/input-area/ComposerSlashMenu.tsx +137 -0
  7. package/src/composer/input-area/ComposerSlashRow.tsx +75 -0
  8. package/src/composer/input-area/ConnectionStatusMenuItem.tsx +34 -0
  9. package/src/composer/input-area/FadePresence.tsx +31 -0
  10. package/src/composer/input-area/InputActions.tsx +63 -0
  11. package/src/composer/input-area/InputArea.tsx +513 -0
  12. package/src/composer/input-area/InputBanners.tsx +61 -0
  13. package/src/composer/input-area/PromoBanner.tsx +53 -0
  14. package/src/composer/input-area/composerCompact.ts +52 -0
  15. package/src/composer/input-area/composerPrediction.ts +51 -0
  16. package/src/composer/input-area/composerSlashItems.ts +206 -0
  17. package/src/composer/input-area/composerSlashOptionId.ts +7 -0
  18. package/src/composer/input-area/composerSlashPosition.ts +40 -0
  19. package/src/composer/input-area/composerSlashTrigger.ts +50 -0
  20. package/src/composer/input-area/index.ts +30 -0
  21. package/src/composer/input-area/inputPresets.ts +14 -0
  22. package/src/composer/input-area/motion.ts +7 -0
  23. package/src/composer/input-area/types.ts +25 -0
  24. package/src/composer/input-area/useComposerCompact.ts +46 -0
  25. package/src/composer/input-area/useComposerSlashMenu.ts +203 -0
  26. package/src/composer/input-area/useInputAreaPrediction.ts +49 -0
  27. package/src/index.ts +21 -0
  28. package/src/ui/button.tsx +11 -2
  29. package/src/ui/dropdown-menu.tsx +35 -7
  30. package/tokens/README.md +2 -2
  31. package/src/sonner.ts +0 -2
@@ -0,0 +1,49 @@
1
+ import { useEffect, useState } from "react";
2
+ import {
3
+ ghostSuggestion,
4
+ scheduleCompletion,
5
+ shouldSkipPrediction,
6
+ } from "./composerPrediction";
7
+
8
+ /**
9
+ * As-you-type ghost text for `InputArea`. The caller renders `suggestion` and
10
+ * owns accepting it. A result shows only while the draft it was requested for
11
+ * is still the current draft. Pass `getPrediction` to make the request.
12
+ */
13
+ export function useInputAreaPrediction({
14
+ value,
15
+ suspended = false,
16
+ enabled = true,
17
+ getPrediction,
18
+ }: {
19
+ value: string;
20
+ suspended?: boolean;
21
+ enabled?: boolean;
22
+ getPrediction?: (text: string) => Promise<string>;
23
+ }): { suggestion: string | undefined; dismiss: () => void } {
24
+ const [result, setResult] = useState<{ forValue: string; text: string }>();
25
+ const [dismissedFor, setDismissedFor] = useState<string>();
26
+
27
+ const idle =
28
+ !enabled ||
29
+ getPrediction === undefined ||
30
+ suspended ||
31
+ shouldSkipPrediction(value);
32
+ const settled = result?.forValue === value || dismissedFor === value;
33
+
34
+ // Debounced request: it has to react to the draft changing.
35
+ useEffect(() => {
36
+ if (idle || settled || getPrediction === undefined) return;
37
+ return scheduleCompletion(
38
+ value,
39
+ getPrediction,
40
+ (text) => setResult({ forValue: value, text }),
41
+ );
42
+ }, [value, idle, settled, getPrediction]);
43
+
44
+ const visible = !idle && dismissedFor !== value && result?.forValue === value;
45
+ return {
46
+ suggestion: visible ? ghostSuggestion(value, result.text) : undefined,
47
+ dismiss: () => setDismissedFor(value),
48
+ };
49
+ }
package/src/index.ts CHANGED
@@ -100,3 +100,24 @@ export * from "./ai-elements/suggestion";
100
100
  export * from "./audio";
101
101
 
102
102
  export * from "./composer";
103
+ export { toast } from "sonner";
104
+
105
+ // Shell: router-free pieces. Shell's own `cn` and `ClassValue` are not re-exported;
106
+ // use the root `cn` (clsx + tailwind-merge).
107
+ export { SidebarHeader } from "../shell/src/SidebarHeader";
108
+ export type { SidebarHeaderProps } from "../shell/src/SidebarHeader";
109
+ export { PillTabs } from "../shell/src/PillTabs";
110
+ export type { PillTabItem, PillTabsProps } from "../shell/src/PillTabs";
111
+ export { SessionsHoverCard } from "../shell/src/SessionsHoverCard";
112
+ export type {
113
+ SessionsHoverCardContext,
114
+ SessionsHoverCardProps,
115
+ SessionsHoverCardSurface,
116
+ } from "../shell/src/SessionsHoverCard";
117
+
118
+ // App helpers: confirm skip, update watcher, settings chrome, stable auth.
119
+ export * from "../app/src/index";
120
+
121
+ // Native tokens (JS values that match tokens.css).
122
+ export { tokens } from "../tokens/src/native";
123
+ export type { Tokens } from "../tokens/src/native";
package/src/ui/button.tsx CHANGED
@@ -39,17 +39,26 @@ export interface ButtonProps
39
39
  React.ButtonHTMLAttributes<HTMLButtonElement>,
40
40
  VariantProps<typeof buttonVariants> {
41
41
  asChild?: boolean;
42
+ /** Rendered before the children. Ignored with `asChild`. */
43
+ startContent?: React.ReactNode;
42
44
  }
43
45
 
44
46
  const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
45
- ({ className, variant, size, asChild = false, ...props }, ref) => {
47
+ ({ className, variant, size, asChild = false, startContent, children, ...props }, ref) => {
46
48
  const Comp = asChild ? Slot : "button";
47
49
  return (
48
50
  <Comp
49
51
  className={cn(buttonVariants({ variant, size, className }))}
50
52
  ref={ref}
51
53
  {...props}
52
- />
54
+ >
55
+ {asChild ? children : (
56
+ <>
57
+ {startContent}
58
+ {children}
59
+ </>
60
+ )}
61
+ </Comp>
53
62
  );
54
63
  },
55
64
  );
@@ -75,14 +75,42 @@ const DropdownMenuItem = React.forwardRef<
75
75
  React.ComponentRef<typeof DropdownMenuPrimitive.Item>,
76
76
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
77
77
  inset?: boolean;
78
+ /** Leading icon or mark. Ignored with `asChild`. */
79
+ startContent?: React.ReactNode;
80
+ /** Second line under the label. Ignored with `asChild`. */
81
+ description?: React.ReactNode;
78
82
  }
79
- >(({ className, inset, ...props }, ref) => (
80
- <DropdownMenuPrimitive.Item
81
- ref={ref}
82
- className={cn(menuItemClass, inset && "pl-8", className)}
83
- {...props}
84
- />
85
- ));
83
+ >(
84
+ (
85
+ { className, inset, startContent, description, children, asChild, ...props },
86
+ ref,
87
+ ) => (
88
+ <DropdownMenuPrimitive.Item
89
+ ref={ref}
90
+ asChild={asChild}
91
+ className={cn(menuItemClass, inset && "pl-8", className)}
92
+ {...props}
93
+ >
94
+ {asChild || (startContent === undefined && description === undefined) ? (
95
+ children
96
+ ) : (
97
+ <>
98
+ {startContent}
99
+ {description === undefined ? (
100
+ children
101
+ ) : (
102
+ <span className="flex min-w-0 flex-col">
103
+ <span>{children}</span>
104
+ <span className="text-xs text-muted-foreground">
105
+ {description}
106
+ </span>
107
+ </span>
108
+ )}
109
+ </>
110
+ )}
111
+ </DropdownMenuPrimitive.Item>
112
+ ),
113
+ );
86
114
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
87
115
 
88
116
  const DropdownMenuCheckboxItem = React.forwardRef<
package/tokens/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # `@vvedantb/ui/tokens`
2
2
 
3
- Design tokens and shared Tailwind v4 CSS for the vvedantb web apps, plus JS tokens for React Native. These are subpaths of `@vvedantb/ui`, source-exported: no build step. Paths in the `File` column are relative to `packages/ui/tokens/`.
3
+ Design tokens and shared Tailwind v4 CSS for the vvedantb web apps. The CSS and Tailwind preset are subpaths of `@vvedantb/ui`; the native JS tokens are named exports of the root (`tokens`, `Tokens`). Source-exported: no build step. Paths in the `File` column are relative to `packages/ui/tokens/`.
4
4
 
5
5
  ## Exports
6
6
 
7
7
  | Export | File | What it is |
8
8
  | --- | --- | --- |
9
9
  | `@vvedantb/ui/tokens`, `@vvedantb/ui/tokens/tokens.css` | `src/tokens.css` | Colour, radius, shadow, ease and font tokens (`@theme`), light/dark variables, `dark` variant, `*` border and `body` defaults. In 0.2.1 it also defines shadcn-style aliases (`primary`, `muted-foreground`, `secondary`, `destructive`, `card`, `popover`, `input`, `ring`) that point at the same tokens. |
10
- | `@vvedantb/ui/tokens/native` | `src/native.ts` | JS colours, radii and spacing for React Native. `@vvedantb/native-ui` keeps its own copy in `src/tokens.ts`; a test keeps the two equal. |
10
+ | `tokens` and `Tokens` from `@vvedantb/ui` | `src/native.ts` | JS colours, radii and spacing for React Native. `@vvedantb/native-ui` keeps its own copy in `src/tokens.ts`; a test keeps the two equal. |
11
11
  | `@vvedantb/ui/tokens/css/base.css` | `src/css/base.css` | `html` touch/accent, `::selection`, control transitions, pointer cursor, range accent (`@layer base`). |
12
12
  | `@vvedantb/ui/tokens/css/dialog.css` | `src/css/dialog.css` | Unlayered `max-width: none` for `@vvedantb/ui` compact (bottom-sheet) dialogs. |
13
13
  | `@vvedantb/ui/tokens/css/modal.css` | `src/css/modal.css` | `.t-modal`, `.is-open`, `.is-closing` and `t-modal-presence-wait` (`@layer components`). |
package/src/sonner.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./ui/sonner";
2
- export { toast } from "sonner";