reflet-sdk 0.6.4 → 0.6.6
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/CHANGELOG.md +23 -0
- package/README.md +100 -2
- package/dist/{client-DAdWdIFY.js → client-oFFfRxAM.js} +135 -59
- package/dist/client-oFFfRxAM.js.map +1 -0
- package/dist/client-transport-B7BdVU7J.d.ts +150 -0
- package/dist/client-transport-B7BdVU7J.d.ts.map +1 -0
- package/dist/{devtools-layer-DgmM3RhW.js → devtools-layer-B91EVgqg.js} +417 -916
- package/dist/devtools-layer-B91EVgqg.js.map +1 -0
- package/dist/devtools-next.js +1 -1
- package/dist/devtools-vite.js +2 -2
- package/dist/feedback.d.ts +7 -1
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +105 -57
- package/dist/feedback.js.map +1 -1
- package/dist/{handler-BSNmdHXv.js → handler-yA_knIf3.js} +4 -4
- package/dist/{handler-BSNmdHXv.js.map → handler-yA_knIf3.js.map} +1 -1
- package/dist/index-Buum9tIY.d.ts +230 -0
- package/dist/index-Buum9tIY.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/options-CIBazDPp.d.ts.map +1 -1
- package/dist/protocol-vJhQHTcB.js +390 -0
- package/dist/protocol-vJhQHTcB.js.map +1 -0
- package/dist/{react-context-Caq1fodf.js → react-context-Kazo_JCz.js} +3 -14
- package/dist/react-context-Kazo_JCz.js.map +1 -0
- package/dist/react.d.ts +43 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +389 -3
- package/dist/react.js.map +1 -1
- package/dist/selection-outline-NzAAAZXR.js +51 -0
- package/dist/selection-outline-NzAAAZXR.js.map +1 -0
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/sessions-panel-DVyWzZ3C.js +6011 -0
- package/dist/sessions-panel-DVyWzZ3C.js.map +1 -0
- package/dist/{submit-Cd-g1Dtg.js → submit-DYGZQVdG.js} +49 -74
- package/dist/submit-DYGZQVdG.js.map +1 -0
- package/dist/surveys.d.ts +3 -0
- package/dist/surveys.js +2 -0
- package/dist/team-activation-DCqh71bl.js +24 -0
- package/dist/team-activation-DCqh71bl.js.map +1 -0
- package/dist/team-layer-F-9BE4hc.js +423 -0
- package/dist/team-layer-F-9BE4hc.js.map +1 -0
- package/dist/{types-DnaDEN9Y.d.ts → types-B3XiHPqy.d.ts} +4 -9
- package/dist/types-B3XiHPqy.d.ts.map +1 -0
- package/dist/use-survey-session-LK6sN1Fg.js +1247 -0
- package/dist/use-survey-session-LK6sN1Fg.js.map +1 -0
- package/dist/z-index-CwokqVq_.js +15 -0
- package/dist/z-index-CwokqVq_.js.map +1 -0
- package/package.json +6 -2
- package/dist/client-DAdWdIFY.js.map +0 -1
- package/dist/client-DF1fdsSC.d.ts +0 -131
- package/dist/client-DF1fdsSC.d.ts.map +0 -1
- package/dist/devtools-layer-DgmM3RhW.js.map +0 -1
- package/dist/protocol-ClqTFzwR.js +0 -35
- package/dist/protocol-ClqTFzwR.js.map +0 -1
- package/dist/react-context-Caq1fodf.js.map +0 -1
- package/dist/submit-Cd-g1Dtg.js.map +0 -1
- package/dist/types-DnaDEN9Y.d.ts.map +0 -1
package/dist/feedback.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ElementSelection, u as FeedbackContext, w as RefletUser } from "./types-
|
|
1
|
+
import { c as ElementSelection, u as FeedbackContext, w as RefletUser } from "./types-B3XiHPqy.js";
|
|
2
2
|
import { ReactNode, RefObject } from "react";
|
|
3
3
|
//#region src/feedback/types.d.ts
|
|
4
4
|
declare const ANNOTATION_TOOLS: readonly ["pen", "arrow", "rectangle", "text", "spotlight", "highlight", "blur"];
|
|
@@ -72,6 +72,8 @@ interface FeedbackTriggerProps {
|
|
|
72
72
|
ref: RefObject<HTMLButtonElement | null>;
|
|
73
73
|
}
|
|
74
74
|
interface RefletFeedbackProps {
|
|
75
|
+
/** Hosts the team sign-in page. Defaults to https://www.reflet.app. */
|
|
76
|
+
appUrl?: string;
|
|
75
77
|
baseUrl?: string;
|
|
76
78
|
captureConsole?: boolean;
|
|
77
79
|
captureOnOpen?: boolean;
|
|
@@ -94,6 +96,8 @@ interface RefletFeedbackProps {
|
|
|
94
96
|
primaryColor?: string;
|
|
95
97
|
publicKey?: string;
|
|
96
98
|
renderTrigger?: (props: FeedbackTriggerProps) => ReactNode;
|
|
99
|
+
/** Shown once activated by the `reflet-team` URL parameter or a stored sign-in. Defaults to true. */
|
|
100
|
+
teamTools?: boolean;
|
|
97
101
|
theme?: "auto" | "dark" | "light";
|
|
98
102
|
user?: RefletUser;
|
|
99
103
|
userToken?: string;
|
|
@@ -105,6 +109,8 @@ interface CaptureOptions {
|
|
|
105
109
|
element?: Element;
|
|
106
110
|
excludeSelectors?: string[];
|
|
107
111
|
maxWidth?: number;
|
|
112
|
+
/** Edits the detached clone, never the live page. */
|
|
113
|
+
prepareClone?: (clone: Element) => void;
|
|
108
114
|
/** Hard cap for one capture attempt before falling back. Default 10s. */
|
|
109
115
|
timeout?: number;
|
|
110
116
|
}
|
package/dist/feedback.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feedback.d.ts","names":[],"sources":["../src/feedback/types.ts","../src/feedback/core/capture.ts","../src/feedback/core/element-selector.ts","../src/feedback/core/page-context.ts","../src/feedback/widget.tsx"],"mappings":";;;cAMM;KAUM,yBAAyB;UAEpB;EACf;EACA;;UAGe;EACf;EACA,KAAK;EACL;EAEA,SAAS;EACT,OAAO;EACP;EACA,MAAM;;UAGS;EACf,MAAM;EACN;EACA;EAEA;EACA;;UAae;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAiDe;EACf;EACA,KAAK,UAAU;;UAGA;
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","names":[],"sources":["../src/feedback/types.ts","../src/feedback/core/capture.ts","../src/feedback/core/element-selector.ts","../src/feedback/core/page-context.ts","../src/feedback/widget.tsx"],"mappings":";;;cAMM;KAUM,yBAAyB;UAEpB;EACf;EACA;;UAGe;EACf;EACA,KAAK;EACL;EAEA,SAAS;EACT,OAAO;EACP;EACA,MAAM;;UAGS;EACf,MAAM;EACN;EACA;EAEA;EACA;;UAae;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAiDe;EACf;EACA,KAAK,UAAU;;UAGA;;EAEf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,QAAQ;EACjB,WAAW;EACX;EACA;EACA,aAAa;IAAU;;EACvB;EACA,YAAY;IAAU;;EACtB;EACA;EACA;EACA,iBAAiB,OAAO,yBAAyB;;EAEjD;EACA;EACA,OAAO;EACP;;;;UC6De;;EAEf,UAAU;EACV;EACA;;EAEA,gBAAgB,OAAO;;EAEvB;;;;;;;;;;wBAoIoB,gBACpB,UAAS,iBACR,QAAQ;wBAkDK,eAAe,OAAO;;;;wBC7ItB,sBAAsB,SAAS,UAAU;;;;wBCjMzC,mBAAmB;EACjC;IACE;;;wBC3BY,eAAe,OAAO,sCAAmB,IAAA"}
|
package/dist/feedback.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { n as Reflet } from "./client-
|
|
3
|
-
import { A as SquareIcon,
|
|
4
|
-
import {
|
|
2
|
+
import { n as Reflet } from "./client-oFFfRxAM.js";
|
|
3
|
+
import { A as SquareIcon, C as ChevronDownIcon, D as MoreIcon, E as HighlightIcon, F as UndoIcon, H as MAX_SELECTION_COMMENT_LENGTH, I as isDegenerate, J as maskSecrets, L as normalizeRect, M as TargetIcon, N as TextIcon, O as PencilIcon, P as TrashIcon, R as DEFAULT_WIDGET_LABELS, S as CheckIcon, T as GripIcon, U as buildElementSelection, V as collectPageContext, _ as matchesHotkey, b as CameraIcon, c as useFloatingPosition, d as drawAnnotations, et as WIDGET_MARKER, f as listenOnPageAndWidget, g as isSubmitEnter, h as stopClicksAtHost, i as submitWidgetFeedback, it as releaseCapture, k as SpotlightIcon, n as createFeedbackTransport, o as ElementPicker, p as listenToKeydown, rt as capturedViewportSize, t as attachPreparedScreenshots, tt as captureViewport, v as ArrowIcon, w as CloseIcon, x as ChatIcon, y as BlurIcon, z as SDK_VERSION } from "./submit-DYGZQVdG.js";
|
|
4
|
+
import { t as RefletContext } from "./react-context-Kazo_JCz.js";
|
|
5
|
+
import { t as hasTeamActivation } from "./team-activation-DCqh71bl.js";
|
|
6
|
+
import { t as SelectionOutline } from "./selection-outline-NzAAAZXR.js";
|
|
7
|
+
import { t as REFLET_Z_INDEX } from "./z-index-CwokqVq_.js";
|
|
5
8
|
import { Suspense, lazy, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
10
|
import { Slider } from "@base-ui/react/slider";
|
|
@@ -666,42 +669,6 @@ function Annotator({ capture, labels, editor, note }) {
|
|
|
666
669
|
});
|
|
667
670
|
}
|
|
668
671
|
//#endregion
|
|
669
|
-
//#region src/feedback/ui/devtools-owner.ts
|
|
670
|
-
const claims = /* @__PURE__ */ new Map();
|
|
671
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
672
|
-
function notify() {
|
|
673
|
-
for (const listener of listeners) listener();
|
|
674
|
-
}
|
|
675
|
-
function subscribe(listener) {
|
|
676
|
-
listeners.add(listener);
|
|
677
|
-
return () => listeners.delete(listener);
|
|
678
|
-
}
|
|
679
|
-
function currentOwner() {
|
|
680
|
-
for (const [token, claim] of claims) if (claim.hasWidget) return token;
|
|
681
|
-
return claims.keys().next().value;
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
* One devtools bar per page, however many RefletFeedback instances mount:
|
|
685
|
-
* the one with a visible widget wins, so its bar can step aside for its panel.
|
|
686
|
-
*/
|
|
687
|
-
function useOwnsDevtools(wantsDevtools, hasWidget) {
|
|
688
|
-
const [token] = useState(() => Symbol("reflet-devtools"));
|
|
689
|
-
useEffect(() => {
|
|
690
|
-
if (!wantsDevtools) return;
|
|
691
|
-
claims.set(token, { hasWidget });
|
|
692
|
-
notify();
|
|
693
|
-
return () => {
|
|
694
|
-
claims.delete(token);
|
|
695
|
-
notify();
|
|
696
|
-
};
|
|
697
|
-
}, [
|
|
698
|
-
hasWidget,
|
|
699
|
-
token,
|
|
700
|
-
wantsDevtools
|
|
701
|
-
]);
|
|
702
|
-
return useSyncExternalStore(subscribe, () => currentOwner() === token, () => false);
|
|
703
|
-
}
|
|
704
|
-
//#endregion
|
|
705
672
|
//#region src/feedback/ui/launcher.tsx
|
|
706
673
|
function Launcher({ isOpen, label, onClick, buttonRef }) {
|
|
707
674
|
return /* @__PURE__ */ jsxs("button", {
|
|
@@ -1281,6 +1248,52 @@ function useWidgetLauncher(state) {
|
|
|
1281
1248
|
};
|
|
1282
1249
|
}
|
|
1283
1250
|
//#endregion
|
|
1251
|
+
//#region src/feedback/ui/page-ownership.ts
|
|
1252
|
+
function createPageOwnership(name) {
|
|
1253
|
+
const claims = /* @__PURE__ */ new Map();
|
|
1254
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1255
|
+
const notify = () => {
|
|
1256
|
+
for (const listener of listeners) listener();
|
|
1257
|
+
};
|
|
1258
|
+
const subscribe = (listener) => {
|
|
1259
|
+
listeners.add(listener);
|
|
1260
|
+
return () => listeners.delete(listener);
|
|
1261
|
+
};
|
|
1262
|
+
const currentOwner = () => {
|
|
1263
|
+
for (const [token, claim] of claims) if (claim.hasWidget) return token;
|
|
1264
|
+
return claims.keys().next().value;
|
|
1265
|
+
};
|
|
1266
|
+
function useOwns(wants, hasWidget) {
|
|
1267
|
+
const [token] = useState(() => Symbol(name));
|
|
1268
|
+
useEffect(() => {
|
|
1269
|
+
if (!wants) return;
|
|
1270
|
+
claims.set(token, { hasWidget });
|
|
1271
|
+
notify();
|
|
1272
|
+
return () => {
|
|
1273
|
+
claims.delete(token);
|
|
1274
|
+
notify();
|
|
1275
|
+
};
|
|
1276
|
+
}, [
|
|
1277
|
+
hasWidget,
|
|
1278
|
+
token,
|
|
1279
|
+
wants
|
|
1280
|
+
]);
|
|
1281
|
+
return useSyncExternalStore(subscribe, () => currentOwner() === token, () => false);
|
|
1282
|
+
}
|
|
1283
|
+
function useIsClaimed() {
|
|
1284
|
+
return useSyncExternalStore(subscribe, () => claims.size > 0, () => false);
|
|
1285
|
+
}
|
|
1286
|
+
return {
|
|
1287
|
+
useIsClaimed,
|
|
1288
|
+
useOwns
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
const devtoolsOwnership = createPageOwnership("reflet-devtools");
|
|
1292
|
+
const teamToolsOwnership = createPageOwnership("reflet-team-tools");
|
|
1293
|
+
const useOwnsDevtools = devtoolsOwnership.useOwns;
|
|
1294
|
+
const useHasDevtoolsOnPage = devtoolsOwnership.useIsClaimed;
|
|
1295
|
+
const useOwnsTeamTools = teamToolsOwnership.useOwns;
|
|
1296
|
+
//#endregion
|
|
1284
1297
|
//#region src/feedback/ui/annotation/styles.ts
|
|
1285
1298
|
const ANNOTATOR_STYLES = `
|
|
1286
1299
|
.overlay { margin: 0; border: 0; padding: 0; width: 100vw; max-width: none; height: 100dvh; max-height: none; position: fixed; inset: 0; z-index: ${REFLET_Z_INDEX.annotatorOverlay}; display: flex; flex-direction: column; background: transparent; color: var(--rf-text); font: 13px/1.45 ui-sans-serif, system-ui, sans-serif; }
|
|
@@ -1822,8 +1835,7 @@ function serializeArgument(value) {
|
|
|
1822
1835
|
if (typeof value === "function") return "[function]";
|
|
1823
1836
|
return String(value);
|
|
1824
1837
|
}
|
|
1825
|
-
function
|
|
1826
|
-
const message = args.map(serializeArgument).join(" ");
|
|
1838
|
+
function clip(message) {
|
|
1827
1839
|
return message.length > MAX_MESSAGE_LENGTH ? `${message.slice(0, 999)}…` : message;
|
|
1828
1840
|
}
|
|
1829
1841
|
/**
|
|
@@ -1838,7 +1850,7 @@ function startConsoleRecorder(options) {
|
|
|
1838
1850
|
if (!(active && message)) return;
|
|
1839
1851
|
buffer.push({
|
|
1840
1852
|
level,
|
|
1841
|
-
message,
|
|
1853
|
+
message: clip(maskSecrets(message)),
|
|
1842
1854
|
timestamp: Date.now()
|
|
1843
1855
|
});
|
|
1844
1856
|
if (buffer.length > limit) buffer.splice(0, buffer.length - limit);
|
|
@@ -1848,7 +1860,7 @@ function startConsoleRecorder(options) {
|
|
|
1848
1860
|
for (const method of RECORDED_METHODS) {
|
|
1849
1861
|
const original = console[method];
|
|
1850
1862
|
const wrapper = (...args) => {
|
|
1851
|
-
push(method,
|
|
1863
|
+
push(method, args.map(serializeArgument).join(" "));
|
|
1852
1864
|
Reflect.apply(original, console, args);
|
|
1853
1865
|
};
|
|
1854
1866
|
originals.set(method, original);
|
|
@@ -2291,7 +2303,7 @@ function useWidgetState(props) {
|
|
|
2291
2303
|
setStep("compose");
|
|
2292
2304
|
return submission.submit({
|
|
2293
2305
|
context: {
|
|
2294
|
-
...activeScreenshot?.context ?? collectPageContext({ sdkVersion: "0.6.
|
|
2306
|
+
...activeScreenshot?.context ?? collectPageContext({ sdkVersion: "0.6.6" }),
|
|
2295
2307
|
consoleEvents: consoleRef.current?.events(),
|
|
2296
2308
|
metadata: props.metadata,
|
|
2297
2309
|
selections
|
|
@@ -2357,31 +2369,67 @@ function useWidgetState(props) {
|
|
|
2357
2369
|
}
|
|
2358
2370
|
//#endregion
|
|
2359
2371
|
//#region src/feedback/widget.tsx
|
|
2360
|
-
const DevtoolsLayer = process.env.NODE_ENV === "development" ? lazy(() => import("./devtools-layer-
|
|
2372
|
+
const DevtoolsLayer = process.env.NODE_ENV === "development" ? lazy(() => import("./devtools-layer-B91EVgqg.js").then((module) => ({ default: module.DevtoolsLayer }))) : null;
|
|
2373
|
+
const TeamLayer = lazy(() => import("./team-layer-F-9BE4hc.js").then((module) => ({ default: module.TeamLayer })));
|
|
2374
|
+
const DEFAULT_APP_URL = "https://www.reflet.app";
|
|
2375
|
+
const ignoreChanges = () => () => void 0;
|
|
2376
|
+
/** Activation reads the URL and storage, which only exist in the browser: the server renders without team tools. */
|
|
2377
|
+
function useTeamToolsKey(options) {
|
|
2378
|
+
const { props, publicKey } = options;
|
|
2379
|
+
const hasDevtoolsOnPage = useHasDevtoolsOnPage();
|
|
2380
|
+
const isActivated = useSyncExternalStore(ignoreChanges, () => props.teamTools !== false && publicKey !== null && hasTeamActivation(publicKey), () => false);
|
|
2381
|
+
return useOwnsTeamTools(isActivated && !hasDevtoolsOnPage, options.hasWidget) ? publicKey : null;
|
|
2382
|
+
}
|
|
2361
2383
|
function RefletFeedback(props) {
|
|
2362
2384
|
const state = useWidgetState(props);
|
|
2363
2385
|
const launcher = useWidgetLauncher(state);
|
|
2364
2386
|
const showsWidget = props.enabled !== false && !state.isDismissed;
|
|
2365
2387
|
const showsDevtools = useOwnsDevtools(props.devtools !== false && DevtoolsLayer !== null, showsWidget) && DevtoolsLayer !== null;
|
|
2366
|
-
|
|
2388
|
+
const teamToolsKey = useTeamToolsKey({
|
|
2389
|
+
hasWidget: showsWidget,
|
|
2390
|
+
props,
|
|
2391
|
+
publicKey: state.publicKey
|
|
2392
|
+
});
|
|
2393
|
+
if (!(showsWidget || showsDevtools || teamToolsKey)) return null;
|
|
2367
2394
|
return /* @__PURE__ */ jsxs(Fragment, { children: [showsWidget && props.renderTrigger?.(launcher.triggerProps), /* @__PURE__ */ jsxs(ShadowPortal, {
|
|
2368
2395
|
offset: props.offset ?? 20,
|
|
2369
2396
|
primaryColor: props.primaryColor,
|
|
2370
2397
|
theme: props.theme ?? "auto",
|
|
2371
|
-
children: [
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2398
|
+
children: [
|
|
2399
|
+
showsWidget && /* @__PURE__ */ jsx(WidgetContents, {
|
|
2400
|
+
launcher,
|
|
2401
|
+
props,
|
|
2402
|
+
state
|
|
2403
|
+
}),
|
|
2404
|
+
showsDevtools && /* @__PURE__ */ jsx(Suspense, {
|
|
2405
|
+
fallback: null,
|
|
2406
|
+
children: /* @__PURE__ */ jsx(DevtoolsLayer, {
|
|
2407
|
+
isWidgetOpen: showsWidget && state.isOpen,
|
|
2408
|
+
position: props.position ?? "bottom-right",
|
|
2409
|
+
publicKey: state.publicKey
|
|
2410
|
+
})
|
|
2411
|
+
}),
|
|
2412
|
+
teamToolsKey && /* @__PURE__ */ jsx(TeamTools, {
|
|
2413
|
+
props,
|
|
2414
|
+
publicKey: teamToolsKey
|
|
2381
2415
|
})
|
|
2382
|
-
|
|
2416
|
+
]
|
|
2383
2417
|
})] });
|
|
2384
2418
|
}
|
|
2419
|
+
function TeamTools({ props, publicKey }) {
|
|
2420
|
+
const context = useContext(RefletContext);
|
|
2421
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
2422
|
+
fallback: null,
|
|
2423
|
+
children: /* @__PURE__ */ jsx(TeamLayer, {
|
|
2424
|
+
connection: {
|
|
2425
|
+
apiUrl: props.baseUrl ?? context?.baseUrl ?? "https://harmless-clam-802.convex.site",
|
|
2426
|
+
appUrl: props.appUrl ?? DEFAULT_APP_URL,
|
|
2427
|
+
publicKey
|
|
2428
|
+
},
|
|
2429
|
+
position: props.position ?? "bottom-right"
|
|
2430
|
+
})
|
|
2431
|
+
});
|
|
2432
|
+
}
|
|
2385
2433
|
function WidgetContents({ launcher, props, state }) {
|
|
2386
2434
|
const labels = {
|
|
2387
2435
|
...DEFAULT_WIDGET_LABELS,
|