@raggle-ai/scout-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @raggle-ai/scout-ui
2
+
3
+ Reusable React project search components for Raggle Scout consumers.
4
+
5
+ ```tsx
6
+ import { ProjectSearchList } from "@raggle-ai/scout-ui";
7
+ import "@raggle-ai/scout-ui/styles.css";
8
+
9
+ <ProjectSearchList projects={projects} onSelect={setProject} />;
10
+ ```
11
+
12
+ ## Publishing
13
+
14
+ The package publishes from `.github/workflows/publish.yml` on every push to `main` and from manual workflow dispatch.
15
+
16
+ The workflow validates the package on GitHub-hosted Actions, checks the tarball with `npm pack --dry-run`, and publishes only when the current package version does not already exist on npm.
17
+
18
+ Configure npm trusted publishing for package `@raggle-ai/scout-ui` with GitHub organization `raggle-ai`, repository `scout-ui`, and workflow filename `publish.yml`.
19
+
20
+ npm trusted publishing supports GitHub-hosted runners. The publish job uses `ubuntu-latest` instead of Blacksmith so npm can verify the OIDC token.
@@ -0,0 +1,3 @@
1
+ export { ProjectSearchList } from "./project-search-list.js";
2
+ export type { ProjectSearchItem, ProjectSearchListProps, } from "./project-search-list.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { ProjectSearchList } from "./project-search-list.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface ProjectSearchItem {
2
+ id: string;
3
+ name: string;
4
+ worktree: string;
5
+ parentFolders?: string;
6
+ repositoryLabel?: string;
7
+ iconUrl?: string;
8
+ currentBranch?: string;
9
+ }
10
+ export interface ProjectSearchListProps<Project extends ProjectSearchItem> {
11
+ projects: readonly Project[];
12
+ selectedProjectId?: string | null;
13
+ onSelect(project: Project): void;
14
+ placeholder?: string;
15
+ emptyMessage?: string;
16
+ ariaLabel?: string;
17
+ autoFocus?: boolean;
18
+ maxResults?: number;
19
+ }
20
+ export declare function ProjectSearchList<Project extends ProjectSearchItem>({ projects, selectedProjectId, onSelect, placeholder, emptyMessage, ariaLabel, autoFocus, maxResults, }: ProjectSearchListProps<Project>): import("react").JSX.Element;
21
+ //# sourceMappingURL=project-search-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-search-list.d.ts","sourceRoot":"","sources":["../src/project-search-list.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,iBAAiB;IACvE,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,iBAAiB,EAAE,EACnE,QAAQ,EACR,iBAAwB,EACxB,QAAQ,EACR,WAAkC,EAClC,YAAmC,EACnC,SAA6B,EAC7B,SAAgB,EAChB,UAAqC,GACtC,EAAE,sBAAsB,CAAC,OAAO,CAAC,+BAiHjC"}
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
3
+ export function ProjectSearchList({ projects, selectedProjectId = null, onSelect, placeholder = "Search projects...", emptyMessage = "No projects found.", ariaLabel = "Search projects", autoFocus = true, maxResults = Number.POSITIVE_INFINITY, }) {
4
+ const [search, setSearch] = useState("");
5
+ const [activeIndex, setActiveIndex] = useState(0);
6
+ const listRef = useRef(null);
7
+ const normalizedSearch = search.trim().toLowerCase();
8
+ const filtered = useMemo(() => projects.filter((project) => !normalizedSearch ||
9
+ project.name.toLowerCase().includes(normalizedSearch) ||
10
+ project.worktree.toLowerCase().includes(normalizedSearch)), [normalizedSearch, projects]);
11
+ const visible = useMemo(() => filtered.slice(0, maxResults), [filtered, maxResults]);
12
+ useEffect(() => setActiveIndex(0), [search]);
13
+ const selectActiveProject = useCallback(() => {
14
+ const project = visible[Math.max(0, Math.min(activeIndex, visible.length - 1))];
15
+ if (project)
16
+ onSelect(project);
17
+ }, [activeIndex, onSelect, visible]);
18
+ const handleKeyDown = useCallback((event) => {
19
+ if (event.key === "ArrowDown") {
20
+ event.preventDefault();
21
+ setActiveIndex((previous) => Math.min(previous + 1, Math.max(0, visible.length - 1)));
22
+ }
23
+ else if (event.key === "ArrowUp") {
24
+ event.preventDefault();
25
+ setActiveIndex((previous) => Math.max(previous - 1, 0));
26
+ }
27
+ else if (event.key === "Enter") {
28
+ event.preventDefault();
29
+ selectActiveProject();
30
+ }
31
+ }, [selectActiveProject, visible.length]);
32
+ useEffect(() => {
33
+ const activeElement = listRef.current?.querySelector('[data-active="true"]');
34
+ activeElement?.scrollIntoView({ block: "nearest" });
35
+ }, [activeIndex]);
36
+ return (_jsx("div", { className: "scout-project-search", onKeyDown: handleKeyDown, children: _jsxs("ul", { ref: listRef, className: "scout-project-list", role: "listbox", "aria-label": ariaLabel, children: [_jsx("li", { className: "scout-project-search-row", children: _jsx("input", { className: "scout-project-search-input", placeholder: placeholder, value: search, onChange: (event) => setSearch(event.target.value), autoFocus: autoFocus }) }), filtered.length === 0 && (_jsx("li", { className: "scout-project-empty", children: emptyMessage })), visible.map((project, index) => (_jsx("li", { role: "option", "aria-selected": selectedProjectId === project.id, children: _jsxs("button", { type: "button", className: `scout-project-option${selectedProjectId === project.id ? " is-selected" : ""}${index === activeIndex ? " is-active" : ""}`, "data-active": index === activeIndex, onClick: () => onSelect(project), children: [_jsxs("span", { className: "scout-project-option-left", children: [project.iconUrl && (_jsx("img", { className: "scout-project-option-icon", src: project.iconUrl, alt: "" })), _jsxs("span", { className: "scout-project-option-title", children: [_jsx("span", { className: "scout-project-option-name", children: project.name }), project.parentFolders && (_jsx("span", { className: "scout-project-option-subtitle", children: project.parentFolders }))] })] }), _jsx("span", { className: "scout-project-option-repository", children: project.repositoryLabel ?? project.currentBranch ?? "" })] }) }, project.id)))] }) }));
37
+ }
38
+ //# sourceMappingURL=project-search-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-search-list.js","sourceRoot":"","sources":["../src/project-search-list.tsx"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@raggle-ai/scout-ui",
3
+ "version": "0.1.0",
4
+ "description": "Reusable React project search components for Raggle Scout",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/raggle-ai/scout-ui.git"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ },
18
+ "./styles.css": "./src/styles.css"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "src/styles.css",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "prebuild": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
27
+ "build": "tsc -p tsconfig.json",
28
+ "prepack": "npm run build",
29
+ "publish:ci": "node scripts/publish-ci.mjs",
30
+ "typecheck": "tsc -p tsconfig.json --noEmit",
31
+ "lint": "prettier --check \"src/**/*.{ts,tsx,css}\"",
32
+ "fix-lint": "prettier --write \"src/**/*.{ts,tsx,css}\""
33
+ },
34
+ "peerDependencies": {
35
+ "react": ">=18"
36
+ },
37
+ "devDependencies": {
38
+ "@types/react": "^19.0.10",
39
+ "prettier": "^3.9.6",
40
+ "react": "^19.0.0",
41
+ "typescript": "^5.8.2"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }
package/src/styles.css ADDED
@@ -0,0 +1,140 @@
1
+ .scout-project-search {
2
+ box-sizing: border-box;
3
+ width: 100%;
4
+ height: 100%;
5
+ overflow: hidden;
6
+ background: var(--scout-project-shell, #fff);
7
+ color: var(--scout-project-text, #17181c);
8
+ font-family:
9
+ ui-sans-serif,
10
+ system-ui,
11
+ -apple-system,
12
+ sans-serif;
13
+ font-size: 14px;
14
+ }
15
+
16
+ .scout-project-search *,
17
+ .scout-project-search *::before,
18
+ .scout-project-search *::after {
19
+ box-sizing: border-box;
20
+ }
21
+
22
+ .scout-project-list {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 2px;
26
+ width: 100%;
27
+ height: 100%;
28
+ margin: 0;
29
+ padding: 4px;
30
+ overflow-y: auto;
31
+ list-style: none;
32
+ }
33
+
34
+ .scout-project-search-row {
35
+ position: sticky;
36
+ top: 0;
37
+ z-index: 2;
38
+ padding: 8px 8px 4px;
39
+ background: var(--scout-project-shell, #fff);
40
+ }
41
+
42
+ .scout-project-search-input {
43
+ width: 100%;
44
+ border: 1px solid var(--scout-project-border, #e4e6ea);
45
+ border-radius: 8px;
46
+ background: var(--scout-project-field, #f3f4f6);
47
+ color: var(--scout-project-text, #17181c);
48
+ padding: 6px 8px;
49
+ font: inherit;
50
+ font-size: 12px;
51
+ }
52
+
53
+ .scout-project-search-input:focus {
54
+ border-color: var(--scout-project-accent, #3565e0);
55
+ outline: none;
56
+ }
57
+
58
+ .scout-project-option {
59
+ display: grid;
60
+ grid-template-columns: minmax(0, 1fr) auto;
61
+ align-items: center;
62
+ gap: 16px;
63
+ width: 100%;
64
+ min-height: 40px;
65
+ border: 0;
66
+ border-radius: 8px;
67
+ background: transparent;
68
+ color: inherit;
69
+ padding: 6px 8px;
70
+ font: inherit;
71
+ text-align: left;
72
+ cursor: pointer;
73
+ }
74
+
75
+ .scout-project-option:hover,
76
+ .scout-project-option.is-active {
77
+ background: var(--scout-project-active, #d8d8d9);
78
+ }
79
+
80
+ .scout-project-option.is-selected {
81
+ color: var(--scout-project-accent, #3565e0);
82
+ }
83
+
84
+ .scout-project-option-left {
85
+ display: flex;
86
+ align-items: center;
87
+ gap: 8px;
88
+ min-width: 0;
89
+ }
90
+
91
+ .scout-project-option-icon {
92
+ width: 20px;
93
+ height: 20px;
94
+ flex: none;
95
+ border-radius: 4px;
96
+ object-fit: cover;
97
+ }
98
+
99
+ .scout-project-option-title {
100
+ display: flex;
101
+ align-items: baseline;
102
+ gap: 10px;
103
+ min-width: 0;
104
+ }
105
+
106
+ .scout-project-option-name,
107
+ .scout-project-option-subtitle,
108
+ .scout-project-option-repository {
109
+ overflow: hidden;
110
+ text-overflow: ellipsis;
111
+ white-space: nowrap;
112
+ }
113
+
114
+ .scout-project-option-name {
115
+ min-width: 0;
116
+ color: var(--scout-project-name, #111318);
117
+ font-size: 13px;
118
+ font-weight: 600;
119
+ }
120
+
121
+ .scout-project-option-subtitle {
122
+ min-width: 0;
123
+ color: var(--scout-project-muted, #737883);
124
+ font-size: 12px;
125
+ font-weight: 500;
126
+ }
127
+
128
+ .scout-project-option-repository {
129
+ max-width: 220px;
130
+ color: var(--scout-project-repository, #626873);
131
+ font-size: 12px;
132
+ font-weight: 500;
133
+ text-align: right;
134
+ }
135
+
136
+ .scout-project-empty {
137
+ padding: 8px;
138
+ color: var(--scout-project-muted, #737883);
139
+ font-size: 12px;
140
+ }