hocmai-feedback-widget 0.2.1 → 0.2.3

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.
Files changed (59) hide show
  1. package/README.md +78 -113
  2. package/dist/capture/device-detection.d.ts +13 -0
  3. package/dist/capture/fonts.d.ts +4 -0
  4. package/dist/capture/index.d.ts +14 -0
  5. package/dist/capture/mathjax-fonts.d.ts +5 -0
  6. package/dist/capture/types.d.ts +25 -0
  7. package/dist/ckeditor.mjs +113 -0
  8. package/dist/ckeditor.mjs.map +1 -0
  9. package/dist/components/CkEditor.d.ts +14 -0
  10. package/dist/components/FeedbackWidget.d.ts +13 -1
  11. package/dist/context/FeedbackContext.d.ts +14 -2
  12. package/dist/hocmai-feedback-widget.mjs +7550 -0
  13. package/dist/hocmai-feedback-widget.mjs.map +1 -0
  14. package/dist/index.d.ts +4 -2
  15. package/package.json +39 -29
  16. package/src/App.tsx +147 -58
  17. package/src/capture/device-detection.ts +52 -0
  18. package/src/capture/fonts.ts +34 -0
  19. package/src/capture/index.ts +361 -0
  20. package/src/capture/mathjax-fonts.ts +143 -0
  21. package/src/capture/types.ts +34 -0
  22. package/src/ckeditor.d.ts +14 -0
  23. package/src/components/CkEditor.tsx +130 -0
  24. package/src/components/CropOverlay.tsx +29 -47
  25. package/src/components/FeedbackWidget.tsx +105 -93
  26. package/src/context/FeedbackContext.tsx +49 -9
  27. package/src/index.ts +9 -3
  28. package/src/main.tsx +7 -9
  29. package/src/utils/device.ts +14 -14
  30. package/dist/support-feedback-lib.es.js +0 -3946
  31. package/dist/support-feedback-lib.umd.js +0 -84
  32. package/dist/test-mobile-screenshot.html +0 -211
  33. package/dist/test-simple-capture.html +0 -107
  34. package/dist/utils/screenshot/background-renderer.d.ts +0 -3
  35. package/dist/utils/screenshot/canvas-renderer.d.ts +0 -9
  36. package/dist/utils/screenshot/cleanup.d.ts +0 -3
  37. package/dist/utils/screenshot/device-detection.d.ts +0 -16
  38. package/dist/utils/screenshot/element-collector.d.ts +0 -10
  39. package/dist/utils/screenshot/image-renderer.d.ts +0 -21
  40. package/dist/utils/screenshot/performance.d.ts +0 -3
  41. package/dist/utils/screenshot/svg-renderer.d.ts +0 -24
  42. package/dist/utils/screenshot/text-renderer.d.ts +0 -23
  43. package/dist/utils/screenshot/types.d.ts +0 -35
  44. package/dist/utils/screenshot.d.ts +0 -9
  45. package/dist/vite.svg +0 -1
  46. package/src/App.css +0 -42
  47. package/src/assets/react.svg +0 -1
  48. package/src/index.css +0 -68
  49. package/src/utils/screenshot/background-renderer.ts +0 -54
  50. package/src/utils/screenshot/canvas-renderer.ts +0 -343
  51. package/src/utils/screenshot/cleanup.ts +0 -32
  52. package/src/utils/screenshot/device-detection.ts +0 -90
  53. package/src/utils/screenshot/element-collector.ts +0 -134
  54. package/src/utils/screenshot/image-renderer.ts +0 -148
  55. package/src/utils/screenshot/performance.ts +0 -57
  56. package/src/utils/screenshot/svg-renderer.ts +0 -149
  57. package/src/utils/screenshot/text-renderer.ts +0 -212
  58. package/src/utils/screenshot/types.ts +0 -40
  59. package/src/utils/screenshot.ts +0 -83
