@solhun/feedback-kit-web 0.10.0 → 0.12.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/dist/index.cjs +113 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +113 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElementInfo, FeedbackPin, FeedbackScreenshot, FeedbackHint, FeedbackReport, SubmitOutcome, QueueStatus, ReportParts, ScreenshotCapture, ScreenshotReencode, RouteWatcher, WidgetControllerOpts, HintProvider, WidgetController, FeedbackStorage, ContextProviders, DiagnosticsInstallOpts, RouteTrailStore } from '@solhun/feedback-kit-core';
|
|
1
|
+
import { ElementInfo, FeedbackPin, FeedbackScreenshot, FeedbackHint, FeedbackReport, SubmitOutcome, QueueStatus, ReportParts, ScreenshotCapture, ScreenshotReencode, RouteWatcher, WidgetControllerOpts, HintProvider, WidgetController, FeedbackAdapter, FeedbackStorage, ContextProviders, DiagnosticsInstallOpts, RouteTrailStore } from '@solhun/feedback-kit-core';
|
|
2
2
|
export { COMMENT_MAX_CHARS, COMMENT_REQUIRED_MESSAGE, COMMENT_TOO_LONG_MESSAGE, ElementInfo, ElementLike, FLOATING_BUTTON_ID, FeedbackAdapter, FeedbackConfig, FeedbackContext, FeedbackHint, FeedbackPin, FeedbackReport, FeedbackStorage, FeedbackUser, HintCatalog, HintElementRule, HintPlatform, HintProvider, HintRankInput, HintScope, MODAL_ACTION_HINT_TOGGLE, MODAL_ACTION_PICK, ModalSubmitStatus, ReportModalController, ReportModalState, ResolvedConfig, SCREENSHOT_FAILED_MESSAGE, SOURCE_ATTR, SUBMIT_DONE_MESSAGE, SUBMIT_PENDING_MESSAGE, ScreenshotStatus, SubmitResult, Visibility, VisibilityEnv, VisibilityFn, WidgetController, WidgetPosition, WidgetScreen, WidgetState, denormalizePin, normalizePin, parseSourceAttr, rankHints, resolveConfig, shouldShowWidget, sourceFromElement } from '@solhun/feedback-kit-core';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
|
|
@@ -391,6 +391,11 @@ interface WebWidget {
|
|
|
391
391
|
widget: WidgetController;
|
|
392
392
|
picking: ElementPickingController;
|
|
393
393
|
store: MarkerStore;
|
|
394
|
+
/**
|
|
395
|
+
* "이 화면의 제보가 어디로 가나" 조회. 어댑터가 지원하지 않으면 `null` 이고,
|
|
396
|
+
* 그러면 설정 화면이 "확인 못 했습니다"를 보여준다. 표시용이라 없어도 제보에는 영향이 없다.
|
|
397
|
+
*/
|
|
398
|
+
fetchConnection: NonNullable<FeedbackAdapter["fetchConnection"]> | null;
|
|
394
399
|
dispose(): void;
|
|
395
400
|
}
|
|
396
401
|
declare function createWebWidget(opts: WebWidgetOpts): WebWidget;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElementInfo, FeedbackPin, FeedbackScreenshot, FeedbackHint, FeedbackReport, SubmitOutcome, QueueStatus, ReportParts, ScreenshotCapture, ScreenshotReencode, RouteWatcher, WidgetControllerOpts, HintProvider, WidgetController, FeedbackStorage, ContextProviders, DiagnosticsInstallOpts, RouteTrailStore } from '@solhun/feedback-kit-core';
|
|
1
|
+
import { ElementInfo, FeedbackPin, FeedbackScreenshot, FeedbackHint, FeedbackReport, SubmitOutcome, QueueStatus, ReportParts, ScreenshotCapture, ScreenshotReencode, RouteWatcher, WidgetControllerOpts, HintProvider, WidgetController, FeedbackAdapter, FeedbackStorage, ContextProviders, DiagnosticsInstallOpts, RouteTrailStore } from '@solhun/feedback-kit-core';
|
|
2
2
|
export { COMMENT_MAX_CHARS, COMMENT_REQUIRED_MESSAGE, COMMENT_TOO_LONG_MESSAGE, ElementInfo, ElementLike, FLOATING_BUTTON_ID, FeedbackAdapter, FeedbackConfig, FeedbackContext, FeedbackHint, FeedbackPin, FeedbackReport, FeedbackStorage, FeedbackUser, HintCatalog, HintElementRule, HintPlatform, HintProvider, HintRankInput, HintScope, MODAL_ACTION_HINT_TOGGLE, MODAL_ACTION_PICK, ModalSubmitStatus, ReportModalController, ReportModalState, ResolvedConfig, SCREENSHOT_FAILED_MESSAGE, SOURCE_ATTR, SUBMIT_DONE_MESSAGE, SUBMIT_PENDING_MESSAGE, ScreenshotStatus, SubmitResult, Visibility, VisibilityEnv, VisibilityFn, WidgetController, WidgetPosition, WidgetScreen, WidgetState, denormalizePin, normalizePin, parseSourceAttr, rankHints, resolveConfig, shouldShowWidget, sourceFromElement } from '@solhun/feedback-kit-core';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
|
|
@@ -391,6 +391,11 @@ interface WebWidget {
|
|
|
391
391
|
widget: WidgetController;
|
|
392
392
|
picking: ElementPickingController;
|
|
393
393
|
store: MarkerStore;
|
|
394
|
+
/**
|
|
395
|
+
* "이 화면의 제보가 어디로 가나" 조회. 어댑터가 지원하지 않으면 `null` 이고,
|
|
396
|
+
* 그러면 설정 화면이 "확인 못 했습니다"를 보여준다. 표시용이라 없어도 제보에는 영향이 없다.
|
|
397
|
+
*/
|
|
398
|
+
fetchConnection: NonNullable<FeedbackAdapter["fetchConnection"]> | null;
|
|
394
399
|
dispose(): void;
|
|
395
400
|
}
|
|
396
401
|
declare function createWebWidget(opts: WebWidgetOpts): WebWidget;
|
package/dist/index.js
CHANGED
|
@@ -1062,6 +1062,11 @@ function hintSourceFrom(queue) {
|
|
|
1062
1062
|
const cacheKey = adapter.hintsCacheKey ?? "default";
|
|
1063
1063
|
return { fetchHints: adapter.fetchHints.bind(adapter), cacheKey };
|
|
1064
1064
|
}
|
|
1065
|
+
function connectionSourceFrom(queue) {
|
|
1066
|
+
const adapter = queue.adapter;
|
|
1067
|
+
if (!adapter || typeof adapter.fetchConnection !== "function") return null;
|
|
1068
|
+
return adapter.fetchConnection.bind(adapter);
|
|
1069
|
+
}
|
|
1065
1070
|
function resolveHintProvider(opts) {
|
|
1066
1071
|
if (opts.hintProvider) return opts.hintProvider;
|
|
1067
1072
|
if (opts.hints) {
|
|
@@ -1147,6 +1152,7 @@ function createWebWidget(opts) {
|
|
|
1147
1152
|
widget,
|
|
1148
1153
|
picking,
|
|
1149
1154
|
store,
|
|
1155
|
+
fetchConnection: connectionSourceFrom(opts.queue),
|
|
1150
1156
|
dispose() {
|
|
1151
1157
|
picking.dispose();
|
|
1152
1158
|
widget.dispose();
|
|
@@ -1174,7 +1180,7 @@ import {
|
|
|
1174
1180
|
} from "react";
|
|
1175
1181
|
|
|
1176
1182
|
// src/version.ts
|
|
1177
|
-
var VERSION = true ? "0.
|
|
1183
|
+
var VERSION = true ? "0.12.0" : "dev";
|
|
1178
1184
|
|
|
1179
1185
|
// src/dev-clipboard.ts
|
|
1180
1186
|
import { sourceFromElement } from "@solhun/feedback-kit-core";
|
|
@@ -1252,6 +1258,36 @@ function resolveDevMode(propValue, stored) {
|
|
|
1252
1258
|
if (stored !== null) return stored;
|
|
1253
1259
|
return propValue === true;
|
|
1254
1260
|
}
|
|
1261
|
+
var SETTINGS_FLAG = "fk-settings";
|
|
1262
|
+
var SESSION_KEY = "feedback-kit:settings-visible";
|
|
1263
|
+
function isSettingsRequested(search, session) {
|
|
1264
|
+
const store = session === void 0 ? sessionStorageOrNull() : session;
|
|
1265
|
+
let requested = false;
|
|
1266
|
+
try {
|
|
1267
|
+
requested = new URLSearchParams(search).get(SETTINGS_FLAG) === "1";
|
|
1268
|
+
} catch {
|
|
1269
|
+
requested = false;
|
|
1270
|
+
}
|
|
1271
|
+
if (requested) {
|
|
1272
|
+
try {
|
|
1273
|
+
store?.setItem(SESSION_KEY, "1");
|
|
1274
|
+
} catch {
|
|
1275
|
+
}
|
|
1276
|
+
return true;
|
|
1277
|
+
}
|
|
1278
|
+
try {
|
|
1279
|
+
return store?.getItem(SESSION_KEY) === "1";
|
|
1280
|
+
} catch {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function sessionStorageOrNull() {
|
|
1285
|
+
try {
|
|
1286
|
+
return globalThis.sessionStorage ?? null;
|
|
1287
|
+
} catch {
|
|
1288
|
+
return null;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1255
1291
|
|
|
1256
1292
|
// src/feedback-kit.tsx
|
|
1257
1293
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1749,10 +1785,15 @@ function FeedbackKit(props) {
|
|
|
1749
1785
|
const [pickingState, setPickingState] = useState(INITIAL_PICKING_STATE);
|
|
1750
1786
|
const [announcement, setAnnouncement] = useState(null);
|
|
1751
1787
|
const [devMode, setDevMode] = useState(() => resolveDevMode(props.devMode, readDevPreference()));
|
|
1752
|
-
const [
|
|
1788
|
+
const [devToggleAvailable] = useState(
|
|
1753
1789
|
() => props.devMode === true || isDevSettingsHost(globalThis.location?.hostname ?? "")
|
|
1754
1790
|
);
|
|
1791
|
+
const [devSettingsAvailable] = useState(
|
|
1792
|
+
() => props.devMode === true || isDevSettingsHost(globalThis.location?.hostname ?? "") || isSettingsRequested(globalThis.location?.search ?? "")
|
|
1793
|
+
);
|
|
1755
1794
|
const [devSettingsOpen, setDevSettingsOpen] = useState(false);
|
|
1795
|
+
const [connection, setConnection] = useState(null);
|
|
1796
|
+
const [connectionState, setConnectionState] = useState("idle");
|
|
1756
1797
|
const devClipsRef = useRef([]);
|
|
1757
1798
|
const [devClipCount, setDevClipCount] = useState(0);
|
|
1758
1799
|
const [devFallbackText, setDevFallbackText] = useState(null);
|
|
@@ -1912,6 +1953,20 @@ function FeedbackKit(props) {
|
|
|
1912
1953
|
if (devClipsRef.current.length === 0) return;
|
|
1913
1954
|
await putOnClipboard(renderDevClipList(devClipsRef.current));
|
|
1914
1955
|
}
|
|
1956
|
+
function openDevSettings() {
|
|
1957
|
+
setDevSettingsOpen(true);
|
|
1958
|
+
if (connectionState !== "idle") return;
|
|
1959
|
+
const fetchConnection = activeKit.fetchConnection;
|
|
1960
|
+
if (!fetchConnection) {
|
|
1961
|
+
setConnectionState("fail");
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
setConnectionState("loading");
|
|
1965
|
+
void fetchConnection().then((value) => {
|
|
1966
|
+
setConnection(value);
|
|
1967
|
+
setConnectionState(value ? "done" : "fail");
|
|
1968
|
+
}).catch(() => setConnectionState("fail"));
|
|
1969
|
+
}
|
|
1915
1970
|
function toggleDevMode(next) {
|
|
1916
1971
|
writeDevPreference(next);
|
|
1917
1972
|
setDevMode(next);
|
|
@@ -2033,7 +2088,7 @@ function FeedbackKit(props) {
|
|
|
2033
2088
|
"data-fk-dev-settings-toggle": "",
|
|
2034
2089
|
"aria-label": "\uD53C\uB4DC\uBC31 \uC124\uC815",
|
|
2035
2090
|
"aria-expanded": devSettingsOpen,
|
|
2036
|
-
onClick: () => setDevSettingsOpen(
|
|
2091
|
+
onClick: () => devSettingsOpen ? setDevSettingsOpen(false) : openDevSettings(),
|
|
2037
2092
|
style: {
|
|
2038
2093
|
...baseButton,
|
|
2039
2094
|
width: 46,
|
|
@@ -2165,6 +2220,7 @@ function FeedbackKit(props) {
|
|
|
2165
2220
|
{
|
|
2166
2221
|
type: "checkbox",
|
|
2167
2222
|
checked: devMode,
|
|
2223
|
+
disabled: !devToggleAvailable,
|
|
2168
2224
|
onChange: (event) => toggleDevMode(event.currentTarget.checked),
|
|
2169
2225
|
style: { marginTop: 3 }
|
|
2170
2226
|
}
|
|
@@ -2178,11 +2234,61 @@ function FeedbackKit(props) {
|
|
|
2178
2234
|
] })
|
|
2179
2235
|
] })
|
|
2180
2236
|
] }),
|
|
2181
|
-
/* @__PURE__ */ jsxs(
|
|
2182
|
-
"
|
|
2237
|
+
/* @__PURE__ */ jsxs(
|
|
2238
|
+
"div",
|
|
2239
|
+
{
|
|
2240
|
+
"data-fk-connection": "",
|
|
2241
|
+
style: {
|
|
2242
|
+
marginTop: 12,
|
|
2243
|
+
paddingTop: 12,
|
|
2244
|
+
borderTop: `1px solid ${TOKENS.line}`,
|
|
2245
|
+
fontSize: 12.5
|
|
2246
|
+
},
|
|
2247
|
+
children: [
|
|
2248
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 700, marginBottom: 6 }, children: "\uBCF4\uB0B4\uB294 \uACF3" }),
|
|
2249
|
+
connectionState === "loading" ? /* @__PURE__ */ jsx("div", { style: { color: TOKENS.muted }, children: "\uD655\uC778\uD558\uB294 \uC911\u2026" }) : connectionState === "fail" || !connection ? (
|
|
2250
|
+
// 조용히 비우면 "연결이 없다"로 읽힌다. 못 물어봤다는 것과 없다는 것은 다르다.
|
|
2251
|
+
/* @__PURE__ */ jsx("div", { style: { color: TOKENS.muted }, children: "\uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(\uC218\uC9D1\uCC98\uAC00 \uC751\uB2F5\uD558\uC9C0 \uC54A\uC74C)." })
|
|
2252
|
+
) : /* @__PURE__ */ jsxs("ul", { style: { margin: 0, paddingLeft: 16, color: TOKENS.ink, lineHeight: 1.7 }, children: [
|
|
2253
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2254
|
+
"\uC218\uC9D1\uCC98 \xB7 ",
|
|
2255
|
+
connection.project.name ?? "\uC774\uB984 \uC5C6\uB294 \uD504\uB85C\uC81D\uD2B8"
|
|
2256
|
+
] }),
|
|
2257
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2258
|
+
"Linear \xB7",
|
|
2259
|
+
" ",
|
|
2260
|
+
connection.linear.connected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2261
|
+
connection.linear.teamName ?? "\uC5F0\uACB0\uB41C \uD300",
|
|
2262
|
+
connection.linear.projectName ? ` / ${connection.linear.projectName}` : "",
|
|
2263
|
+
" \u2014 ",
|
|
2264
|
+
/* @__PURE__ */ jsx("b", { children: connection.linear.autoExport ? "\uC81C\uBCF4\uAC00 \uC790\uB3D9\uC73C\uB85C \uB098\uAC11\uB2C8\uB2E4" : "\uC790\uB3D9 \uBC1C\uC1A1 \uAEBC\uC9D0" })
|
|
2265
|
+
] }) : "\uC5F0\uACB0 \uC5C6\uC74C"
|
|
2266
|
+
] }),
|
|
2267
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2268
|
+
"Symphony \xB7",
|
|
2269
|
+
" ",
|
|
2270
|
+
connection.symphonySlug ? `${connection.symphonySlug} \uAC00 \uCC98\uB9AC` : "\uC790\uB3D9 \uCC98\uB9AC \uC548 \uD568"
|
|
2271
|
+
] })
|
|
2272
|
+
] }),
|
|
2273
|
+
devMode ? (
|
|
2274
|
+
// 개발용 모드가 켜져 있으면 위 목록은 "원래 가던 곳"일 뿐이다. 그대로 두면
|
|
2275
|
+
// 지금도 거기로 가는 줄 읽는다.
|
|
2276
|
+
/* @__PURE__ */ jsx("div", { style: { marginTop: 8, color: TOKENS.warning, fontWeight: 700 }, children: "\uC9C0\uAE08\uC740 \uC5B4\uB514\uC5D0\uB3C4 \uC548 \uBCF4\uB0C5\uB2C8\uB2E4 \u2014 \uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uAC00 \uCF1C\uC838 \uC788\uC2B5\uB2C8\uB2E4." })
|
|
2277
|
+
) : null
|
|
2278
|
+
]
|
|
2279
|
+
}
|
|
2280
|
+
),
|
|
2281
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "12px 0 0", color: TOKENS.muted, fontSize: 12 }, children: devToggleAvailable ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2282
|
+
"\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uB294 \uB85C\uCEEC(",
|
|
2183
2283
|
/* @__PURE__ */ jsx("code", { children: "localhost" }),
|
|
2184
|
-
")\uC5D0\uC11C\uB9CC \
|
|
2185
|
-
] }),
|
|
2284
|
+
")\uC5D0\uC11C\uB9CC \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uBC30\uD3EC\uB41C \uD654\uBA74\uC5D0\uC11C \uC2E4\uC0AC\uC6A9\uC790\uAC00 \uCF1C\uBA74 \uADF8 \uC0AC\uB78C \uC81C\uBCF4\uAC00 \uC5B4\uB514\uC5D0\uB3C4 \uC548 \uB0A8\uAE30 \uB54C\uBB38\uC785\uB2C8\uB2E4."
|
|
2285
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2286
|
+
"\uC5EC\uAE30\uC11C\uB294 ",
|
|
2287
|
+
/* @__PURE__ */ jsx("b", { children: "\uBCF4\uAE30\uB9CC" }),
|
|
2288
|
+
" \uB429\uB2C8\uB2E4. \uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uB294 \uB85C\uCEEC(",
|
|
2289
|
+
/* @__PURE__ */ jsx("code", { children: "localhost" }),
|
|
2290
|
+
")\uC5D0\uC11C\uB9CC \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uC2E4\uC0AC\uC6A9\uC790\uAC00 \uCF1C\uBA74 \uADF8 \uC0AC\uB78C \uC81C\uBCF4\uAC00 \uC5B4\uB514\uC5D0\uB3C4 \uC548 \uB0A8\uAE30 \uB54C\uBB38\uC785\uB2C8\uB2E4."
|
|
2291
|
+
] }) }),
|
|
2186
2292
|
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: 12 }, children: /* @__PURE__ */ jsx("button", { type: "button", style: baseButton, onClick: () => setDevSettingsOpen(false), children: "\uB2EB\uAE30" }) })
|
|
2187
2293
|
]
|
|
2188
2294
|
}
|