lynx-console 0.6.0 → 0.6.1

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 CHANGED
@@ -222,6 +222,35 @@ const useConsole = () => {
222
222
  };
223
223
  };
224
224
 
225
+ //#endregion
226
+ //#region src/hooks/useLatestFcp.ts
227
+ const pickFcp = (entry) => {
228
+ if (entry.entryType !== "metric" || entry.name !== "fcp") return void 0;
229
+ const raw = entry.rawEntry;
230
+ if (raw?.totalFcp?.duration !== void 0) return raw.totalFcp;
231
+ if (raw?.lynxFcp?.duration !== void 0) return raw.lynxFcp;
232
+ };
233
+ const useLatestFcp = () => {
234
+ const [fcp, setFcp] = (0, _lynx_js_react.useState)(() => {
235
+ const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];
236
+ for (let i = performances.length - 1; i >= 0; i--) {
237
+ const entry = performances[i];
238
+ if (!entry) continue;
239
+ const found = pickFcp(entry);
240
+ if (found) return found;
241
+ }
242
+ });
243
+ (0, _lynx_js_react.useEffect)(() => {
244
+ const state = globalThis.__LYNX_CONSOLE__?.state;
245
+ if (!state?.subscribePerformance) return;
246
+ return state.subscribePerformance((entry) => {
247
+ const found = pickFcp(entry);
248
+ if (found) setFcp(found);
249
+ });
250
+ }, []);
251
+ return fcp;
252
+ };
253
+
225
254
  //#endregion
226
255
  //#region src/hooks/useNetwork.ts
227
256
  const useNetwork = () => {
@@ -484,7 +513,8 @@ const LogPanel = ({ logs, clearLogs }) => {
484
513
  params: {
485
514
  position: logsRef.current.length - 1,
486
515
  smooth
487
- }
516
+ },
517
+ fail: () => {}
488
518
  }).exec();
489
519
  };
