@kelet-ai/feedback-ui 0.7.0 → 1.0.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 CHANGED
@@ -261,7 +261,7 @@ For implicit feedback, understanding how state changes are processed:
261
261
  // User types: "Hello" → "Hello World" → "Hello World!"
262
262
  // Only sends ONE feedback after user stops typing
263
263
  const [text, setText] = useFeedbackState('', 'editor', {
264
- debounceMs: 1500, // Wait 1.5s after last change
264
+ debounceMs: 3000, // Wait 3s after last change
265
265
  });
266
266
  ```
267
267
 
@@ -535,7 +535,7 @@ interface FeedbackData {
535
535
 
536
536
  | Option | Type | Default | Description |
537
537
  | ---------------------- | ------------------------------------ | --------------------- | -------------------------------------- |
538
- | `debounceMs` | `number` | `1500` | Debounce time in milliseconds |
538
+ | `debounceMs` | `number` | `3000` | Debounce time in milliseconds |
539
539
  | `diffType` | `'git' \| 'object' \| 'json'` | `'git'` | Diff output format |
540
540
  | `compareWith` | `(a: T, b: T) => boolean` | `undefined` | Custom equality function |
541
541
  | `metadata` | `Record<string, any>` | `{}` | Additional metadata |
@@ -8,6 +8,7 @@ interface KeletContextValue {
8
8
  interface KeletProviderProps {
9
9
  apiKey?: string;
10
10
  project: string;
11
+ baseUrl?: string;
11
12
  }
12
13
  export declare const KeletContext: React.Context<KeletContextValue | null>;
13
14
  export declare const useKelet: () => KeletContextValue;
@@ -353,7 +353,7 @@ function requireJsxRuntime() {
353
353
  }
354
354
  var jsxRuntimeExports = requireJsxRuntime();
355
355
  const KeletContext = createContext(null);
356
- const KeletBaseUrl = "https://api.kelet.ai/api";
356
+ const DefaultKeletBaseUrl = "https://api.kelet.ai/api";
357
357
  const useKelet = () => {
358
358
  const context = useContext(KeletContext);
359
359
  if (!context) {
@@ -373,7 +373,7 @@ const useDefaultFeedbackHandler = () => {
373
373
  return context.feedback;
374
374
  }
375
375
  };
376
- const KeletProvider = ({ apiKey, project, children }) => {
376
+ const KeletProvider = ({ apiKey, project, baseUrl, children }) => {
377
377
  const parentContext = useContext(KeletContext);
378
378
  const resolvedApiKey = apiKey || parentContext?.api_key;
379
379
  if (!resolvedApiKey) {
@@ -382,7 +382,8 @@ const KeletProvider = ({ apiKey, project, children }) => {
382
382
  );
383
383
  }
384
384
  const feedback = async (data) => {
385
- const url = `${KeletBaseUrl}/projects/${project}/feedback`;
385
+ const resolvedBaseUrl = baseUrl || DefaultKeletBaseUrl;
386
+ const url = `${resolvedBaseUrl}/projects/${project}/feedback`;
386
387
  const req = {
387
388
  tx_id: data.tx_id,
388
389
  source: data.source || "EXPLICIT",
@@ -1864,7 +1865,7 @@ function splitLines(text) {
1864
1865
  }
1865
1866
  return result;
1866
1867
  }
1867
- function formatDiff(oldValue, newValue, diffType = "git", context = 3) {
1868
+ function formatDiff(oldValue, newValue, diffType = "git", context = 1) {
1868
1869
  switch (diffType) {
1869
1870
  case "git":
1870
1871
  return formatGitDiff(oldValue, newValue, context);
@@ -1876,7 +1877,7 @@ function formatDiff(oldValue, newValue, diffType = "git", context = 3) {
1876
1877
  return formatGitDiff(oldValue, newValue, context);
1877
1878
  }
1878
1879
  }
1879
- function formatGitDiff(oldValue, newValue, context = 3) {
1880
+ function formatGitDiff(oldValue, newValue, context = 1) {
1880
1881
  const oldStr = stringify(oldValue);
1881
1882
  const newStr = stringify(newValue);
1882
1883
  const patch = createTwoFilesPatch(
@@ -1892,7 +1893,20 @@ function formatGitDiff(oldValue, newValue, context = 3) {
1892
1893
  "",
1893
1894
  { context }
1894
1895
  );
1895
- return patch.split("\n").slice(2).join("\n");
1896
+ const lines = patch.split("\n");
1897
+ const filtered = lines.filter((line) => {
1898
+ if (!line) return false;
1899
+ if (line === "\") return false;
1900
+ if (line.startsWith("@@")) return false;
1901
+ if (line.startsWith("---") || line.startsWith("+++")) return false;
1902
+ if (line.startsWith(" ")) return false;
1903
+ if (line.startsWith("+") || line.startsWith("-")) return true;
1904
+ return false;
1905
+ });
1906
+ while (filtered.length && filtered[0].trim() === "") filtered.shift();
1907
+ while (filtered.length && filtered[filtered.length - 1].trim() === "")
1908
+ filtered.pop();
1909
+ return filtered.join("\n");
1896
1910
  }
1897
1911
  function formatObjectDiff(oldValue, newValue) {
1898
1912
  const differences = deepDiffExports.diff(oldValue, newValue) || [];
@@ -2005,19 +2019,22 @@ function stringify(value) {
2005
2019
  function useStateChangeTracking(currentState, tx_id, options) {
2006
2020
  const defaultFeedbackHandler = useDefaultFeedbackHandler();
2007
2021
  const feedbackHandler = options?.onFeedback || defaultFeedbackHandler;
2008
- const debounceMs = options?.debounceMs ?? 1500;
2022
+ const debounceMs = options?.debounceMs ?? 3e3;
2009
2023
  const diffType = options?.diffType ?? "git";
2010
2024
  const compareWith = options?.compareWith;
2011
2025
  const defaultTriggerName = options?.default_trigger_name ?? "auto_state_change";
2012
2026
  const ignoreInitialNullish = options?.ignoreInitialNullish ?? true;
2013
2027
  const prevStateRef = useRef(currentState);
2014
- const changeStartStateRef = useRef(currentState);
2015
2028
  const isFirstRenderRef = useRef(true);
2016
2029
  const initialStateRef = useRef(currentState);
2030
+ const initialWasNullishRef = useRef(currentState == null);
2017
2031
  const hasHadNonNullishStateRef = useRef(
2018
2032
  currentState != null
2019
2033
  // != null catches both null and undefined
2020
2034
  );
2035
+ const hasEligibleBaselineRef = useRef(
2036
+ !(ignoreInitialNullish && currentState == null)
2037
+ );
2021
2038
  const timeoutRef = useRef(null);
2022
2039
  const currentTriggerNameRef = useRef(void 0);
2023
2040
  const sendFeedback = useCallback(
@@ -2052,7 +2069,7 @@ function useStateChangeTracking(currentState, tx_id, options) {
2052
2069
  const newTriggerName = trigger_name || defaultTriggerName;
2053
2070
  if (timeoutRef.current && currentTriggerNameRef.current && currentTriggerNameRef.current !== newTriggerName) {
2054
2071
  clearTimeout(timeoutRef.current);
2055
- const startState = changeStartStateRef.current;
2072
+ const startState = initialStateRef.current;
2056
2073
  const currentStateBeforeChange = currentState;
2057
2074
  sendFeedback(
2058
2075
  startState,
@@ -2069,39 +2086,41 @@ function useStateChangeTracking(currentState, tx_id, options) {
2069
2086
  if (isFirstRenderRef.current) {
2070
2087
  isFirstRenderRef.current = false;
2071
2088
  prevStateRef.current = currentState;
2072
- changeStartStateRef.current = currentState;
2089
+ if (!ignoreInitialNullish || currentState != null) {
2090
+ initialStateRef.current = currentState;
2091
+ hasEligibleBaselineRef.current = true;
2092
+ }
2073
2093
  return;
2074
2094
  }
2075
2095
  const prevState = prevStateRef.current;
2076
2096
  const isEqual = compareWith ? compareWith(prevState, currentState) : JSON.stringify(prevState) === JSON.stringify(currentState);
2077
2097
  if (!isEqual) {
2078
- const shouldIgnoreChange = ignoreInitialNullish && initialStateRef.current == null && // Initial state was nullish
2098
+ const shouldIgnoreChange = ignoreInitialNullish && initialWasNullishRef.current && // True initial state was nullish
2079
2099
  !hasHadNonNullishStateRef.current && // We haven't had non-nullish state before
2080
2100
  currentState != null;
2081
2101
  if (currentState != null) {
2082
2102
  hasHadNonNullishStateRef.current = true;
2083
2103
  }
2084
2104
  if (shouldIgnoreChange) {
2105
+ initialStateRef.current = currentState;
2106
+ hasEligibleBaselineRef.current = true;
2085
2107
  prevStateRef.current = currentState;
2086
- changeStartStateRef.current = currentState;
2087
2108
  return;
2088
2109
  }
2089
- if (!timeoutRef.current) {
2090
- changeStartStateRef.current = prevState;
2091
- }
2092
2110
  if (timeoutRef.current) {
2093
2111
  clearTimeout(timeoutRef.current);
2094
2112
  }
2095
2113
  prevStateRef.current = currentState;
2096
2114
  timeoutRef.current = setTimeout(() => {
2097
- const startState = changeStartStateRef.current;
2115
+ const startState = initialStateRef.current;
2098
2116
  const finalState = currentState;
2099
- sendFeedback(
2100
- startState,
2101
- finalState,
2102
- currentTriggerNameRef.current || defaultTriggerName
2103
- );
2104
- changeStartStateRef.current = finalState;
2117
+ if (hasEligibleBaselineRef.current) {
2118
+ sendFeedback(
2119
+ startState,
2120
+ finalState,
2121
+ currentTriggerNameRef.current || defaultTriggerName
2122
+ );
2123
+ }
2105
2124
  timeoutRef.current = null;
2106
2125
  }, debounceMs);
2107
2126
  }