@david-xpn/llm-ui-feedback 0.1.15 → 0.1.16

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/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/FeedbackWidget.tsx
2
- import { useReducer, useCallback as useCallback4, useEffect as useEffect5, useMemo, useRef as useRef3 } from "react";
2
+ import { useReducer, useCallback as useCallback4, useEffect as useEffect5, useMemo, useRef as useRef4 } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
 
5
5
  // src/utils/color.ts
@@ -513,7 +513,7 @@ function SidePanel({
513
513
  "Feedback Session",
514
514
  /* @__PURE__ */ jsxs4("span", { style: { fontSize: 11, fontWeight: 400, color: "#9ca3af", marginLeft: 6 }, children: [
515
515
  "v",
516
- "0.1.15"
516
+ "0.1.16"
517
517
  ] })
518
518
  ] }),
519
519
  /* @__PURE__ */ jsx4(
@@ -933,7 +933,7 @@ Comment: ${comment.trim()}`] : []
933
933
  }
934
934
 
935
935
  // src/components/SubmitModal.tsx
936
- import { useState as useState5, useEffect as useEffect3 } from "react";
936
+ import { useState as useState5, useEffect as useEffect3, useRef as useRef2 } from "react";
937
937
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
938
938
  function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedUrl, api }) {
939
939
  const [title, setTitle] = useState5("");
@@ -946,6 +946,10 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
946
946
  const [projects, setProjects] = useState5([]);
947
947
  const [labels, setLabels] = useState5([]);
948
948
  const [selectedProjectId, setSelectedProjectId] = useState5("");
949
+ const [projectSearch, setProjectSearch] = useState5("");
950
+ const [projectDropdownOpen, setProjectDropdownOpen] = useState5(false);
951
+ const projectInputRef = useRef2(null);
952
+ const projectDropdownRef = useRef2(null);
949
953
  const [selectedLabelIds, setSelectedLabelIds] = useState5([]);
950
954
  const [linearError, setLinearError] = useState5(null);
951
955
  useEffect3(() => {
@@ -962,7 +966,9 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
962
966
  if (cancelled) return;
963
967
  setProjects(p);
964
968
  setLabels(l);
965
- if (p.length > 0) setSelectedProjectId(p[0].id);
969
+ if (p.length > 0) {
970
+ setSelectedProjectId(p[0].id);
971
+ }
966
972
  setLinearLoading(false);
967
973
  });
968
974
  }).catch((err) => {
@@ -979,6 +985,25 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
979
985
  useEffect3(() => {
980
986
  if (!ticketTitleEdited) setTicketTitle(title);
981
987
  }, [title, ticketTitleEdited]);
988
+ useEffect3(() => {
989
+ function handleClickOutside(e) {
990
+ if (projectDropdownRef.current && !projectDropdownRef.current.contains(e.target) && projectInputRef.current && !projectInputRef.current.contains(e.target)) {
991
+ setProjectDropdownOpen(false);
992
+ }
993
+ }
994
+ document.addEventListener("mousedown", handleClickOutside);
995
+ return () => document.removeEventListener("mousedown", handleClickOutside);
996
+ }, []);
997
+ const filteredProjects = projects.filter(
998
+ (p) => p.name.toLowerCase().includes(projectSearch.toLowerCase())
999
+ );
1000
+ const selectedProject = projects.find((p) => p.id === selectedProjectId);
1001
+ const projectDisplayName = (p) => p.name + (p.teams[0] ? ` \u2014 ${p.teams[0].key}` : "");
1002
+ const handleProjectSelect = (p) => {
1003
+ setSelectedProjectId(p.id);
1004
+ setProjectSearch("");
1005
+ setProjectDropdownOpen(false);
1006
+ };
982
1007
  const handleSubmit = () => {
983
1008
  if (!title.trim() || submitting) return;
984
1009
  if (createTicket && linearConfigured && ticketTitle.trim()) {
@@ -1010,7 +1035,8 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
1010
1035
  border: "1px solid #d1d5db",
1011
1036
  fontSize: 14,
1012
1037
  boxSizing: "border-box",
1013
- background: "#fff"
1038
+ background: "#fff",
1039
+ color: "#111827"
1014
1040
  };
1015
1041
  return /* @__PURE__ */ jsx6(
1016
1042
  "div",
@@ -1194,21 +1220,71 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
1194
1220
  }
1195
1221
  )
1196
1222
  ] }),
1197
- /* @__PURE__ */ jsxs6("div", { children: [
1223
+ /* @__PURE__ */ jsxs6("div", { style: { position: "relative" }, children: [
1198
1224
  /* @__PURE__ */ jsx6("label", { style: { display: "block", fontSize: 12, color: "#6b7280", marginBottom: 4 }, children: "Project" }),
1199
- /* @__PURE__ */ jsxs6(
1200
- "select",
1225
+ /* @__PURE__ */ jsx6(
1226
+ "input",
1227
+ {
1228
+ ref: projectInputRef,
1229
+ type: "text",
1230
+ value: projectDropdownOpen ? projectSearch : selectedProject ? projectDisplayName(selectedProject) : "",
1231
+ onChange: (e) => {
1232
+ setProjectSearch(e.target.value);
1233
+ setProjectDropdownOpen(true);
1234
+ },
1235
+ onFocus: () => {
1236
+ setProjectSearch("");
1237
+ setProjectDropdownOpen(true);
1238
+ },
1239
+ placeholder: "Search projects\u2026",
1240
+ style: inputStyle
1241
+ }
1242
+ ),
1243
+ projectDropdownOpen && /* @__PURE__ */ jsx6(
1244
+ "div",
1201
1245
  {
1202
- value: selectedProjectId,
1203
- onChange: (e) => setSelectedProjectId(e.target.value),
1204
- style: { ...inputStyle, appearance: "auto" },
1205
- children: [
1206
- projects.length === 0 && /* @__PURE__ */ jsx6("option", { value: "", children: "(no projects)" }),
1207
- projects.map((p) => /* @__PURE__ */ jsxs6("option", { value: p.id, children: [
1208
- p.name,
1209
- p.teams[0] ? ` \u2014 ${p.teams[0].key}` : ""
1210
- ] }, p.id))
1211
- ]
1246
+ ref: projectDropdownRef,
1247
+ style: {
1248
+ position: "absolute",
1249
+ top: "100%",
1250
+ left: 0,
1251
+ right: 0,
1252
+ maxHeight: 160,
1253
+ overflowY: "auto",
1254
+ background: "#fff",
1255
+ border: "1px solid #d1d5db",
1256
+ borderRadius: 8,
1257
+ boxShadow: "0 4px 12px rgba(0,0,0,0.12)",
1258
+ zIndex: 10,
1259
+ marginTop: 2
1260
+ },
1261
+ children: filteredProjects.length === 0 ? /* @__PURE__ */ jsx6("div", { style: { padding: "8px 12px", fontSize: 13, color: "#9ca3af" }, children: "No matching projects" }) : filteredProjects.map((p) => /* @__PURE__ */ jsxs6(
1262
+ "div",
1263
+ {
1264
+ onClick: () => handleProjectSelect(p),
1265
+ style: {
1266
+ padding: "8px 12px",
1267
+ fontSize: 13,
1268
+ cursor: "pointer",
1269
+ background: p.id === selectedProjectId ? "#eff6ff" : "#fff",
1270
+ color: "#111827"
1271
+ },
1272
+ onMouseEnter: (e) => {
1273
+ e.currentTarget.style.background = "#f3f4f6";
1274
+ },
1275
+ onMouseLeave: (e) => {
1276
+ e.currentTarget.style.background = p.id === selectedProjectId ? "#eff6ff" : "#fff";
1277
+ },
1278
+ children: [
1279
+ p.name,
1280
+ p.teams[0] && /* @__PURE__ */ jsxs6("span", { style: { color: "#9ca3af" }, children: [
1281
+ " \u2014 ",
1282
+ p.teams[0].key
1283
+ ] })
1284
+ ]
1285
+ },
1286
+ p.id
1287
+ ))
1212
1288
  }
1213
1289
  )
1214
1290
  ] }),
@@ -1383,7 +1459,7 @@ ${propsStr}`);
1383
1459
  }
