@david-xpn/llm-ui-feedback 0.1.3 → 0.1.5

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.d.mts CHANGED
@@ -59,8 +59,8 @@ interface CapturedContext {
59
59
  interface FeedbackWidgetProps {
60
60
  /** Tenant identifier — required. */
61
61
  clientId: string;
62
- /** Backend API URL. Defaults to the production Lambda Function URL. */
63
- apiUrl?: string;
62
+ /** Backend API URL required. */
63
+ apiUrl: string;
64
64
  /** Corner position for the floating button. Default: 'bottom-right' */
65
65
  position?: WidgetPosition;
66
66
  /** Hex color for the FAB accent. Default: '#3b82f6' */
package/dist/index.d.ts CHANGED
@@ -59,8 +59,8 @@ interface CapturedContext {
59
59
  interface FeedbackWidgetProps {
60
60
  /** Tenant identifier — required. */
61
61
  clientId: string;
62
- /** Backend API URL. Defaults to the production Lambda Function URL. */
63
- apiUrl?: string;
62
+ /** Backend API URL required. */
63
+ apiUrl: string;
64
64
  /** Corner position for the floating button. Default: 'bottom-right' */
65
65
  position?: WidgetPosition;
66
66
  /** Hex color for the FAB accent. Default: '#3b82f6' */
package/dist/index.js CHANGED
@@ -826,13 +826,23 @@ function DraftModal({ pendingContext, addingDraft, onAdd, onCancel }) {
826
826
  // src/components/SubmitModal.tsx
827
827
  var import_react5 = require("react");
828
828
  var import_jsx_runtime6 = require("react/jsx-runtime");
829
- function SubmitModal({ count, onSubmit, onCancel, submitting }) {
829
+ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedUrl }) {
830
830
  const [title, setTitle] = (0, import_react5.useState)("");
831
+ const [copied, setCopied] = (0, import_react5.useState)(false);
831
832
  const handleSubmit = () => {
832
833
  if (title.trim() && !submitting) {
833
834
  onSubmit(title.trim());
834
835
  }
835
836
  };
837
+ const handleCopy = async () => {
838
+ if (!submittedUrl) return;
839
+ try {
840
+ await navigator.clipboard.writeText(submittedUrl);
841
+ setCopied(true);
842
+ setTimeout(() => setCopied(false), 2e3);
843
+ } catch {
844
+ }
845
+ };
836
846
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
837
847
  "div",
838
848
  {
@@ -847,9 +857,12 @@ function SubmitModal({ count, onSubmit, onCancel, submitting }) {
847
857
  fontFamily: "system-ui, sans-serif"
848
858
  },
849
859
  onClick: (e) => {
850
- if (e.target === e.currentTarget && !submitting) onCancel();
860
+ if (e.target === e.currentTarget) {
861
+ if (submittedUrl) onDone();
862
+ else if (!submitting) onCancel();
863
+ }
851
864
  },
852
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
865
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
853
866
  "div",
854
867
  {
855
868
  style: {
@@ -860,7 +873,64 @@ function SubmitModal({ count, onSubmit, onCancel, submitting }) {
860
873
  maxWidth: "90vw",
861
874
  boxShadow: "0 8px 32px rgba(0,0,0,0.2)"
862
875
  },
863
- children: [
876
+ children: submittedUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
877
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { margin: "0 0 16px", fontSize: 16 }, children: "Feedback Submitted" }),
878
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { margin: "0 0 12px", fontSize: 14, color: "#6b7280" }, children: "Share this link to view the feedback:" }),
879
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
881
+ "input",
882
+ {
883
+ type: "text",
884
+ value: submittedUrl,
885
+ readOnly: true,
886
+ onFocus: (e) => e.target.select(),
887
+ style: {
888
+ flex: 1,
889
+ padding: 10,
890
+ borderRadius: 8,
891
+ border: "1px solid #d1d5db",
892
+ fontSize: 13,
893
+ boxSizing: "border-box",
894
+ color: "#374151",
895
+ background: "#f9fafb"
896
+ }
897
+ }
898
+ ),
899
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
900
+ "button",
901
+ {
902
+ onClick: handleCopy,
903
+ style: {
904
+ padding: "8px 14px",
905
+ borderRadius: 8,
906
+ border: "1px solid #d1d5db",
907
+ background: copied ? "#dcfce7" : "#f3f4f6",
908
+ color: copied ? "#166534" : "#374151",
909
+ fontSize: 13,
910
+ cursor: "pointer",
911
+ whiteSpace: "nowrap"
912
+ },
913
+ children: copied ? "Copied!" : "Copy"
914
+ }
915
+ )
916
+ ] }),
917
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
918
+ "button",
919
+ {
920
+ onClick: onDone,
921
+ style: {
922
+ padding: "8px 16px",
923
+ borderRadius: 6,
924
+ border: "none",
925
+ background: "#3b82f6",
926
+ color: "#fff",
927
+ fontSize: 13,
928
+ cursor: "pointer"
929
+ },
930
+ children: "Done"
931
+ }
932
+ ) })
933
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
864
934
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { style: { margin: "0 0 16px", fontSize: 16 }, children: "Submit Feedback" }),
865
935
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: { margin: "0 0 12px", fontSize: 14, color: "#6b7280" }, children: [
866
936
  count,
@@ -925,7 +995,7 @@ function SubmitModal({ count, onSubmit, onCancel, submitting }) {
925
995
  }
926
996
  )
