@iloveagents/foundry-web-primitives 0.3.0 → 0.4.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 +10 -0
- package/dist/button.d.ts +11 -0
- package/dist/button.js +33 -0
- package/dist/checkbox.d.ts +4 -0
- package/dist/checkbox.js +8 -0
- package/dist/field.d.ts +11 -0
- package/dist/field.js +8 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/input.d.ts +4 -0
- package/dist/input.js +9 -0
- package/dist/textarea.d.ts +4 -0
- package/dist/textarea.js +9 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +5 -0
- package/package.json +19 -5
- package/AGENTS.md +0 -45
- package/CHANGELOG.md +0 -97
- package/CLAUDE.md +0 -1
- package/src/button.tsx +0 -49
- package/src/checkbox.tsx +0 -28
- package/src/field.tsx +0 -46
- package/src/index.ts +0 -7
- package/src/input.tsx +0 -15
- package/src/textarea.tsx +0 -15
- package/src/utils.ts +0 -6
package/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# @iloveagents/foundry-web-primitives
|
|
2
|
+
|
|
3
|
+
Leaf React primitives used by Foundry UI.
|
|
4
|
+
|
|
5
|
+
Exports small building blocks such as `Button`, `Input`, `Textarea`, `Field`,
|
|
6
|
+
`FieldSet`, `Checkbox`, and `cn`. Higher-level chat, shell, panel, and runtime
|
|
7
|
+
components live in `@iloveagents/foundry-web-ui`.
|
|
8
|
+
|
|
9
|
+
This package publishes built ESM JavaScript and `.d.ts` declarations. Host apps
|
|
10
|
+
using Tailwind v4 should scan `@iloveagents/foundry-web-primitives/dist`.
|
package/dist/button.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
11
|
+
export { Button, buttonVariants };
|
package/dist/button.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "./utils.js";
|
|
6
|
+
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
10
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
11
|
+
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
13
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
14
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
default: "h-9 px-4 py-2",
|
|
18
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
19
|
+
lg: "h-10 rounded-md px-8",
|
|
20
|
+
icon: "h-9 w-9",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
size: "default",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
29
|
+
const Comp = asChild ? Slot : "button";
|
|
30
|
+
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, ...props }));
|
|
31
|
+
});
|
|
32
|
+
Button.displayName = "Button";
|
|
33
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
3
|
+
declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
4
|
+
export { Checkbox };
|
package/dist/checkbox.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
4
|
+
import { Check } from "lucide-react";
|
|
5
|
+
import { cn } from "./utils.js";
|
|
6
|
+
const Checkbox = React.forwardRef(({ className, ...props }, ref) => (_jsx(CheckboxPrimitive.Root, { ref: ref, className: cn("peer size-4 shrink-0 rounded border border-border bg-background shadow-sm outline-none transition", "focus-visible:ring-2 focus-visible:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50", "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground", className), ...props, children: _jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: _jsx(Check, { className: "size-3.5" }) }) })));
|
|
7
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
8
|
+
export { Checkbox };
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
export declare function Field({ label, hint, error, htmlFor, action, className, children, }: {
|
|
3
|
+
label?: ReactNode;
|
|
4
|
+
hint?: ReactNode;
|
|
5
|
+
error?: ReactNode;
|
|
6
|
+
htmlFor?: string;
|
|
7
|
+
action?: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function FieldSet({ className, ...props }: ComponentPropsWithoutRef<"div">): import("react/jsx-runtime").JSX.Element;
|
package/dist/field.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./utils.js";
|
|
3
|
+
export function Field({ label, hint, error, htmlFor, action, className, children, }) {
|
|
4
|
+
return (_jsxs("label", { className: cn("block space-y-1.5", className), htmlFor: htmlFor, children: [label || action ? (_jsxs("span", { className: "flex items-center justify-between gap-3", children: [label ? (_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: label })) : (_jsx("span", {})), action] })) : null, children, hint ? _jsx("span", { className: "block text-xs text-muted-foreground", children: hint }) : null, error ? _jsx("span", { className: "block text-xs text-destructive", children: error }) : null] }));
|
|
5
|
+
}
|
|
6
|
+
export function FieldSet({ className, ...props }) {
|
|
7
|
+
return _jsx("div", { className: cn("grid gap-4", className), ...props });
|
|
8
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { cn } from "./utils.js";
|
|
2
|
+
export { Button, buttonVariants } from "./button.js";
|
|
3
|
+
export type { ButtonProps } from "./button.js";
|
|
4
|
+
export { Checkbox } from "./checkbox.js";
|
|
5
|
+
export { Input, inputClassName } from "./input.js";
|
|
6
|
+
export { Textarea, textareaClassName } from "./textarea.js";
|
|
7
|
+
export { Field, FieldSet } from "./field.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { cn } from "./utils.js";
|
|
2
|
+
export { Button, buttonVariants } from "./button.js";
|
|
3
|
+
export { Checkbox } from "./checkbox.js";
|
|
4
|
+
export { Input, inputClassName } from "./input.js";
|
|
5
|
+
export { Textarea, textareaClassName } from "./textarea.js";
|
|
6
|
+
export { Field, FieldSet } from "./field.js";
|
package/dist/input.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare const inputClassName = "flex h-10 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
3
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
4
|
+
export { Input, inputClassName };
|
package/dist/input.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "./utils.js";
|
|
4
|
+
const inputClassName = "flex h-10 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
5
|
+
const Input = React.forwardRef(({ className, type = "text", ...props }, ref) => {
|
|
6
|
+
return _jsx("input", { ref: ref, type: type, className: cn(inputClassName, className), ...props });
|
|
7
|
+
});
|
|
8
|
+
Input.displayName = "Input";
|
|
9
|
+
export { Input, inputClassName };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare const textareaClassName = "flex min-h-24 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
3
|
+
declare const Textarea: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
4
|
+
export { Textarea, textareaClassName };
|
package/dist/textarea.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "./utils.js";
|
|
4
|
+
const textareaClassName = "flex min-h-24 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
5
|
+
const Textarea = React.forwardRef(({ className, ...props }, ref) => {
|
|
6
|
+
return _jsx("textarea", { ref: ref, className: cn(textareaClassName, className), ...props });
|
|
7
|
+
});
|
|
8
|
+
Textarea.displayName = "Textarea";
|
|
9
|
+
export { Textarea, textareaClassName };
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iloveagents/foundry-web-primitives",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"license": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
9
13
|
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
10
19
|
"publishConfig": {
|
|
11
20
|
"access": "public"
|
|
12
21
|
},
|
|
@@ -25,10 +34,15 @@
|
|
|
25
34
|
"devDependencies": {
|
|
26
35
|
"@types/react": "^19.2.2",
|
|
27
36
|
"jsdom": "^28.1.0",
|
|
37
|
+
"lucide-react": ">=0.400.0",
|
|
38
|
+
"react": "^19.0.0",
|
|
39
|
+
"react-dom": "^19.0.0",
|
|
28
40
|
"typescript": "~5.9.3",
|
|
29
41
|
"vitest": "^4.1.4"
|
|
30
42
|
},
|
|
31
43
|
"scripts": {
|
|
32
|
-
"
|
|
44
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/fix-dts-extensions.mjs dist",
|
|
45
|
+
"test:unit": "vitest run --passWithNoTests",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
33
47
|
}
|
|
34
48
|
}
|
package/AGENTS.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
Stateless UI primitives for the LastSpace agent UI. Published as `@iloveagents/foundry-web-primitives`.
|
|
2
|
-
|
|
3
|
-
# Architecture
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
src/
|
|
7
|
-
index.ts ← barrel export (all public API)
|
|
8
|
-
utils.ts ← cn() — clsx + tailwind-merge
|
|
9
|
-
button.tsx ← Button + buttonVariants
|
|
10
|
-
checkbox.tsx ← Checkbox (Radix UI)
|
|
11
|
-
field.tsx ← Field, FieldSet (form-row composition)
|
|
12
|
-
input.tsx ← Input + inputClassName
|
|
13
|
-
textarea.tsx ← Textarea + textareaClassName
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
# Import boundary
|
|
17
|
-
|
|
18
|
-
- MUST NOT import from `@lastspace/*` (zero workspace dependencies — pure leaf package). **Enforced** by the `OPEN_CORE_GRAPH` rule in `packages/web-ui/src/__tests__/open-core-guards.test.ts`.
|
|
19
|
-
- MUST NOT use `@/` path aliases (relative imports only). Convention; not currently guarded for this package — guard coverage tracked under #92's follow-ups.
|
|
20
|
-
- MUST NOT import from any `apps/`, `features/`, or `pages/`. Convention; same status as above.
|
|
21
|
-
|
|
22
|
-
# What goes here
|
|
23
|
-
|
|
24
|
-
Stateless, generic UI building blocks. Specifically:
|
|
25
|
-
|
|
26
|
-
- shadcn-style primitives wrapping Radix UI roots
|
|
27
|
-
- Layout/composition helpers (`Field` rows for forms)
|
|
28
|
-
- Pure styling utilities (`cn`, variant helpers)
|
|
29
|
-
|
|
30
|
-
# What does NOT go here
|
|
31
|
-
|
|
32
|
-
- Any component that touches a Zustand store, agent runtime, or theme runtime
|
|
33
|
-
- Any component that renders into a portal AND needs theming (Dialog, Popover, DropdownMenu — those stay in `@iloveagents/foundry-web-ui` until the theme-runtime coupling is refactored)
|
|
34
|
-
- Any component with backend / API knowledge
|
|
35
|
-
|
|
36
|
-
# Theming
|
|
37
|
-
|
|
38
|
-
Components use Tailwind utility classes referencing CSS variables (shadcn convention):
|
|
39
|
-
- `bg-background`, `text-foreground`, `border-border`, `bg-primary`, `text-primary-foreground`, `bg-muted`, `text-muted-foreground`, `bg-accent`, `text-accent-foreground`, `border-input`, `ring-ring`, `bg-destructive`, `text-destructive-foreground`, `bg-secondary`, `text-secondary-foreground`
|
|
40
|
-
|
|
41
|
-
Consumers must define these tokens in their app's CSS (see `apps/web/src/index.css` for the canonical definitions).
|
|
42
|
-
|
|
43
|
-
# Bundle-size budget
|
|
44
|
-
|
|
45
|
-
`@iloveagents/foundry-web-primitives` ≤30 KB gz — **target, not yet enforced**. The `size-limit` infrastructure scaffolds in a follow-up PR on #92. Until then, manually check the build output. Adding heavier components (Dialog, Popover, table primitives) is fine if they stay zero-coupled, but watch the budget.
|
package/CHANGELOG.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# @iloveagents/foundry-web-primitives
|
|
2
|
-
|
|
3
|
-
## 0.3.0
|
|
4
|
-
|
|
5
|
-
## 0.2.2
|
|
6
|
-
|
|
7
|
-
### Patch Changes
|
|
8
|
-
|
|
9
|
-
- 8184a8c: shell: URL is authoritative for the runtime threadId — fixes
|
|
10
|
-
resume-creates-new-conversation race
|
|
11
|
-
|
|
12
|
-
`ChatConversationAwareRuntime` previously computed
|
|
13
|
-
`effectiveThreadId = sticky ?? urlMatch ?? freshIdRef.current`.
|
|
14
|
-
When the user navigated from one chat to another via a Recents
|
|
15
|
-
click, the synchronous render that followed the URL change had:
|
|
16
|
-
- `urlMatch = B` (read from the now-updated `useLocation`)
|
|
17
|
-
- `sticky = A` (the active-chat-store hadn't been updated by
|
|
18
|
-
`useTrackActiveChatFromUrl`'s `useEffect` yet — effects run
|
|
19
|
-
AFTER the commit phase)
|
|
20
|
-
|
|
21
|
-
`sticky ?? urlMatch` picked `A` (the previous chat). The AG-UI
|
|
22
|
-
adapter was constructed with `threadId = A`. The first message the
|
|
23
|
-
user sent went to `/api/agent` with `thread_id = A`, the middleware
|
|
24
|
-
created a new row keyed by `A`... wait actually no, here's what
|
|
25
|
-
happens — the runtime mints a fresh runner UUID when given a
|
|
26
|
-
mismatched threadId; that fresh UUID became a new conversation row,
|
|
27
|
-
appearing as "Untitled chat" at the top of the sidebar while the
|
|
28
|
-
URL still said `/chat/B`. Two active-looking dots: one for `B`
|
|
29
|
-
(NavLink URL match), one for the new row (statusDot from the
|
|
30
|
-
updated active-chat-store after the lazy ensure ran).
|
|
31
|
-
|
|
32
|
-
Swap the priority: `urlMatch ?? sticky ?? freshIdRef.current`. The
|
|
33
|
-
URL is authoritative whenever it's set (i.e. on `/chat/<id>`
|
|
34
|
-
routes), eliminating the stale-sticky race entirely. `sticky` is
|
|
35
|
-
still consulted as the second-priority fallback for non-chat
|
|
36
|
-
routes (`/spaces`, `/tasks`) so the popout chat stays "live" while
|
|
37
|
-
the user browses workspaces — that's the original purpose of
|
|
38
|
-
`useStickyConversationId` and it's preserved.
|
|
39
|
-
|
|
40
|
-
## 0.2.1
|
|
41
|
-
|
|
42
|
-
### Patch Changes
|
|
43
|
-
|
|
44
|
-
- No source changes. Bumped in lock-step with the fixed group so the
|
|
45
|
-
whole group can publish at a version number that's free across all
|
|
46
|
-
four packages. `@iloveagents/foundry-agent@0.2.0` and
|
|
47
|
-
`@iloveagents/foundry-web-primitives@0.2.0` were blocked by an old
|
|
48
|
-
npm reservation; `shell` and `ui` published at 0.2.0 successfully.
|
|
49
|
-
0.2.1 unblocks the two stuck packages without leaving the fixed
|
|
50
|
-
group drifting.
|
|
51
|
-
|
|
52
|
-
## 0.2.0
|
|
53
|
-
|
|
54
|
-
### Minor Changes
|
|
55
|
-
|
|
56
|
-
- shell: ChatConversationConfig API + sticky-runtime threadId — bumped as
|
|
57
|
-
part of the fixed group with `foundry-web-shell` / `foundry-web-ui` /
|
|
58
|
-
`foundry-agent`. No direct source changes in this package.
|
|
59
|
-
|
|
60
|
-
### NOTE: 1.0.0 / 1.0.1 were accidental
|
|
61
|
-
|
|
62
|
-
These version numbers were published briefly on 2026-05-27 due to the
|
|
63
|
-
peerDep cascade bug in the sibling packages (see `foundry-agent`'s 0.2.0
|
|
64
|
-
changelog entry), then unpublished. The version numbers themselves are
|
|
65
|
-
now permanently reserved on npm and CANNOT be re-published. Do not
|
|
66
|
-
depend on 1.0.x.
|
|
67
|
-
|
|
68
|
-
## 0.1.5
|
|
69
|
-
|
|
70
|
-
## 0.1.4
|
|
71
|
-
|
|
72
|
-
## 0.1.3
|
|
73
|
-
|
|
74
|
-
## 0.1.2
|
|
75
|
-
|
|
76
|
-
## 0.1.1
|
|
77
|
-
|
|
78
|
-
### Patch Changes
|
|
79
|
-
|
|
80
|
-
- 689d3e9: feat(sidebar): distinct file-drop affordance for nav containers
|
|
81
|
-
|
|
82
|
-
`useNavItemDnd` now exposes `isFileDragOver` separately from `isDragOver`
|
|
83
|
-
so consuming nav items can render a prominent file-drop visual (dashed
|
|
84
|
-
primary outline + soft primary background + Upload icon) when the user
|
|
85
|
-
is dragging native files over the container. Previously file drags
|
|
86
|
-
shared the same subtle ring as entity-move drags, so users couldn't
|
|
87
|
-
tell that a folder accepted external files. Applies to all five nav-
|
|
88
|
-
item shapes (action-row leaf, button leaf, `NestedFolderItem`,
|
|
89
|
-
`CollapsibleNavItem` with children/actions, `NavLink` fallthrough) and
|
|
90
|
-
updates `ContainerDropZone` for visual parity.
|
|
91
|
-
|
|
92
|
-
Also fixes a related regression: the capture-phase
|
|
93
|
-
`onDragEnterCapture` / `onDragOverCapture` handlers were calling
|
|
94
|
-
`e.stopPropagation()`, which short-circuits React's synthetic dispatch
|
|
95
|
-
and prevented the bubble-phase `onDragEnter` (where state actually
|
|
96
|
-
mutates) from running. Removed — `preventDefault()` alone is enough to
|
|
97
|
-
mark the element as droppable.
|
package/CLAUDE.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@AGENTS.md
|
package/src/button.tsx
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
-
|
|
5
|
-
import { cn } from "./utils.ts";
|
|
6
|
-
|
|
7
|
-
const buttonVariants = cva(
|
|
8
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
9
|
-
{
|
|
10
|
-
variants: {
|
|
11
|
-
variant: {
|
|
12
|
-
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
13
|
-
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
14
|
-
outline:
|
|
15
|
-
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
16
|
-
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
17
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
18
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
19
|
-
},
|
|
20
|
-
size: {
|
|
21
|
-
default: "h-9 px-4 py-2",
|
|
22
|
-
sm: "h-8 rounded-md px-3 text-xs",
|
|
23
|
-
lg: "h-10 rounded-md px-8",
|
|
24
|
-
icon: "h-9 w-9",
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
defaultVariants: {
|
|
28
|
-
variant: "default",
|
|
29
|
-
size: "default",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
export interface ButtonProps
|
|
35
|
-
extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
36
|
-
asChild?: boolean;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
40
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
41
|
-
const Comp = asChild ? Slot : "button";
|
|
42
|
-
return (
|
|
43
|
-
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
|
44
|
-
);
|
|
45
|
-
},
|
|
46
|
-
);
|
|
47
|
-
Button.displayName = "Button";
|
|
48
|
-
|
|
49
|
-
export { Button, buttonVariants };
|
package/src/checkbox.tsx
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
3
|
-
import { Check } from "lucide-react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "./utils.ts";
|
|
6
|
-
|
|
7
|
-
const Checkbox = React.forwardRef<
|
|
8
|
-
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
9
|
-
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
10
|
-
>(({ className, ...props }, ref) => (
|
|
11
|
-
<CheckboxPrimitive.Root
|
|
12
|
-
ref={ref}
|
|
13
|
-
className={cn(
|
|
14
|
-
"peer size-4 shrink-0 rounded border border-border bg-background shadow-sm outline-none transition",
|
|
15
|
-
"focus-visible:ring-2 focus-visible:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50",
|
|
16
|
-
"data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
17
|
-
className,
|
|
18
|
-
)}
|
|
19
|
-
{...props}
|
|
20
|
-
>
|
|
21
|
-
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
|
|
22
|
-
<Check className="size-3.5" />
|
|
23
|
-
</CheckboxPrimitive.Indicator>
|
|
24
|
-
</CheckboxPrimitive.Root>
|
|
25
|
-
));
|
|
26
|
-
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
27
|
-
|
|
28
|
-
export { Checkbox };
|
package/src/field.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "./utils.ts";
|
|
4
|
-
|
|
5
|
-
export function Field({
|
|
6
|
-
label,
|
|
7
|
-
hint,
|
|
8
|
-
error,
|
|
9
|
-
htmlFor,
|
|
10
|
-
action,
|
|
11
|
-
className,
|
|
12
|
-
children,
|
|
13
|
-
}: {
|
|
14
|
-
label?: ReactNode;
|
|
15
|
-
hint?: ReactNode;
|
|
16
|
-
error?: ReactNode;
|
|
17
|
-
htmlFor?: string;
|
|
18
|
-
action?: ReactNode;
|
|
19
|
-
className?: string;
|
|
20
|
-
children: ReactNode;
|
|
21
|
-
}) {
|
|
22
|
-
return (
|
|
23
|
-
<label className={cn("block space-y-1.5", className)} htmlFor={htmlFor}>
|
|
24
|
-
{label || action ? (
|
|
25
|
-
<span className="flex items-center justify-between gap-3">
|
|
26
|
-
{label ? (
|
|
27
|
-
<span className="text-xs font-medium text-muted-foreground">{label}</span>
|
|
28
|
-
) : (
|
|
29
|
-
<span />
|
|
30
|
-
)}
|
|
31
|
-
{action}
|
|
32
|
-
</span>
|
|
33
|
-
) : null}
|
|
34
|
-
{children}
|
|
35
|
-
{hint ? <span className="block text-xs text-muted-foreground">{hint}</span> : null}
|
|
36
|
-
{error ? <span className="block text-xs text-destructive">{error}</span> : null}
|
|
37
|
-
</label>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function FieldSet({
|
|
42
|
-
className,
|
|
43
|
-
...props
|
|
44
|
-
}: ComponentPropsWithoutRef<"div">) {
|
|
45
|
-
return <div className={cn("grid gap-4", className)} {...props} />;
|
|
46
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { cn } from "./utils.ts";
|
|
2
|
-
export { Button, buttonVariants } from "./button.tsx";
|
|
3
|
-
export type { ButtonProps } from "./button.tsx";
|
|
4
|
-
export { Checkbox } from "./checkbox.tsx";
|
|
5
|
-
export { Input, inputClassName } from "./input.tsx";
|
|
6
|
-
export { Textarea, textareaClassName } from "./textarea.tsx";
|
|
7
|
-
export { Field, FieldSet } from "./field.tsx";
|
package/src/input.tsx
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "./utils.ts";
|
|
4
|
-
|
|
5
|
-
const inputClassName =
|
|
6
|
-
"flex h-10 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
7
|
-
|
|
8
|
-
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
|
9
|
-
({ className, type = "text", ...props }, ref) => {
|
|
10
|
-
return <input ref={ref} type={type} className={cn(inputClassName, className)} {...props} />;
|
|
11
|
-
},
|
|
12
|
-
);
|
|
13
|
-
Input.displayName = "Input";
|
|
14
|
-
|
|
15
|
-
export { Input, inputClassName };
|
package/src/textarea.tsx
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "./utils.ts";
|
|
4
|
-
|
|
5
|
-
const textareaClassName =
|
|
6
|
-
"flex min-h-24 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/15 disabled:cursor-not-allowed disabled:opacity-50";
|
|
7
|
-
|
|
8
|
-
const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<"textarea">>(
|
|
9
|
-
({ className, ...props }, ref) => {
|
|
10
|
-
return <textarea ref={ref} className={cn(textareaClassName, className)} {...props} />;
|
|
11
|
-
},
|
|
12
|
-
);
|
|
13
|
-
Textarea.displayName = "Textarea";
|
|
14
|
-
|
|
15
|
-
export { Textarea, textareaClassName };
|