490
520
  (0, _lynx_js_react.useEffect)(() => {
@@ -1498,7 +1528,7 @@ const FloatingButton = ({ bindtap, children, initialPosition }) => {
1498
1528
  }
1499
1529
  };
1500
1530
  const isDragging = phase === "dragging";
1501
- return <view className={"fb-wrapper"} consume-slide-event={[[-180, 180]]} style={{
1531
+ return <view className={"fb-wrapper"} style={{
1502
1532
  ...positionStyle,
1503
1533
  transform: isDragging ? "scale(1.05)" : "scale(1)",
1504
1534
  transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
@@ -1520,18 +1550,8 @@ const FloatingButton = ({ bindtap, children, initialPosition }) => {
1520
1550
  const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
1521
1551
  const [isOpen, setIsOpen] = (0, _lynx_js_react.useState)(false);
1522
1552
  const [shouldClose, setShouldClose] = (0, _lynx_js_react.useState)(false);
1523
- const { performances } = usePerformance();
1553
+ const latestFcp = useLatestFcp();
1524
1554
  const colors = (0, _lynx_js_react.useMemo)(() => getColors(theme), [theme]);
1525
- const latestFcp = (0, _lynx_js_react.useMemo)(() => {
1526
- for (let i = performances.length - 1; i >= 0; i--) {
1527
- const perf = performances[i];
1528
- if (perf && perf.entryType === "metric" && perf.name === "fcp") {
1529
- const metricEntry = perf.rawEntry;
1530
- if (metricEntry?.totalFcp?.duration !== void 0) return metricEntry.totalFcp;
1531
- if (metricEntry?.lynxFcp?.duration !== void 0) return metricEntry.lynxFcp;
1532
- }
1533
- }
1534
- }, [performances]);
1535
1555
  (0, _lynx_js_react.useImperativeHandle)(ref, () => ({
1536
1556
  open: () => {
1537
1557
  setIsOpen(true);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAeE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAIE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAeE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAIE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
package/dist/index.mjs CHANGED
@@ -222,6 +222,35 @@ const useConsole = () => {
222
222
  };
223
223
  };
224
224
 
225
+ //#endregion
226
+ //#region src/hooks/useLatestFcp.ts
227
+ const pickFcp = (entry) => {
228
+ if (entry.entryType !== "metric" || entry.name !== "fcp") return void 0;
229
+ const raw = entry.rawEntry;
230
+ if (raw?.totalFcp?.duration !== void 0) return raw.totalFcp;
231
+ if (raw?.lynxFcp?.duration !== void 0) return raw.lynxFcp;
232
+ };
233
+ const useLatestFcp = () => {
234
+ const [fcp, setFcp] = useState(() => {
235
+ const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];
236
+ for (let i = performances.length - 1; i >= 0; i--) {
237
+ const entry = performances[i];
238
+ if (!entry) continue;
239
+ const found = pickFcp(entry);
240
+ if (found) return found;
241
+ }
242
+ });
243
+ useEffect(() => {
244
+ const state = globalThis.__LYNX_CONSOLE__?.state;
245
+ if (!state?.subscribePerformance) return;
246
+ return state.subscribePerformance((entry) => {
247
+ const found = pickFcp(entry);
248
+ if (found) setFcp(found);
249
+ });
250
+ }, []);
251
+ return fcp;
252
+ };
253
+
225
254
  //#endregion
226
255
  //#region src/hooks/useNetwork.ts
227
256
  const useNetwork = () => {
@@ -484,7 +513,8 @@ const LogPanel = ({ logs, clearLogs }) => {
484
513
  params: {
485
514
  position: logsRef.current.length - 1,
486
515
  smooth
487
- }
516
+ },
517
+ fail: () => {}
488
518
  }).exec();
489
519
  };
490
520
  useEffect(() => {
@@ -1498,7 +1528,7 @@ const FloatingButton = ({ bindtap, children, initialPosition }) => {
1498
1528
  }
1499
1529
  };
1500
1530
  const isDragging = phase === "dragging";
1501
- return <view className={"fb-wrapper"} consume-slide-event={[[-180, 180]]} style={{
1531
+ return <view className={"fb-wrapper"} style={{
1502
1532
  ...positionStyle,
1503
1533
  transform: isDragging ? "scale(1.05)" : "scale(1)",
1504
1534
  transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
@@ -1520,18 +1550,8 @@ const FloatingButton = ({ bindtap, children, initialPosition }) => {
1520
1550
  const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
1521
1551
  const [isOpen, setIsOpen] = useState(false);
1522
1552
  const [shouldClose, setShouldClose] = useState(false);
1523
- const { performances } = usePerformance();
1553
+ const latestFcp = useLatestFcp();
1524
1554
  const colors = useMemo(() => getColors(theme), [theme]);
1525
- const latestFcp = useMemo(() => {
1526
- for (let i = performances.length - 1; i >= 0; i--) {
1527
- const perf = performances[i];
1528
- if (perf && perf.entryType === "metric" && perf.name === "fcp") {
1529
- const metricEntry = perf.rawEntry;
1530
- if (metricEntry?.totalFcp?.duration !== void 0) return metricEntry.totalFcp;
1531
- if (metricEntry?.lynxFcp?.duration !== void 0) return metricEntry.lynxFcp;
1532
- }
1533
- }
1534
- }, [performances]);
1535
1555
  useImperativeHandle(ref, () => ({
1536
1556
  open: () => {
1537
1557
  setIsOpen(true);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/hooks/useKeyboardHeight.ts","../src/styles/theme.ts","../src/styles/ThemeContext.ts","../src/components/BottomSheet.tsx","../src/hooks/useConsole.ts","../src/hooks/useNetwork.ts","../src/hooks/usePerformance.ts","../src/utils/parseCssStyle.ts","../src/utils/parseFormat.ts","../src/components/LogPanel.tsx","../src/components/NetworkDetailSection.tsx","../src/components/NetworkPanel.tsx","../src/components/PerformancePanel.tsx","../src/components/Tabs.tsx","../src/components/ConsolePanel.tsx","../src/hooks/useLongPressDrag.ts","../src/components/FloatingButton.tsx","../src/index.tsx"],"sourcesContent":["import { useLynxGlobalEventListener, useState } from \"@lynx-js/react\";\n\nexport function useKeyboardHeight() {\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n\n useLynxGlobalEventListener(\n \"keyboardstatuschanged\",\n (status: \"on\" | \"off\", height: number) => {\n setKeyboardHeight(status === \"on\" ? height : 0);\n },\n );\n\n return keyboardHeight;\n}\n","export type Theme = \"light\" | \"dark\";\n\nconst lightColors = {\n palette: {\n blue100: \"#eff6ff\",\n blue600: \"#5e98fe\",\n gray100: \"#f7f8f9\",\n gray400: \"#dcdee3\",\n green100: \"#edfaf6\",\n green600: \"#10ab7d\",\n purple100: \"#f5f3fe\",\n purple600: \"#9f84fb\",\n red100: \"#fdf0f0\",\n red600: \"#fc6a66\",\n red900: \"#921708\",\n staticWhite: \"#ffffff\",\n yellow100: \"#fff7de\",\n yellow600: \"#c49725\",\n yellow900: \"#4f3e1f\",\n },\n fg: {\n neutral: \"#1a1c20\",\n placeholder: \"#b0b3ba\",\n disabled: \"#d1d3d8\",\n neutralMuted: \"#555d6d\",\n neutralSubtle: \"#868b94\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#ffffff\",\n layerFloating: \"#ffffff\",\n neutralWeak: \"#f3f4f5\",\n },\n stroke: {\n neutralSubtle: \"#0000000c\",\n neutralWeak: \"#dcdee3\",\n },\n} as const;\n\nconst darkColors = {\n palette: {\n blue100: \"#202742\",\n blue600: \"#1e82eb\",\n gray100: \"#16171b\",\n gray400: \"#393d46\",\n green100: \"#202926\",\n green600: \"#1b946d\",\n purple100: \"#28213b\",\n purple600: \"#8e6bee\",\n red100: \"#322323\",\n red600: \"#f73526\",\n red900: \"#f8c5c3\",\n staticWhite: \"#ffffff\",\n yellow100: \"#302819\",\n yellow600: \"#b6720d\",\n yellow900: \"#e5d49b\",\n },\n fg: {\n neutral: \"#f3f4f5\",\n placeholder: \"#868b94\",\n disabled: \"#5b606a\",\n neutralMuted: \"#dcdee3\",\n neutralSubtle: \"#b0b3ba\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#16171b\",\n layerFloating: \"#1d2025\",\n neutralWeak: \"#2b2e35\",\n },\n stroke: {\n neutralSubtle: \"#ffffff0d\",\n neutralWeak: \"#393d46\",\n },\n} as const;\n\nconst colorMap = {\n light: lightColors,\n dark: darkColors,\n} as const;\n\nexport const fontWeight = {\n regular: \"400\",\n medium: \"500\",\n bold: \"700\",\n} as const;\n\nexport const duration = {\n d4: \"200ms\",\n d6: \"300ms\",\n} as const;\n\nexport function getColors(theme: Theme) {\n return colorMap[theme];\n}\n\nexport type ThemeColors = ReturnType<typeof getColors>;\n","import { createContext, useContext } from \"@lynx-js/react\";\nimport { getColors, type ThemeColors } from \"./theme\";\n\nconst ThemeContext = createContext<ThemeColors>(getColors(\"light\"));\n\nexport const ThemeProvider = ThemeContext.Provider;\n\nexport function useThemeColors(): ThemeColors {\n return useContext(ThemeContext);\n}\n","import { type ReactNode, useEffect, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\nimport { useKeyboardHeight } from \"../hooks/useKeyboardHeight\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration, fontWeight } from \"../styles/theme\";\nimport \"./BottomSheet.css\";\n\ninterface BottomSheetProps {\n children: ReactNode;\n title?: string;\n footer?: ReactNode;\n onClose: () => void;\n isOpen: boolean;\n shouldClose?: boolean;\n safeAreaInsetBottom?: string;\n}\n\nconst MIN_HEIGHT = 200;\nconst MAX_HEIGHT = 700;\nconst DEFAULT_HEIGHT = 500;\nconst CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘\n\n// 마지막 높이 저장\nlet savedHeight: number | null = null;\n\nexport default function BottomSheet({\n children,\n title,\n footer,\n onClose,\n isOpen,\n shouldClose = false,\n safeAreaInsetBottom = \"25px\",\n}: BottomSheetProps) {\n const colors = useThemeColors();\n const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [isDragging, setIsDragging] = useState(false);\n const [dragStartY, setDragStartY] = useState(0);\n const [dragStartHeight, setDragStartHeight] = useState(\n savedHeight ?? DEFAULT_HEIGHT,\n );\n const [isOpening, setIsOpening] = useState(true);\n const [isClosing, setIsClosing] = useState(false);\n const keyboardHeight = useKeyboardHeight();\n\n // 닫기 애니메이션 처리\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n onClose();\n }, 300);\n };\n\n // 아래에서 올라오는 애니메이션\n useEffect(() => {\n requestAnimationFrame(() => {\n setIsOpening(false);\n });\n }, []);\n\n // 외부에서 닫기 요청 시 애니메이션 처리\n useEffect(() => {\n if (shouldClose && !isClosing) {\n handleClose();\n }\n }, [shouldClose, isClosing]);\n\n // 높이 변경 시 저장\n useEffect(() => {\n savedHeight = sheetHeight;\n }, [sheetHeight]);\n\n if (!isOpen) return null;\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n setIsDragging(true);\n setDragStartY(e.detail.y);\n setDragStartHeight(sheetHeight);\n setTempHeight(sheetHeight);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n if (!isDragging) return;\n const deltaY = dragStartY - e.detail.y;\n const newHeight = Math.min(\n Math.max(dragStartHeight + deltaY, MIN_HEIGHT),\n MAX_HEIGHT,\n );\n setTempHeight(newHeight);\n };\n\n const handleTouchEnd = () => {\n setIsDragging(false);\n\n // 아래로 일정 30px 이상 드래그하면 닫기\n const dragDistance = dragStartHeight - tempHeight;\n setSheetHeight(tempHeight);\n if (dragDistance > CLOSE_DRAG_THRESHOLD) {\n handleClose();\n }\n };\n\n return (\n <scroll-view\n className=\"bs-backdrop\"\n style={{\n background: colors.bg.overlay,\n opacity: isOpening || isClosing ? 0 : 1,\n transition: `opacity ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n <view className=\"bs-overlay\" bindtap={handleClose}>\n <view\n className=\"bs-content\"\n catchtap={() => {}}\n style={{\n background: colors.bg.layerFloating,\n height: `${\n keyboardHeight > 0\n ? Math.min(\n MAX_HEIGHT,\n (isDragging ? tempHeight : sheetHeight) + keyboardHeight,\n )\n : isDragging\n ? tempHeight\n : sheetHeight\n }px`,\n transform:\n isOpening || isClosing ? \"translateY(100%)\" : \"translateY(0)\",\n transition: isDragging\n ? \"none\"\n : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1), height ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n {/* catchtap: 이벤트 버블링 차단 */}\n <view\n className=\"bs-handleContainer\"\n bindtouchstart={handleTouchStart}\n bindtouchmove={handleTouchMove}\n bindtouchend={handleTouchEnd}\n >\n <view\n className=\"bs-handle\"\n style={{ backgroundColor: colors.palette.gray400 }}\n />\n </view>\n <view className=\"bs-header\">\n {title && (\n <text\n className=\"bs-title t7\"\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n {title}\n </text>\n )}\n </view>\n <view\n className=\"bs-body\"\n style={{\n paddingBottom:\n keyboardHeight > 0\n ? `${keyboardHeight}px`\n : safeAreaInsetBottom,\n }}\n >\n {children}\n </view>\n {footer && <view className=\"bs-footer\">{footer}</view>}\n </view>\n </view>\n </scroll-view>\n );\n}\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { LogEntry } from \"../types\";\n\nexport const useConsole = () => {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs === \"undefined\") {\n console.warn(\"[LynxConsole] Log monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setLogs([...(state.logs ?? [])]);\n\n const updateLogs = (_entry: LogEntry) => {\n setLogs([...(state.logs ?? [])]);\n };\n\n const unsubscribe = state.logSubscribe?.(updateLogs);\n\n return unsubscribe;\n }, []);\n\n const clearLogs = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.logs = [];\n setLogs([]);\n }\n };\n\n return { logs, clearLogs };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\n\nexport const useNetwork = () => {\n const [networks, setNetworks] = useState<NetworkEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks === \"undefined\") {\n console.warn(\"[LynxConsole] Network monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setNetworks([...(state.networks ?? [])]);\n\n const updateNetworks = (_entry: NetworkEntry) => {\n setNetworks([...(state.networks ?? [])]);\n };\n\n const unsubscribe = state.subscribeNetwork?.(updateNetworks);\n\n return unsubscribe;\n }, []);\n\n const clearNetworks = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.networks = [];\n state.networksMap?.clear();\n setNetworks([]);\n }\n };\n\n return { networks, clearNetworks };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { PerformanceEntryData } from \"../types\";\n\nexport const usePerformance = () => {\n const [performances, setPerformances] = useState<PerformanceEntryData[]>([]);\n\n useEffect(() => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances === \"undefined\"\n ) {\n console.warn(\"[LynxConsole] Performance monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setPerformances([...(state.performances ?? [])]);\n\n const updatePerformances = (_entry: PerformanceEntryData) => {\n setPerformances([...(state.performances ?? [])]);\n };\n\n const unsubscribe = state.subscribePerformance?.(updatePerformances);\n\n return unsubscribe;\n }, []);\n\n const clearPerformances = () => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances !== \"undefined\"\n ) {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.performances = [];\n setPerformances([]);\n }\n };\n\n return { performances, clearPerformances };\n};\n","export type StyleObject = Record<string, string>;\n\nconst DANGEROUS_VALUE = /url\\s*\\(|expression\\s*\\(|@import/i;\n\nconst toCamelCase = (name: string): string => {\n if (name.startsWith(\"--\")) return name;\n return name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n};\n\nexport const parseCssString = (css: string): StyleObject => {\n const result: StyleObject = {};\n for (const raw of css.split(\";\")) {\n const decl = raw.trim();\n if (!decl) continue;\n const colon = decl.indexOf(\":\");\n if (colon <= 0) continue;\n const name = decl.slice(0, colon).trim().toLowerCase();\n const value = decl.slice(colon + 1).trim();\n if (!name || !value) continue;\n if (DANGEROUS_VALUE.test(value)) continue;\n result[toCamelCase(name)] = value;\n }\n return result;\n};\n","import { parseCssString, type StyleObject } from \"./parseCssStyle\";\n\nexport type LogSegment =\n | { type: \"text\"; text: string; style?: StyleObject }\n | { type: \"arg\"; value: unknown };\n\nexport interface ParsedLogArgs {\n segments: LogSegment[];\n rest: unknown[];\n}\n\nconst HAS_FORMAT = /%[csdifoO%]/;\n\nconst formatNumber = (v: unknown, int: boolean): string => {\n const n =\n typeof v === \"number\"\n ? int\n ? Math.trunc(v)\n : v\n : typeof v === \"symbol\"\n ? Number.NaN\n : int\n ? parseInt(String(v), 10)\n : parseFloat(String(v));\n return Number.isNaN(n) ? \"NaN\" : String(n);\n};\n\nexport const parseConsoleArgs = (args: unknown[]): ParsedLogArgs => {\n const first = args[0];\n if (typeof first !== \"string\" || !HAS_FORMAT.test(first)) {\n return { segments: [], rest: args };\n }\n\n const segments: LogSegment[] = [];\n let currentText = \"\";\n let currentStyle: StyleObject | undefined;\n let argIndex = 1;\n let lastIndex = 0;\n\n const flushText = () => {\n if (currentText) {\n segments.push({ type: \"text\", text: currentText, style: currentStyle });\n currentText = \"\";\n }\n };\n\n const re = /%([csdifoO%])/g;\n let match: RegExpExecArray | null = re.exec(first);\n while (match !== null) {\n currentText += first.slice(lastIndex, match.index);\n lastIndex = re.lastIndex;\n const spec = match[1];\n\n if (spec === \"%\") {\n currentText += \"%\";\n } else if (argIndex >= args.length) {\n currentText += match[0];\n } else {\n const arg = args[argIndex++];\n switch (spec) {\n case \"c\":\n flushText();\n currentStyle =\n typeof arg === \"string\" ? parseCssString(arg) : undefined;\n break;\n case \"s\":\n currentText += String(arg);\n break;\n case \"d\":\n case \"i\":\n currentText += formatNumber(arg, true);\n break;\n case \"f\":\n currentText += formatNumber(arg, false);\n break;\n case \"o\":\n case \"O\":\n flushText();\n segments.push({ type: \"arg\", value: arg });\n break;\n }\n }\n\n match = re.exec(first);\n }\n currentText += first.slice(lastIndex);\n flushText();\n\n return { segments, rest: args.slice(argIndex) };\n};\n","import { useEffect, useMemo, useRef, useState } from \"@lynx-js/react\";\nimport type { BaseEvent, InputInputEvent, NodesRef } from \"@lynx-js/types\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport { parseConsoleArgs } from \"../utils/parseFormat\";\nimport \"./ConsolePanel.css\";\n\nconst LOG_LEVELS: LogLevel[] = [\"log\", \"info\", \"warn\", \"error\"];\n\nlet savedEnabledLevels: Set<LogLevel> | null = null;\nlet savedSearchQuery = \"\";\nlet closeFilterDropdown: (() => void) | null = null;\n\nexport const dismissFilterDropdown = () => closeFilterDropdown?.();\n\ninterface LogPanelProps {\n logs: LogEntry[];\n clearLogs: () => void;\n}\n\nconst runCode = (code: string) => {\n try {\n // biome-ignore lint: intentional REPL tool\n const result = eval(code);\n if (result instanceof Promise) {\n result.then((r) => console.log(r)).catch((e) => console.error(e));\n } else {\n console.log(result);\n }\n } catch (e) {\n console.error(e);\n }\n};\n\nfunction getLevelColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"log\":\n return colors.palette.green600;\n case \"info\":\n return colors.palette.blue600;\n case \"warn\":\n return colors.palette.yellow600;\n case \"error\":\n return colors.palette.red600;\n }\n}\n\nfunction getLogItemBg(\n colors: ThemeColors,\n level: LogLevel,\n): string | undefined {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nfunction getStringColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.fg.neutral;\n }\n}\n\nfunction getPrimitiveColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.palette.blue600;\n }\n}\n\nexport const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {\n const colors = useThemeColors();\n const [expandedArgs, setExpandedArgs] = useState(new Set());\n const [code, setCode] = useState(\"\");\n const [enabledLevels, setEnabledLevels] = useState<Set<LogLevel>>(\n () => savedEnabledLevels ?? new Set(LOG_LEVELS),\n );\n const [filterOpen, setFilterOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState(savedSearchQuery);\n const inputRef = useRef<NodesRef>(null);\n const searchInputRef = useRef<NodesRef>(null);\n const listRef = useRef<NodesRef>(null);\n\n useEffect(() => {\n savedEnabledLevels = enabledLevels;\n }, [enabledLevels]);\n\n useEffect(() => {\n savedSearchQuery = searchQuery;\n }, [searchQuery]);\n\n useEffect(() => {\n if (savedSearchQuery) {\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: savedSearchQuery } })\n .exec();\n }\n }, []);\n\n useEffect(() => {\n closeFilterDropdown = () => setFilterOpen(false);\n return () => {\n closeFilterDropdown = null;\n };\n }, []);\n\n const filteredLogs = useMemo(\n () =>\n logs.filter((log) => {\n if (!enabledLevels.has(log.level)) return false;\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return log.args.some((arg) =>\n String(arg).toLowerCase().includes(query),\n );\n }\n return true;\n }),\n [logs, enabledLevels, searchQuery],\n );\n const logsRef = useRef(filteredLogs);\n logsRef.current = filteredLogs;\n\n const toggleLevel = (level: LogLevel) => {\n setEnabledLevels((prev) => {\n const next = new Set(prev);\n if (next.has(level)) {\n next.delete(level);\n } else {\n next.add(level);\n }\n return next;\n });\n };\n\n const scrollToBottom = (smooth: boolean) => {\n if (logsRef.current.length === 0) return;\n listRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: { position: logsRef.current.length - 1, smooth },\n })\n .exec();\n };\n\n useEffect(() => {\n scrollToBottom(true);\n }, [filteredLogs]);\n\n const toggleArg = (key: string) => {\n setExpandedArgs((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n };\n\n const handleRun = () => {\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCode(\"\");\n inputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n runCode(trimmed);\n };\n\n const renderArg = (\n arg: unknown,\n parentKey: string,\n level: \"log\" | \"info\" | \"warn\" | \"error\",\n ): React.ReactNode => {\n const key = parentKey;\n const isExpanded = expandedArgs.has(key);\n\n if (arg === null) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n null\n </text>\n );\n }\n\n if (arg === undefined) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n undefined\n </text>\n );\n }\n\n if (typeof arg === \"string\") {\n const MAX_LENGTH = 80;\n const shouldTruncate = arg.length > MAX_LENGTH;\n const strColor = getStringColor(colors, level);\n\n if (!shouldTruncate) {\n return (\n <text\n className={\"cp-argString t3\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {arg}\n </text>\n );\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argString t3\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {isExpanded ? arg : `${arg.slice(0, MAX_LENGTH)}...`}\n </text>\n </view>\n </view>\n );\n }\n\n if (typeof arg === \"number\" || typeof arg === \"boolean\") {\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n }\n\n if (typeof arg === \"object\") {\n let preview = \"Object\";\n if (Array.isArray(arg)) {\n preview = `Array(${arg.length})`;\n } else if (arg instanceof Map) {\n preview = `Map(${arg.size})`;\n } else if (arg instanceof Set) {\n preview = `Set(${arg.size})`;\n } else if (arg instanceof Date) {\n preview = `Date`;\n } else if (arg instanceof RegExp) {\n preview = `RegExp`;\n } else if (arg instanceof Error) {\n preview = `${arg.constructor.name}`;\n } else if (arg?.constructor?.name && arg.constructor.name !== \"Object\") {\n preview = arg.constructor.name;\n }\n\n let jsonString: string;\n if (arg instanceof Map) {\n const entries = Array.from(arg.entries()).map(\n ([k, v]) => ` [${stringify(k)}, ${stringify(v)}]`,\n );\n jsonString = `{\\n${entries.join(\",\\n\")}\\n}`;\n } else if (arg instanceof Set) {\n const values = Array.from(arg.values()).map((v) => stringify(v));\n jsonString = `{\\n${values.join(\", \")}\\n}`;\n } else {\n jsonString =\n stringify(arg, null, 2, { references: true }) ?? String(arg);\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argObjectPreview t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {preview}\n </text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text\n className={\"cp-argObjectJson t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {jsonString}\n </text>\n </view>\n )}\n </view>\n );\n }\n\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => {\n if (filterOpen) setFilterOpen(false);\n }}\n >\n <view className={\"cp-logHeader\"}>\n <view className={\"cp-filterWrapper\"}>\n <view\n className={\"cp-filterButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n catchtap={() => setFilterOpen((v) => !v)}\n >\n <text\n className={\"cp-filterButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n Filter ▼\n </text>\n </view>\n {filterOpen && (\n <view\n className={\"cp-filterDropdown\"}\n style={{\n backgroundColor: colors.bg.layerFloating,\n borderColor: colors.stroke.neutralSubtle,\n }}\n catchtap={() => {}}\n >\n {LOG_LEVELS.map((level) => (\n <view\n key={level}\n className={\"cp-filterOption\"}\n bindtap={() => toggleLevel(level)}\n >\n <text\n className={\"cp-filterCheckbox t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text\n className={\"cp-filterLabel t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {level.toUpperCase()}\n </text>\n </view>\n ))}\n </view>\n )}\n </view>\n <view\n className={\"cp-searchWrapper\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"cp-searchPrompt t6\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"Search logs...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setSearchQuery(e.detail.value)\n }\n />\n {searchQuery.length > 0 && (\n <view\n className={\"cp-searchClear\"}\n bindtap={() => {\n setSearchQuery(\"\");\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n }}\n >\n <text\n className={\"cp-searchClearText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n ✕\n </text>\n </view>\n )}\n </view>\n <view style={{ display: \"flex\", flexDirection: \"row\", gap: 8 }}>\n <view\n className={\"cp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearLogs}\n >\n <text\n className={\"cp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n </view>\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\n className={\"cp-logList\"}\n preload-buffer-count={10}\n initial-scroll-index={Math.max(0, filteredLogs.length - 1)}\n >\n {filteredLogs.length === 0 ? (\n <list-item item-key=\"empty-state\">\n <view className={\"cp-placeholder\"}>\n <text\n className={\"cp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No logs yet. Try console.log(\"Hello!\")\n </text>\n </view>\n </list-item>\n ) : (\n filteredLogs.map((log) => {\n return (\n <list-item key={log.id} item-key={log.id}>\n <view\n className={\"cp-logItem\"}\n style={{\n backgroundColor: getLogItemBg(colors, log.level),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view className={\"cp-logItemHeader\"}>\n <text\n className={\"cp-logLevel t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getLevelColor(colors, log.level),\n }}\n >\n {log.level.toUpperCase()}\n </text>\n <text\n className={\"cp-logTime t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(log.timestamp).toISOString()}\n </text>\n </view>\n <view className={\"cp-logArgsContainer\"}>\n {(() => {\n const { segments, rest } = parseConsoleArgs(log.args);\n const baseTextStyle = {\n color: getStringColor(colors, log.level),\n fontWeight: fontWeight.regular,\n };\n const wrap = (key: string, content: React.ReactNode) => (\n <view\n key={key}\n className={\"cp-logArgItem\"}\n style={{ fontWeight: fontWeight.regular }}\n >\n {content}\n </view>\n );\n return (\n <>\n {segments.map((seg, index) => {\n const key = `${log.id}-seg-${index.toString()}`;\n return wrap(\n key,\n seg.type === \"text\" ? (\n <text\n className={\"cp-argString t3\"}\n style={{ ...baseTextStyle, ...seg.style }}\n >\n {seg.text}\n </text>\n ) : (\n renderArg(seg.value, key, log.level)\n ),\n );\n })}\n {rest.map((arg, index) => {\n const key = `${log.id}-rest-${index.toString()}`;\n return wrap(key, renderArg(arg, key, log.level));\n })}\n </>\n );\n })()}\n </view>\n </view>\n </list-item>\n );\n })\n )}\n </list>\n <view className={\"cp-replInputRow\"}>\n <text\n className={\"cp-replPrompt t10\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={inputRef}\n className={\"cp-replInput t5\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"enter code...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setCode(e.detail.value)\n }\n bindconfirm={handleRun}\n />\n <view\n className={\"cp-replRunButton\"}\n style={{ backgroundColor: colors.palette.green100 }}\n bindtap={handleRun}\n >\n <text\n className={\"cp-replRunButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.palette.green600,\n }}\n >\n Run\n </text>\n </view>\n </view>\n </view>\n );\n};\n","import { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkDetailSectionProps {\n headers?: Record<string, string> | undefined;\n body?: string | undefined;\n error?: string | undefined;\n}\n\nexport const NetworkDetailSection = ({\n headers = {},\n body = \"\",\n error = \"\",\n}: NetworkDetailSectionProps) => {\n const colors = useThemeColors();\n\n return (\n <>\n {/* Headers */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Headers\n </text>\n {headers && Object.keys(headers).length > 0 ? (\n <view className={\"np-table\"}>\n {Object.entries(headers).map(([key, value]) => (\n <view\n key={key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {value}\n </text>\n </view>\n ))}\n </view>\n ) : (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No headers\n </text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Body\n </text>\n {error && (\n <text\n className={\"np-errorText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n }}\n >\n {error}\n </text>\n )}\n {body && (\n <text\n className={\"np-bodyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n }}\n >\n {body}\n </text>\n )}\n {!error && !body && (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No body\n </text>\n )}\n </view>\n </>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { NetworkEntry } from \"../types\";\nimport { NetworkDetailSection } from \"./NetworkDetailSection\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkPanelProps {\n networks: NetworkEntry[];\n clearNetworks: () => void;\n}\n\ntype TabType = \"general\" | \"request\" | \"response\";\n\nfunction getMethodColors(colors: ThemeColors, method: string) {\n switch (method) {\n case \"GET\":\n return {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"POST\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"PUT\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n case \"PATCH\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"DELETE\":\n return {\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\n }\n}\n\nfunction getStatusCodeColor(\n colors: ThemeColors,\n variant: \"success\" | \"error\" | \"pending\",\n): string {\n switch (variant) {\n case \"success\":\n return colors.palette.green600;\n case \"error\":\n return colors.palette.red600;\n case \"pending\":\n return colors.fg.neutralSubtle;\n }\n}\n\nfunction getItemBg(colors: ThemeColors, status: string): string | undefined {\n switch (status) {\n case \"pending\":\n return colors.palette.gray100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nexport const NetworkPanel = ({\n networks,\n clearNetworks,\n}: NetworkPanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<TabType>(\"general\");\n const formatDuration = (duration?: number): string => {\n if (!duration) return \"-\";\n if (duration < 1000) return `${duration}ms`;\n return `${(duration / 1000).toFixed(2)}s`;\n };\n\n const extractPath = (url: string): string => {\n const pathMatch = url.match(/^https?:\\/\\/[^/]+(.*)$/);\n if (pathMatch?.[1]) {\n return pathMatch[1].startsWith(\"/\")\n ? pathMatch[1].slice(1)\n : pathMatch[1];\n }\n return url;\n };\n\n const getGeneralInfo = (network: NetworkEntry) => {\n return [\n { key: \"URL\", value: network.url },\n { key: \"Method\", value: network.method },\n network.statusCode\n ? { key: \"Status\", value: String(network.statusCode) }\n : null,\n {\n key: \"Request Time\",\n value: new Date(network.startTime).toISOString(),\n },\n network.endTime\n ? {\n key: \"Response Time\",\n value: new Date(network.endTime).toISOString(),\n }\n : null,\n network.duration\n ? { key: \"Duration\", value: formatDuration(network.duration) }\n : null,\n ].filter((item) => item !== null);\n };\n\n const getStatusCodeVariant = (\n status: string,\n statusCode?: number,\n ): \"success\" | \"error\" | \"pending\" => {\n if (status === \"pending\") return \"pending\";\n if (status === \"error\") return \"error\";\n if (statusCode && statusCode >= 200 && statusCode < 300) return \"success\";\n return \"error\";\n };\n\n return (\n <view className={\"np-container\"}>\n <view className={\"np-header\"}>\n <text\n className={\"np-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n Total: {networks.length} requests\n </text>\n <view\n className={\"np-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearNetworks}\n >\n <text\n className={\"np-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text\n className={\"np-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No network requests yet\n </text>\n </view>\n ) : (\n <list scroll-orientation=\"vertical\" className={\"np-list\"}>\n {networks.map((network) => (\n <list-item key={network.id} item-key={network.id}>\n <view\n className={\"np-item\"}\n style={{\n backgroundColor: getItemBg(colors, network.status),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view\n className={\"np-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n <text\n className={\"np-method t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getMethodColors(colors, network.method),\n }}\n >\n {network.method}\n </text>\n {network.statusCode && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getStatusCodeColor(\n colors,\n getStatusCodeVariant(\n network.status,\n network.statusCode,\n ),\n ),\n }}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n Pending...\n </text>\n )}\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {formatDuration(network.duration)}\n </text>\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n {extractPath(network.url)}\n </text>\n\n {selectedId === network.id && (\n <view\n className={\"np-detailsContainer\"}\n style={{ borderTopColor: colors.stroke.neutralSubtle }}\n >\n {/* Tabs */}\n <view className={\"np-tabs\"}>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"general\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"general\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n General\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"request\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"request\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Request\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"response\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"response\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Response\n </text>\n </view>\n </view>\n\n {/* Tab Content */}\n <view className={\"np-tabContent\"}>\n {activeTab === \"general\" && (\n <view className={\"np-table\"}>\n {getGeneralInfo(network).map((item) => (\n <view\n key={item.key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {item.key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {item.value}\n </text>\n </view>\n ))}\n </view>\n )}\n\n {activeTab === \"request\" && (\n <NetworkDetailSection\n headers={network.requestHeaders}\n body={network.requestBody}\n />\n )}\n\n {activeTab === \"response\" && (\n <NetworkDetailSection\n headers={network.responseHeaders}\n body={network.responseBody}\n error={network.error}\n />\n )}\n </view>\n </view>\n )}\n </view>\n </list-item>\n ))}\n </list>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { PerformanceEntryData } from \"../types\";\nimport \"./PerformancePanel.css\";\n\ninterface PerformancePanelProps {\n performances: PerformanceEntryData[];\n clearPerformances: () => void;\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst isMetricFcpEntry = (entry: PerformanceEntryData): boolean => {\n return entry.entryType === \"metric\" && entry.name === \"fcp\";\n};\n\nconst extractFcpMetrics = (entry: PerformanceEntryData) => {\n if (!isMetricFcpEntry(entry) || !entry.rawEntry) {\n return null;\n }\n\n const metricEntry = entry.rawEntry as MetricFcpEntry;\n\n return {\n totalFcp: metricEntry.totalFcp ?? undefined,\n lynxFcp: metricEntry.lynxFcp ?? undefined,\n fcp: metricEntry.fcp ?? undefined,\n };\n};\n\nconst formatDuration = (ms?: number): string => {\n if (ms === undefined) return \"-\";\n return `${ms.toFixed(2)}ms`;\n};\n\nconst getPrimaryFcpLabel = (entry: PerformanceEntryData): string => {\n const fcpMetrics = extractFcpMetrics(entry);\n if (!fcpMetrics) return \"\";\n\n const { totalFcp, lynxFcp, fcp } = fcpMetrics;\n\n if (totalFcp?.duration !== undefined) {\n return `totalFcp: ${formatDuration(totalFcp.duration)}`;\n }\n if (lynxFcp?.duration !== undefined) {\n return `lynxFcp: ${formatDuration(lynxFcp.duration)}`;\n }\n if (fcp?.duration !== undefined) {\n return `fcp: ${formatDuration(fcp.duration)}`;\n }\n return \"\";\n};\n\nfunction getEntryTypeColors(colors: ThemeColors, entryType: string) {\n switch (entryType) {\n case \"init\":\n return {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"metric\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"pipeline\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"resource\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\n }\n}\n\nexport const PerformancePanel = ({\n performances,\n clearPerformances,\n}: PerformancePanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n if (performances.length === 0) {\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n 0 entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text\n className={\"pp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No performance data yet...\n </text>\n </view>\n </view>\n );\n }\n\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {performances.length} entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n <list scroll-orientation=\"vertical\" className={\"pp-list\"}>\n {performances.map((perf) => {\n const isMetricFcp = isMetricFcpEntry(perf);\n const fcpMetrics = extractFcpMetrics(perf);\n const primaryFcp = getPrimaryFcpLabel(perf);\n const { totalFcp, lynxFcp, fcp } = fcpMetrics ?? {};\n\n return (\n <list-item key={perf.id} item-key={perf.id}>\n <view\n className={\"pp-item\"}\n style={{ borderBottomColor: colors.stroke.neutralWeak }}\n >\n <view\n className={\"pp-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n <text\n className={\"pp-entryType t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getEntryTypeColors(colors, perf.entryType),\n }}\n >\n {perf.entryType}\n </text>\n <text\n className={\"pp-entryName t2\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {perf.name}\n </text>\n <text\n className={\"pp-timestamp t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(perf.timestamp).toISOString()}\n </text>\n </view>\n\n <view\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n {isMetricFcp && primaryFcp && (\n <text\n className={\"pp-fcpHighlight t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n }}\n >\n {primaryFcp}\n </text>\n )}\n </view>\n\n {selectedId === perf.id && (\n <view className={\"pp-detailsContainer\"}>\n {isMetricFcp && fcpMetrics && (\n <view className={\"pp-fcpSection\"}>\n {totalFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 전체 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n PrepareTemplate Start부터 Paint End 까지 걸리는\n 시간\n </text>\n </view>\n )}\n\n {lynxFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n LynxFCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n Bundle Load 시작부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n\n {fcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 렌더링 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n TemplateBundle 준비부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n </view>\n )}\n\n {!!perf.rawEntry && (\n <view\n className={\"pp-rawEntrySection\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-detailTitle t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n Raw Entry\n </text>\n <text\n className={\"pp-rawEntry t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {String(\n stringify(perf.rawEntry, null, 2, {\n references: true,\n }),\n )}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </list>\n </view>\n );\n};\n","import { type ReactNode, useRef, useState } from \"@lynx-js/react\";\nimport type { ListSnapEvent, NodesRef } from \"@lynx-js/types\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./Tabs.css\";\n\ntype TabsProps = {\n items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }>;\n onTabChange?: () => void;\n};\n\nexport default function Tabs(props: TabsProps) {\n const colors = useThemeColors();\n const tabContentsRef = useRef<NodesRef>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const tabSize =\n props.items.length < 4\n ? undefined\n : `t${Math.max(1, 5 - (props.items.length - 3))}`;\n\n return (\n <view className={\"tabs-root\"}>\n <view\n className={\"tabs-header\"}\n style={{\n boxShadow: `inset 0 -1px 0 0 ${colors.stroke.neutralSubtle}`,\n }}\n >\n {props.items.map((item, i) => (\n <view\n key={item.key}\n className={\"tabs-triggerButton\"}\n bindtap={() => {\n setActiveIndex(i);\n props.onTabChange?.();\n\n tabContentsRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: {\n position: i,\n smooth: true,\n },\n })\n .exec();\n }}\n >\n <text\n className={`tabs-triggerButtonText${tabSize ? ` ${tabSize}` : \"\"}`}\n style={{\n fontWeight: fontWeight.bold,\n color:\n i === activeIndex\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n {item.label}\n </text>\n {i === 0 && (\n <view\n className={\"tabs-triggerIndicator\"}\n style={{ transform: `translateX(${activeIndex * 100}%)` }}\n >\n <view\n className={\"tabs-triggerIndicatorLine\"}\n style={{ backgroundColor: colors.fg.neutral }}\n />\n </view>\n )}\n </view>\n ))}\n </view>\n\n <list\n ref={tabContentsRef}\n className={\"tabs-contents\"}\n scroll-orientation=\"horizontal\"\n item-snap={{ factor: 0, offset: 0 }}\n bindscroll={() => props.onTabChange?.()}\n bindsnap={(e: ListSnapEvent) => {\n setActiveIndex(e.detail.position);\n }}\n bounces={false}\n preload-buffer-count={props.items.length}\n >\n {props.items.map((item) => (\n <list-item\n key={item.key}\n item-key={item.key}\n recyclable={false}\n className={\"tabs-content\"}\n >\n {item.renderContent()}\n </list-item>\n ))}\n </list>\n </view>\n );\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { dismissFilterDropdown, LogPanel } from \"./LogPanel\";\nimport { NetworkPanel } from \"./NetworkPanel\";\nimport { PerformancePanel } from \"./PerformancePanel\";\nimport Tabs from \"./Tabs\";\n\ninterface ConsolePanelProps {\n customTabs?: CustomTab[];\n}\n\nexport const ConsolePanel = ({ customTabs }: ConsolePanelProps) => {\n const { logs, clearLogs } = useConsole();\n const { networks, clearNetworks } = useNetwork();\n const { performances, clearPerformances } = usePerformance();\n\n const state = globalThis.__LYNX_CONSOLE__?.state;\n\n const items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }> = [];\n\n if (state?.logs) {\n items.push({\n key: \"log\",\n label: \"Log\",\n renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,\n });\n }\n\n if (state?.networks) {\n items.push({\n key: \"network\",\n label: \"Network\",\n renderContent: () => (\n <NetworkPanel networks={networks} clearNetworks={clearNetworks} />\n ),\n });\n }\n\n if (state?.performances) {\n items.push({\n key: \"performance\",\n label: \"Perf\",\n renderContent: () => (\n <PerformancePanel\n performances={performances}\n clearPerformances={clearPerformances}\n />\n ),\n });\n }\n\n if (customTabs) {\n for (const tab of customTabs) {\n items.push({\n key: tab.key,\n label: tab.label,\n renderContent: tab.renderContent,\n });\n }\n }\n\n if (items.length === 0) {\n return null;\n }\n\n return (\n <view className=\"cp-container\">\n <Tabs onTabChange={dismissFilterDropdown} items={items} />\n </view>\n );\n};\n","import { useRef, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\n\nconst LONG_PRESS_DURATION = 400;\nconst MOVE_THRESHOLD = 5;\n\nconst DEFAULT_RIGHT = 16;\nconst DEFAULT_BOTTOM = 84;\n\ntype VerticalAxis = \"top\" | \"bottom\";\ntype HorizontalAxis = \"left\" | \"right\";\n\nexport interface InitialPosition {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n}\n\ninterface ResolvedAnchors {\n vertical: VerticalAxis;\n horizontal: HorizontalAxis;\n x: number;\n y: number;\n}\n\nfunction resolveAnchors(initial?: InitialPosition): ResolvedAnchors {\n // top/left이 명시되면 그것이 anchor가 돼요. 둘 다 명시되면 top/left가 이겨요.\n const vertical: VerticalAxis = initial?.top !== undefined ? \"top\" : \"bottom\";\n const horizontal: HorizontalAxis =\n initial?.left !== undefined ? \"left\" : \"right\";\n\n const y =\n vertical === \"top\"\n ? (initial?.top ?? 0)\n : (initial?.bottom ?? DEFAULT_BOTTOM);\n const x =\n horizontal === \"left\"\n ? (initial?.left ?? 0)\n : (initial?.right ?? DEFAULT_RIGHT);\n\n return { vertical, horizontal, x, y };\n}\n\ninterface SavedState {\n vertical: VerticalAxis;\n horizontal: HorizontalAxis;\n x: number;\n y: number;\n}\n\nlet saved: SavedState | null = null;\n\ninterface UseLongPressDragOptions {\n initialPosition?: InitialPosition;\n}\n\nexport function useLongPressDrag(\n onTap: () => void,\n options?: UseLongPressDragOptions,\n) {\n const anchors = resolveAnchors(options?.initialPosition);\n\n // 저장된 위치는 anchor 조합이 동일할 때만 복원해요.\n const snapshot = saved;\n let initX = anchors.x;\n let initY = anchors.y;\n if (\n snapshot !== null &&\n snapshot.vertical === anchors.vertical &&\n snapshot.horizontal === anchors.horizontal\n ) {\n initX = snapshot.x;\n initY = snapshot.y;\n }\n\n const [x, setX] = useState(initX);\n const [y, setY] = useState(initY);\n const [phase, setPhase] = useState<\"idle\" | \"dragging\" | \"releasing\">(\"idle\");\n const [tempX, setTempX] = useState(initX);\n const [tempY, setTempY] = useState(initY);\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const draggingRef = useRef(false);\n const startRef = useRef({ x: 0, y: 0, ax: 0, ay: 0 });\n\n // anchor 방향에 따라 드래그 부호 결정. right/bottom anchor면 드래그 방향과 값 변화가 반대.\n const xSign = anchors.horizontal === \"right\" ? -1 : 1;\n const ySign = anchors.vertical === \"bottom\" ? -1 : 1;\n\n const clearTimer = () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n startRef.current = {\n x: e.detail.x,\n y: e.detail.y,\n ax: x,\n ay: y,\n };\n draggingRef.current = false;\n\n timerRef.current = setTimeout(() => {\n draggingRef.current = true;\n setPhase(\"dragging\");\n setTempX(x);\n setTempY(y);\n }, LONG_PRESS_DURATION);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n const dx = e.detail.x - startRef.current.x;\n const dy = e.detail.y - startRef.current.y;\n\n if (\n !draggingRef.current &&\n (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)\n ) {\n clearTimer();\n }\n\n if (!draggingRef.current) return;\n\n setTempX(startRef.current.ax + xSign * dx);\n setTempY(startRef.current.ay + ySign * dy);\n };\n\n const handleTouchEnd = () => {\n clearTimer();\n\n if (draggingRef.current) {\n setX(tempX);\n setY(tempY);\n saved = {\n vertical: anchors.vertical,\n horizontal: anchors.horizontal,\n x: tempX,\n y: tempY,\n };\n setPhase(\"releasing\");\n draggingRef.current = false;\n setTimeout(() => setPhase(\"idle\"), 300);\n } else {\n onTap();\n }\n };\n\n const isDragging = phase === \"dragging\";\n const currentX = isDragging ? tempX : x;\n const currentY = isDragging ? tempY : y;\n\n const positionStyle = {\n [anchors.horizontal]: `${currentX}px`,\n [anchors.vertical]: `${currentY}px`,\n } as { top?: string; left?: string; right?: string; bottom?: string };\n\n return {\n phase,\n positionStyle,\n clearTimer,\n handlers: {\n catchtouchstart: handleTouchStart,\n catchtouchmove: handleTouchMove,\n catchtouchend: handleTouchEnd,\n },\n };\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport {\n type InitialPosition,\n useLongPressDrag,\n} from \"../hooks/useLongPressDrag\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration } from \"../styles/theme\";\nimport \"./FloatingButton.css\";\n\ninterface FloatingButtonProps {\n bindtap: () => void;\n children: ReactNode;\n initialPosition?: InitialPosition;\n}\n\nconst SHINE_STYLES = {\n idle: {\n transform: \"scale(0)\",\n opacity: 0,\n },\n dragging: {\n transform: \"scale(1)\",\n opacity: 1,\n transition: \"transform 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n releasing: {\n transform: \"scale(1)\",\n opacity: 0,\n transition: \"opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n} as const;\n\nexport const FloatingButton = ({\n bindtap,\n children,\n initialPosition,\n}: FloatingButtonProps) => {\n const colors = useThemeColors();\n const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(\n bindtap,\n { initialPosition },\n );\n\n const handleReload = () => {\n try {\n lynx.reload({}, () => {\n console.log(\"reloaded!\");\n });\n } catch (e) {\n console.error(\"[LynxConsole] reload failed:\", e);\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return (\n <view\n className={\"fb-wrapper\"}\n consume-slide-event={[[-180, 180]]}\n style={{\n ...positionStyle,\n transform: isDragging ? \"scale(1.05)\" : \"scale(1)\",\n transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n {...handlers}\n >\n <view\n className={\"fb-button\"}\n style={{ backgroundColor: colors.palette.green600 }}\n >\n {children}\n <view className={\"fb-shineOverlay\"} style={SHINE_STYLES[phase]} />\n </view>\n <view\n className={\"fb-reloadButton\"}\n style={{ backgroundColor: colors.palette.green600 }}\n catchtouchstart={() => clearTimer()}\n bindtap={handleReload}\n >\n <text\n className={\"fb-reloadIcon\"}\n style={{ color: colors.palette.staticWhite }}\n >\n {\"\\u21BB\"}\n </text>\n </view>\n </view>\n );\n};\n","import {\n type ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useState,\n} from \"@lynx-js/react\";\nimport BottomSheet from \"./components/BottomSheet.jsx\";\nimport { ConsolePanel } from \"./components/ConsolePanel.jsx\";\nimport \"./components/FloatingButton.css\";\nimport \"./styles/tokens.css\";\nimport { FloatingButton } from \"./components/FloatingButton.jsx\";\nimport { usePerformance } from \"./hooks/usePerformance\";\nimport { ThemeProvider } from \"./styles/ThemeContext\";\nimport { getColors } from \"./styles/theme\";\nimport type { CustomTab } from \"./types\";\n\nexport interface LynxConsoleHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n}\n\nexport interface LynxConsoleProps {\n theme?: \"light\" | \"dark\";\n safeAreaInsetBottom?: string;\n customTabs?: CustomTab[];\n initialPosition?: {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n };\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(\n (\n {\n theme = \"light\",\n safeAreaInsetBottom = \"50px\",\n customTabs,\n initialPosition,\n },\n ref: ForwardedRef<LynxConsoleHandle>,\n ) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shouldClose, setShouldClose] = useState(false);\n const { performances } = usePerformance();\n const colors = useMemo(() => getColors(theme), [theme]);\n\n const latestFcp = useMemo(() => {\n for (let i = performances.length - 1; i >= 0; i--) {\n const perf = performances[i];\n if (perf && perf.entryType === \"metric\" && perf.name === \"fcp\") {\n const metricEntry = perf.rawEntry as MetricFcpEntry | undefined;\n // totalFcp를 먼저 시도하고, 없으면 lynxFcp 반환\n if (metricEntry?.totalFcp?.duration !== undefined) {\n return metricEntry.totalFcp;\n }\n if (metricEntry?.lynxFcp?.duration !== undefined) {\n return metricEntry.lynxFcp;\n }\n }\n }\n return undefined;\n }, [performances]);\n\n useImperativeHandle(ref, () => ({\n open: () => {\n setIsOpen(true);\n setShouldClose(false);\n },\n close: () => {\n setShouldClose(true);\n },\n isOpen: () => isOpen,\n }));\n\n const handleOpenBottomSheet = () => {\n setIsOpen(true);\n setShouldClose(false);\n };\n\n const handleCloseBottomSheet = () => {\n setIsOpen(false);\n setShouldClose(false);\n };\n\n return (\n <ThemeProvider value={colors}>\n <view\n style={{\n backgroundColor: colors.bg.layerDefault,\n color: colors.fg.neutral,\n }}\n >\n <FloatingButton\n bindtap={handleOpenBottomSheet}\n initialPosition={initialPosition}\n >\n <text\n className=\"fb-title t4\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n LynxConsole\n </text>\n <text\n className=\"fb-subtitle t3\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n {`${latestFcp?.name ?? \"FCP\"}: ${latestFcp?.duration ? latestFcp.duration.toFixed(2) : \"--\"}ms`}\n </text>\n </FloatingButton>\n {isOpen && (\n <BottomSheet\n isOpen={isOpen}\n shouldClose={shouldClose}\n onClose={handleCloseBottomSheet}\n title=\"Lynx Console\"\n safeAreaInsetBottom={safeAreaInsetBottom}\n >\n <ConsolePanel customTabs={customTabs} />\n </BottomSheet>\n )}\n </view>\n </ThemeProvider>\n );\n },\n);\n\nexport type { CustomTab } from \"./types\";\nexport default LynxConsole;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/hooks/useKeyboardHeight.ts","../src/styles/theme.ts","../src/styles/ThemeContext.ts","../src/components/BottomSheet.tsx","../src/hooks/useConsole.ts","../src/hooks/useLatestFcp.ts","../src/hooks/useNetwork.ts","../src/hooks/usePerformance.ts","../src/utils/parseCssStyle.ts","../src/utils/parseFormat.ts","../src/components/LogPanel.tsx","../src/components/NetworkDetailSection.tsx","../src/components/NetworkPanel.tsx","../src/components/PerformancePanel.tsx","../src/components/Tabs.tsx","../src/components/ConsolePanel.tsx","../src/hooks/useLongPressDrag.ts","../src/components/FloatingButton.tsx","../src/index.tsx"],"sourcesContent":["import { useLynxGlobalEventListener, useState } from \"@lynx-js/react\";\n\nexport function useKeyboardHeight() {\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n\n useLynxGlobalEventListener(\n \"keyboardstatuschanged\",\n (status: \"on\" | \"off\", height: number) => {\n setKeyboardHeight(status === \"on\" ? height : 0);\n },\n );\n\n return keyboardHeight;\n}\n","export type Theme = \"light\" | \"dark\";\n\nconst lightColors = {\n palette: {\n blue100: \"#eff6ff\",\n blue600: \"#5e98fe\",\n gray100: \"#f7f8f9\",\n gray400: \"#dcdee3\",\n green100: \"#edfaf6\",\n green600: \"#10ab7d\",\n purple100: \"#f5f3fe\",\n purple600: \"#9f84fb\",\n red100: \"#fdf0f0\",\n red600: \"#fc6a66\",\n red900: \"#921708\",\n staticWhite: \"#ffffff\",\n yellow100: \"#fff7de\",\n yellow600: \"#c49725\",\n yellow900: \"#4f3e1f\",\n },\n fg: {\n neutral: \"#1a1c20\",\n placeholder: \"#b0b3ba\",\n disabled: \"#d1d3d8\",\n neutralMuted: \"#555d6d\",\n neutralSubtle: \"#868b94\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#ffffff\",\n layerFloating: \"#ffffff\",\n neutralWeak: \"#f3f4f5\",\n },\n stroke: {\n neutralSubtle: \"#0000000c\",\n neutralWeak: \"#dcdee3\",\n },\n} as const;\n\nconst darkColors = {\n palette: {\n blue100: \"#202742\",\n blue600: \"#1e82eb\",\n gray100: \"#16171b\",\n gray400: \"#393d46\",\n green100: \"#202926\",\n green600: \"#1b946d\",\n purple100: \"#28213b\",\n purple600: \"#8e6bee\",\n red100: \"#322323\",\n red600: \"#f73526\",\n red900: \"#f8c5c3\",\n staticWhite: \"#ffffff\",\n yellow100: \"#302819\",\n yellow600: \"#b6720d\",\n yellow900: \"#e5d49b\",\n },\n fg: {\n neutral: \"#f3f4f5\",\n placeholder: \"#868b94\",\n disabled: \"#5b606a\",\n neutralMuted: \"#dcdee3\",\n neutralSubtle: \"#b0b3ba\",\n },\n bg: {\n overlay: \"#00000074\",\n layerDefault: \"#16171b\",\n layerFloating: \"#1d2025\",\n neutralWeak: \"#2b2e35\",\n },\n stroke: {\n neutralSubtle: \"#ffffff0d\",\n neutralWeak: \"#393d46\",\n },\n} as const;\n\nconst colorMap = {\n light: lightColors,\n dark: darkColors,\n} as const;\n\nexport const fontWeight = {\n regular: \"400\",\n medium: \"500\",\n bold: \"700\",\n} as const;\n\nexport const duration = {\n d4: \"200ms\",\n d6: \"300ms\",\n} as const;\n\nexport function getColors(theme: Theme) {\n return colorMap[theme];\n}\n\nexport type ThemeColors = ReturnType<typeof getColors>;\n","import { createContext, useContext } from \"@lynx-js/react\";\nimport { getColors, type ThemeColors } from \"./theme\";\n\nconst ThemeContext = createContext<ThemeColors>(getColors(\"light\"));\n\nexport const ThemeProvider = ThemeContext.Provider;\n\nexport function useThemeColors(): ThemeColors {\n return useContext(ThemeContext);\n}\n","import { type ReactNode, useEffect, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\nimport { useKeyboardHeight } from \"../hooks/useKeyboardHeight\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration, fontWeight } from \"../styles/theme\";\nimport \"./BottomSheet.css\";\n\ninterface BottomSheetProps {\n children: ReactNode;\n title?: string;\n footer?: ReactNode;\n onClose: () => void;\n isOpen: boolean;\n shouldClose?: boolean;\n safeAreaInsetBottom?: string;\n}\n\nconst MIN_HEIGHT = 200;\nconst MAX_HEIGHT = 700;\nconst DEFAULT_HEIGHT = 500;\nconst CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘\n\n// 마지막 높이 저장\nlet savedHeight: number | null = null;\n\nexport default function BottomSheet({\n children,\n title,\n footer,\n onClose,\n isOpen,\n shouldClose = false,\n safeAreaInsetBottom = \"25px\",\n}: BottomSheetProps) {\n const colors = useThemeColors();\n const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);\n const [isDragging, setIsDragging] = useState(false);\n const [dragStartY, setDragStartY] = useState(0);\n const [dragStartHeight, setDragStartHeight] = useState(\n savedHeight ?? DEFAULT_HEIGHT,\n );\n const [isOpening, setIsOpening] = useState(true);\n const [isClosing, setIsClosing] = useState(false);\n const keyboardHeight = useKeyboardHeight();\n\n // 닫기 애니메이션 처리\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n onClose();\n }, 300);\n };\n\n // 아래에서 올라오는 애니메이션\n useEffect(() => {\n requestAnimationFrame(() => {\n setIsOpening(false);\n });\n }, []);\n\n // 외부에서 닫기 요청 시 애니메이션 처리\n useEffect(() => {\n if (shouldClose && !isClosing) {\n handleClose();\n }\n }, [shouldClose, isClosing]);\n\n // 높이 변경 시 저장\n useEffect(() => {\n savedHeight = sheetHeight;\n }, [sheetHeight]);\n\n if (!isOpen) return null;\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n setIsDragging(true);\n setDragStartY(e.detail.y);\n setDragStartHeight(sheetHeight);\n setTempHeight(sheetHeight);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n if (!isDragging) return;\n const deltaY = dragStartY - e.detail.y;\n const newHeight = Math.min(\n Math.max(dragStartHeight + deltaY, MIN_HEIGHT),\n MAX_HEIGHT,\n );\n setTempHeight(newHeight);\n };\n\n const handleTouchEnd = () => {\n setIsDragging(false);\n\n // 아래로 일정 30px 이상 드래그하면 닫기\n const dragDistance = dragStartHeight - tempHeight;\n setSheetHeight(tempHeight);\n if (dragDistance > CLOSE_DRAG_THRESHOLD) {\n handleClose();\n }\n };\n\n return (\n <scroll-view\n className=\"bs-backdrop\"\n style={{\n background: colors.bg.overlay,\n opacity: isOpening || isClosing ? 0 : 1,\n transition: `opacity ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n <view className=\"bs-overlay\" bindtap={handleClose}>\n <view\n className=\"bs-content\"\n catchtap={() => {}}\n style={{\n background: colors.bg.layerFloating,\n height: `${\n keyboardHeight > 0\n ? Math.min(\n MAX_HEIGHT,\n (isDragging ? tempHeight : sheetHeight) + keyboardHeight,\n )\n : isDragging\n ? tempHeight\n : sheetHeight\n }px`,\n transform:\n isOpening || isClosing ? \"translateY(100%)\" : \"translateY(0)\",\n transition: isDragging\n ? \"none\"\n : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1), height ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n >\n {/* catchtap: 이벤트 버블링 차단 */}\n <view\n className=\"bs-handleContainer\"\n bindtouchstart={handleTouchStart}\n bindtouchmove={handleTouchMove}\n bindtouchend={handleTouchEnd}\n >\n <view\n className=\"bs-handle\"\n style={{ backgroundColor: colors.palette.gray400 }}\n />\n </view>\n <view className=\"bs-header\">\n {title && (\n <text\n className=\"bs-title t7\"\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n {title}\n </text>\n )}\n </view>\n <view\n className=\"bs-body\"\n style={{\n paddingBottom:\n keyboardHeight > 0\n ? `${keyboardHeight}px`\n : safeAreaInsetBottom,\n }}\n >\n {children}\n </view>\n {footer && <view className=\"bs-footer\">{footer}</view>}\n </view>\n </view>\n </scroll-view>\n );\n}\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { LogEntry } from \"../types\";\n\nexport const useConsole = () => {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs === \"undefined\") {\n console.warn(\"[LynxConsole] Log monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setLogs([...(state.logs ?? [])]);\n\n const updateLogs = (_entry: LogEntry) => {\n setLogs([...(state.logs ?? [])]);\n };\n\n const unsubscribe = state.logSubscribe?.(updateLogs);\n\n return unsubscribe;\n }, []);\n\n const clearLogs = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.logs !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.logs = [];\n setLogs([]);\n }\n };\n\n return { logs, clearLogs };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { PerformanceEntryData } from \"../types\";\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpRawEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst pickFcp = (entry: PerformanceEntryData): FcpMetric | undefined => {\n if (entry.entryType !== \"metric\" || entry.name !== \"fcp\") return undefined;\n const raw = entry.rawEntry as MetricFcpRawEntry | undefined;\n if (raw?.totalFcp?.duration !== undefined) return raw.totalFcp;\n if (raw?.lynxFcp?.duration !== undefined) return raw.lynxFcp;\n return undefined;\n};\n\nexport const useLatestFcp = (): FcpMetric | undefined => {\n const [fcp, setFcp] = useState<FcpMetric | undefined>(() => {\n const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];\n for (let i = performances.length - 1; i >= 0; i--) {\n const entry = performances[i];\n if (!entry) continue;\n const found = pickFcp(entry);\n if (found) return found;\n }\n return undefined;\n });\n\n useEffect(() => {\n const state = globalThis.__LYNX_CONSOLE__?.state;\n if (!state?.subscribePerformance) return;\n\n const unsubscribe = state.subscribePerformance((entry) => {\n const found = pickFcp(entry);\n if (found) setFcp(found);\n });\n\n return unsubscribe;\n }, []);\n\n return fcp;\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { NetworkEntry } from \"../types\";\n\nexport const useNetwork = () => {\n const [networks, setNetworks] = useState<NetworkEntry[]>([]);\n\n useEffect(() => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks === \"undefined\") {\n console.warn(\"[LynxConsole] Network monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setNetworks([...(state.networks ?? [])]);\n\n const updateNetworks = (_entry: NetworkEntry) => {\n setNetworks([...(state.networks ?? [])]);\n };\n\n const unsubscribe = state.subscribeNetwork?.(updateNetworks);\n\n return unsubscribe;\n }, []);\n\n const clearNetworks = () => {\n if (typeof globalThis.__LYNX_CONSOLE__?.state?.networks !== \"undefined\") {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.networks = [];\n state.networksMap?.clear();\n setNetworks([]);\n }\n };\n\n return { networks, clearNetworks };\n};\n","import { useEffect, useState } from \"@lynx-js/react\";\nimport type { PerformanceEntryData } from \"../types\";\n\nexport const usePerformance = () => {\n const [performances, setPerformances] = useState<PerformanceEntryData[]>([]);\n\n useEffect(() => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances === \"undefined\"\n ) {\n console.warn(\"[LynxConsole] Performance monitoring not initialized\");\n return;\n }\n\n const state = globalThis.__LYNX_CONSOLE__.state;\n\n setPerformances([...(state.performances ?? [])]);\n\n const updatePerformances = (_entry: PerformanceEntryData) => {\n setPerformances([...(state.performances ?? [])]);\n };\n\n const unsubscribe = state.subscribePerformance?.(updatePerformances);\n\n return unsubscribe;\n }, []);\n\n const clearPerformances = () => {\n if (\n typeof globalThis.__LYNX_CONSOLE__?.state?.performances !== \"undefined\"\n ) {\n const state = globalThis.__LYNX_CONSOLE__.state;\n state.performances = [];\n setPerformances([]);\n }\n };\n\n return { performances, clearPerformances };\n};\n","export type StyleObject = Record<string, string>;\n\nconst DANGEROUS_VALUE = /url\\s*\\(|expression\\s*\\(|@import/i;\n\nconst toCamelCase = (name: string): string => {\n if (name.startsWith(\"--\")) return name;\n return name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n};\n\nexport const parseCssString = (css: string): StyleObject => {\n const result: StyleObject = {};\n for (const raw of css.split(\";\")) {\n const decl = raw.trim();\n if (!decl) continue;\n const colon = decl.indexOf(\":\");\n if (colon <= 0) continue;\n const name = decl.slice(0, colon).trim().toLowerCase();\n const value = decl.slice(colon + 1).trim();\n if (!name || !value) continue;\n if (DANGEROUS_VALUE.test(value)) continue;\n result[toCamelCase(name)] = value;\n }\n return result;\n};\n","import { parseCssString, type StyleObject } from \"./parseCssStyle\";\n\nexport type LogSegment =\n | { type: \"text\"; text: string; style?: StyleObject }\n | { type: \"arg\"; value: unknown };\n\nexport interface ParsedLogArgs {\n segments: LogSegment[];\n rest: unknown[];\n}\n\nconst HAS_FORMAT = /%[csdifoO%]/;\n\nconst formatNumber = (v: unknown, int: boolean): string => {\n const n =\n typeof v === \"number\"\n ? int\n ? Math.trunc(v)\n : v\n : typeof v === \"symbol\"\n ? Number.NaN\n : int\n ? parseInt(String(v), 10)\n : parseFloat(String(v));\n return Number.isNaN(n) ? \"NaN\" : String(n);\n};\n\nexport const parseConsoleArgs = (args: unknown[]): ParsedLogArgs => {\n const first = args[0];\n if (typeof first !== \"string\" || !HAS_FORMAT.test(first)) {\n return { segments: [], rest: args };\n }\n\n const segments: LogSegment[] = [];\n let currentText = \"\";\n let currentStyle: StyleObject | undefined;\n let argIndex = 1;\n let lastIndex = 0;\n\n const flushText = () => {\n if (currentText) {\n segments.push({ type: \"text\", text: currentText, style: currentStyle });\n currentText = \"\";\n }\n };\n\n const re = /%([csdifoO%])/g;\n let match: RegExpExecArray | null = re.exec(first);\n while (match !== null) {\n currentText += first.slice(lastIndex, match.index);\n lastIndex = re.lastIndex;\n const spec = match[1];\n\n if (spec === \"%\") {\n currentText += \"%\";\n } else if (argIndex >= args.length) {\n currentText += match[0];\n } else {\n const arg = args[argIndex++];\n switch (spec) {\n case \"c\":\n flushText();\n currentStyle =\n typeof arg === \"string\" ? parseCssString(arg) : undefined;\n break;\n case \"s\":\n currentText += String(arg);\n break;\n case \"d\":\n case \"i\":\n currentText += formatNumber(arg, true);\n break;\n case \"f\":\n currentText += formatNumber(arg, false);\n break;\n case \"o\":\n case \"O\":\n flushText();\n segments.push({ type: \"arg\", value: arg });\n break;\n }\n }\n\n match = re.exec(first);\n }\n currentText += first.slice(lastIndex);\n flushText();\n\n return { segments, rest: args.slice(argIndex) };\n};\n","import { useEffect, useMemo, useRef, useState } from \"@lynx-js/react\";\nimport type { BaseEvent, InputInputEvent, NodesRef } from \"@lynx-js/types\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { LogEntry, LogLevel } from \"../types\";\nimport { parseConsoleArgs } from \"../utils/parseFormat\";\nimport \"./ConsolePanel.css\";\n\nconst LOG_LEVELS: LogLevel[] = [\"log\", \"info\", \"warn\", \"error\"];\n\nlet savedEnabledLevels: Set<LogLevel> | null = null;\nlet savedSearchQuery = \"\";\nlet closeFilterDropdown: (() => void) | null = null;\n\nexport const dismissFilterDropdown = () => closeFilterDropdown?.();\n\ninterface LogPanelProps {\n logs: LogEntry[];\n clearLogs: () => void;\n}\n\nconst runCode = (code: string) => {\n try {\n // biome-ignore lint: intentional REPL tool\n const result = eval(code);\n if (result instanceof Promise) {\n result.then((r) => console.log(r)).catch((e) => console.error(e));\n } else {\n console.log(result);\n }\n } catch (e) {\n console.error(e);\n }\n};\n\nfunction getLevelColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"log\":\n return colors.palette.green600;\n case \"info\":\n return colors.palette.blue600;\n case \"warn\":\n return colors.palette.yellow600;\n case \"error\":\n return colors.palette.red600;\n }\n}\n\nfunction getLogItemBg(\n colors: ThemeColors,\n level: LogLevel,\n): string | undefined {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nfunction getStringColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.fg.neutral;\n }\n}\n\nfunction getPrimitiveColor(colors: ThemeColors, level: LogLevel): string {\n switch (level) {\n case \"warn\":\n return colors.palette.yellow900;\n case \"error\":\n return colors.palette.red900;\n default:\n return colors.palette.blue600;\n }\n}\n\nexport const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {\n const colors = useThemeColors();\n const [expandedArgs, setExpandedArgs] = useState(new Set());\n const [code, setCode] = useState(\"\");\n const [enabledLevels, setEnabledLevels] = useState<Set<LogLevel>>(\n () => savedEnabledLevels ?? new Set(LOG_LEVELS),\n );\n const [filterOpen, setFilterOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState(savedSearchQuery);\n const inputRef = useRef<NodesRef>(null);\n const searchInputRef = useRef<NodesRef>(null);\n const listRef = useRef<NodesRef>(null);\n\n useEffect(() => {\n savedEnabledLevels = enabledLevels;\n }, [enabledLevels]);\n\n useEffect(() => {\n savedSearchQuery = searchQuery;\n }, [searchQuery]);\n\n useEffect(() => {\n if (savedSearchQuery) {\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: savedSearchQuery } })\n .exec();\n }\n }, []);\n\n useEffect(() => {\n closeFilterDropdown = () => setFilterOpen(false);\n return () => {\n closeFilterDropdown = null;\n };\n }, []);\n\n const filteredLogs = useMemo(\n () =>\n logs.filter((log) => {\n if (!enabledLevels.has(log.level)) return false;\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return log.args.some((arg) =>\n String(arg).toLowerCase().includes(query),\n );\n }\n return true;\n }),\n [logs, enabledLevels, searchQuery],\n );\n const logsRef = useRef(filteredLogs);\n logsRef.current = filteredLogs;\n\n const toggleLevel = (level: LogLevel) => {\n setEnabledLevels((prev) => {\n const next = new Set(prev);\n if (next.has(level)) {\n next.delete(level);\n } else {\n next.add(level);\n }\n return next;\n });\n };\n\n const scrollToBottom = (smooth: boolean) => {\n if (logsRef.current.length === 0) return;\n listRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: { position: logsRef.current.length - 1, smooth },\n // 연속 로그로 진행 중이던 smooth 스크롤이 중단될 때 나는 무해한 경고를 무시\n fail: () => {},\n })\n .exec();\n };\n\n useEffect(() => {\n scrollToBottom(true);\n }, [filteredLogs]);\n\n const toggleArg = (key: string) => {\n setExpandedArgs((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n };\n\n const handleRun = () => {\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCode(\"\");\n inputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n runCode(trimmed);\n };\n\n const renderArg = (\n arg: unknown,\n parentKey: string,\n level: \"log\" | \"info\" | \"warn\" | \"error\",\n ): React.ReactNode => {\n const key = parentKey;\n const isExpanded = expandedArgs.has(key);\n\n if (arg === null) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n null\n </text>\n );\n }\n\n if (arg === undefined) {\n return (\n <text\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n undefined\n </text>\n );\n }\n\n if (typeof arg === \"string\") {\n const MAX_LENGTH = 80;\n const shouldTruncate = arg.length > MAX_LENGTH;\n const strColor = getStringColor(colors, level);\n\n if (!shouldTruncate) {\n return (\n <text\n className={\"cp-argString t3\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {arg}\n </text>\n );\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argString t3\"}\n style={{ color: strColor, fontWeight: fontWeight.regular }}\n >\n {isExpanded ? arg : `${arg.slice(0, MAX_LENGTH)}...`}\n </text>\n </view>\n </view>\n );\n }\n\n if (typeof arg === \"number\" || typeof arg === \"boolean\") {\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n }\n\n if (typeof arg === \"object\") {\n let preview = \"Object\";\n if (Array.isArray(arg)) {\n preview = `Array(${arg.length})`;\n } else if (arg instanceof Map) {\n preview = `Map(${arg.size})`;\n } else if (arg instanceof Set) {\n preview = `Set(${arg.size})`;\n } else if (arg instanceof Date) {\n preview = `Date`;\n } else if (arg instanceof RegExp) {\n preview = `RegExp`;\n } else if (arg instanceof Error) {\n preview = `${arg.constructor.name}`;\n } else if (arg?.constructor?.name && arg.constructor.name !== \"Object\") {\n preview = arg.constructor.name;\n }\n\n let jsonString: string;\n if (arg instanceof Map) {\n const entries = Array.from(arg.entries()).map(\n ([k, v]) => ` [${stringify(k)}, ${stringify(v)}]`,\n );\n jsonString = `{\\n${entries.join(\",\\n\")}\\n}`;\n } else if (arg instanceof Set) {\n const values = Array.from(arg.values()).map((v) => stringify(v));\n jsonString = `{\\n${values.join(\", \")}\\n}`;\n } else {\n jsonString =\n stringify(arg, null, 2, { references: true }) ?? String(arg);\n }\n\n return (\n <view className={\"cp-argObject\"}>\n <view className={\"cp-argObjectHeader\"} bindtap={() => toggleArg(key)}>\n <text\n className={\"cp-toggleIndicator t2\"}\n style={{\n color: colors.fg.neutralSubtle,\n fontWeight: fontWeight.regular,\n }}\n >\n {isExpanded ? \"▼\" : \"▶\"}\n </text>\n <text\n className={\"cp-argObjectPreview t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {preview}\n </text>\n </view>\n {isExpanded && (\n <view className={\"cp-argObjectContent\"}>\n <text\n className={\"cp-argObjectJson t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {jsonString}\n </text>\n </view>\n )}\n </view>\n );\n }\n\n return (\n <text\n className={\"cp-argPrimitive t3\"}\n style={{\n color: getPrimitiveColor(colors, level),\n fontWeight: fontWeight.regular,\n }}\n >\n {String(arg)}\n </text>\n );\n };\n\n return (\n <view\n className={\"cp-logContainer\"}\n bindtap={() => {\n if (filterOpen) setFilterOpen(false);\n }}\n >\n <view className={\"cp-logHeader\"}>\n <view className={\"cp-filterWrapper\"}>\n <view\n className={\"cp-filterButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n catchtap={() => setFilterOpen((v) => !v)}\n >\n <text\n className={\"cp-filterButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n Filter ▼\n </text>\n </view>\n {filterOpen && (\n <view\n className={\"cp-filterDropdown\"}\n style={{\n backgroundColor: colors.bg.layerFloating,\n borderColor: colors.stroke.neutralSubtle,\n }}\n catchtap={() => {}}\n >\n {LOG_LEVELS.map((level) => (\n <view\n key={level}\n className={\"cp-filterOption\"}\n bindtap={() => toggleLevel(level)}\n >\n <text\n className={\"cp-filterCheckbox t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {enabledLevels.has(level) ? \"✅\" : \"⬜\"}\n </text>\n <text\n className={\"cp-filterLabel t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: getLevelColor(colors, level),\n }}\n >\n {level.toUpperCase()}\n </text>\n </view>\n ))}\n </view>\n )}\n </view>\n <view\n className={\"cp-searchWrapper\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"cp-searchPrompt t6\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={searchInputRef}\n className={\"cp-searchInput t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"Search logs...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setSearchQuery(e.detail.value)\n }\n />\n {searchQuery.length > 0 && (\n <view\n className={\"cp-searchClear\"}\n bindtap={() => {\n setSearchQuery(\"\");\n searchInputRef.current\n ?.invoke({ method: \"setValue\", params: { value: \"\" } })\n .exec();\n }}\n >\n <text\n className={\"cp-searchClearText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n ✕\n </text>\n </view>\n )}\n </view>\n <view style={{ display: \"flex\", flexDirection: \"row\", gap: 8 }}>\n <view\n className={\"cp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearLogs}\n >\n <text\n className={\"cp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n </view>\n <list\n ref={listRef}\n scroll-orientation=\"vertical\"\n className={\"cp-logList\"}\n preload-buffer-count={10}\n initial-scroll-index={Math.max(0, filteredLogs.length - 1)}\n >\n {filteredLogs.length === 0 ? (\n <list-item item-key=\"empty-state\">\n <view className={\"cp-placeholder\"}>\n <text\n className={\"cp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No logs yet. Try console.log(\"Hello!\")\n </text>\n </view>\n </list-item>\n ) : (\n filteredLogs.map((log) => {\n return (\n <list-item key={log.id} item-key={log.id}>\n <view\n className={\"cp-logItem\"}\n style={{\n backgroundColor: getLogItemBg(colors, log.level),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view className={\"cp-logItemHeader\"}>\n <text\n className={\"cp-logLevel t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getLevelColor(colors, log.level),\n }}\n >\n {log.level.toUpperCase()}\n </text>\n <text\n className={\"cp-logTime t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(log.timestamp).toISOString()}\n </text>\n </view>\n <view className={\"cp-logArgsContainer\"}>\n {(() => {\n const { segments, rest } = parseConsoleArgs(log.args);\n const baseTextStyle = {\n color: getStringColor(colors, log.level),\n fontWeight: fontWeight.regular,\n };\n const wrap = (key: string, content: React.ReactNode) => (\n <view\n key={key}\n className={\"cp-logArgItem\"}\n style={{ fontWeight: fontWeight.regular }}\n >\n {content}\n </view>\n );\n return (\n <>\n {segments.map((seg, index) => {\n const key = `${log.id}-seg-${index.toString()}`;\n return wrap(\n key,\n seg.type === \"text\" ? (\n <text\n className={\"cp-argString t3\"}\n style={{ ...baseTextStyle, ...seg.style }}\n >\n {seg.text}\n </text>\n ) : (\n renderArg(seg.value, key, log.level)\n ),\n );\n })}\n {rest.map((arg, index) => {\n const key = `${log.id}-rest-${index.toString()}`;\n return wrap(key, renderArg(arg, key, log.level));\n })}\n </>\n );\n })()}\n </view>\n </view>\n </list-item>\n );\n })\n )}\n </list>\n <view className={\"cp-replInputRow\"}>\n <text\n className={\"cp-replPrompt t10\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.placeholder,\n }}\n >\n {\"›\"}\n </text>\n <input\n ref={inputRef}\n className={\"cp-replInput t5\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n caretColor: colors.palette.green600,\n }}\n placeholder=\"enter code...\"\n bindinput={(e: BaseEvent<\"bindinput\", InputInputEvent>) =>\n setCode(e.detail.value)\n }\n bindconfirm={handleRun}\n />\n <view\n className={\"cp-replRunButton\"}\n style={{ backgroundColor: colors.palette.green100 }}\n bindtap={handleRun}\n >\n <text\n className={\"cp-replRunButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.palette.green600,\n }}\n >\n Run\n </text>\n </view>\n </view>\n </view>\n );\n};\n","import { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkDetailSectionProps {\n headers?: Record<string, string> | undefined;\n body?: string | undefined;\n error?: string | undefined;\n}\n\nexport const NetworkDetailSection = ({\n headers = {},\n body = \"\",\n error = \"\",\n}: NetworkDetailSectionProps) => {\n const colors = useThemeColors();\n\n return (\n <>\n {/* Headers */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Headers\n </text>\n {headers && Object.keys(headers).length > 0 ? (\n <view className={\"np-table\"}>\n {Object.entries(headers).map(([key, value]) => (\n <view\n key={key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {value}\n </text>\n </view>\n ))}\n </view>\n ) : (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No headers\n </text>\n )}\n </view>\n\n {/* Body */}\n <view className={\"np-detailSection\"}>\n <text\n className={\"np-detailSectionTitle t3\"}\n style={{ fontWeight: fontWeight.bold, color: colors.fg.neutral }}\n >\n Body\n </text>\n {error && (\n <text\n className={\"np-errorText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n }}\n >\n {error}\n </text>\n )}\n {body && (\n <text\n className={\"np-bodyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n }}\n >\n {body}\n </text>\n )}\n {!error && !body && (\n <text\n className={\"np-emptyText t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No body\n </text>\n )}\n </view>\n </>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { NetworkEntry } from \"../types\";\nimport { NetworkDetailSection } from \"./NetworkDetailSection\";\nimport \"./NetworkPanel.css\";\n\ninterface NetworkPanelProps {\n networks: NetworkEntry[];\n clearNetworks: () => void;\n}\n\ntype TabType = \"general\" | \"request\" | \"response\";\n\nfunction getMethodColors(colors: ThemeColors, method: string) {\n switch (method) {\n case \"GET\":\n return {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"POST\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"PUT\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n case \"PATCH\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"DELETE\":\n return {\n color: colors.palette.red600,\n backgroundColor: colors.palette.red100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\n }\n}\n\nfunction getStatusCodeColor(\n colors: ThemeColors,\n variant: \"success\" | \"error\" | \"pending\",\n): string {\n switch (variant) {\n case \"success\":\n return colors.palette.green600;\n case \"error\":\n return colors.palette.red600;\n case \"pending\":\n return colors.fg.neutralSubtle;\n }\n}\n\nfunction getItemBg(colors: ThemeColors, status: string): string | undefined {\n switch (status) {\n case \"pending\":\n return colors.palette.gray100;\n case \"error\":\n return colors.palette.red100;\n default:\n return undefined;\n }\n}\n\nexport const NetworkPanel = ({\n networks,\n clearNetworks,\n}: NetworkPanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<TabType>(\"general\");\n const formatDuration = (duration?: number): string => {\n if (!duration) return \"-\";\n if (duration < 1000) return `${duration}ms`;\n return `${(duration / 1000).toFixed(2)}s`;\n };\n\n const extractPath = (url: string): string => {\n const pathMatch = url.match(/^https?:\\/\\/[^/]+(.*)$/);\n if (pathMatch?.[1]) {\n return pathMatch[1].startsWith(\"/\")\n ? pathMatch[1].slice(1)\n : pathMatch[1];\n }\n return url;\n };\n\n const getGeneralInfo = (network: NetworkEntry) => {\n return [\n { key: \"URL\", value: network.url },\n { key: \"Method\", value: network.method },\n network.statusCode\n ? { key: \"Status\", value: String(network.statusCode) }\n : null,\n {\n key: \"Request Time\",\n value: new Date(network.startTime).toISOString(),\n },\n network.endTime\n ? {\n key: \"Response Time\",\n value: new Date(network.endTime).toISOString(),\n }\n : null,\n network.duration\n ? { key: \"Duration\", value: formatDuration(network.duration) }\n : null,\n ].filter((item) => item !== null);\n };\n\n const getStatusCodeVariant = (\n status: string,\n statusCode?: number,\n ): \"success\" | \"error\" | \"pending\" => {\n if (status === \"pending\") return \"pending\";\n if (status === \"error\") return \"error\";\n if (statusCode && statusCode >= 200 && statusCode < 300) return \"success\";\n return \"error\";\n };\n\n return (\n <view className={\"np-container\"}>\n <view className={\"np-header\"}>\n <text\n className={\"np-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n Total: {networks.length} requests\n </text>\n <view\n className={\"np-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n bindtap={clearNetworks}\n >\n <text\n className={\"np-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n {networks.length === 0 ? (\n <view className={\"np-placeholder\"}>\n <text\n className={\"np-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No network requests yet\n </text>\n </view>\n ) : (\n <list scroll-orientation=\"vertical\" className={\"np-list\"}>\n {networks.map((network) => (\n <list-item key={network.id} item-key={network.id}>\n <view\n className={\"np-item\"}\n style={{\n backgroundColor: getItemBg(colors, network.status),\n borderBottomColor: colors.stroke.neutralWeak,\n }}\n >\n <view\n className={\"np-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n <text\n className={\"np-method t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getMethodColors(colors, network.method),\n }}\n >\n {network.method}\n </text>\n {network.statusCode && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: getStatusCodeColor(\n colors,\n getStatusCodeVariant(\n network.status,\n network.statusCode,\n ),\n ),\n }}\n >\n {network.statusCode}\n </text>\n )}\n {network.status === \"pending\" && (\n <text\n className={\"np-statusCode t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n Pending...\n </text>\n )}\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {formatDuration(network.duration)}\n </text>\n <text\n className={\"np-time t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(network.startTime).toISOString()}\n </text>\n </view>\n\n <text\n className={\"np-path t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n bindtap={() =>\n setSelectedId(selectedId === network.id ? null : network.id)\n }\n >\n {extractPath(network.url)}\n </text>\n\n {selectedId === network.id && (\n <view\n className={\"np-detailsContainer\"}\n style={{ borderTopColor: colors.stroke.neutralSubtle }}\n >\n {/* Tabs */}\n <view className={\"np-tabs\"}>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"general\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"general\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"general\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n General\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"request\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"request\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"request\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Request\n </text>\n </view>\n <view\n className={\"np-tab\"}\n style={{\n backgroundColor:\n activeTab === \"response\"\n ? colors.bg.neutralWeak\n : undefined,\n }}\n bindtap={() => setActiveTab(\"response\")}\n >\n <text\n className={\"np-tabText t4\"}\n style={{\n fontWeight: fontWeight.medium,\n color:\n activeTab === \"response\"\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n Response\n </text>\n </view>\n </view>\n\n {/* Tab Content */}\n <view className={\"np-tabContent\"}>\n {activeTab === \"general\" && (\n <view className={\"np-table\"}>\n {getGeneralInfo(network).map((item) => (\n <view\n key={item.key}\n className={\"np-tableRow\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"np-tableKey t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutralSubtle,\n }}\n >\n {item.key}\n </text>\n <text\n className={\"np-tableValue t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutral,\n }}\n >\n {item.value}\n </text>\n </view>\n ))}\n </view>\n )}\n\n {activeTab === \"request\" && (\n <NetworkDetailSection\n headers={network.requestHeaders}\n body={network.requestBody}\n />\n )}\n\n {activeTab === \"response\" && (\n <NetworkDetailSection\n headers={network.responseHeaders}\n body={network.responseBody}\n error={network.error}\n />\n )}\n </view>\n </view>\n )}\n </view>\n </list-item>\n ))}\n </list>\n )}\n </view>\n );\n};\n","import { useState } from \"@lynx-js/react\";\nimport { stringify } from \"javascript-stringify\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight, type ThemeColors } from \"../styles/theme\";\nimport type { PerformanceEntryData } from \"../types\";\nimport \"./PerformancePanel.css\";\n\ninterface PerformancePanelProps {\n performances: PerformanceEntryData[];\n clearPerformances: () => void;\n}\n\ninterface FcpMetric {\n name: string;\n duration: number;\n}\n\ninterface MetricFcpEntry {\n totalFcp?: FcpMetric;\n lynxFcp?: FcpMetric;\n fcp?: FcpMetric;\n}\n\nconst isMetricFcpEntry = (entry: PerformanceEntryData): boolean => {\n return entry.entryType === \"metric\" && entry.name === \"fcp\";\n};\n\nconst extractFcpMetrics = (entry: PerformanceEntryData) => {\n if (!isMetricFcpEntry(entry) || !entry.rawEntry) {\n return null;\n }\n\n const metricEntry = entry.rawEntry as MetricFcpEntry;\n\n return {\n totalFcp: metricEntry.totalFcp ?? undefined,\n lynxFcp: metricEntry.lynxFcp ?? undefined,\n fcp: metricEntry.fcp ?? undefined,\n };\n};\n\nconst formatDuration = (ms?: number): string => {\n if (ms === undefined) return \"-\";\n return `${ms.toFixed(2)}ms`;\n};\n\nconst getPrimaryFcpLabel = (entry: PerformanceEntryData): string => {\n const fcpMetrics = extractFcpMetrics(entry);\n if (!fcpMetrics) return \"\";\n\n const { totalFcp, lynxFcp, fcp } = fcpMetrics;\n\n if (totalFcp?.duration !== undefined) {\n return `totalFcp: ${formatDuration(totalFcp.duration)}`;\n }\n if (lynxFcp?.duration !== undefined) {\n return `lynxFcp: ${formatDuration(lynxFcp.duration)}`;\n }\n if (fcp?.duration !== undefined) {\n return `fcp: ${formatDuration(fcp.duration)}`;\n }\n return \"\";\n};\n\nfunction getEntryTypeColors(colors: ThemeColors, entryType: string) {\n switch (entryType) {\n case \"init\":\n return {\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n };\n case \"metric\":\n return {\n color: colors.palette.green600,\n backgroundColor: colors.palette.green100,\n };\n case \"pipeline\":\n return {\n color: colors.palette.purple600,\n backgroundColor: colors.palette.purple100,\n };\n case \"resource\":\n return {\n color: colors.palette.yellow600,\n backgroundColor: colors.palette.yellow100,\n };\n default:\n return {\n color: colors.fg.neutral,\n backgroundColor: colors.bg.neutralWeak,\n };\n }\n}\n\nexport const PerformancePanel = ({\n performances,\n clearPerformances,\n}: PerformancePanelProps) => {\n const colors = useThemeColors();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n if (performances.length === 0) {\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n 0 entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n <view className={\"pp-placeholder\"}>\n <text\n className={\"pp-placeholderText t4\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.disabled,\n }}\n >\n No performance data yet...\n </text>\n </view>\n </view>\n );\n }\n\n return (\n <view className={\"pp-container\"}>\n <view\n className={\"pp-header\"}\n style={{ borderBottomColor: colors.stroke.neutralSubtle }}\n >\n <text\n className={\"pp-count t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {performances.length} entries\n </text>\n <view\n bindtap={clearPerformances}\n className={\"pp-clearButton\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-clearButtonText t3\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutralMuted,\n }}\n >\n 🗑\n </text>\n </view>\n </view>\n\n <list scroll-orientation=\"vertical\" className={\"pp-list\"}>\n {performances.map((perf) => {\n const isMetricFcp = isMetricFcpEntry(perf);\n const fcpMetrics = extractFcpMetrics(perf);\n const primaryFcp = getPrimaryFcpLabel(perf);\n const { totalFcp, lynxFcp, fcp } = fcpMetrics ?? {};\n\n return (\n <list-item key={perf.id} item-key={perf.id}>\n <view\n className={\"pp-item\"}\n style={{ borderBottomColor: colors.stroke.neutralWeak }}\n >\n <view\n className={\"pp-itemHeader\"}\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n <text\n className={\"pp-entryType t2\"}\n style={{\n fontWeight: fontWeight.bold,\n ...getEntryTypeColors(colors, perf.entryType),\n }}\n >\n {perf.entryType}\n </text>\n <text\n className={\"pp-entryName t2\"}\n style={{\n fontWeight: fontWeight.medium,\n color: colors.fg.neutral,\n }}\n >\n {perf.name}\n </text>\n <text\n className={\"pp-timestamp t2\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {new Date(perf.timestamp).toISOString()}\n </text>\n </view>\n\n <view\n bindtap={() =>\n setSelectedId(selectedId === perf.id ? null : perf.id)\n }\n >\n {isMetricFcp && primaryFcp && (\n <text\n className={\"pp-fcpHighlight t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n backgroundColor: colors.palette.blue100,\n }}\n >\n {primaryFcp}\n </text>\n )}\n </view>\n\n {selectedId === perf.id && (\n <view className={\"pp-detailsContainer\"}>\n {isMetricFcp && fcpMetrics && (\n <view className={\"pp-fcpSection\"}>\n {totalFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 전체 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(totalFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n PrepareTemplate Start부터 Paint End 까지 걸리는\n 시간\n </text>\n </view>\n )}\n\n {lynxFcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n LynxFCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(lynxFcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n Bundle Load 시작부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n\n {fcp !== undefined && (\n <view\n className={\"pp-fcpMetric\"}\n style={{ backgroundColor: colors.bg.layerDefault }}\n >\n <view className={\"pp-fcpMetricHeader\"}>\n <text\n className={\"pp-fcpMetricName t2\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n 렌더링 FCP\n </text>\n <text\n className={\"pp-fcpMetricValue t1\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.palette.blue600,\n }}\n >\n {formatDuration(fcp.duration)}\n </text>\n </view>\n <text\n className={\"pp-fcpMetricDescription t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n TemplateBundle 준비부터 Paint End 까지 걸리는 시간\n </text>\n </view>\n )}\n </view>\n )}\n\n {!!perf.rawEntry && (\n <view\n className={\"pp-rawEntrySection\"}\n style={{ backgroundColor: colors.bg.neutralWeak }}\n >\n <text\n className={\"pp-detailTitle t3\"}\n style={{\n fontWeight: fontWeight.bold,\n color: colors.fg.neutral,\n }}\n >\n Raw Entry\n </text>\n <text\n className={\"pp-rawEntry t3\"}\n style={{\n fontWeight: fontWeight.regular,\n color: colors.fg.neutralSubtle,\n }}\n >\n {String(\n stringify(perf.rawEntry, null, 2, {\n references: true,\n }),\n )}\n </text>\n </view>\n )}\n </view>\n )}\n </view>\n </list-item>\n );\n })}\n </list>\n </view>\n );\n};\n","import { type ReactNode, useRef, useState } from \"@lynx-js/react\";\nimport type { ListSnapEvent, NodesRef } from \"@lynx-js/types\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { fontWeight } from \"../styles/theme\";\nimport \"./Tabs.css\";\n\ntype TabsProps = {\n items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }>;\n onTabChange?: () => void;\n};\n\nexport default function Tabs(props: TabsProps) {\n const colors = useThemeColors();\n const tabContentsRef = useRef<NodesRef>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n const tabSize =\n props.items.length < 4\n ? undefined\n : `t${Math.max(1, 5 - (props.items.length - 3))}`;\n\n return (\n <view className={\"tabs-root\"}>\n <view\n className={\"tabs-header\"}\n style={{\n boxShadow: `inset 0 -1px 0 0 ${colors.stroke.neutralSubtle}`,\n }}\n >\n {props.items.map((item, i) => (\n <view\n key={item.key}\n className={\"tabs-triggerButton\"}\n bindtap={() => {\n setActiveIndex(i);\n props.onTabChange?.();\n\n tabContentsRef.current\n ?.invoke({\n method: \"scrollToPosition\",\n params: {\n position: i,\n smooth: true,\n },\n })\n .exec();\n }}\n >\n <text\n className={`tabs-triggerButtonText${tabSize ? ` ${tabSize}` : \"\"}`}\n style={{\n fontWeight: fontWeight.bold,\n color:\n i === activeIndex\n ? colors.fg.neutral\n : colors.fg.neutralSubtle,\n }}\n >\n {item.label}\n </text>\n {i === 0 && (\n <view\n className={\"tabs-triggerIndicator\"}\n style={{ transform: `translateX(${activeIndex * 100}%)` }}\n >\n <view\n className={\"tabs-triggerIndicatorLine\"}\n style={{ backgroundColor: colors.fg.neutral }}\n />\n </view>\n )}\n </view>\n ))}\n </view>\n\n <list\n ref={tabContentsRef}\n className={\"tabs-contents\"}\n scroll-orientation=\"horizontal\"\n item-snap={{ factor: 0, offset: 0 }}\n bindscroll={() => props.onTabChange?.()}\n bindsnap={(e: ListSnapEvent) => {\n setActiveIndex(e.detail.position);\n }}\n bounces={false}\n preload-buffer-count={props.items.length}\n >\n {props.items.map((item) => (\n <list-item\n key={item.key}\n item-key={item.key}\n recyclable={false}\n className={\"tabs-content\"}\n >\n {item.renderContent()}\n </list-item>\n ))}\n </list>\n </view>\n );\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport { useConsole, useNetwork, usePerformance } from \"../hooks\";\nimport type { CustomTab } from \"../types\";\nimport \"./ConsolePanel.css\";\nimport { dismissFilterDropdown, LogPanel } from \"./LogPanel\";\nimport { NetworkPanel } from \"./NetworkPanel\";\nimport { PerformancePanel } from \"./PerformancePanel\";\nimport Tabs from \"./Tabs\";\n\ninterface ConsolePanelProps {\n customTabs?: CustomTab[];\n}\n\nexport const ConsolePanel = ({ customTabs }: ConsolePanelProps) => {\n const { logs, clearLogs } = useConsole();\n const { networks, clearNetworks } = useNetwork();\n const { performances, clearPerformances } = usePerformance();\n\n const state = globalThis.__LYNX_CONSOLE__?.state;\n\n const items: Array<{\n key: string;\n label: string;\n renderContent: () => ReactNode;\n }> = [];\n\n if (state?.logs) {\n items.push({\n key: \"log\",\n label: \"Log\",\n renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,\n });\n }\n\n if (state?.networks) {\n items.push({\n key: \"network\",\n label: \"Network\",\n renderContent: () => (\n <NetworkPanel networks={networks} clearNetworks={clearNetworks} />\n ),\n });\n }\n\n if (state?.performances) {\n items.push({\n key: \"performance\",\n label: \"Perf\",\n renderContent: () => (\n <PerformancePanel\n performances={performances}\n clearPerformances={clearPerformances}\n />\n ),\n });\n }\n\n if (customTabs) {\n for (const tab of customTabs) {\n items.push({\n key: tab.key,\n label: tab.label,\n renderContent: tab.renderContent,\n });\n }\n }\n\n if (items.length === 0) {\n return null;\n }\n\n return (\n <view className=\"cp-container\">\n <Tabs onTabChange={dismissFilterDropdown} items={items} />\n </view>\n );\n};\n","import { useRef, useState } from \"@lynx-js/react\";\nimport type { BaseTouchEvent, Target } from \"@lynx-js/types\";\n\nconst LONG_PRESS_DURATION = 400;\nconst MOVE_THRESHOLD = 5;\n\nconst DEFAULT_RIGHT = 16;\nconst DEFAULT_BOTTOM = 84;\n\ntype VerticalAxis = \"top\" | \"bottom\";\ntype HorizontalAxis = \"left\" | \"right\";\n\nexport interface InitialPosition {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n}\n\ninterface ResolvedAnchors {\n vertical: VerticalAxis;\n horizontal: HorizontalAxis;\n x: number;\n y: number;\n}\n\nfunction resolveAnchors(initial?: InitialPosition): ResolvedAnchors {\n // top/left이 명시되면 그것이 anchor가 돼요. 둘 다 명시되면 top/left가 이겨요.\n const vertical: VerticalAxis = initial?.top !== undefined ? \"top\" : \"bottom\";\n const horizontal: HorizontalAxis =\n initial?.left !== undefined ? \"left\" : \"right\";\n\n const y =\n vertical === \"top\"\n ? (initial?.top ?? 0)\n : (initial?.bottom ?? DEFAULT_BOTTOM);\n const x =\n horizontal === \"left\"\n ? (initial?.left ?? 0)\n : (initial?.right ?? DEFAULT_RIGHT);\n\n return { vertical, horizontal, x, y };\n}\n\ninterface SavedState {\n vertical: VerticalAxis;\n horizontal: HorizontalAxis;\n x: number;\n y: number;\n}\n\nlet saved: SavedState | null = null;\n\ninterface UseLongPressDragOptions {\n initialPosition?: InitialPosition;\n}\n\nexport function useLongPressDrag(\n onTap: () => void,\n options?: UseLongPressDragOptions,\n) {\n const anchors = resolveAnchors(options?.initialPosition);\n\n // 저장된 위치는 anchor 조합이 동일할 때만 복원해요.\n const snapshot = saved;\n let initX = anchors.x;\n let initY = anchors.y;\n if (\n snapshot !== null &&\n snapshot.vertical === anchors.vertical &&\n snapshot.horizontal === anchors.horizontal\n ) {\n initX = snapshot.x;\n initY = snapshot.y;\n }\n\n const [x, setX] = useState(initX);\n const [y, setY] = useState(initY);\n const [phase, setPhase] = useState<\"idle\" | \"dragging\" | \"releasing\">(\"idle\");\n const [tempX, setTempX] = useState(initX);\n const [tempY, setTempY] = useState(initY);\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const draggingRef = useRef(false);\n const startRef = useRef({ x: 0, y: 0, ax: 0, ay: 0 });\n\n // anchor 방향에 따라 드래그 부호 결정. right/bottom anchor면 드래그 방향과 값 변화가 반대.\n const xSign = anchors.horizontal === \"right\" ? -1 : 1;\n const ySign = anchors.vertical === \"bottom\" ? -1 : 1;\n\n const clearTimer = () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const handleTouchStart = (e: BaseTouchEvent<Target>) => {\n startRef.current = {\n x: e.detail.x,\n y: e.detail.y,\n ax: x,\n ay: y,\n };\n draggingRef.current = false;\n\n timerRef.current = setTimeout(() => {\n draggingRef.current = true;\n setPhase(\"dragging\");\n setTempX(x);\n setTempY(y);\n }, LONG_PRESS_DURATION);\n };\n\n const handleTouchMove = (e: BaseTouchEvent<Target>) => {\n const dx = e.detail.x - startRef.current.x;\n const dy = e.detail.y - startRef.current.y;\n\n if (\n !draggingRef.current &&\n (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)\n ) {\n clearTimer();\n }\n\n if (!draggingRef.current) return;\n\n setTempX(startRef.current.ax + xSign * dx);\n setTempY(startRef.current.ay + ySign * dy);\n };\n\n const handleTouchEnd = () => {\n clearTimer();\n\n if (draggingRef.current) {\n setX(tempX);\n setY(tempY);\n saved = {\n vertical: anchors.vertical,\n horizontal: anchors.horizontal,\n x: tempX,\n y: tempY,\n };\n setPhase(\"releasing\");\n draggingRef.current = false;\n setTimeout(() => setPhase(\"idle\"), 300);\n } else {\n onTap();\n }\n };\n\n const isDragging = phase === \"dragging\";\n const currentX = isDragging ? tempX : x;\n const currentY = isDragging ? tempY : y;\n\n const positionStyle = {\n [anchors.horizontal]: `${currentX}px`,\n [anchors.vertical]: `${currentY}px`,\n } as { top?: string; left?: string; right?: string; bottom?: string };\n\n return {\n phase,\n positionStyle,\n clearTimer,\n handlers: {\n catchtouchstart: handleTouchStart,\n catchtouchmove: handleTouchMove,\n catchtouchend: handleTouchEnd,\n },\n };\n}\n","import type { ReactNode } from \"@lynx-js/react\";\nimport {\n type InitialPosition,\n useLongPressDrag,\n} from \"../hooks/useLongPressDrag\";\nimport { useThemeColors } from \"../styles/ThemeContext\";\nimport { duration } from \"../styles/theme\";\nimport \"./FloatingButton.css\";\n\ninterface FloatingButtonProps {\n bindtap: () => void;\n children: ReactNode;\n initialPosition?: InitialPosition;\n}\n\nconst SHINE_STYLES = {\n idle: {\n transform: \"scale(0)\",\n opacity: 0,\n },\n dragging: {\n transform: \"scale(1)\",\n opacity: 1,\n transition: \"transform 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n releasing: {\n transform: \"scale(1)\",\n opacity: 0,\n transition: \"opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)\",\n },\n} as const;\n\nexport const FloatingButton = ({\n bindtap,\n children,\n initialPosition,\n}: FloatingButtonProps) => {\n const colors = useThemeColors();\n const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(\n bindtap,\n { initialPosition },\n );\n\n const handleReload = () => {\n try {\n lynx.reload({}, () => {\n console.log(\"reloaded!\");\n });\n } catch (e) {\n console.error(\"[LynxConsole] reload failed:\", e);\n }\n };\n\n const isDragging = phase === \"dragging\";\n\n return (\n <view\n className={\"fb-wrapper\"}\n style={{\n ...positionStyle,\n transform: isDragging ? \"scale(1.05)\" : \"scale(1)\",\n transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`,\n }}\n {...handlers}\n >\n <view\n className={\"fb-button\"}\n style={{ backgroundColor: colors.palette.green600 }}\n >\n {children}\n <view className={\"fb-shineOverlay\"} style={SHINE_STYLES[phase]} />\n </view>\n <view\n className={\"fb-reloadButton\"}\n style={{ backgroundColor: colors.palette.green600 }}\n catchtouchstart={() => clearTimer()}\n bindtap={handleReload}\n >\n <text\n className={\"fb-reloadIcon\"}\n style={{ color: colors.palette.staticWhite }}\n >\n {\"\\u21BB\"}\n </text>\n </view>\n </view>\n );\n};\n","import {\n type ForwardedRef,\n forwardRef,\n useImperativeHandle,\n useMemo,\n useState,\n} from \"@lynx-js/react\";\nimport BottomSheet from \"./components/BottomSheet.jsx\";\nimport { ConsolePanel } from \"./components/ConsolePanel.jsx\";\nimport \"./components/FloatingButton.css\";\nimport \"./styles/tokens.css\";\nimport { FloatingButton } from \"./components/FloatingButton.jsx\";\nimport { useLatestFcp } from \"./hooks/useLatestFcp\";\nimport { ThemeProvider } from \"./styles/ThemeContext\";\nimport { getColors } from \"./styles/theme\";\nimport type { CustomTab } from \"./types\";\n\nexport interface LynxConsoleHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n}\n\nexport interface LynxConsoleProps {\n theme?: \"light\" | \"dark\";\n safeAreaInsetBottom?: string;\n customTabs?: CustomTab[];\n initialPosition?: {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n };\n}\n\nconst LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(\n (\n {\n theme = \"light\",\n safeAreaInsetBottom = \"50px\",\n customTabs,\n initialPosition,\n },\n ref: ForwardedRef<LynxConsoleHandle>,\n ) => {\n const [isOpen, setIsOpen] = useState(false);\n const [shouldClose, setShouldClose] = useState(false);\n const latestFcp = useLatestFcp();\n const colors = useMemo(() => getColors(theme), [theme]);\n\n useImperativeHandle(ref, () => ({\n open: () => {\n setIsOpen(true);\n setShouldClose(false);\n },\n close: () => {\n setShouldClose(true);\n },\n isOpen: () => isOpen,\n }));\n\n const handleOpenBottomSheet = () => {\n setIsOpen(true);\n setShouldClose(false);\n };\n\n const handleCloseBottomSheet = () => {\n setIsOpen(false);\n setShouldClose(false);\n };\n\n return (\n <ThemeProvider value={colors}>\n <view\n style={{\n backgroundColor: colors.bg.layerDefault,\n color: colors.fg.neutral,\n }}\n >\n <FloatingButton\n bindtap={handleOpenBottomSheet}\n initialPosition={initialPosition}\n >\n <text\n className=\"fb-title t4\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n LynxConsole\n </text>\n <text\n className=\"fb-subtitle t3\"\n style={{ fontWeight: \"400\", color: colors.palette.staticWhite }}\n >\n {`${latestFcp?.name ?? \"FCP\"}: ${latestFcp?.duration ? latestFcp.duration.toFixed(2) : \"--\"}ms`}\n </text>\n </FloatingButton>\n {isOpen && (\n <BottomSheet\n isOpen={isOpen}\n shouldClose={shouldClose}\n onClose={handleCloseBottomSheet}\n title=\"Lynx Console\"\n safeAreaInsetBottom={safeAreaInsetBottom}\n >\n <ConsolePanel customTabs={customTabs} />\n </BottomSheet>\n )}\n </view>\n </ThemeProvider>\n );\n },\n);\n\nexport type { CustomTab } from \"./types\";\nexport default LynxConsole;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lynx-console",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -56,7 +56,6 @@ export const FloatingButton = ({
56
56
  return (
57
57
  <view
58
58
  className={"fb-wrapper"}
59
- consume-slide-event={[[-180, 180]]}
60
59
  style={{
61
60
  ...positionStyle,
62
61
  transform: isDragging ? "scale(1.05)" : "scale(1)",
@@ -154,6 +154,8 @@ export const LogPanel = ({ logs, clearLogs }: LogPanelProps) => {
154
154
  ?.invoke({
155
155
  method: "scrollToPosition",
156
156
  params: { position: logsRef.current.length - 1, smooth },
157
+ // 연속 로그로 진행 중이던 smooth 스크롤이 중단될 때 나는 무해한 경고를 무시
158
+ fail: () => {},
157
159
  })
158
160
  .exec();
159
161
  };
@@ -1,3 +1,4 @@
1
1
  export { useConsole } from "./useConsole";
2
+ export { useLatestFcp } from "./useLatestFcp";
2
3
  export { useNetwork } from "./useNetwork";
3
4
  export { usePerformance } from "./usePerformance";
@@ -0,0 +1,48 @@
1
+ import { useEffect, useState } from "@lynx-js/react";
2
+ import type { PerformanceEntryData } from "../types";
3
+
4
+ interface FcpMetric {
5
+ name: string;
6
+ duration: number;
7
+ }
8
+
9
+ interface MetricFcpRawEntry {
10
+ totalFcp?: FcpMetric;
11
+ lynxFcp?: FcpMetric;
12
+ fcp?: FcpMetric;
13
+ }
14
+
15
+ const pickFcp = (entry: PerformanceEntryData): FcpMetric | undefined => {
16
+ if (entry.entryType !== "metric" || entry.name !== "fcp") return undefined;
17
+ const raw = entry.rawEntry as MetricFcpRawEntry | undefined;
18
+ if (raw?.totalFcp?.duration !== undefined) return raw.totalFcp;
19
+ if (raw?.lynxFcp?.duration !== undefined) return raw.lynxFcp;
20
+ return undefined;
21
+ };
22
+
23
+ export const useLatestFcp = (): FcpMetric | undefined => {
24
+ const [fcp, setFcp] = useState<FcpMetric | undefined>(() => {
25
+ const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];
26
+ for (let i = performances.length - 1; i >= 0; i--) {
27
+ const entry = performances[i];
28
+ if (!entry) continue;
29
+ const found = pickFcp(entry);
30
+ if (found) return found;
31
+ }
32
+ return undefined;
33
+ });
34
+
35
+ useEffect(() => {
36
+ const state = globalThis.__LYNX_CONSOLE__?.state;
37
+ if (!state?.subscribePerformance) return;
38
+
39
+ const unsubscribe = state.subscribePerformance((entry) => {
40
+ const found = pickFcp(entry);
41
+ if (found) setFcp(found);
42
+ });
43
+
44
+ return unsubscribe;
45
+ }, []);
46
+
47
+ return fcp;
48
+ };
package/src/index.tsx CHANGED
@@ -10,7 +10,7 @@ import { ConsolePanel } from "./components/ConsolePanel.jsx";
10
10
  import "./components/FloatingButton.css";
11
11
  import "./styles/tokens.css";
12
12
  import { FloatingButton } from "./components/FloatingButton.jsx";
13
- import { usePerformance } from "./hooks/usePerformance";
13
+ import { useLatestFcp } from "./hooks/useLatestFcp";
14
14
  import { ThemeProvider } from "./styles/ThemeContext";
15
15
  import { getColors } from "./styles/theme";
16
16
  import type { CustomTab } from "./types";
@@ -33,17 +33,6 @@ export interface LynxConsoleProps {
33
33
  };
34
34
  }
35
35
 
36
- interface FcpMetric {
37
- name: string;
38
- duration: number;
39
- }
40
-
41
- interface MetricFcpEntry {
42
- totalFcp?: FcpMetric;
43
- lynxFcp?: FcpMetric;
44
- fcp?: FcpMetric;
45
- }
46
-
47
36
  const LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(
48
37
  (
49
38
  {
@@ -56,26 +45,9 @@ const LynxConsole = forwardRef<LynxConsoleHandle, LynxConsoleProps>(
56
45
  ) => {
57
46
  const [isOpen, setIsOpen] = useState(false);
58
47
  const [shouldClose, setShouldClose] = useState(false);
59
- const { performances } = usePerformance();
48
+ const latestFcp = useLatestFcp();
60
49
  const colors = useMemo(() => getColors(theme), [theme]);
61
50
 
62
- const latestFcp = useMemo(() => {
63
- for (let i = performances.length - 1; i >= 0; i--) {
64
- const perf = performances[i];
65
- if (perf && perf.entryType === "metric" && perf.name === "fcp") {
66
- const metricEntry = perf.rawEntry as MetricFcpEntry | undefined;
67
- // totalFcp를 먼저 시도하고, 없으면 lynxFcp 반환
68
- if (metricEntry?.totalFcp?.duration !== undefined) {
69
- return metricEntry.totalFcp;
70
- }
71
- if (metricEntry?.lynxFcp?.duration !== undefined) {
72
- return metricEntry.lynxFcp;
73
- }
74
- }
75
- }
76
- return undefined;
77
- }, [performances]);
78
-
79
51
  useImperativeHandle(ref, () => ({
80
52
  open: () => {
81
53
  setIsOpen(true);