927
997
  ] })
928
- ]
998
+ ] })
929
999
  }
930
1000
  )
931
1001
  }
@@ -1214,9 +1284,6 @@ function createApiClient(apiUrl, clientId) {
1214
1284
  };
1215
1285
  }
1216
1286
 
1217
- // src/config.ts
1218
- var DEFAULT_API_URL = "https://your-lambda-function-url.lambda-url.us-east-1.on.aws";
1219
-
1220
1287
  // src/components/FeedbackWidget.tsx
1221
1288
  var import_jsx_runtime7 = require("react/jsx-runtime");
1222
1289
  var CONTAINER_ID = "llm-ui-feedback-root";
@@ -1237,7 +1304,8 @@ var initialState = {
1237
1304
  selectedDraftIds: /* @__PURE__ */ new Set(),
1238
1305
  submitModalOpen: false,
1239
1306
  addingDraft: false,
1240
- submitting: false
1307
+ submitting: false,
1308
+ submittedShareUrl: null
1241
1309
  };
1242
1310
  function widgetReducer(state, action) {
1243
1311
  switch (action.type) {
@@ -1282,12 +1350,15 @@ function widgetReducer(state, action) {
1282
1350
  return { ...state, submitModalOpen: false };
1283
1351
  case "SET_SUBMITTING":
1284
1352
  return { ...state, submitting: action.submitting };
1353
+ case "SUBMIT_SUCCESS":
1354
+ return { ...state, submitting: false, submittedShareUrl: action.shareUrl };
1285
1355
  case "SUBMIT_COMPLETE": {
1286
1356
  const submitted = new Set(action.submittedIds);
1287
1357
  return {
1288
1358
  ...state,
1289
1359
  submitting: false,
1290
1360
  submitModalOpen: false,
1361
+ submittedShareUrl: null,
1291
1362
  drafts: state.drafts.filter((d) => !submitted.has(d.id)),
1292
1363
  selectedDraftIds: /* @__PURE__ */ new Set()
1293
1364
  };
@@ -1316,7 +1387,7 @@ function isEditableTarget(el) {
1316
1387
  }
1317
1388
  function FeedbackWidget({
1318
1389
  clientId,
1319
- apiUrl = DEFAULT_API_URL,
1390
+ apiUrl,
1320
1391
  position = "bottom-right",
1321
1392
  buttonColor = "#3b82f6",
1322
1393
  hotkey
@@ -1465,16 +1536,24 @@ function FeedbackWidget({
1465
1536
  });
1466
1537
  }
1467
1538
  }, [api]);
1539
+ const submittedDraftIdsRef = (0, import_react7.useRef)([]);
1468
1540
  const handleSubmit = (0, import_react7.useCallback)(async (title) => {
1469
1541
  dispatch({ type: "SET_SUBMITTING", submitting: true });
1470
1542
  const draftIds = Array.from(state.selectedDraftIds);
1543
+ submittedDraftIdsRef.current = draftIds;
1471
1544
  try {
1472
- await api.submitSession({ title, draftIds });
1473
- dispatch({ type: "SUBMIT_COMPLETE", submittedIds: draftIds });
1545
+ const result = await api.submitSession({ title, draftIds });
1546
+ const group = result.feedbackGroup;
1547
+ const shareUrl = group.shareToken ? `${apiUrl}/feedback-groups/${group.id}/markdown?token=${group.shareToken}` : "";
1548
+ dispatch({ type: "SUBMIT_SUCCESS", shareUrl });
1474
1549
  } catch {
1475
1550
  dispatch({ type: "SET_SUBMITTING", submitting: false });
1476
1551
  }
1477
- }, [state.selectedDraftIds, api]);
1552
+ }, [state.selectedDraftIds, api, apiUrl]);
1553
+ const handleSubmitDone = (0, import_react7.useCallback)(() => {
1554
+ dispatch({ type: "SUBMIT_COMPLETE", submittedIds: submittedDraftIdsRef.current });
1555
+ submittedDraftIdsRef.current = [];
1556
+ }, []);
1478
1557
  if (session.status === "loading") return null;
1479
1558
  return (0, import_react_dom.createPortal)(
1480
1559
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
@@ -1521,7 +1600,9 @@ function FeedbackWidget({
1521
1600
  count: state.selectedDraftIds.size,
1522
1601
  onSubmit: handleSubmit,
1523
1602
  onCancel: () => dispatch({ type: "CLOSE_SUBMIT_MODAL" }),
1524
- submitting: state.submitting
1603
+ onDone: handleSubmitDone,
1604
+ submitting: state.submitting,
1605
+ submittedUrl: state.submittedShareUrl
1525
1606
  }
1526
1607
  )
1527
1608
  ] }),