@solhun/feedback-kit-web 0.8.0 → 0.10.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 +418 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +388 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -354,6 +354,31 @@ interface WebWidgetOpts extends Omit<WidgetControllerOpts, "platform" | "initial
|
|
|
354
354
|
};
|
|
355
355
|
/** 요소를 고른 뒤 띄울 UI. 기본은 `popup`. */
|
|
356
356
|
pickTarget?: PickTarget;
|
|
357
|
+
/**
|
|
358
|
+
* 플로팅 버튼을 눌렀을 때 무엇이 열리는가. **웹 기본은 `"pick"`(요소 지목)** 이다.
|
|
359
|
+
*
|
|
360
|
+
* 웹 제보는 대개 "이 요소요" 라서, 지목을 매번 켜게 하면 그 한 단계가 계속 남는다. 0.8.0
|
|
361
|
+
* 까지는 모달이 기본이었으므로, 그 동작을 유지하려면 `"report"` 를 준다.
|
|
362
|
+
*
|
|
363
|
+
* 앱에는 지목이 없어 이 설정이 없다(앱은 언제나 모달이다) — 없는 기능을 켤 수는 없다.
|
|
364
|
+
*/
|
|
365
|
+
defaultMode?: "pick" | "report";
|
|
366
|
+
/**
|
|
367
|
+
* 개발용 모드. 제보를 **수집처로 보내지 않고 클립보드에 복사**한다.
|
|
368
|
+
*
|
|
369
|
+
* 개발자가 로컬에서 고치는 중일 때 라쏘런 왕복(보내고·트리아지하고·이슈가 되고)이 오히려
|
|
370
|
+
* 느리다. 정작 고칠 사람은 지금 그 화면을 보고 있는 본인이다.
|
|
371
|
+
*
|
|
372
|
+
* **기본은 꺼짐**이다. 이건 초기값일 뿐이고, 사람이 화면의 톱니(설정)에서 켜거나 끄면
|
|
373
|
+
* 그 선택이 이 값을 이긴다 — 안 그러면 개발 빌드에서 끄려고 또 코드를 고쳐야 한다.
|
|
374
|
+
* 톱니는 **로컬(`localhost`)에서만** 뜬다. 배포된 화면에서 실사용자가 켜면 그 사람 제보는
|
|
375
|
+
* 어디에도 안 남고 본인은 보냈다고 믿는다. 이 값을 `true` 로 주면 톱니도 같이 뜬다.
|
|
376
|
+
*
|
|
377
|
+
* 켜져 있는 동안은 그 사실이 화면에 계속 보인다(조용한 유실을 막는 유일한 방어).
|
|
378
|
+
*
|
|
379
|
+
* 웹 전용이다. 앱에는 DOM 이 없어 선택자·컴포넌트 경로·소스 경로가 성립하지 않는다.
|
|
380
|
+
*/
|
|
381
|
+
devMode?: boolean;
|
|
357
382
|
/**
|
|
358
383
|
* 정적 힌트 목록(설정으로 직접 넘김). 주면 서버에서 받아오지 않는다 — 도입 초기·오프라인
|
|
359
384
|
* 데모·테스트용이다. 서버 목록과 합치지 않는다(둘을 섞으면 무엇이 보이는지 설명이 안 된다).
|
package/dist/index.d.ts
CHANGED
|
@@ -354,6 +354,31 @@ interface WebWidgetOpts extends Omit<WidgetControllerOpts, "platform" | "initial
|
|
|
354
354
|
};
|
|
355
355
|
/** 요소를 고른 뒤 띄울 UI. 기본은 `popup`. */
|
|
356
356
|
pickTarget?: PickTarget;
|
|
357
|
+
/**
|
|
358
|
+
* 플로팅 버튼을 눌렀을 때 무엇이 열리는가. **웹 기본은 `"pick"`(요소 지목)** 이다.
|
|
359
|
+
*
|
|
360
|
+
* 웹 제보는 대개 "이 요소요" 라서, 지목을 매번 켜게 하면 그 한 단계가 계속 남는다. 0.8.0
|
|
361
|
+
* 까지는 모달이 기본이었으므로, 그 동작을 유지하려면 `"report"` 를 준다.
|
|
362
|
+
*
|
|
363
|
+
* 앱에는 지목이 없어 이 설정이 없다(앱은 언제나 모달이다) — 없는 기능을 켤 수는 없다.
|
|
364
|
+
*/
|
|
365
|
+
defaultMode?: "pick" | "report";
|
|
366
|
+
/**
|
|
367
|
+
* 개발용 모드. 제보를 **수집처로 보내지 않고 클립보드에 복사**한다.
|
|
368
|
+
*
|
|
369
|
+
* 개발자가 로컬에서 고치는 중일 때 라쏘런 왕복(보내고·트리아지하고·이슈가 되고)이 오히려
|
|
370
|
+
* 느리다. 정작 고칠 사람은 지금 그 화면을 보고 있는 본인이다.
|
|
371
|
+
*
|
|
372
|
+
* **기본은 꺼짐**이다. 이건 초기값일 뿐이고, 사람이 화면의 톱니(설정)에서 켜거나 끄면
|
|
373
|
+
* 그 선택이 이 값을 이긴다 — 안 그러면 개발 빌드에서 끄려고 또 코드를 고쳐야 한다.
|
|
374
|
+
* 톱니는 **로컬(`localhost`)에서만** 뜬다. 배포된 화면에서 실사용자가 켜면 그 사람 제보는
|
|
375
|
+
* 어디에도 안 남고 본인은 보냈다고 믿는다. 이 값을 `true` 로 주면 톱니도 같이 뜬다.
|
|
376
|
+
*
|
|
377
|
+
* 켜져 있는 동안은 그 사실이 화면에 계속 보인다(조용한 유실을 막는 유일한 방어).
|
|
378
|
+
*
|
|
379
|
+
* 웹 전용이다. 앱에는 DOM 이 없어 선택자·컴포넌트 경로·소스 경로가 성립하지 않는다.
|
|
380
|
+
*/
|
|
381
|
+
devMode?: boolean;
|
|
357
382
|
/**
|
|
358
383
|
* 정적 힌트 목록(설정으로 직접 넘김). 주면 서버에서 받아오지 않는다 — 도입 초기·오프라인
|
|
359
384
|
* 데모·테스트용이다. 서버 목록과 합치지 않는다(둘을 섞으면 무엇이 보이는지 설명이 안 된다).
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { resolveConfig, shouldShowWidget } from "@solhun/feedback-kit-core";
|
|
3
|
-
import { parseSourceAttr, SOURCE_ATTR, sourceFromElement } from "@solhun/feedback-kit-core";
|
|
3
|
+
import { parseSourceAttr, SOURCE_ATTR, sourceFromElement as sourceFromElement2 } from "@solhun/feedback-kit-core";
|
|
4
4
|
import {
|
|
5
5
|
COMMENT_MAX_CHARS as COMMENT_MAX_CHARS3,
|
|
6
6
|
COMMENT_REQUIRED_MESSAGE,
|
|
@@ -1174,7 +1174,84 @@ import {
|
|
|
1174
1174
|
} from "react";
|
|
1175
1175
|
|
|
1176
1176
|
// src/version.ts
|
|
1177
|
-
var VERSION = true ? "0.
|
|
1177
|
+
var VERSION = true ? "0.10.0" : "dev";
|
|
1178
|
+
|
|
1179
|
+
// src/dev-clipboard.ts
|
|
1180
|
+
import { sourceFromElement } from "@solhun/feedback-kit-core";
|
|
1181
|
+
function sourceLine(item) {
|
|
1182
|
+
const mapping = sourceFromElement(item.element ?? void 0);
|
|
1183
|
+
if (!mapping.sourceFile) return null;
|
|
1184
|
+
return mapping.sourceLine === null ? `\uC18C\uC2A4: ${mapping.sourceFile}` : `\uC18C\uC2A4: ${mapping.sourceFile}:${mapping.sourceLine}`;
|
|
1185
|
+
}
|
|
1186
|
+
function elementLine(element) {
|
|
1187
|
+
if (!element) return null;
|
|
1188
|
+
const selector = element.selector ?? element.tag;
|
|
1189
|
+
const text = element.text?.trim();
|
|
1190
|
+
return text ? `\uC694\uC18C: ${selector} "${text}"` : `\uC694\uC18C: ${selector}`;
|
|
1191
|
+
}
|
|
1192
|
+
function componentLine(element) {
|
|
1193
|
+
const summary = element?.attributes?.["react-components"];
|
|
1194
|
+
return summary ? `\uCEF4\uD3EC\uB10C\uD2B8: ${summary}` : null;
|
|
1195
|
+
}
|
|
1196
|
+
function renderDevClipItem(item) {
|
|
1197
|
+
const lines = [`[\uD53C\uB4DC\uBC31] ${item.comment.trim()}`];
|
|
1198
|
+
const screen = item.screen?.trim();
|
|
1199
|
+
if (screen) lines.push(`\uD654\uBA74: ${screen}`);
|
|
1200
|
+
const element = elementLine(item.element);
|
|
1201
|
+
if (element) lines.push(element);
|
|
1202
|
+
const component = componentLine(item.element);
|
|
1203
|
+
if (component) lines.push(component);
|
|
1204
|
+
const source = sourceLine(item);
|
|
1205
|
+
if (source) lines.push(source);
|
|
1206
|
+
if (item.priority && item.priority !== "unset") lines.push(`\uC6B0\uC120\uC21C\uC704: ${item.priority}`);
|
|
1207
|
+
return lines.join("\n");
|
|
1208
|
+
}
|
|
1209
|
+
function renderDevClipList(items) {
|
|
1210
|
+
if (items.length === 0) return "";
|
|
1211
|
+
if (items.length === 1) return renderDevClipItem(items[0]);
|
|
1212
|
+
return items.map((item, index) => `${index + 1}. ${renderDevClipItem(item).split("\n").join("\n ")}`).join("\n\n");
|
|
1213
|
+
}
|
|
1214
|
+
async function writeToClipboard(text) {
|
|
1215
|
+
const clipboard = globalThis.navigator?.clipboard;
|
|
1216
|
+
if (!clipboard?.writeText) return false;
|
|
1217
|
+
try {
|
|
1218
|
+
await clipboard.writeText(text);
|
|
1219
|
+
return true;
|
|
1220
|
+
} catch {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// src/dev-preference.ts
|
|
1226
|
+
var STORAGE_KEY = "feedback-kit:dev-mode";
|
|
1227
|
+
function isDevSettingsHost(hostname) {
|
|
1228
|
+
const host = hostname.trim().toLowerCase();
|
|
1229
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") return true;
|
|
1230
|
+
return host.endsWith(".localhost") || host.endsWith(".local");
|
|
1231
|
+
}
|
|
1232
|
+
function readDevPreference() {
|
|
1233
|
+
try {
|
|
1234
|
+
const raw = globalThis.localStorage?.getItem(STORAGE_KEY);
|
|
1235
|
+
if (raw === "on") return true;
|
|
1236
|
+
if (raw === "off") return false;
|
|
1237
|
+
return null;
|
|
1238
|
+
} catch {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function writeDevPreference(value) {
|
|
1243
|
+
try {
|
|
1244
|
+
const storage = globalThis.localStorage;
|
|
1245
|
+
if (!storage) return;
|
|
1246
|
+
if (value === null) storage.removeItem(STORAGE_KEY);
|
|
1247
|
+
else storage.setItem(STORAGE_KEY, value ? "on" : "off");
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function resolveDevMode(propValue, stored) {
|
|
1252
|
+
if (stored !== null) return stored;
|
|
1253
|
+
return propValue === true;
|
|
1254
|
+
}
|
|
1178
1255
|
|
|
1179
1256
|
// src/feedback-kit.tsx
|
|
1180
1257
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1443,7 +1520,10 @@ function PickBar({
|
|
|
1443
1520
|
markerCount,
|
|
1444
1521
|
onToggle,
|
|
1445
1522
|
onTogglePause,
|
|
1446
|
-
onClearMarkers
|
|
1523
|
+
onClearMarkers,
|
|
1524
|
+
onReportWholeScreen,
|
|
1525
|
+
devClipCount,
|
|
1526
|
+
onCopyAll
|
|
1447
1527
|
}) {
|
|
1448
1528
|
return /* @__PURE__ */ jsxs(
|
|
1449
1529
|
"div",
|
|
@@ -1498,6 +1578,48 @@ function PickBar({
|
|
|
1498
1578
|
]
|
|
1499
1579
|
}
|
|
1500
1580
|
),
|
|
1581
|
+
/* @__PURE__ */ jsxs(
|
|
1582
|
+
"button",
|
|
1583
|
+
{
|
|
1584
|
+
type: "button",
|
|
1585
|
+
"data-fk-pick-whole": "",
|
|
1586
|
+
title: "\uAC00\uB9AC\uD0A8 \uC694\uC18C \uC5C6\uC774 \uC774 \uD654\uBA74 \uC804\uCCB4\uC5D0 \uB300\uD574 \uC81C\uBCF4\uD569\uB2C8\uB2E4.",
|
|
1587
|
+
onClick: onReportWholeScreen,
|
|
1588
|
+
style: {
|
|
1589
|
+
...baseButton,
|
|
1590
|
+
display: "inline-flex",
|
|
1591
|
+
alignItems: "center",
|
|
1592
|
+
gap: 6,
|
|
1593
|
+
whiteSpace: "nowrap"
|
|
1594
|
+
},
|
|
1595
|
+
children: [
|
|
1596
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u25A3" }),
|
|
1597
|
+
"\uD654\uBA74 \uC804\uCCB4\uB85C \uBCF4\uB0B4\uAE30"
|
|
1598
|
+
]
|
|
1599
|
+
}
|
|
1600
|
+
),
|
|
1601
|
+
devClipCount > 0 ? /* @__PURE__ */ jsxs(
|
|
1602
|
+
"button",
|
|
1603
|
+
{
|
|
1604
|
+
type: "button",
|
|
1605
|
+
"data-fk-copy-all": devClipCount,
|
|
1606
|
+
title: "\uC774\uBC88 \uC138\uC158\uC5D0 \uCC0D\uC740 \uAC83\uC744 \uBC88\uD638 \uB9E4\uAE34 \uBAA9\uB85D \uD558\uB098\uB85C \uBCF5\uC0AC\uD569\uB2C8\uB2E4.",
|
|
1607
|
+
onClick: onCopyAll,
|
|
1608
|
+
style: {
|
|
1609
|
+
...baseButton,
|
|
1610
|
+
display: "inline-flex",
|
|
1611
|
+
alignItems: "center",
|
|
1612
|
+
gap: 6,
|
|
1613
|
+
whiteSpace: "nowrap",
|
|
1614
|
+
fontWeight: 600
|
|
1615
|
+
},
|
|
1616
|
+
children: [
|
|
1617
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u29C9" }),
|
|
1618
|
+
"\uC804\uBD80 \uBCF5\uC0AC ",
|
|
1619
|
+
devClipCount
|
|
1620
|
+
]
|
|
1621
|
+
}
|
|
1622
|
+
) : null,
|
|
1501
1623
|
markerCount > 0 ? /* @__PURE__ */ jsxs(
|
|
1502
1624
|
"button",
|
|
1503
1625
|
{
|
|
@@ -1626,6 +1748,14 @@ function FeedbackKit(props) {
|
|
|
1626
1748
|
const [widgetState, setWidgetState] = useState(null);
|
|
1627
1749
|
const [pickingState, setPickingState] = useState(INITIAL_PICKING_STATE);
|
|
1628
1750
|
const [announcement, setAnnouncement] = useState(null);
|
|
1751
|
+
const [devMode, setDevMode] = useState(() => resolveDevMode(props.devMode, readDevPreference()));
|
|
1752
|
+
const [devSettingsAvailable] = useState(
|
|
1753
|
+
() => props.devMode === true || isDevSettingsHost(globalThis.location?.hostname ?? "")
|
|
1754
|
+
);
|
|
1755
|
+
const [devSettingsOpen, setDevSettingsOpen] = useState(false);
|
|
1756
|
+
const devClipsRef = useRef([]);
|
|
1757
|
+
const [devClipCount, setDevClipCount] = useState(0);
|
|
1758
|
+
const [devFallbackText, setDevFallbackText] = useState(null);
|
|
1629
1759
|
const {
|
|
1630
1760
|
queue,
|
|
1631
1761
|
createReport,
|
|
@@ -1750,6 +1880,56 @@ function FeedbackKit(props) {
|
|
|
1750
1880
|
if (root) root.style.visibility = previousVisibility;
|
|
1751
1881
|
}
|
|
1752
1882
|
}
|
|
1883
|
+
function currentClip() {
|
|
1884
|
+
const state = pickingState.popup;
|
|
1885
|
+
if (!state) return null;
|
|
1886
|
+
return {
|
|
1887
|
+
comment: state.comment,
|
|
1888
|
+
element: state.element ?? null,
|
|
1889
|
+
screen: typeof location === "undefined" ? null : location.pathname
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1892
|
+
async function putOnClipboard(text) {
|
|
1893
|
+
const ok = await writeToClipboard(text);
|
|
1894
|
+
setDevFallbackText(ok ? null : text);
|
|
1895
|
+
}
|
|
1896
|
+
function commitPopup() {
|
|
1897
|
+
if (devMode) {
|
|
1898
|
+
void copyOne();
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
void activeKit.picking.saveAnnotation();
|
|
1902
|
+
}
|
|
1903
|
+
async function copyOne() {
|
|
1904
|
+
const clip = currentClip();
|
|
1905
|
+
if (!clip || clip.comment.trim() === "") return;
|
|
1906
|
+
devClipsRef.current = [...devClipsRef.current, clip];
|
|
1907
|
+
setDevClipCount(devClipsRef.current.length);
|
|
1908
|
+
activeKit.picking.cancelAnnotation();
|
|
1909
|
+
await putOnClipboard(renderDevClipItem(clip));
|
|
1910
|
+
}
|
|
1911
|
+
async function copyAll() {
|
|
1912
|
+
if (devClipsRef.current.length === 0) return;
|
|
1913
|
+
await putOnClipboard(renderDevClipList(devClipsRef.current));
|
|
1914
|
+
}
|
|
1915
|
+
function toggleDevMode(next) {
|
|
1916
|
+
writeDevPreference(next);
|
|
1917
|
+
setDevMode(next);
|
|
1918
|
+
devClipsRef.current = [];
|
|
1919
|
+
setDevClipCount(0);
|
|
1920
|
+
setDevFallbackText(null);
|
|
1921
|
+
setAnnouncement(
|
|
1922
|
+
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."
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
async function pressFloatingButton() {
|
|
1926
|
+
if (props.defaultMode !== "report" && !pickingActive) {
|
|
1927
|
+
setAnnouncement(null);
|
|
1928
|
+
activeKit.widget.startPicking();
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
await openReport();
|
|
1932
|
+
}
|
|
1753
1933
|
async function openReport() {
|
|
1754
1934
|
setAnnouncement(null);
|
|
1755
1935
|
await withOwnUiHidden(() => activeKit.widget.openReport());
|
|
@@ -1799,8 +1979,26 @@ function FeedbackKit(props) {
|
|
|
1799
1979
|
}
|
|
1800
1980
|
function submitReport(event) {
|
|
1801
1981
|
event.preventDefault();
|
|
1982
|
+
if (devMode) {
|
|
1983
|
+
void copyFromModal();
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1802
1986
|
void activeKit.widget.submitReport();
|
|
1803
1987
|
}
|
|
1988
|
+
async function copyFromModal() {
|
|
1989
|
+
const modalState = activeKit.widget.getState().modal;
|
|
1990
|
+
if (modalState.comment.trim() === "") return;
|
|
1991
|
+
const clip = {
|
|
1992
|
+
comment: modalState.comment,
|
|
1993
|
+
element: modalState.element ?? null,
|
|
1994
|
+
screen: typeof location === "undefined" ? null : location.pathname,
|
|
1995
|
+
priority: modalState.priority
|
|
1996
|
+
};
|
|
1997
|
+
devClipsRef.current = [...devClipsRef.current, clip];
|
|
1998
|
+
setDevClipCount(devClipsRef.current.length);
|
|
1999
|
+
activeKit.widget.confirmCloseReport();
|
|
2000
|
+
await putOnClipboard(renderDevClipItem(clip));
|
|
2001
|
+
}
|
|
1804
2002
|
const floating = screen === "button" || screen === "picking";
|
|
1805
2003
|
const hoverBox = pickingState.hovered?.boundingBox;
|
|
1806
2004
|
const popup = pickingState.popup;
|
|
@@ -1812,45 +2010,199 @@ function FeedbackKit(props) {
|
|
|
1812
2010
|
style: { fontFamily: FONT_STACK, color: TOKENS.ink, fontSize: 14, lineHeight: 1.45 },
|
|
1813
2011
|
children: [
|
|
1814
2012
|
/* @__PURE__ */ jsx("style", { children: `@keyframes feedback-kit-spin{to{transform:rotate(360deg)}}` }),
|
|
1815
|
-
floating ?
|
|
1816
|
-
|
|
2013
|
+
floating ? (
|
|
2014
|
+
// 톱니와 피드백 버튼을 한 상자에 넣는다. 각각 fixed 로 두면 버튼 글자 길이가
|
|
2015
|
+
// 바뀔 때마다 좌표를 다시 맞춰야 하고, 그러다 겹친다.
|
|
2016
|
+
/* @__PURE__ */ jsxs(
|
|
2017
|
+
"div",
|
|
2018
|
+
{
|
|
2019
|
+
style: {
|
|
2020
|
+
position: "fixed",
|
|
2021
|
+
right: 24,
|
|
2022
|
+
bottom: 24,
|
|
2023
|
+
zIndex: 2147483600,
|
|
2024
|
+
display: "flex",
|
|
2025
|
+
alignItems: "center",
|
|
2026
|
+
gap: 8
|
|
2027
|
+
},
|
|
2028
|
+
children: [
|
|
2029
|
+
devSettingsAvailable ? /* @__PURE__ */ jsx(
|
|
2030
|
+
"button",
|
|
2031
|
+
{
|
|
2032
|
+
type: "button",
|
|
2033
|
+
"data-fk-dev-settings-toggle": "",
|
|
2034
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uC124\uC815",
|
|
2035
|
+
"aria-expanded": devSettingsOpen,
|
|
2036
|
+
onClick: () => setDevSettingsOpen((open) => !open),
|
|
2037
|
+
style: {
|
|
2038
|
+
...baseButton,
|
|
2039
|
+
width: 46,
|
|
2040
|
+
minHeight: 46,
|
|
2041
|
+
padding: 0,
|
|
2042
|
+
borderRadius: 23,
|
|
2043
|
+
boxShadow: TOKENS.shadow,
|
|
2044
|
+
fontSize: 17,
|
|
2045
|
+
lineHeight: 1
|
|
2046
|
+
},
|
|
2047
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2699" })
|
|
2048
|
+
}
|
|
2049
|
+
) : null,
|
|
2050
|
+
/* @__PURE__ */ jsx(
|
|
2051
|
+
"button",
|
|
2052
|
+
{
|
|
2053
|
+
ref: floatingButtonRef,
|
|
2054
|
+
id: FLOATING_BUTTON_ID,
|
|
2055
|
+
type: "button",
|
|
2056
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uBCF4\uB0B4\uAE30",
|
|
2057
|
+
onClick: () => void pressFloatingButton(),
|
|
2058
|
+
style: {
|
|
2059
|
+
...primaryButton,
|
|
2060
|
+
minWidth: 112,
|
|
2061
|
+
minHeight: 46,
|
|
2062
|
+
borderRadius: 24,
|
|
2063
|
+
boxShadow: TOKENS.shadow
|
|
2064
|
+
},
|
|
2065
|
+
children: "\uD53C\uB4DC\uBC31"
|
|
2066
|
+
}
|
|
2067
|
+
)
|
|
2068
|
+
]
|
|
2069
|
+
}
|
|
2070
|
+
)
|
|
2071
|
+
) : null,
|
|
2072
|
+
floating && devMode ? (
|
|
2073
|
+
// 켠 줄 모르고 제보하면 "보냈다"고 믿는데 수집처엔 아무것도 안 남는다.
|
|
2074
|
+
// 조용한 유실이라 이 표시가 유일한 방어다. 버튼 **밖**에 두는 이유는 버튼의
|
|
2075
|
+
// 접근성 이름을 오염시키지 않기 위해서다.
|
|
2076
|
+
/* @__PURE__ */ jsx(
|
|
2077
|
+
"span",
|
|
2078
|
+
{
|
|
2079
|
+
"data-fk-dev-badge": "",
|
|
2080
|
+
"aria-label": "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC\uAC00 \uCF1C\uC838 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uC81C\uBCF4\uAC00 \uC218\uC9D1\uCC98\uB85C \uAC00\uC9C0 \uC54A\uACE0 \uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC\uB429\uB2C8\uB2E4",
|
|
2081
|
+
style: {
|
|
2082
|
+
position: "fixed",
|
|
2083
|
+
right: 24,
|
|
2084
|
+
bottom: 62,
|
|
2085
|
+
zIndex: 2147483601,
|
|
2086
|
+
padding: "2px 8px",
|
|
2087
|
+
borderRadius: 6,
|
|
2088
|
+
background: TOKENS.warning,
|
|
2089
|
+
color: "#1f2933",
|
|
2090
|
+
fontSize: 11,
|
|
2091
|
+
fontWeight: 700,
|
|
2092
|
+
pointerEvents: "none"
|
|
2093
|
+
},
|
|
2094
|
+
children: "\uAC1C\uBC1C\uC6A9 \u2014 \uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC"
|
|
2095
|
+
}
|
|
2096
|
+
)
|
|
2097
|
+
) : null,
|
|
2098
|
+
devFallbackText !== null ? /* @__PURE__ */ jsxs(
|
|
2099
|
+
"div",
|
|
1817
2100
|
{
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
"aria-label": "\uD53C\uB4DC\uBC31 \uBCF4\uB0B4\uAE30",
|
|
1822
|
-
onClick: () => void openReport(),
|
|
2101
|
+
role: "dialog",
|
|
2102
|
+
"aria-label": "\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBABB \uC368\uC11C \uB300\uC2E0 \uBCF4\uC5EC\uC90D\uB2C8\uB2E4",
|
|
2103
|
+
"data-fk-dev-fallback": "",
|
|
1823
2104
|
style: {
|
|
1824
|
-
...primaryButton,
|
|
1825
2105
|
position: "fixed",
|
|
1826
2106
|
right: 24,
|
|
1827
|
-
bottom:
|
|
1828
|
-
zIndex:
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
borderRadius:
|
|
1832
|
-
|
|
2107
|
+
bottom: 92,
|
|
2108
|
+
zIndex: 2147483602,
|
|
2109
|
+
width: "min(420px, calc(100vw - 48px))",
|
|
2110
|
+
border: `1px solid ${TOKENS.line}`,
|
|
2111
|
+
borderRadius: 12,
|
|
2112
|
+
background: TOKENS.surface,
|
|
2113
|
+
padding: 12,
|
|
2114
|
+
boxShadow: TOKENS.shadow,
|
|
2115
|
+
pointerEvents: "auto"
|
|
1833
2116
|
},
|
|
1834
|
-
children:
|
|
2117
|
+
children: [
|
|
2118
|
+
/* @__PURE__ */ jsx("div", { style: { marginBottom: 6, color: TOKENS.muted, fontSize: 12 }, children: "\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uC4F0\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC544\uB798\uC5D0\uC11C \uC9C1\uC811 \uBCF5\uC0AC\uD558\uC138\uC694." }),
|
|
2119
|
+
/* @__PURE__ */ jsx(
|
|
2120
|
+
"textarea",
|
|
2121
|
+
{
|
|
2122
|
+
readOnly: true,
|
|
2123
|
+
value: devFallbackText,
|
|
2124
|
+
onFocus: (event) => event.currentTarget.select(),
|
|
2125
|
+
style: { ...inputStyle, height: 140, fontFamily: "ui-monospace, monospace", fontSize: 12 }
|
|
2126
|
+
}
|
|
2127
|
+
),
|
|
2128
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: 8 }, children: /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setDevFallbackText(null), style: baseButton, children: "\uB2EB\uAE30" }) })
|
|
2129
|
+
]
|
|
1835
2130
|
}
|
|
1836
2131
|
) : null,
|
|
1837
|
-
announcement && !modal.open ? /* @__PURE__ */
|
|
2132
|
+
devSettingsOpen || announcement && !modal.open ? /* @__PURE__ */ jsxs(
|
|
1838
2133
|
"div",
|
|
1839
2134
|
{
|
|
1840
|
-
role: "status",
|
|
1841
|
-
"aria-live": "polite",
|
|
1842
2135
|
style: {
|
|
1843
2136
|
position: "fixed",
|
|
1844
2137
|
right: 24,
|
|
1845
2138
|
bottom: 82,
|
|
1846
2139
|
zIndex: 2147483601,
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
boxShadow: TOKENS.shadow
|
|
2140
|
+
display: "flex",
|
|
2141
|
+
flexDirection: "column",
|
|
2142
|
+
alignItems: "flex-end",
|
|
2143
|
+
gap: 8
|
|
1852
2144
|
},
|
|
1853
|
-
children:
|
|
2145
|
+
children: [
|
|
2146
|
+
devSettingsOpen ? /* @__PURE__ */ jsxs(
|
|
2147
|
+
"div",
|
|
2148
|
+
{
|
|
2149
|
+
role: "dialog",
|
|
2150
|
+
"aria-label": "\uD53C\uB4DC\uBC31 \uC124\uC815",
|
|
2151
|
+
"data-fk-dev-settings": "",
|
|
2152
|
+
style: {
|
|
2153
|
+
width: 292,
|
|
2154
|
+
maxWidth: "calc(100vw - 48px)",
|
|
2155
|
+
padding: 14,
|
|
2156
|
+
borderRadius: 12,
|
|
2157
|
+
border: `1px solid ${TOKENS.line}`,
|
|
2158
|
+
background: TOKENS.surface,
|
|
2159
|
+
boxShadow: TOKENS.shadow
|
|
2160
|
+
},
|
|
2161
|
+
children: [
|
|
2162
|
+
/* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "flex-start", gap: 9, cursor: "pointer" }, children: [
|
|
2163
|
+
/* @__PURE__ */ jsx(
|
|
2164
|
+
"input",
|
|
2165
|
+
{
|
|
2166
|
+
type: "checkbox",
|
|
2167
|
+
checked: devMode,
|
|
2168
|
+
onChange: (event) => toggleDevMode(event.currentTarget.checked),
|
|
2169
|
+
style: { marginTop: 3 }
|
|
2170
|
+
}
|
|
2171
|
+
),
|
|
2172
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2173
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 700 }, children: "\uAC1C\uBC1C\uC6A9 \uBAA8\uB4DC" }),
|
|
2174
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "block", marginTop: 4, color: TOKENS.muted, fontSize: 12.5 }, children: [
|
|
2175
|
+
"\uCF1C\uBA74 \uC81C\uBCF4\uB97C \uC218\uC9D1\uCC98\uB85C \uBCF4\uB0B4\uC9C0 \uC54A\uACE0 ",
|
|
2176
|
+
/* @__PURE__ */ jsx("b", { children: "\uD074\uB9BD\uBCF4\uB4DC\uB85C \uBCF5\uC0AC" }),
|
|
2177
|
+
"\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."
|
|
2178
|
+
] })
|
|
2179
|
+
] })
|
|
2180
|
+
] }),
|
|
2181
|
+
/* @__PURE__ */ jsxs("p", { style: { margin: "12px 0 0", color: TOKENS.muted, fontSize: 12 }, children: [
|
|
2182
|
+
"\uC774 \uC124\uC815\uC740 \uB85C\uCEEC(",
|
|
2183
|
+
/* @__PURE__ */ jsx("code", { children: "localhost" }),
|
|
2184
|
+
")\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."
|
|
2185
|
+
] }),
|
|
2186
|
+
/* @__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
|
+
]
|
|
2188
|
+
}
|
|
2189
|
+
) : null,
|
|
2190
|
+
announcement && !modal.open ? /* @__PURE__ */ jsx(
|
|
2191
|
+
"div",
|
|
2192
|
+
{
|
|
2193
|
+
role: "status",
|
|
2194
|
+
"aria-live": "polite",
|
|
2195
|
+
style: {
|
|
2196
|
+
padding: "10px 14px",
|
|
2197
|
+
borderRadius: 10,
|
|
2198
|
+
background: TOKENS.ink,
|
|
2199
|
+
color: TOKENS.surface,
|
|
2200
|
+
boxShadow: TOKENS.shadow
|
|
2201
|
+
},
|
|
2202
|
+
children: announcement
|
|
2203
|
+
}
|
|
2204
|
+
) : null
|
|
2205
|
+
]
|
|
1854
2206
|
}
|
|
1855
2207
|
) : null,
|
|
1856
2208
|
screen === "modal" && modal.open ? /* @__PURE__ */ jsx(
|
|
@@ -2109,7 +2461,7 @@ function FeedbackKit(props) {
|
|
|
2109
2461
|
opacity: modal.canSubmit ? 1 : 0.5,
|
|
2110
2462
|
cursor: modal.canSubmit ? "pointer" : "not-allowed"
|
|
2111
2463
|
},
|
|
2112
|
-
children: modal.submitStatus === "sending" ? "\uC804\uC1A1 \uC911\u2026" : "\uBCF4\uB0B4\uAE30"
|
|
2464
|
+
children: modal.submitStatus === "sending" ? "\uC804\uC1A1 \uC911\u2026" : devMode ? "\uBCF5\uC0AC" : "\uBCF4\uB0B4\uAE30"
|
|
2113
2465
|
}
|
|
2114
2466
|
)
|
|
2115
2467
|
] })
|
|
@@ -2188,7 +2540,10 @@ function FeedbackKit(props) {
|
|
|
2188
2540
|
markerCount: pickingState.markers.length,
|
|
2189
2541
|
onToggle: togglePicking,
|
|
2190
2542
|
onTogglePause: () => activeKit.picking.togglePause(),
|
|
2191
|
-
onClearMarkers: () => activeKit.picking.clearMarkers()
|
|
2543
|
+
onClearMarkers: () => activeKit.picking.clearMarkers(),
|
|
2544
|
+
onReportWholeScreen: () => void openReport(),
|
|
2545
|
+
devClipCount: devMode ? devClipCount : 0,
|
|
2546
|
+
onCopyAll: () => void copyAll()
|
|
2192
2547
|
}
|
|
2193
2548
|
),
|
|
2194
2549
|
pickingState.markers.map((marker, index) => /* @__PURE__ */ jsx(
|
|
@@ -2225,7 +2580,7 @@ function FeedbackKit(props) {
|
|
|
2225
2580
|
"aria-label": "\uC694\uC18C \uC8FC\uC11D",
|
|
2226
2581
|
onSubmit: (event) => {
|
|
2227
2582
|
event.preventDefault();
|
|
2228
|
-
|
|
2583
|
+
commitPopup();
|
|
2229
2584
|
},
|
|
2230
2585
|
onPaste: (event) => {
|
|
2231
2586
|
if (!firstImageOf(event.clipboardData)) return;
|
|
@@ -2307,7 +2662,7 @@ function FeedbackKit(props) {
|
|
|
2307
2662
|
const native = event.nativeEvent;
|
|
2308
2663
|
if (native.isComposing) return;
|
|
2309
2664
|
event.preventDefault();
|
|
2310
|
-
|
|
2665
|
+
commitPopup();
|
|
2311
2666
|
},
|
|
2312
2667
|
rows: 2,
|
|
2313
2668
|
placeholder: "\uBB34\uC5C7\uC774 \uBB38\uC81C\uC778\uAC00\uC694? (Enter \uB85C \uBCF4\uB0B4\uAE30)",
|
|
@@ -2378,7 +2733,7 @@ function FeedbackKit(props) {
|
|
|
2378
2733
|
opacity: popup.canSave && !popup.saving ? 1 : 0.5,
|
|
2379
2734
|
cursor: popup.canSave && !popup.saving ? "pointer" : "not-allowed"
|
|
2380
2735
|
},
|
|
2381
|
-
children: popup.saving ? "\uBCF4\uB0B4\uB294 \uC911\u2026" : "\uBCF4\uB0B4\uAE30"
|
|
2736
|
+
children: popup.saving ? "\uBCF4\uB0B4\uB294 \uC911\u2026" : devMode ? "\uBCF5\uC0AC" : "\uBCF4\uB0B4\uAE30"
|
|
2382
2737
|
}
|
|
2383
2738
|
)
|
|
2384
2739
|
] })
|
|
@@ -2460,7 +2815,7 @@ export {
|
|
|
2460
2815
|
reencodeWebScreenshot,
|
|
2461
2816
|
resolveConfig,
|
|
2462
2817
|
shouldShowWidget,
|
|
2463
|
-
sourceFromElement,
|
|
2818
|
+
sourceFromElement2 as sourceFromElement,
|
|
2464
2819
|
visibleText,
|
|
2465
2820
|
webContextProviders,
|
|
2466
2821
|
webDiagnosticsOptions,
|