@cornercue/react 0.1.0-beta.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.cjs +85 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +56 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var core = require('@cornercue/core');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/FeedbackButton.tsx
|
|
8
|
+
var sharedWidget = null;
|
|
9
|
+
var widgetRefCount = 0;
|
|
10
|
+
function getSharedWidget(config) {
|
|
11
|
+
if (!sharedWidget) {
|
|
12
|
+
sharedWidget = new core.CornerCueWidget(config);
|
|
13
|
+
}
|
|
14
|
+
widgetRefCount++;
|
|
15
|
+
return sharedWidget;
|
|
16
|
+
}
|
|
17
|
+
function releaseSharedWidget() {
|
|
18
|
+
widgetRefCount--;
|
|
19
|
+
if (widgetRefCount <= 0 && sharedWidget) {
|
|
20
|
+
sharedWidget.destroy();
|
|
21
|
+
sharedWidget = null;
|
|
22
|
+
widgetRefCount = 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function FeedbackButton({
|
|
26
|
+
projectId,
|
|
27
|
+
user,
|
|
28
|
+
metadata,
|
|
29
|
+
defaultType,
|
|
30
|
+
config,
|
|
31
|
+
// events - reserved for future use
|
|
32
|
+
children,
|
|
33
|
+
className
|
|
34
|
+
}) {
|
|
35
|
+
const triggerRef = react.useRef(null);
|
|
36
|
+
const widgetRef = react.useRef(null);
|
|
37
|
+
react.useEffect(() => {
|
|
38
|
+
widgetRef.current = getSharedWidget(config);
|
|
39
|
+
return () => {
|
|
40
|
+
releaseSharedWidget();
|
|
41
|
+
widgetRef.current = null;
|
|
42
|
+
};
|
|
43
|
+
}, [config]);
|
|
44
|
+
const handleClick = react.useCallback(
|
|
45
|
+
(e) => {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
const widget = widgetRef.current;
|
|
49
|
+
const trigger = triggerRef.current;
|
|
50
|
+
if (!widget || !trigger) return;
|
|
51
|
+
if (widget.isWidgetOpen()) {
|
|
52
|
+
widget.close();
|
|
53
|
+
} else {
|
|
54
|
+
widget.open(trigger, {
|
|
55
|
+
projectId,
|
|
56
|
+
user: user ?? null,
|
|
57
|
+
metadata: metadata ?? null,
|
|
58
|
+
defaultType
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
[projectId, user, metadata, defaultType]
|
|
63
|
+
);
|
|
64
|
+
if (!react.isValidElement(children)) {
|
|
65
|
+
console.warn("FeedbackButton: children must be a valid React element");
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
67
|
+
}
|
|
68
|
+
const childElement = children;
|
|
69
|
+
return react.cloneElement(childElement, {
|
|
70
|
+
ref: triggerRef,
|
|
71
|
+
onClick: (e) => {
|
|
72
|
+
childElement.props.onClick?.(e);
|
|
73
|
+
handleClick(e);
|
|
74
|
+
},
|
|
75
|
+
className: className ? `${childElement.props.className || ""} ${className}`.trim() : childElement.props.className
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Object.defineProperty(exports, "CornerCueWidget", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
get: function () { return core.CornerCueWidget; }
|
|
82
|
+
});
|
|
83
|
+
exports.FeedbackButton = FeedbackButton;
|
|
84
|
+
//# sourceMappingURL=index.cjs.map
|
|
85
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/FeedbackButton.tsx"],"names":["CornerCueWidget","useRef","useEffect","useCallback","isValidElement","cloneElement"],"mappings":";;;;;;;AA+DA,IAAI,YAAA,GAAuC,IAAA;AAC3C,IAAI,cAAA,GAAiB,CAAA;AAErB,SAAS,gBAAgB,MAAA,EAAwC;AAC/D,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,YAAA,GAAe,IAAIA,qBAAgB,MAAM,CAAA;AAAA,EAC3C;AACA,EAAA,cAAA,EAAA;AACA,EAAA,OAAO,YAAA;AACT;AAEA,SAAS,mBAAA,GAA4B;AACnC,EAAA,cAAA,EAAA;AACA,EAAA,IAAI,cAAA,IAAkB,KAAK,YAAA,EAAc;AACvC,IAAA,YAAA,CAAa,OAAA,EAAQ;AACrB,IAAA,YAAA,GAAe,IAAA;AACf,IAAA,cAAA,GAAiB,CAAA;AAAA,EACnB;AACF;AAgBO,SAAS,cAAA,CAAe;AAAA,EAC7B,SAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA;AAAA;AAAA,EAEA,QAAA;AAAA,EACA;AACF,CAAA,EAAsC;AACpC,EAAA,MAAM,UAAA,GAAaC,aAAoB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAYA,aAA+B,IAAI,CAAA;AAGrD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,SAAA,CAAU,OAAA,GAAU,gBAAgB,MAAM,CAAA;AAE1C,IAAA,OAAO,MAAM;AACX,MAAA,mBAAA,EAAoB;AACpB,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AAAA,IACtB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAGX,EAAA,MAAM,WAAA,GAAcC,iBAAA;AAAA,IAClB,CAAC,CAAA,KAAkB;AACjB,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,CAAA,CAAE,eAAA,EAAgB;AAElB,MAAA,MAAM,SAAS,SAAA,CAAU,OAAA;AACzB,MAAA,MAAM,UAAU,UAAA,CAAW,OAAA;AAE3B,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,EAAS;AAEzB,MAAA,IAAI,MAAA,CAAO,cAAa,EAAG;AACzB,QAAA,MAAA,CAAO,KAAA,EAAM;AAAA,MACf,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,OAAA,EAAS;AAAA,UACnB,SAAA;AAAA,UACA,MAAM,IAAA,IAAQ,IAAA;AAAA,UACd,UAAU,QAAA,IAAY,IAAA;AAAA,UACtB;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAA,EAAW,IAAA,EAAM,QAAA,EAAU,WAAW;AAAA,GACzC;AAGA,EAAA,IAAI,CAACC,oBAAA,CAAe,QAAQ,CAAA,EAAG;AAC7B,IAAA,OAAA,CAAQ,KAAK,wDAAwD,CAAA;AACrE,IAAA,6DAAU,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,YAAA,GAAe,QAAA;AAMrB,EAAA,OAAOC,mBAAa,YAAA,EAAc;AAAA,IAChC,GAAA,EAAK,UAAA;AAAA,IACL,OAAA,EAAS,CAAC,CAAA,KAAkB;AAE1B,MAAA,YAAA,CAAa,KAAA,CAAM,UAAU,CAAC,CAAA;AAC9B,MAAA,WAAA,CAAY,CAAC,CAAA;AAAA,IACf,CAAA;AAAA,IACA,SAAA,EAAW,SAAA,GACP,CAAA,EAAG,YAAA,CAAa,KAAA,CAAM,SAAA,IAAa,EAAE,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,GAC1D,aAAa,KAAA,CAAM;AAAA,GACxB,CAAA;AACH","file":"index.cjs","sourcesContent":["import React, {\n useRef,\n useEffect,\n useCallback,\n cloneElement,\n isValidElement,\n type ReactElement,\n type ReactNode,\n type MouseEvent,\n} from \"react\";\nimport {\n CornerCueWidget,\n type WidgetConfig,\n type UserInfo,\n type Metadata,\n type WidgetEvents,\n type FeedbackType,\n} from \"@cornercue/core\";\n\nexport interface FeedbackButtonProps {\n /**\n * Project ID for submissions\n */\n projectId: string;\n\n /**\n * User information to attach to feedback\n */\n user?: UserInfo | null;\n\n /**\n * Additional metadata to attach to feedback\n */\n metadata?: Metadata | null;\n\n /**\n * Default feedback type to open directly (skips menu)\n * Options: 'bug' | 'feature' | 'feedback'\n */\n defaultType?: FeedbackType;\n\n /**\n * Widget configuration overrides\n */\n config?: WidgetConfig;\n\n /**\n * Event callbacks\n */\n events?: WidgetEvents;\n\n /**\n * The trigger element (button, link, etc.)\n */\n children: ReactNode;\n\n /**\n * Additional class name for the wrapper\n */\n className?: string;\n}\n\n// Shared widget instance\nlet sharedWidget: CornerCueWidget | null = null;\nlet widgetRefCount = 0;\n\nfunction getSharedWidget(config?: WidgetConfig): CornerCueWidget {\n if (!sharedWidget) {\n sharedWidget = new CornerCueWidget(config);\n }\n widgetRefCount++;\n return sharedWidget;\n}\n\nfunction releaseSharedWidget(): void {\n widgetRefCount--;\n if (widgetRefCount <= 0 && sharedWidget) {\n sharedWidget.destroy();\n sharedWidget = null;\n widgetRefCount = 0;\n }\n}\n\n/**\n * React component that wraps a trigger element and opens the feedback widget on click.\n *\n * @example\n * ```tsx\n * <FeedbackButton\n * projectId=\"your-project-id\"\n * user={{ id: 'user123', email: 'user@example.com' }}\n * metadata={{ plan: 'pro' }}\n * >\n * <button>Give Feedback</button>\n * </FeedbackButton>\n * ```\n */\nexport function FeedbackButton({\n projectId,\n user,\n metadata,\n defaultType,\n config,\n // events - reserved for future use\n children,\n className,\n}: FeedbackButtonProps): ReactElement {\n const triggerRef = useRef<HTMLElement>(null);\n const widgetRef = useRef<CornerCueWidget | null>(null);\n\n // Initialize widget on mount\n useEffect(() => {\n widgetRef.current = getSharedWidget(config);\n\n return () => {\n releaseSharedWidget();\n widgetRef.current = null;\n };\n }, [config]);\n\n // Handle click on trigger\n const handleClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const widget = widgetRef.current;\n const trigger = triggerRef.current;\n\n if (!widget || !trigger) return;\n\n if (widget.isWidgetOpen()) {\n widget.close();\n } else {\n widget.open(trigger, {\n projectId,\n user: user ?? null,\n metadata: metadata ?? null,\n defaultType,\n });\n }\n },\n [projectId, user, metadata, defaultType]\n );\n\n // Clone the child element to add ref and click handler\n if (!isValidElement(children)) {\n console.warn(\"FeedbackButton: children must be a valid React element\");\n return <>{children}</>;\n }\n\n const childElement = children as ReactElement<{\n ref?: React.Ref<HTMLElement>;\n onClick?: (e: MouseEvent) => void;\n className?: string;\n }>;\n\n return cloneElement(childElement, {\n ref: triggerRef,\n onClick: (e: MouseEvent) => {\n // Call original onClick if present\n childElement.props.onClick?.(e);\n handleClick(e);\n },\n className: className\n ? `${childElement.props.className || \"\"} ${className}`.trim()\n : childElement.props.className,\n });\n}\n\n// Re-export types\nexport type {\n WidgetConfig,\n UserInfo,\n Metadata,\n FeedbackType,\n WidgetEvents,\n OpenOptions,\n} from \"@cornercue/core\";\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
|
+
import { UserInfo, Metadata, FeedbackType, WidgetConfig, WidgetEvents } from '@cornercue/core';
|
|
3
|
+
export { CornerCueWidget, FeedbackType, Metadata, OpenOptions, UserInfo, WidgetConfig, WidgetEvents } from '@cornercue/core';
|
|
4
|
+
|
|
5
|
+
interface FeedbackButtonProps {
|
|
6
|
+
/**
|
|
7
|
+
* Project ID for submissions
|
|
8
|
+
*/
|
|
9
|
+
projectId: string;
|
|
10
|
+
/**
|
|
11
|
+
* User information to attach to feedback
|
|
12
|
+
*/
|
|
13
|
+
user?: UserInfo | null;
|
|
14
|
+
/**
|
|
15
|
+
* Additional metadata to attach to feedback
|
|
16
|
+
*/
|
|
17
|
+
metadata?: Metadata | null;
|
|
18
|
+
/**
|
|
19
|
+
* Default feedback type to open directly (skips menu)
|
|
20
|
+
* Options: 'bug' | 'feature' | 'feedback'
|
|
21
|
+
*/
|
|
22
|
+
defaultType?: FeedbackType;
|
|
23
|
+
/**
|
|
24
|
+
* Widget configuration overrides
|
|
25
|
+
*/
|
|
26
|
+
config?: WidgetConfig;
|
|
27
|
+
/**
|
|
28
|
+
* Event callbacks
|
|
29
|
+
*/
|
|
30
|
+
events?: WidgetEvents;
|
|
31
|
+
/**
|
|
32
|
+
* The trigger element (button, link, etc.)
|
|
33
|
+
*/
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Additional class name for the wrapper
|
|
37
|
+
*/
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* React component that wraps a trigger element and opens the feedback widget on click.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <FeedbackButton
|
|
46
|
+
* projectId="your-project-id"
|
|
47
|
+
* user={{ id: 'user123', email: 'user@example.com' }}
|
|
48
|
+
* metadata={{ plan: 'pro' }}
|
|
49
|
+
* >
|
|
50
|
+
* <button>Give Feedback</button>
|
|
51
|
+
* </FeedbackButton>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function FeedbackButton({ projectId, user, metadata, defaultType, config, children, className, }: FeedbackButtonProps): ReactElement;
|
|
55
|
+
|
|
56
|
+
export { FeedbackButton, type FeedbackButtonProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
|
+
import { UserInfo, Metadata, FeedbackType, WidgetConfig, WidgetEvents } from '@cornercue/core';
|
|
3
|
+
export { CornerCueWidget, FeedbackType, Metadata, OpenOptions, UserInfo, WidgetConfig, WidgetEvents } from '@cornercue/core';
|
|
4
|
+
|
|
5
|
+
interface FeedbackButtonProps {
|
|
6
|
+
/**
|
|
7
|
+
* Project ID for submissions
|
|
8
|
+
*/
|
|
9
|
+
projectId: string;
|
|
10
|
+
/**
|
|
11
|
+
* User information to attach to feedback
|
|
12
|
+
*/
|
|
13
|
+
user?: UserInfo | null;
|
|
14
|
+
/**
|
|
15
|
+
* Additional metadata to attach to feedback
|
|
16
|
+
*/
|
|
17
|
+
metadata?: Metadata | null;
|
|
18
|
+
/**
|
|
19
|
+
* Default feedback type to open directly (skips menu)
|
|
20
|
+
* Options: 'bug' | 'feature' | 'feedback'
|
|
21
|
+
*/
|
|
22
|
+
defaultType?: FeedbackType;
|
|
23
|
+
/**
|
|
24
|
+
* Widget configuration overrides
|
|
25
|
+
*/
|
|
26
|
+
config?: WidgetConfig;
|
|
27
|
+
/**
|
|
28
|
+
* Event callbacks
|
|
29
|
+
*/
|
|
30
|
+
events?: WidgetEvents;
|
|
31
|
+
/**
|
|
32
|
+
* The trigger element (button, link, etc.)
|
|
33
|
+
*/
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Additional class name for the wrapper
|
|
37
|
+
*/
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* React component that wraps a trigger element and opens the feedback widget on click.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <FeedbackButton
|
|
46
|
+
* projectId="your-project-id"
|
|
47
|
+
* user={{ id: 'user123', email: 'user@example.com' }}
|
|
48
|
+
* metadata={{ plan: 'pro' }}
|
|
49
|
+
* >
|
|
50
|
+
* <button>Give Feedback</button>
|
|
51
|
+
* </FeedbackButton>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function FeedbackButton({ projectId, user, metadata, defaultType, config, children, className, }: FeedbackButtonProps): ReactElement;
|
|
55
|
+
|
|
56
|
+
export { FeedbackButton, type FeedbackButtonProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useRef, useEffect, useCallback, isValidElement, cloneElement } from 'react';
|
|
2
|
+
import { CornerCueWidget } from '@cornercue/core';
|
|
3
|
+
export { CornerCueWidget } from '@cornercue/core';
|
|
4
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/FeedbackButton.tsx
|
|
7
|
+
var sharedWidget = null;
|
|
8
|
+
var widgetRefCount = 0;
|
|
9
|
+
function getSharedWidget(config) {
|
|
10
|
+
if (!sharedWidget) {
|
|
11
|
+
sharedWidget = new CornerCueWidget(config);
|
|
12
|
+
}
|
|
13
|
+
widgetRefCount++;
|
|
14
|
+
return sharedWidget;
|
|
15
|
+
}
|
|
16
|
+
function releaseSharedWidget() {
|
|
17
|
+
widgetRefCount--;
|
|
18
|
+
if (widgetRefCount <= 0 && sharedWidget) {
|
|
19
|
+
sharedWidget.destroy();
|
|
20
|
+
sharedWidget = null;
|
|
21
|
+
widgetRefCount = 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function FeedbackButton({
|
|
25
|
+
projectId,
|
|
26
|
+
user,
|
|
27
|
+
metadata,
|
|
28
|
+
defaultType,
|
|
29
|
+
config,
|
|
30
|
+
// events - reserved for future use
|
|
31
|
+
children,
|
|
32
|
+
className
|
|
33
|
+
}) {
|
|
34
|
+
const triggerRef = useRef(null);
|
|
35
|
+
const widgetRef = useRef(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
widgetRef.current = getSharedWidget(config);
|
|
38
|
+
return () => {
|
|
39
|
+
releaseSharedWidget();
|
|
40
|
+
widgetRef.current = null;
|
|
41
|
+
};
|
|
42
|
+
}, [config]);
|
|
43
|
+
const handleClick = useCallback(
|
|
44
|
+
(e) => {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
e.stopPropagation();
|
|
47
|
+
const widget = widgetRef.current;
|
|
48
|
+
const trigger = triggerRef.current;
|
|
49
|
+
if (!widget || !trigger) return;
|
|
50
|
+
if (widget.isWidgetOpen()) {
|
|
51
|
+
widget.close();
|
|
52
|
+
} else {
|
|
53
|
+
widget.open(trigger, {
|
|
54
|
+
projectId,
|
|
55
|
+
user: user ?? null,
|
|
56
|
+
metadata: metadata ?? null,
|
|
57
|
+
defaultType
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[projectId, user, metadata, defaultType]
|
|
62
|
+
);
|
|
63
|
+
if (!isValidElement(children)) {
|
|
64
|
+
console.warn("FeedbackButton: children must be a valid React element");
|
|
65
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
66
|
+
}
|
|
67
|
+
const childElement = children;
|
|
68
|
+
return cloneElement(childElement, {
|
|
69
|
+
ref: triggerRef,
|
|
70
|
+
onClick: (e) => {
|
|
71
|
+
childElement.props.onClick?.(e);
|
|
72
|
+
handleClick(e);
|
|
73
|
+
},
|
|
74
|
+
className: className ? `${childElement.props.className || ""} ${className}`.trim() : childElement.props.className
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { FeedbackButton };
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/FeedbackButton.tsx"],"names":[],"mappings":";;;;;;AA+DA,IAAI,YAAA,GAAuC,IAAA;AAC3C,IAAI,cAAA,GAAiB,CAAA;AAErB,SAAS,gBAAgB,MAAA,EAAwC;AAC/D,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,YAAA,GAAe,IAAI,gBAAgB,MAAM,CAAA;AAAA,EAC3C;AACA,EAAA,cAAA,EAAA;AACA,EAAA,OAAO,YAAA;AACT;AAEA,SAAS,mBAAA,GAA4B;AACnC,EAAA,cAAA,EAAA;AACA,EAAA,IAAI,cAAA,IAAkB,KAAK,YAAA,EAAc;AACvC,IAAA,YAAA,CAAa,OAAA,EAAQ;AACrB,IAAA,YAAA,GAAe,IAAA;AACf,IAAA,cAAA,GAAiB,CAAA;AAAA,EACnB;AACF;AAgBO,SAAS,cAAA,CAAe;AAAA,EAC7B,SAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA;AAAA;AAAA,EAEA,QAAA;AAAA,EACA;AACF,CAAA,EAAsC;AACpC,EAAA,MAAM,UAAA,GAAa,OAAoB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,OAA+B,IAAI,CAAA;AAGrD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,SAAA,CAAU,OAAA,GAAU,gBAAgB,MAAM,CAAA;AAE1C,IAAA,OAAO,MAAM;AACX,MAAA,mBAAA,EAAoB;AACpB,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AAAA,IACtB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAGX,EAAA,MAAM,WAAA,GAAc,WAAA;AAAA,IAClB,CAAC,CAAA,KAAkB;AACjB,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,CAAA,CAAE,eAAA,EAAgB;AAElB,MAAA,MAAM,SAAS,SAAA,CAAU,OAAA;AACzB,MAAA,MAAM,UAAU,UAAA,CAAW,OAAA;AAE3B,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,OAAA,EAAS;AAEzB,MAAA,IAAI,MAAA,CAAO,cAAa,EAAG;AACzB,QAAA,MAAA,CAAO,KAAA,EAAM;AAAA,MACf,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,OAAA,EAAS;AAAA,UACnB,SAAA;AAAA,UACA,MAAM,IAAA,IAAQ,IAAA;AAAA,UACd,UAAU,QAAA,IAAY,IAAA;AAAA,UACtB;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAA,EAAW,IAAA,EAAM,QAAA,EAAU,WAAW;AAAA,GACzC;AAGA,EAAA,IAAI,CAAC,cAAA,CAAe,QAAQ,CAAA,EAAG;AAC7B,IAAA,OAAA,CAAQ,KAAK,wDAAwD,CAAA;AACrE,IAAA,uCAAU,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,YAAA,GAAe,QAAA;AAMrB,EAAA,OAAO,aAAa,YAAA,EAAc;AAAA,IAChC,GAAA,EAAK,UAAA;AAAA,IACL,OAAA,EAAS,CAAC,CAAA,KAAkB;AAE1B,MAAA,YAAA,CAAa,KAAA,CAAM,UAAU,CAAC,CAAA;AAC9B,MAAA,WAAA,CAAY,CAAC,CAAA;AAAA,IACf,CAAA;AAAA,IACA,SAAA,EAAW,SAAA,GACP,CAAA,EAAG,YAAA,CAAa,KAAA,CAAM,SAAA,IAAa,EAAE,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,GAC1D,aAAa,KAAA,CAAM;AAAA,GACxB,CAAA;AACH","file":"index.js","sourcesContent":["import React, {\n useRef,\n useEffect,\n useCallback,\n cloneElement,\n isValidElement,\n type ReactElement,\n type ReactNode,\n type MouseEvent,\n} from \"react\";\nimport {\n CornerCueWidget,\n type WidgetConfig,\n type UserInfo,\n type Metadata,\n type WidgetEvents,\n type FeedbackType,\n} from \"@cornercue/core\";\n\nexport interface FeedbackButtonProps {\n /**\n * Project ID for submissions\n */\n projectId: string;\n\n /**\n * User information to attach to feedback\n */\n user?: UserInfo | null;\n\n /**\n * Additional metadata to attach to feedback\n */\n metadata?: Metadata | null;\n\n /**\n * Default feedback type to open directly (skips menu)\n * Options: 'bug' | 'feature' | 'feedback'\n */\n defaultType?: FeedbackType;\n\n /**\n * Widget configuration overrides\n */\n config?: WidgetConfig;\n\n /**\n * Event callbacks\n */\n events?: WidgetEvents;\n\n /**\n * The trigger element (button, link, etc.)\n */\n children: ReactNode;\n\n /**\n * Additional class name for the wrapper\n */\n className?: string;\n}\n\n// Shared widget instance\nlet sharedWidget: CornerCueWidget | null = null;\nlet widgetRefCount = 0;\n\nfunction getSharedWidget(config?: WidgetConfig): CornerCueWidget {\n if (!sharedWidget) {\n sharedWidget = new CornerCueWidget(config);\n }\n widgetRefCount++;\n return sharedWidget;\n}\n\nfunction releaseSharedWidget(): void {\n widgetRefCount--;\n if (widgetRefCount <= 0 && sharedWidget) {\n sharedWidget.destroy();\n sharedWidget = null;\n widgetRefCount = 0;\n }\n}\n\n/**\n * React component that wraps a trigger element and opens the feedback widget on click.\n *\n * @example\n * ```tsx\n * <FeedbackButton\n * projectId=\"your-project-id\"\n * user={{ id: 'user123', email: 'user@example.com' }}\n * metadata={{ plan: 'pro' }}\n * >\n * <button>Give Feedback</button>\n * </FeedbackButton>\n * ```\n */\nexport function FeedbackButton({\n projectId,\n user,\n metadata,\n defaultType,\n config,\n // events - reserved for future use\n children,\n className,\n}: FeedbackButtonProps): ReactElement {\n const triggerRef = useRef<HTMLElement>(null);\n const widgetRef = useRef<CornerCueWidget | null>(null);\n\n // Initialize widget on mount\n useEffect(() => {\n widgetRef.current = getSharedWidget(config);\n\n return () => {\n releaseSharedWidget();\n widgetRef.current = null;\n };\n }, [config]);\n\n // Handle click on trigger\n const handleClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const widget = widgetRef.current;\n const trigger = triggerRef.current;\n\n if (!widget || !trigger) return;\n\n if (widget.isWidgetOpen()) {\n widget.close();\n } else {\n widget.open(trigger, {\n projectId,\n user: user ?? null,\n metadata: metadata ?? null,\n defaultType,\n });\n }\n },\n [projectId, user, metadata, defaultType]\n );\n\n // Clone the child element to add ref and click handler\n if (!isValidElement(children)) {\n console.warn(\"FeedbackButton: children must be a valid React element\");\n return <>{children}</>;\n }\n\n const childElement = children as ReactElement<{\n ref?: React.Ref<HTMLElement>;\n onClick?: (e: MouseEvent) => void;\n className?: string;\n }>;\n\n return cloneElement(childElement, {\n ref: triggerRef,\n onClick: (e: MouseEvent) => {\n // Call original onClick if present\n childElement.props.onClick?.(e);\n handleClick(e);\n },\n className: className\n ? `${childElement.props.className || \"\"} ${className}`.trim()\n : childElement.props.className,\n });\n}\n\n// Re-export types\nexport type {\n WidgetConfig,\n UserInfo,\n Metadata,\n FeedbackType,\n WidgetEvents,\n OpenOptions,\n} from \"@cornercue/core\";\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cornercue/react",
|
|
3
|
+
"version": "0.1.0-beta.5",
|
|
4
|
+
"description": "CornerCue feedback widget - React component",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@cornercue/core": "workspace:*"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=17.0.0",
|
|
34
|
+
"react-dom": ">=17.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "^18.2.0",
|
|
38
|
+
"@types/react-dom": "^18.2.0",
|
|
39
|
+
"react": "^18.2.0",
|
|
40
|
+
"react-dom": "^18.2.0",
|
|
41
|
+
"tsup": "^8.0.0",
|
|
42
|
+
"typescript": "^5.3.0"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"feedback",
|
|
46
|
+
"widget",
|
|
47
|
+
"cornercue",
|
|
48
|
+
"react",
|
|
49
|
+
"component"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT"
|
|
52
|
+
}
|