@@ -1,8 +1,20 @@
1
1
  import React, { createContext, useContext, useState, type ReactNode } from 'react';
2
2
  import FeedbackWidget, { type FeedbackData } from '../components/FeedbackWidget';
3
+ import type { CkEditorProps } from '../components/CkEditor';
4
+
5
+ export type FeedbackSubmitHandler = (data: FeedbackData) => Promise<void> | void;
3
6
 
4
7
  interface FeedbackContextType {
5
- openFeedback: (questionId: string | number, contextData?: any) => void;
8
+ /**
9
+ * Open the report form.
10
+ * @param onSubmit optional per-call handler; overrides the Provider's onSubmit
11
+ * for this submission. Lets you handle submit from anywhere.
12
+ */
13
+ openFeedback: (
14
+ questionId: string | number,
15
+ contextData?: any,
16
+ onSubmit?: FeedbackSubmitHandler
17
+ ) => void;
6
18
  closeFeedback: () => void;
7
19
  isOpen: boolean;
8
20
  activeQuestionId: string | number | null;
@@ -20,47 +32,75 @@ export const useFeedback = () => {
20
32
 
21
33
  interface FeedbackProviderProps {
22
34
  children: ReactNode;
23
- onSubmit: (data: FeedbackData) => Promise<void>;
35
+ /** Default submit handler. Optional — you can instead pass one per call via openFeedback. */
36
+ onSubmit?: FeedbackSubmitHandler;
24
37
  themeColor?: string;
38
+ /** Use the rich-text editor for the description instead of a plain textarea. */
39
+ isCkEditor?: boolean;
40
+ /** Editor component for the description (from `hocmai-feedback-widget/ckeditor` or your own). */
41
+ descriptionEditor?: React.ComponentType<CkEditorProps>;
25
42
  }
26
43
 
27
44
  export const FeedbackProvider: React.FC<FeedbackProviderProps> = ({
28
45
  children,
29
46
  onSubmit,
30
- themeColor
47
+ themeColor,
48
+ isCkEditor,
49
+ descriptionEditor,
31
50
  }) => {
32
51
  const [isOpen, setIsOpen] = useState(false);
33
52
  const [activeQuestionId, setActiveQuestionId] = useState<string | number | null>(null);
34
53
  const [activeContextData, setActiveContextData] = useState<any>(undefined);
54
+ // Per-call submit handler set by openFeedback (stored via updater so React
55
+ // doesn't treat the function as a state initializer).
56
+ const [activeOnSubmit, setActiveOnSubmit] = useState<FeedbackSubmitHandler | undefined>(undefined);
35
57
 
36
- const openFeedback = (questionId: string | number, contextData?: any) => {
58
+ const openFeedback = (
59
+ questionId: string | number,
60
+ contextData?: any,
61
+ perCallOnSubmit?: FeedbackSubmitHandler
62
+ ) => {
37
63
  setActiveQuestionId(questionId);
38
64
  setActiveContextData(contextData);
65
+ setActiveOnSubmit(() => perCallOnSubmit);
39
66
  setIsOpen(true);
40
67
  };
41
68
 
42
69
  const closeFeedback = () => {
43
70
  setIsOpen(false);
44
- // Optional: Reset active ID after animation, but keeping it ensures state doesn't flicker during close
71
+ };
72
+
73
+ // Resolve handler: per-call → Provider → warn (never crash).
74
+ const effectiveOnSubmit: FeedbackSubmitHandler = async (data) => {
75
+ const handler = activeOnSubmit ?? onSubmit;
76
+ if (!handler) {
77
+ console.warn(
78
+ '[feedback-widget] Bỏ qua gửi báo lỗi: chưa cung cấp onSubmit (ở FeedbackProvider hoặc openFeedback). Dữ liệu:',
79
+ data
80
+ );
81
+ return;
82
+ }
83
+ await handler(data);
45
84
  };
46
85
 
47
86
  return (
48
87
  <FeedbackContext.Provider value={{ openFeedback, closeFeedback, isOpen, activeQuestionId }}>
49
88
  {children}
50
89
 
51
- {/* The Single Global Widget */}
90
+ {/* The single global widget */}
52
91
  {activeQuestionId && (
53
92
  <FeedbackWidget
54
93
  questionId={activeQuestionId}
55
94
  contextData={activeContextData}
56
- onSubmit={onSubmit}
95
+ onSubmit={effectiveOnSubmit}
57
96
  themeColor={themeColor}
97
+ isCkEditor={isCkEditor}
98
+ descriptionEditor={descriptionEditor}
58
99
  isOpen={isOpen}
59
100
  onClose={closeFeedback}
60
- // We don't need triggerComponent here because triggers are distributed
61
101
  triggerComponent={<></>}
62
102
  />
63
103
  )}
64
104
  </FeedbackContext.Provider>
65
105
  );
66
- };
106
+ };
package/src/index.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  export { default as FeedbackWidget } from './components/FeedbackWidget';
2
2
  export type { FeedbackData, FeedbackProps } from './components/FeedbackWidget';
3
+ export type { CkEditorProps } from './components/CkEditor';
3
4
  export { FeedbackProvider, useFeedback } from './context/FeedbackContext';
5
+ export type { FeedbackSubmitHandler } from './context/FeedbackContext';
4
6
 
5
- // Export screenshot utilities
6
- export { captureScreenshot } from './utils/screenshot';
7
- export type { Rect, CaptureProgress } from './utils/screenshot/types';
7
+ // Screenshot utilities (MathJax-CHTML aware, snapdom-based)
8
+ export {
9
+ captureScreenshot,
10
+ captureScreenshotWithOptions,
11
+ prewarmCapture,
12
+ } from './capture';
13
+ export type { Rect, CaptureProgress, CaptureOptions } from './capture/types';
package/src/main.tsx CHANGED
@@ -1,10 +1,8 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import './index.css'
4
- import App from './App.tsx'
1
+ import ReactDOM from 'react-dom/client';
2
+ import App from './App';
5
3
 
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <App />
9
- </StrictMode>,
10
- )
4
+ // NOTE: No <React.StrictMode> on purpose. In dev, StrictMode double-mounts
5
+ // components, and @ckeditor/ckeditor5-react creates a second editor instance
6
+ // during the remount (its async destroy hasn't finished) — showing TWO editors.
7
+ // The host app runs without StrictMode, so this matches production behaviour.
8
+ ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
@@ -1,22 +1,22 @@
1
1
  import { UAParser } from 'ua-parser-js';
2
2
 
3
3
  export interface DeviceInfo {
4
- os: string;
5
- osVersion: string;
6
- browser: string;
7
- browserVersion: string;
8
- deviceType: string;
4
+ os: string;
5
+ osVersion: string;
6
+ browser: string;
7
+ browserVersion: string;
8
+ deviceType: string;
9
9
  }
10
10
 
11
11
  export const getDeviceInfo = (): DeviceInfo => {
12
- const parser = new UAParser();
13
- const result = parser.getResult();
12
+ const parser = new UAParser();
13
+ const result = parser.getResult();
14
14
 
15
- return {
16
- os: result.os.name || 'unknown',
17
- osVersion: result.os.version || 'unknown',
18
- browser: result.browser.name || 'unknown',
19
- browserVersion: result.browser.version || 'unknown',
20
- deviceType: result.device.type || 'desktop', // Default to desktop if empty (common for desktop browsers)
21
- };
15
+ return {
16
+ os: result.os.name || 'unknown',
17
+ osVersion: result.os.version || 'unknown',
18
+ browser: result.browser.name || 'unknown',
19
+ browserVersion: result.browser.version || 'unknown',
20
+ deviceType: result.device.type || 'desktop',
21
+ };
22
22
  };