1384
1460
 
1385
1461
  // src/hooks/useSession.ts
1386
- import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef2 } from "react";
1462
+ import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef3 } from "react";
1387
1463
  var SESSION_TOKEN_KEY = "llm_feedback_session_token";
1388
1464
  var USER_KEY = "llm_feedback_user";
1389
1465
  var AUTH_BYPASS = !!(typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__);
@@ -1400,7 +1476,7 @@ var BYPASS_USER = {
1400
1476
  function useSession(apiUrl, clientId) {
1401
1477
  const [status, setStatus] = useState6(AUTH_BYPASS ? "authenticated" : "loading");
1402
1478
  const [user, setUser] = useState6(AUTH_BYPASS ? BYPASS_USER : null);
1403
- const pendingAuthRef = useRef2(false);
1479
+ const pendingAuthRef = useRef3(false);
1404
1480
  useEffect4(() => {
1405
1481
  if (AUTH_BYPASS) return;
1406
1482
  let cancelled = false;
@@ -1683,7 +1759,7 @@ function FeedbackWidget({
1683
1759
  }) {
1684
1760
  const session = useSession(apiUrl, clientId);
1685
1761
  const [state, dispatch] = useReducer(widgetReducer, initialState);
1686
- const pendingOpenRef = useRef3(false);
1762
+ const pendingOpenRef = useRef4(false);
1687
1763
  const api = useMemo(
1688
1764
  () => createApiClient(apiUrl, clientId),
1689
1765
  [apiUrl, clientId]
@@ -1828,7 +1904,7 @@ function FeedbackWidget({
1828
1904
  });
1829
1905
  }
1830
1906
  }, [api]);
1831
- const submittedDraftIdsRef = useRef3([]);
1907
+ const submittedDraftIdsRef = useRef4([]);
1832
1908
  const handleSubmit = useCallback4(async (title, linearTicket) => {
1833
1909
  dispatch({ type: "SET_SUBMITTING", submitting: true });
1834
1910
  const draftIds = Array.from(state.selectedDraftIds);