@solhun/feedback-kit-web 0.9.0 → 0.11.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 +265 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +265 -39
- 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
|
|
|
@@ -369,8 +369,12 @@ interface WebWidgetOpts extends Omit<WidgetControllerOpts, "platform" | "initial
|
|
|
369
369
|
* 개발자가 로컬에서 고치는 중일 때 라쏘런 왕복(보내고·트리아지하고·이슈가 되고)이 오히려
|
|
370
370
|
* 느리다. 정작 고칠 사람은 지금 그 화면을 보고 있는 본인이다.
|
|
371
371
|
*
|
|
372
|
-
* **기본은
|
|
373
|
-
*
|
|
372
|
+
* **기본은 꺼짐**이다. 이건 초기값일 뿐이고, 사람이 화면의 톱니(설정)에서 켜거나 끄면
|
|
373
|
+
* 그 선택이 이 값을 이긴다 — 안 그러면 개발 빌드에서 끄려고 또 코드를 고쳐야 한다.
|
|
374
|
+
* 톱니는 **로컬(`localhost`)에서만** 뜬다. 배포된 화면에서 실사용자가 켜면 그 사람 제보는
|
|
375
|
+
* 어디에도 안 남고 본인은 보냈다고 믿는다. 이 값을 `true` 로 주면 톱니도 같이 뜬다.
|
|
376
|
+
*
|
|
377
|
+
* 켜져 있는 동안은 그 사실이 화면에 계속 보인다(조용한 유실을 막는 유일한 방어).
|
|
374
378
|
*
|
|
375
379
|
* 웹 전용이다. 앱에는 DOM 이 없어 선택자·컴포넌트 경로·소스 경로가 성립하지 않는다.
|
|
376
380
|
*/
|
|
@@ -387,6 +391,11 @@ interface WebWidget {
|
|
|
387
391
|
widget: WidgetController;
|
|
388
392
|
picking: ElementPickingController;
|
|
389
393
|
store: MarkerStore;
|
|
394
|
+
/**
|
|
395
|
+
* "이 화면의 제보가 어디로 가나" 조회. 어댑터가 지원하지 않으면 `null` 이고,
|
|
396
|
+
* 그러면 설정 화면이 "확인 못 했습니다"를 보여준다. 표시용이라 없어도 제보에는 영향이 없다.
|
|
397
|
+
*/
|
|
398
|
+
fetchConnection: NonNullable<FeedbackAdapter["fetchConnection"]> | null;
|
|
390
399
|
dispose(): void;
|
|
391
400
|
}
|
|
392
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
|
|
|
@@ -369,8 +369,12 @@ interface WebWidgetOpts extends Omit<WidgetControllerOpts, "platform" | "initial
|
|
|
369
369
|
* 개발자가 로컬에서 고치는 중일 때 라쏘런 왕복(보내고·트리아지하고·이슈가 되고)이 오히려
|
|
370
370
|
* 느리다. 정작 고칠 사람은 지금 그 화면을 보고 있는 본인이다.
|
|
371
371
|
*
|
|
372
|
-
* **기본은
|
|
373
|
-
*
|
|
372
|
+
* **기본은 꺼짐**이다. 이건 초기값일 뿐이고, 사람이 화면의 톱니(설정)에서 켜거나 끄면
|
|
373
|
+
* 그 선택이 이 값을 이긴다 — 안 그러면 개발 빌드에서 끄려고 또 코드를 고쳐야 한다.
|
|
374
|
+
* 톱니는 **로컬(`localhost`)에서만** 뜬다. 배포된 화면에서 실사용자가 켜면 그 사람 제보는
|
|
375
|
+
* 어디에도 안 남고 본인은 보냈다고 믿는다. 이 값을 `true` 로 주면 톱니도 같이 뜬다.
|
|
376
|
+
*
|
|
377
|
+
* 켜져 있는 동안은 그 사실이 화면에 계속 보인다(조용한 유실을 막는 유일한 방어).
|
|
374
378
|
*
|
|
375
379
|
* 웹 전용이다. 앱에는 DOM 이 없어 선택자·컴포넌트 경로·소스 경로가 성립하지 않는다.
|
|
376
380
|
*/
|
|
@@ -387,6 +391,11 @@ interface WebWidget {
|
|
|
387
391
|
widget: WidgetController;
|
|
388
392
|
picking: ElementPickingController;
|
|
389
393
|
store: MarkerStore;
|
|
394
|
+
/**
|
|
395
|
+
* "이 화면의 제보가 어디로 가나" 조회. 어댑터가 지원하지 않으면 `null` 이고,
|
|
396
|
+
* 그러면 설정 화면이 "확인 못 했습니다"를 보여준다. 표시용이라 없어도 제보에는 영향이 없다.
|
|
397
|
+
*/
|
|
398
|
+
fetchConnection: NonNullable<FeedbackAdapter["fetchConnection"]> | null;
|
|
390
399
|
dispose(): void;
|
|
391
400
|
}
|
|
392
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.11.0" : "dev";
|
|
1178
1184
|
|
|
1179
1185
|
// src/dev-clipboard.ts
|
|
1180
1186
|
import { sourceFromElement } from "@solhun/feedback-kit-core";
|
|
@@ -1222,6 +1228,37 @@ async function writeToClipboard(text) {
|
|
|
1222
1228
|
}
|
|
1223
1229
|
}
|
|
1224
1230
|
|
|
1231
|
+
// src/dev-preference.ts
|
|
1232
|
+
var STORAGE_KEY = "feedback-kit:dev-mode";
|
|
1233
|
+
function isDevSettingsHost(hostname) {
|
|
1234
|
+
const host = hostname.trim().toLowerCase();
|
|
1235
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") return true;
|
|
1236
|
+
return host.endsWith(".localhost") || host.endsWith(".local");
|
|
1237
|
+
}
|
|
1238
|
+
function readDevPreference() {
|
|
1239
|
+
try {
|
|
1240
|
+
const raw = globalThis.localStorage?.getItem(STORAGE_KEY);
|
|
1241
|
+
if (raw === "on") return true;
|
|
1242
|
+
if (raw === "off") return false;
|
|
1243
|
+
return null;
|
|
1244
|
+
} catch {
|
|
1245
|
+
return null;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function writeDevPreference(value) {
|
|
1249
|
+
try {
|
|
1250
|
+
const storage = globalThis.localStorage;
|
|
1251
|
+
if (!storage) return;
|
|
1252
|
+
if (value === null) storage.removeItem(STORAGE_KEY);
|
|
1253
|
+
else storage.setItem(STORAGE_KEY, value ? "on" : "off");
|
|
1254
|
+
} catch {
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function resolveDevMode(propValue, stored) {
|
|
1258
|
+
if (stored !== null) return stored;
|
|
1259
|
+
return propValue === true;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1225
1262
|
// src/feedback-kit.tsx
|
|
1226
1263
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1227
1264
|
var TOKENS = {
|
|
@@ -1717,7 +1754,13 @@ function FeedbackKit(props) {
|
|
|
1717
1754
|
const [widgetState, setWidgetState] = useState(null);
|
|
1718
1755
|
const [pickingState, setPickingState] = useState(INITIAL_PICKING_STATE);
|
|
1719
1756
|
const [announcement, setAnnouncement] = useState(null);
|
|
1720
|
-
const [devMode] = useState(() => props.devMode
|
|
1757
|
+
const [devMode, setDevMode] = useState(() => resolveDevMode(props.devMode, readDevPreference()));
|
|
1758
|
+
const [devSettingsAvailable] = useState(
|
|
1759
|
+
() => props.devMode === true || isDevSettingsHost(globalThis.location?.hostname ?? "")
|
|
1760
|
+
);
|
|
1761
|
+
const [devSettingsOpen, setDevSettingsOpen] = useState(false);
|
|
1762
|
+
const [connection, setConnection] = useState(null);
|
|
1763
|
+
const [connectionState, setConnectionState] = useState("idle");
|
|
1721
1764
|
const devClipsRef = useRef([]);
|
|
1722
1765
|
const [devClipCount, setDevClipCount] = useState(0);
|
|
1723
1766
|
const [devFallbackText, setDevFallbackText] = useState(null);
|
|
@@ -1858,6 +1901,13 @@ function FeedbackKit(props) {
|
|
|
1858
1901
|
const ok = await writeToClipboard(text);
|
|
1859
1902
|
setDevFallbackText(ok ? null : text);
|
|
1860
1903
|
}
|
|
1904
|
+
function commitPopup() {
|
|
1905
|
+
if (devMode) {
|
|
1906
|
+
void copyOne();
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
void activeKit.picking.saveAnnotation();
|
|
1910
|
+
}
|
|
1861
1911
|
async function copyOne() {
|
|
1862
1912
|
const clip = currentClip();
|
|
1863
1913
|
if (!clip || clip.comment.trim() === "") return;
|
|
@@ -1870,6 +1920,30 @@ function FeedbackKit(props) {
|
|
|
1870
1920
|
if (devClipsRef.current.length === 0) return;
|
|
1871
1921
|
await putOnClipboard(renderDevClipList(devClipsRef.current));
|
|
1872
1922
|
}
|
|
1923
|
+
function openDevSettings() {
|
|
1924
|
+
setDevSettingsOpen(true);
|
|
1925
|
+
if (connectionState !== "idle") return;
|
|
1926
|
+
const fetchConnection = activeKit.fetchConnection;
|
|
1927
|
+
if (!fetchConnection) {
|
|
1928
|
+
setConnectionState("fail");
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
setConnectionState("loading");
|
|
1932
|
+
void fetchConnection().then((value) => {
|
|
1933
|
+
setConnection(value);
|
|
1934
|
+
setConnectionState(value ? "done" : "fail");
|
|
1935
|
+
}).catch(() => setConnectionState("fail"));
|
|
1936
|
+
}
|
|
1937
|
+
function toggleDevMode(next) {
|
|
1938
|
+
writeDevPreference(next);
|
|
1939
|
+
setDevMode(next);
|
|
1940
|
+
devClipsRef.current = [];
|
|
1941
|
+
setDevClipCount(0);
|
|
1942
|
+
setDevFallbackText(null);
|
|
1943
|
+
setAnnouncement(
|
|
1944
|
+
next ? "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uB97C \uCF30\uC2B5\uB2C8\uB2E4. \uC774\uC81C \uC81C\uBCF4\uB294 \uC218\uC9D1\uCC98\uB85C \uAC00\uC9C0 \uC54A\uACE0 \uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC\uB429\uB2C8\uB2E4." : "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uB97C \uAED0\uC2B5\uB2C8\uB2E4. \uC774\uC81C \uC81C\uBCF4\uAC00 \uC218\uC9D1\uCC98\uB85C \uAC11\uB2C8\uB2E4."
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1873
1947
|
async function pressFloatingButton() {
|
|
1874
1948
|
if (props.defaultMode !== "report" && !pickingActive) {
|
|
1875
1949
|
setAnnouncement(null);
|
|
@@ -1927,8 +2001,26 @@ function FeedbackKit(props) {
|
|
|
1927
2001
|
}
|
|
1928
2002
|
function submitReport(event) {
|
|
1929
2003
|
event.preventDefault();
|
|
2004
|
+
if (devMode) {
|
|
2005
|
+
void copyFromModal();
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
1930
2008
|
void activeKit.widget.submitReport();
|
|
1931
2009
|
}
|
|
2010
|
+
async function copyFromModal() {
|
|
2011
|
+
const modalState = activeKit.widget.getState().modal;
|
|
2012
|
+
if (modalState.comment.trim() === "") return;
|
|
2013
|
+
const clip = {
|
|
2014
|
+
comment: modalState.comment,
|
|
2015
|
+
element: modalState.element ?? null,
|
|
2016
|
+
screen: typeof location === "undefined" ? null : location.pathname,
|
|
2017
|
+
priority: modalState.priority
|
|
2018
|
+
};
|
|
2019
|
+
devClipsRef.current = [...devClipsRef.current, clip];
|
|
2020
|
+
setDevClipCount(devClipsRef.current.length);
|
|
2021
|
+
activeKit.widget.confirmCloseReport();
|
|
2022
|
+
await putOnClipboard(renderDevClipItem(clip));
|
|
2023
|
+
}
|
|
1932
2024
|
const floating = screen === "button" || screen === "picking";
|
|
1933
2025
|
const hoverBox = pickingState.hovered?.boundingBox;
|
|
1934
2026
|
const popup = pickingState.popup;
|
|
@@ -1940,27 +2032,64 @@ function FeedbackKit(props) {
|
|
|
1940
2032
|
style: { fontFamily: FONT_STACK, color: TOKENS.ink, fontSize: 14, lineHeight: 1.45 },
|
|
1941
2033
|
children: [
|
|
1942
2034
|
/* @__PURE__ */ jsx("style", { children: `@keyframes feedback-kit-spin{to{transform:rotate(360deg)}}` }),
|
|
1943
|
-
floating ?
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
2035
|
+
floating ? (
|
|
2036
|
+
// 톱니와 피드백 버튼을 한 상자에 넣는다. 각각 fixed 로 두면 버튼 글자 길이가
|
|
2037
|
+
// 바뀔 때마다 좌표를 다시 맞춰야 하고, 그러다 겹친다.
|
|
2038
|
+
/* @__PURE__ */ jsxs(
|
|
2039
|
+
"div",
|
|
2040
|
+
{
|
|
2041
|
+
style: {
|
|
2042
|
+
position: "fixed",
|
|
2043
|
+
right: 24,
|
|
2044
|
+
bottom: 24,
|
|
2045
|
+
zIndex: 2147483600,
|
|
2046
|
+
display: "flex",
|
|
2047
|
+
alignItems: "center",
|
|
2048
|
+
gap: 8
|
|
2049
|
+
},
|
|
2050
|
+
children: [
|
|
2051
|
+
devSettingsAvailable ? /* @__PURE__ */ jsx(
|
|
2052
|
+
"button",
|
|
2053
|
+
{
|
|
2054
|
+
type: "button",
|
|
2055
|
+
"data-fk-dev-settings-toggle": "",
|
|
2056
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uC124\uC815",
|
|
2057
|
+
"aria-expanded": devSettingsOpen,
|
|
2058
|
+
onClick: () => devSettingsOpen ? setDevSettingsOpen(false) : openDevSettings(),
|
|
2059
|
+
style: {
|
|
2060
|
+
...baseButton,
|
|
2061
|
+
width: 46,
|
|
2062
|
+
minHeight: 46,
|
|
2063
|
+
padding: 0,
|
|
2064
|
+
borderRadius: 23,
|
|
2065
|
+
boxShadow: TOKENS.shadow,
|
|
2066
|
+
fontSize: 17,
|
|
2067
|
+
lineHeight: 1
|
|
2068
|
+
},
|
|
2069
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2699" })
|
|
2070
|
+
}
|
|
2071
|
+
) : null,
|
|
2072
|
+
/* @__PURE__ */ jsx(
|
|
2073
|
+
"button",
|
|
2074
|
+
{
|
|
2075
|
+
ref: floatingButtonRef,
|
|
2076
|
+
id: FLOATING_BUTTON_ID,
|
|
2077
|
+
type: "button",
|
|
2078
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uBCF4\uB0B4\uAE30",
|
|
2079
|
+
onClick: () => void pressFloatingButton(),
|
|
2080
|
+
style: {
|
|
2081
|
+
...primaryButton,
|
|
2082
|
+
minWidth: 112,
|
|
2083
|
+
minHeight: 46,
|
|
2084
|
+
borderRadius: 24,
|
|
2085
|
+
boxShadow: TOKENS.shadow
|
|
2086
|
+
},
|
|
2087
|
+
children: "\uD53C\uB4DC\uBC31"
|
|
2088
|
+
}
|
|
2089
|
+
)
|
|
2090
|
+
]
|
|
2091
|
+
}
|
|
2092
|
+
)
|
|
1964
2093
|
) : null,
|
|
1965
2094
|
floating && devMode ? (
|
|
1966
2095
|
// 켠 줄 모르고 제보하면 "보냈다"고 믿는데 수집처엔 아무것도 안 남는다.
|
|
@@ -2022,23 +2151,124 @@ function FeedbackKit(props) {
|
|
|
2022
2151
|
]
|
|
2023
2152
|
}
|
|
2024
2153
|
) : null,
|
|
2025
|
-
announcement && !modal.open ? /* @__PURE__ */
|
|
2154
|
+
devSettingsOpen || announcement && !modal.open ? /* @__PURE__ */ jsxs(
|
|
2026
2155
|
"div",
|
|
2027
2156
|
{
|
|
2028
|
-
role: "status",
|
|
2029
|
-
"aria-live": "polite",
|
|
2030
2157
|
style: {
|
|
2031
2158
|
position: "fixed",
|
|
2032
2159
|
right: 24,
|
|
2033
2160
|
bottom: 82,
|
|
2034
2161
|
zIndex: 2147483601,
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
boxShadow: TOKENS.shadow
|
|
2162
|
+
display: "flex",
|
|
2163
|
+
flexDirection: "column",
|
|
2164
|
+
alignItems: "flex-end",
|
|
2165
|
+
gap: 8
|
|
2040
2166
|
},
|
|
2041
|
-
children:
|
|
2167
|
+
children: [
|
|
2168
|
+
devSettingsOpen ? /* @__PURE__ */ jsxs(
|
|
2169
|
+
"div",
|
|
2170
|
+
{
|
|
2171
|
+
role: "dialog",
|
|
2172
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uC124\uC815",
|
|
2173
|
+
"data-fk-dev-settings": "",
|
|
2174
|
+
style: {
|
|
2175
|
+
width: 292,
|
|
2176
|
+
maxWidth: "calc(100vw - 48px)",
|
|
2177
|
+
padding: 14,
|
|
2178
|
+
borderRadius: 12,
|
|
2179
|
+
border: `1px solid ${TOKENS.line}`,
|
|
2180
|
+
background: TOKENS.surface,
|
|
2181
|
+
boxShadow: TOKENS.shadow
|
|
2182
|
+
},
|
|
2183
|
+
children: [
|
|
2184
|
+
/* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "flex-start", gap: 9, cursor: "pointer" }, children: [
|
|
2185
|
+
/* @__PURE__ */ jsx(
|
|
2186
|
+
"input",
|
|
2187
|
+
{
|
|
2188
|
+
type: "checkbox",
|
|
2189
|
+
checked: devMode,
|
|
2190
|
+
onChange: (event) => toggleDevMode(event.currentTarget.checked),
|
|
2191
|
+
style: { marginTop: 3 }
|
|
2192
|
+
}
|
|
2193
|
+
),
|
|
2194
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2195
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 700 }, children: "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC" }),
|
|
2196
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block", marginTop: 4, color: TOKENS.muted, fontSize: 12.5 }, children: [
|
|
2197
|
+
"\uCF1C\uBA74 \uC81C\uBCF4\uB97C \uC218\uC9D1\uCC98\uB85C \uBCF4\uB0B4\uC9C0 \uC54A\uACE0 ",
|
|
2198
|
+
/* @__PURE__ */ jsx("b", { children: "\uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC" }),
|
|
2199
|
+
"\uD569\uB2C8\uB2E4. \uBD99\uC5EC\uB123\uC73C\uBA74 \uD654\uBA74\xB7\uC694\uC18C\xB7 \uCEF4\uD3EC\uB10C\uD2B8\xB7\uC18C\uC2A4 \uACBD\uB85C\uAC00 \uAC19\uC774 \uB098\uC635\uB2C8\uB2E4."
|
|
2200
|
+
] })
|
|
2201
|
+
] })
|
|
2202
|
+
] }),
|
|
2203
|
+
/* @__PURE__ */ jsxs(
|
|
2204
|
+
"div",
|
|
2205
|
+
{
|
|
2206
|
+
"data-fk-connection": "",
|
|
2207
|
+
style: {
|
|
2208
|
+
marginTop: 12,
|
|
2209
|
+
paddingTop: 12,
|
|
2210
|
+
borderTop: `1px solid ${TOKENS.line}`,
|
|
2211
|
+
fontSize: 12.5
|
|
2212
|
+
},
|
|
2213
|
+
children: [
|
|
2214
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 700, marginBottom: 6 }, children: "\uBCF4\uB0B4\uB294 \uACF3" }),
|
|
2215
|
+
connectionState === "loading" ? /* @__PURE__ */ jsx("div", { style: { color: TOKENS.muted }, children: "\uD655\uC778\uD558\uB294 \uC911\u2026" }) : connectionState === "fail" || !connection ? (
|
|
2216
|
+
// 조용히 비우면 "연결이 없다"로 읽힌다. 못 물어봤다는 것과 없다는 것은 다르다.
|
|
2217
|
+
/* @__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)." })
|
|
2218
|
+
) : /* @__PURE__ */ jsxs("ul", { style: { margin: 0, paddingLeft: 16, color: TOKENS.ink, lineHeight: 1.7 }, children: [
|
|
2219
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2220
|
+
"\uC218\uC9D1\uCC98 \xB7 ",
|
|
2221
|
+
connection.project.name ?? "\uC774\uB984 \uC5C6\uB294 \uD504\uB85C\uC81D\uD2B8"
|
|
2222
|
+
] }),
|
|
2223
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2224
|
+
"Linear \xB7",
|
|
2225
|
+
" ",
|
|
2226
|
+
connection.linear.connected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2227
|
+
connection.linear.teamName ?? "\uC5F0\uACB0\uB41C \uD300",
|
|
2228
|
+
connection.linear.projectName ? ` / ${connection.linear.projectName}` : "",
|
|
2229
|
+
" \u2014 ",
|
|
2230
|
+
/* @__PURE__ */ jsx("b", { children: connection.linear.autoExport ? "\uC81C\uBCF4\uAC00 \uC790\uB3D9\uC73C\uB85C \uB098\uAC11\uB2C8\uB2E4" : "\uC790\uB3D9 \uBC1C\uC1A1 \uAEBC\uC9D0" })
|
|
2231
|
+
] }) : "\uC5F0\uACB0 \uC5C6\uC74C"
|
|
2232
|
+
] }),
|
|
2233
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
2234
|
+
"Symphony \xB7",
|
|
2235
|
+
" ",
|
|
2236
|
+
connection.symphonySlug ? `${connection.symphonySlug} \uAC00 \uCC98\uB9AC` : "\uC790\uB3D9 \uCC98\uB9AC \uC548 \uD568"
|
|
2237
|
+
] })
|
|
2238
|
+
] }),
|
|
2239
|
+
devMode ? (
|
|
2240
|
+
// 개발용 모드가 켜져 있으면 위 목록은 "원래 가던 곳"일 뿐이다. 그대로 두면
|
|
2241
|
+
// 지금도 거기로 가는 줄 읽는다.
|
|
2242
|
+
/* @__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." })
|
|
2243
|
+
) : null
|
|
2244
|
+
]
|
|
2245
|
+
}
|
|
2246
|
+
),
|
|
2247
|
+
/* @__PURE__ */ jsxs("p", { style: { margin: "12px 0 0", color: TOKENS.muted, fontSize: 12 }, children: [
|
|
2248
|
+
"\uC774 \uC124\uC815\uC740 \uB85C\uCEEC(",
|
|
2249
|
+
/* @__PURE__ */ jsx("code", { children: "localhost" }),
|
|
2250
|
+
")\uC5D0\uC11C\uB9CC \uBCF4\uC785\uB2C8\uB2E4. \uBC30\uD3EC\uB41C \uD654\uBA74\uC5D0\uC11C\uB294 \uC2E4\uC0AC\uC6A9\uC790\uAC00 \uCF24 \uC218 \uC5C6\uC5B4\uC57C \uD574\uC11C \uC544\uC608 \uB744\uC6B0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
|
2251
|
+
] }),
|
|
2252
|
+
/* @__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" }) })
|
|
2253
|
+
]
|
|
2254
|
+
}
|
|
2255
|
+
) : null,
|
|
2256
|
+
announcement && !modal.open ? /* @__PURE__ */ jsx(
|
|
2257
|
+
"div",
|
|
2258
|
+
{
|
|
2259
|
+
role: "status",
|
|
2260
|
+
"aria-live": "polite",
|
|
2261
|
+
style: {
|
|
2262
|
+
padding: "10px 14px",
|
|
2263
|
+
borderRadius: 10,
|
|
2264
|
+
background: TOKENS.ink,
|
|
2265
|
+
color: TOKENS.surface,
|
|
2266
|
+
boxShadow: TOKENS.shadow
|
|
2267
|
+
},
|
|
2268
|
+
children: announcement
|
|
2269
|
+
}
|
|
2270
|
+
) : null
|
|
2271
|
+
]
|
|
2042
2272
|
}
|
|
2043
2273
|
) : null,
|
|
2044
2274
|
screen === "modal" && modal.open ? /* @__PURE__ */ jsx(
|
|
@@ -2297,7 +2527,7 @@ function FeedbackKit(props) {
|
|
|
2297
2527
|
opacity: modal.canSubmit ? 1 : 0.5,
|
|
2298
2528
|
cursor: modal.canSubmit ? "pointer" : "not-allowed"
|
|
2299
2529
|
},
|
|
2300
|
-
children: modal.submitStatus === "sending" ? "\uC804\uC1A1 \uC911\u2026" : "\uBCF4\uB0B4\uAE30"
|
|
2530
|
+
children: modal.submitStatus === "sending" ? "\uC804\uC1A1 \uC911\u2026" : devMode ? "\uBCF5\uC0AC" : "\uBCF4\uB0B4\uAE30"
|
|
2301
2531
|
}
|
|
2302
2532
|
)
|
|
2303
2533
|
] })
|
|
@@ -2416,11 +2646,7 @@ function FeedbackKit(props) {
|
|
|
2416
2646
|
"aria-label": "\uC694\uC18C \uC8FC\uC11D",
|
|
2417
2647
|
onSubmit: (event) => {
|
|
2418
2648
|
event.preventDefault();
|
|
2419
|
-
|
|
2420
|
-
void copyOne();
|
|
2421
|
-
return;
|
|
2422
|
-
}
|
|
2423
|
-
void kit.picking.saveAnnotation();
|
|
2649
|
+
commitPopup();
|
|
2424
2650
|
},
|
|
2425
2651
|
onPaste: (event) => {
|
|
2426
2652
|
if (!firstImageOf(event.clipboardData)) return;
|
|
@@ -2502,7 +2728,7 @@ function FeedbackKit(props) {
|
|
|
2502
2728
|
const native = event.nativeEvent;
|
|
2503
2729
|
if (native.isComposing) return;
|
|
2504
2730
|
event.preventDefault();
|
|
2505
|
-
|
|
2731
|
+
commitPopup();
|
|
2506
2732
|
},
|
|
2507
2733
|
rows: 2,
|
|
2508
2734
|
placeholder: "\uBB34\uC5C7\uC774 \uBB38\uC81C\uC778\uAC00\uC694? (Enter \uB85C \uBCF4\uB0B4\uAE30)",
|