@okyrychenko-dev/react-action-guard-devtools 0.1.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/LICENSE +21 -0
- package/README.md +394 -0
- package/dist/index.cjs +893 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +363 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +160 -0
- package/dist/index.d.ts +160 -0
- package/dist/index.js +882 -0
- package/dist/index.js.map +1 -0
- package/package.json +99 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,882 @@
|
|
|
1
|
+
import { uiBlockingStoreApi } from '@okyrychenko-dev/react-action-guard';
|
|
2
|
+
import { memo, useMemo, useEffect, useCallback } from 'react';
|
|
3
|
+
import { createShallowStore } from '@okyrychenko-dev/react-zustand-toolkit';
|
|
4
|
+
import clsx2, { clsx } from 'clsx';
|
|
5
|
+
import { useStore } from 'zustand';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
import { useShallow } from 'zustand/react/shallow';
|
|
8
|
+
|
|
9
|
+
// src/components/actionGuardDevtools/ActionGuardDevtools.tsx
|
|
10
|
+
|
|
11
|
+
// src/store/devtoolsStore.constants.ts
|
|
12
|
+
var DEFAULT_FILTER = {
|
|
13
|
+
actions: ["add", "remove", "update", "cancel", "timeout"],
|
|
14
|
+
scopes: [],
|
|
15
|
+
search: ""
|
|
16
|
+
};
|
|
17
|
+
var DEFAULT_MAX_EVENTS = 200;
|
|
18
|
+
var DEFAULT_TAB = "timeline";
|
|
19
|
+
|
|
20
|
+
// src/store/devtoolsStore.actions.ts
|
|
21
|
+
var createDevtoolsActions = (set, get) => ({
|
|
22
|
+
// Initial State
|
|
23
|
+
events: [],
|
|
24
|
+
maxEvents: DEFAULT_MAX_EVENTS,
|
|
25
|
+
isOpen: false,
|
|
26
|
+
isMinimized: false,
|
|
27
|
+
activeTab: DEFAULT_TAB,
|
|
28
|
+
filter: DEFAULT_FILTER,
|
|
29
|
+
selectedEventId: null,
|
|
30
|
+
isPaused: false,
|
|
31
|
+
// Actions
|
|
32
|
+
/**
|
|
33
|
+
* Add a new event to history
|
|
34
|
+
*
|
|
35
|
+
* @param eventData - Event data without ID (auto-generated)
|
|
36
|
+
*/
|
|
37
|
+
addEvent: (eventData) => {
|
|
38
|
+
if (get().isPaused) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const event = {
|
|
42
|
+
...eventData,
|
|
43
|
+
id: `${String(eventData.timestamp)}-${eventData.blockerId}-${Math.random().toString(36).slice(2, 8)}`
|
|
44
|
+
};
|
|
45
|
+
set((state) => {
|
|
46
|
+
const newEvents = [event, ...state.events];
|
|
47
|
+
if (newEvents.length > state.maxEvents) {
|
|
48
|
+
newEvents.pop();
|
|
49
|
+
}
|
|
50
|
+
return { events: newEvents };
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* Clear all events from history
|
|
55
|
+
*/
|
|
56
|
+
clearEvents: () => {
|
|
57
|
+
set({ events: [], selectedEventId: null });
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* Toggle panel open/closed state
|
|
61
|
+
*/
|
|
62
|
+
toggleOpen: () => {
|
|
63
|
+
set((state) => ({ isOpen: !state.isOpen }));
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* Set panel open state
|
|
67
|
+
*
|
|
68
|
+
* @param open - Whether panel should be open
|
|
69
|
+
*/
|
|
70
|
+
setOpen: (open) => {
|
|
71
|
+
set({ isOpen: open });
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* Toggle minimized state
|
|
75
|
+
*/
|
|
76
|
+
toggleMinimized: () => {
|
|
77
|
+
set((state) => ({ isMinimized: !state.isMinimized }));
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* Set active tab
|
|
81
|
+
*
|
|
82
|
+
* @param tab - Tab to activate
|
|
83
|
+
*/
|
|
84
|
+
setActiveTab: (tab) => {
|
|
85
|
+
set({ activeTab: tab, selectedEventId: null });
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Update filter settings (partial update)
|
|
89
|
+
*
|
|
90
|
+
* @param filterUpdate - Partial filter update
|
|
91
|
+
*/
|
|
92
|
+
setFilter: (filterUpdate) => {
|
|
93
|
+
set((state) => ({
|
|
94
|
+
filter: { ...state.filter, ...filterUpdate }
|
|
95
|
+
}));
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* Reset filters to default
|
|
99
|
+
*/
|
|
100
|
+
resetFilter: () => {
|
|
101
|
+
set({ filter: DEFAULT_FILTER });
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Select an event for detail view
|
|
105
|
+
*
|
|
106
|
+
* @param eventId - Event ID to select (null to deselect)
|
|
107
|
+
*/
|
|
108
|
+
selectEvent: (eventId) => {
|
|
109
|
+
set({ selectedEventId: eventId });
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Toggle pause state (stops/resumes recording)
|
|
113
|
+
*/
|
|
114
|
+
togglePause: () => {
|
|
115
|
+
set((state) => ({ isPaused: !state.isPaused }));
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Set maximum events limit
|
|
119
|
+
*
|
|
120
|
+
* @param max - Maximum number of events to keep
|
|
121
|
+
*/
|
|
122
|
+
setMaxEvents: (max) => {
|
|
123
|
+
set((state) => {
|
|
124
|
+
const events = state.events.length > max ? state.events.slice(0, max) : state.events;
|
|
125
|
+
return { maxEvents: max, events };
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// src/store/devtoolsStore.store.ts
|
|
131
|
+
var {
|
|
132
|
+
useStore: useDevtoolsStore,
|
|
133
|
+
useStoreApi: devtoolsStoreApi
|
|
134
|
+
} = createShallowStore(createDevtoolsActions);
|
|
135
|
+
|
|
136
|
+
// src/store/devtoolsStore.selectors.ts
|
|
137
|
+
function selectFilteredEvents(state) {
|
|
138
|
+
const { events, filter } = state;
|
|
139
|
+
return events.filter((event) => {
|
|
140
|
+
if (filter.actions.length > 0 && !filter.actions.includes(event.action)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (filter.scopes.length > 0) {
|
|
144
|
+
if (!event.config?.scope) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
const eventScopes = Array.isArray(event.config.scope) ? event.config.scope : [event.config.scope];
|
|
148
|
+
const hasMatchingScope = eventScopes.some((s) => filter.scopes.includes(s));
|
|
149
|
+
if (!hasMatchingScope) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (filter.search) {
|
|
154
|
+
const searchLower = filter.search.toLowerCase();
|
|
155
|
+
const matchesId = event.blockerId.toLowerCase().includes(searchLower);
|
|
156
|
+
const matchesReason = event.config?.reason?.toLowerCase().includes(searchLower);
|
|
157
|
+
if (!matchesId && !matchesReason) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function selectUniqueScopes(state) {
|
|
165
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
166
|
+
state.events.forEach((event) => {
|
|
167
|
+
if (event.config?.scope) {
|
|
168
|
+
const eventScopes = Array.isArray(event.config.scope) ? event.config.scope : [event.config.scope];
|
|
169
|
+
eventScopes.forEach((s) => scopes.add(s));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
return Array.from(scopes).sort();
|
|
173
|
+
}
|
|
174
|
+
function selectAllEvents(state) {
|
|
175
|
+
return state.events;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/middleware/devtoolsMiddleware.ts
|
|
179
|
+
var DEVTOOLS_MIDDLEWARE_NAME = "action-guard-devtools";
|
|
180
|
+
function createDevtoolsMiddleware() {
|
|
181
|
+
const addTimestamps = /* @__PURE__ */ new Map();
|
|
182
|
+
return (context) => {
|
|
183
|
+
const { addEvent } = devtoolsStoreApi.getState();
|
|
184
|
+
if (context.action === "add") {
|
|
185
|
+
addTimestamps.set(context.blockerId, context.timestamp);
|
|
186
|
+
}
|
|
187
|
+
let duration;
|
|
188
|
+
if (context.action === "remove" || context.action === "timeout" || context.action === "cancel") {
|
|
189
|
+
const addTime = addTimestamps.get(context.blockerId);
|
|
190
|
+
if (addTime !== void 0) {
|
|
191
|
+
duration = context.timestamp - addTime;
|
|
192
|
+
addTimestamps.delete(context.blockerId);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
addEvent({
|
|
196
|
+
action: context.action,
|
|
197
|
+
blockerId: context.blockerId,
|
|
198
|
+
config: context.config,
|
|
199
|
+
timestamp: context.timestamp,
|
|
200
|
+
prevState: context.prevState,
|
|
201
|
+
duration
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/styles/position.module.css
|
|
207
|
+
var position_default = {};
|
|
208
|
+
|
|
209
|
+
// src/components/devtoolsPanel/DevtoolsPanel.module.css
|
|
210
|
+
var DevtoolsPanel_default = {};
|
|
211
|
+
|
|
212
|
+
// src/components/devtoolsPanel/DevtoolsPanel.utils.ts
|
|
213
|
+
function getPositionClass(position) {
|
|
214
|
+
return position === "left" ? position_default.positionLeft : position_default.positionRight;
|
|
215
|
+
}
|
|
216
|
+
function getPanelClassName(position, isMinimized) {
|
|
217
|
+
return clsx(
|
|
218
|
+
DevtoolsPanel_default.panel,
|
|
219
|
+
position_default.positionBase,
|
|
220
|
+
getPositionClass(position),
|
|
221
|
+
position_default.overlayLayer,
|
|
222
|
+
isMinimized ? DevtoolsPanel_default.panelMinimized : DevtoolsPanel_default.panelExpanded
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/components/activeBlockers/ActiveBlockers.utils.ts
|
|
227
|
+
function formatScope(scope) {
|
|
228
|
+
if (Array.isArray(scope)) {
|
|
229
|
+
return scope.join(", ");
|
|
230
|
+
}
|
|
231
|
+
return scope;
|
|
232
|
+
}
|
|
233
|
+
function formatTimestamp(timestamp) {
|
|
234
|
+
const seconds = Math.floor((Date.now() - timestamp) / 1e3);
|
|
235
|
+
if (seconds < 60) {
|
|
236
|
+
return `${String(seconds)}s ago`;
|
|
237
|
+
}
|
|
238
|
+
if (seconds < 3600) {
|
|
239
|
+
return `${String(Math.floor(seconds / 60))}m ago`;
|
|
240
|
+
}
|
|
241
|
+
return `${String(Math.floor(seconds / 3600))}h ago`;
|
|
242
|
+
}
|
|
243
|
+
function getSortedBlockers(activeBlockers) {
|
|
244
|
+
return Array.from(activeBlockers.entries()).sort(([, a], [, b]) => b.priority - a.priority);
|
|
245
|
+
}
|
|
246
|
+
function createSvgIcon(children, { viewBox = "0 0 24 24" } = {}) {
|
|
247
|
+
return function SvgIcon(props) {
|
|
248
|
+
const { size = 16, color = "currentColor" } = props;
|
|
249
|
+
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox, fill: color, children });
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
var BlockIcon = createSvgIcon(
|
|
253
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2M4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12m8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8" })
|
|
254
|
+
);
|
|
255
|
+
var CloseIcon = createSvgIcon(
|
|
256
|
+
/* @__PURE__ */ jsx("path", { d: "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
257
|
+
);
|
|
258
|
+
var MinimizeIcon = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M6 19h12v2H6z" }));
|
|
259
|
+
var PauseIcon = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M6 19h4V5H6zm8-14v14h4V5z" }));
|
|
260
|
+
var PlayIcon = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M10 8.64 15.27 12 10 15.36zM8 5v14l11-7z" }));
|
|
261
|
+
var ShieldIcon = createSvgIcon(
|
|
262
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2 4 5v6.09c0 5.05 3.41 9.76 8 10.91 4.59-1.15 8-5.86 8-10.91V5zm6 9.09c0 4-2.55 7.7-6 8.83-3.45-1.13-6-4.82-6-8.83v-4.7l6-2.25 6 2.25z" })
|
|
263
|
+
);
|
|
264
|
+
var TrashIcon = createSvgIcon(
|
|
265
|
+
/* @__PURE__ */ jsx("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6zM8 9h8v10H8zm7.5-5-1-1h-5l-1 1H5v2h14V4z" })
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
// src/styles/tokens.ts
|
|
269
|
+
var COLORS = {
|
|
270
|
+
primary: "var(--ag-primary)",
|
|
271
|
+
textDim: "var(--ag-text-dim)"};
|
|
272
|
+
|
|
273
|
+
// src/styles/shared.module.css
|
|
274
|
+
var shared_default = {};
|
|
275
|
+
function Badge(props) {
|
|
276
|
+
const { children, className, style } = props;
|
|
277
|
+
return /* @__PURE__ */ jsx("span", { className: clsx2(shared_default.badge, className), style, children });
|
|
278
|
+
}
|
|
279
|
+
var Badge_default = Badge;
|
|
280
|
+
function Content(props) {
|
|
281
|
+
const { children, className } = props;
|
|
282
|
+
return /* @__PURE__ */ jsx("div", { className: clsx2(shared_default.content, className), children });
|
|
283
|
+
}
|
|
284
|
+
var Content_default = Content;
|
|
285
|
+
function EmptyState(props) {
|
|
286
|
+
const { children, className } = props;
|
|
287
|
+
return /* @__PURE__ */ jsx("div", { className: clsx2(shared_default.emptyState, className), children });
|
|
288
|
+
}
|
|
289
|
+
var EmptyState_default = EmptyState;
|
|
290
|
+
function EventBadge(props) {
|
|
291
|
+
const { children, className, style, action } = props;
|
|
292
|
+
const classes = clsx(shared_default.eventBadge, action && shared_default.eventBadgeAction, className);
|
|
293
|
+
return /* @__PURE__ */ jsx("span", { className: classes, style, "data-action": action, children });
|
|
294
|
+
}
|
|
295
|
+
var EventBadge_default = EventBadge;
|
|
296
|
+
function IconButton(props) {
|
|
297
|
+
const { children, className, type = "button", ...others } = props;
|
|
298
|
+
return /* @__PURE__ */ jsx("button", { type, className: clsx2(shared_default.iconButton, className), ...others, children });
|
|
299
|
+
}
|
|
300
|
+
var IconButton_default = IconButton;
|
|
301
|
+
|
|
302
|
+
// src/components/activeBlockers/ActiveBlockers.module.css
|
|
303
|
+
var ActiveBlockers_default = {};
|
|
304
|
+
function ActiveBlockersEmptyState() {
|
|
305
|
+
return /* @__PURE__ */ jsxs(EmptyState_default, { children: [
|
|
306
|
+
/* @__PURE__ */ jsx("span", { className: ActiveBlockers_default.emptyIcon, children: /* @__PURE__ */ jsx(BlockIcon, { size: 32, color: COLORS.textDim }) }),
|
|
307
|
+
/* @__PURE__ */ jsx("p", { className: ActiveBlockers_default.emptyTitle, children: "No active blockers" }),
|
|
308
|
+
/* @__PURE__ */ jsx("p", { className: ActiveBlockers_default.emptySubtext, children: "The UI is currently unblocked." })
|
|
309
|
+
] });
|
|
310
|
+
}
|
|
311
|
+
var ActiveBlockersEmptyState_default = ActiveBlockersEmptyState;
|
|
312
|
+
function ActiveBlockerItem(props) {
|
|
313
|
+
const { id, blocker } = props;
|
|
314
|
+
return /* @__PURE__ */ jsxs("div", { className: ActiveBlockers_default.blockerItem, children: [
|
|
315
|
+
/* @__PURE__ */ jsxs("div", { className: ActiveBlockers_default.blockerHeader, children: [
|
|
316
|
+
/* @__PURE__ */ jsx("span", { className: ActiveBlockers_default.blockerId, children: id }),
|
|
317
|
+
/* @__PURE__ */ jsx(Badge_default, { className: ActiveBlockers_default.activeBadge, children: "Active" })
|
|
318
|
+
] }),
|
|
319
|
+
/* @__PURE__ */ jsxs("div", { className: ActiveBlockers_default.blockerMeta, children: [
|
|
320
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
321
|
+
"Scope: ",
|
|
322
|
+
formatScope(blocker.scope)
|
|
323
|
+
] }),
|
|
324
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
325
|
+
"Priority: ",
|
|
326
|
+
blocker.priority
|
|
327
|
+
] }),
|
|
328
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
329
|
+
"Reason: ",
|
|
330
|
+
blocker.reason
|
|
331
|
+
] }),
|
|
332
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
333
|
+
"Started: ",
|
|
334
|
+
formatTimestamp(blocker.timestamp)
|
|
335
|
+
] })
|
|
336
|
+
] })
|
|
337
|
+
] });
|
|
338
|
+
}
|
|
339
|
+
var ActiveBlockerItem_default = ActiveBlockerItem;
|
|
340
|
+
function ActiveBlockersList(props) {
|
|
341
|
+
const { blockers } = props;
|
|
342
|
+
return /* @__PURE__ */ jsx(Content_default, { children: blockers.map(([id, blocker]) => /* @__PURE__ */ jsx(ActiveBlockerItem_default, { id, blocker }, id)) });
|
|
343
|
+
}
|
|
344
|
+
var ActiveBlockersList_default = ActiveBlockersList;
|
|
345
|
+
function ActiveBlockers(props) {
|
|
346
|
+
const { store } = props;
|
|
347
|
+
const targetStore = store ?? uiBlockingStoreApi;
|
|
348
|
+
const activeBlockers = useStore(targetStore, (state) => state.activeBlockers);
|
|
349
|
+
const blockers = useMemo(() => getSortedBlockers(activeBlockers), [activeBlockers]);
|
|
350
|
+
if (blockers.length === 0) {
|
|
351
|
+
return /* @__PURE__ */ jsx(ActiveBlockersEmptyState_default, {});
|
|
352
|
+
}
|
|
353
|
+
return /* @__PURE__ */ jsx(ActiveBlockersList_default, { blockers });
|
|
354
|
+
}
|
|
355
|
+
var ActiveBlockers_default2 = ActiveBlockers;
|
|
356
|
+
|
|
357
|
+
// src/components/eventDetails/EventDetails.module.css
|
|
358
|
+
var EventDetails_default = {};
|
|
359
|
+
|
|
360
|
+
// src/components/eventItem/EventItem.module.css
|
|
361
|
+
var EventItem_default = {};
|
|
362
|
+
|
|
363
|
+
// src/components/eventItem/EventItem.utils.ts
|
|
364
|
+
function formatDuration(ms) {
|
|
365
|
+
if (ms < 1e3) {
|
|
366
|
+
return `${String(ms)}ms`;
|
|
367
|
+
}
|
|
368
|
+
if (ms < 6e4) {
|
|
369
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
370
|
+
}
|
|
371
|
+
return `${(ms / 6e4).toFixed(1)}m`;
|
|
372
|
+
}
|
|
373
|
+
function formatScope2(scope) {
|
|
374
|
+
if (!scope) {
|
|
375
|
+
return "global";
|
|
376
|
+
}
|
|
377
|
+
if (Array.isArray(scope)) {
|
|
378
|
+
return scope.join(", ");
|
|
379
|
+
}
|
|
380
|
+
return scope;
|
|
381
|
+
}
|
|
382
|
+
function formatTime(timestamp) {
|
|
383
|
+
const date = new Date(timestamp);
|
|
384
|
+
return date.toLocaleTimeString("en-US", {
|
|
385
|
+
hour12: false,
|
|
386
|
+
hour: "2-digit",
|
|
387
|
+
minute: "2-digit",
|
|
388
|
+
second: "2-digit"
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function EventItemDetails(props) {
|
|
392
|
+
const { event } = props;
|
|
393
|
+
const { config, duration } = event;
|
|
394
|
+
return /* @__PURE__ */ jsxs("div", { className: EventItem_default.eventDetails, children: [
|
|
395
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
396
|
+
"scope: ",
|
|
397
|
+
formatScope2(config?.scope)
|
|
398
|
+
] }),
|
|
399
|
+
duration !== void 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
400
|
+
"duration: ",
|
|
401
|
+
formatDuration(duration)
|
|
402
|
+
] }),
|
|
403
|
+
config?.priority !== void 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
404
|
+
"priority: ",
|
|
405
|
+
config.priority
|
|
406
|
+
] })
|
|
407
|
+
] });
|
|
408
|
+
}
|
|
409
|
+
var EventItemDetails_default = EventItemDetails;
|
|
410
|
+
function EventItemHeader(props) {
|
|
411
|
+
const { event } = props;
|
|
412
|
+
const { action, blockerId, timestamp } = event;
|
|
413
|
+
return /* @__PURE__ */ jsxs("div", { className: EventItem_default.eventHeader, children: [
|
|
414
|
+
/* @__PURE__ */ jsx(EventBadge_default, { action, children: action }),
|
|
415
|
+
/* @__PURE__ */ jsx("span", { className: EventItem_default.eventBlockerId, children: blockerId }),
|
|
416
|
+
/* @__PURE__ */ jsx("span", { className: EventItem_default.eventTime, children: formatTime(timestamp) })
|
|
417
|
+
] });
|
|
418
|
+
}
|
|
419
|
+
var EventItemHeader_default = EventItemHeader;
|
|
420
|
+
function EventItem(props) {
|
|
421
|
+
const { event, selected, onSelect } = props;
|
|
422
|
+
const handleSelect = () => {
|
|
423
|
+
onSelect(selected ? null : event.id);
|
|
424
|
+
};
|
|
425
|
+
return /* @__PURE__ */ jsxs("li", { className: clsx(EventItem_default.eventItem, selected && EventItem_default.selected), onClick: handleSelect, children: [
|
|
426
|
+
/* @__PURE__ */ jsx(EventItemHeader_default, { event }),
|
|
427
|
+
/* @__PURE__ */ jsx(EventItemDetails_default, { event })
|
|
428
|
+
] });
|
|
429
|
+
}
|
|
430
|
+
var EventItem_default2 = memo(EventItem);
|
|
431
|
+
|
|
432
|
+
// src/components/eventDetails/EventDetails.utils.ts
|
|
433
|
+
function formatFullTimestamp(timestamp) {
|
|
434
|
+
const date = new Date(timestamp);
|
|
435
|
+
return date.toLocaleString("en-US", {
|
|
436
|
+
year: "numeric",
|
|
437
|
+
month: "2-digit",
|
|
438
|
+
day: "2-digit",
|
|
439
|
+
hour: "2-digit",
|
|
440
|
+
minute: "2-digit",
|
|
441
|
+
second: "2-digit",
|
|
442
|
+
hour12: false
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function formatRelativeTime(timestamp) {
|
|
446
|
+
const seconds = Math.floor((Date.now() - timestamp) / 1e3);
|
|
447
|
+
if (seconds < 60) {
|
|
448
|
+
return `${String(seconds)}s ago`;
|
|
449
|
+
}
|
|
450
|
+
if (seconds < 3600) {
|
|
451
|
+
return `${String(Math.floor(seconds / 60))}m ago`;
|
|
452
|
+
}
|
|
453
|
+
return `${String(Math.floor(seconds / 3600))}h ago`;
|
|
454
|
+
}
|
|
455
|
+
function EventDetailsContent(props) {
|
|
456
|
+
const { event } = props;
|
|
457
|
+
return /* @__PURE__ */ jsxs("div", { className: EventDetails_default.content, children: [
|
|
458
|
+
/* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
459
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Blocker ID" }),
|
|
460
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.value, children: event.blockerId })
|
|
461
|
+
] }),
|
|
462
|
+
/* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
463
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Timestamp" }),
|
|
464
|
+
/* @__PURE__ */ jsxs("div", { className: EventDetails_default.value, children: [
|
|
465
|
+
formatFullTimestamp(event.timestamp),
|
|
466
|
+
/* @__PURE__ */ jsxs("span", { className: EventDetails_default.mutedInline, children: [
|
|
467
|
+
"(",
|
|
468
|
+
formatRelativeTime(event.timestamp),
|
|
469
|
+
")"
|
|
470
|
+
] })
|
|
471
|
+
] })
|
|
472
|
+
] }),
|
|
473
|
+
event.duration !== void 0 && /* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
474
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Duration" }),
|
|
475
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.value, children: formatDuration(event.duration) })
|
|
476
|
+
] }),
|
|
477
|
+
event.config && /* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
478
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Config" }),
|
|
479
|
+
/* @__PURE__ */ jsxs("div", { className: EventDetails_default.config, children: [
|
|
480
|
+
event.config.scope !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
481
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "scope: " }),
|
|
482
|
+
formatScope2(event.config.scope)
|
|
483
|
+
] }),
|
|
484
|
+
event.config.reason !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
485
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "reason: " }),
|
|
486
|
+
event.config.reason
|
|
487
|
+
] }),
|
|
488
|
+
event.config.priority !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
489
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "priority: " }),
|
|
490
|
+
event.config.priority
|
|
491
|
+
] })
|
|
492
|
+
] })
|
|
493
|
+
] }),
|
|
494
|
+
event.prevState && /* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
495
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Previous State" }),
|
|
496
|
+
/* @__PURE__ */ jsxs("div", { className: EventDetails_default.config, children: [
|
|
497
|
+
event.prevState.scope !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
498
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "scope: " }),
|
|
499
|
+
formatScope2(event.prevState.scope)
|
|
500
|
+
] }),
|
|
501
|
+
event.prevState.reason !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
502
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "reason: " }),
|
|
503
|
+
event.prevState.reason
|
|
504
|
+
] }),
|
|
505
|
+
event.prevState.priority !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
506
|
+
/* @__PURE__ */ jsx("span", { className: EventDetails_default.mutedLabel, children: "priority: " }),
|
|
507
|
+
event.prevState.priority
|
|
508
|
+
] })
|
|
509
|
+
] })
|
|
510
|
+
] }),
|
|
511
|
+
event.source && /* @__PURE__ */ jsxs("div", { className: EventDetails_default.section, children: [
|
|
512
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.label, children: "Source" }),
|
|
513
|
+
/* @__PURE__ */ jsx("div", { className: EventDetails_default.value, children: event.source })
|
|
514
|
+
] })
|
|
515
|
+
] });
|
|
516
|
+
}
|
|
517
|
+
var EventDetailsContent_default = EventDetailsContent;
|
|
518
|
+
function EventDetailsHeader(props) {
|
|
519
|
+
const { action, onClose } = props;
|
|
520
|
+
return /* @__PURE__ */ jsxs("div", { className: EventDetails_default.header, children: [
|
|
521
|
+
/* @__PURE__ */ jsx(EventBadge_default, { action, children: action }),
|
|
522
|
+
/* @__PURE__ */ jsx(IconButton_default, { title: "Close details", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: 16 }) })
|
|
523
|
+
] });
|
|
524
|
+
}
|
|
525
|
+
var EventDetailsHeader_default = EventDetailsHeader;
|
|
526
|
+
function EventDetails(props) {
|
|
527
|
+
const { event, onClose } = props;
|
|
528
|
+
return /* @__PURE__ */ jsxs("div", { className: EventDetails_default.panel, children: [
|
|
529
|
+
/* @__PURE__ */ jsx(EventDetailsHeader_default, { action: event.action, onClose }),
|
|
530
|
+
/* @__PURE__ */ jsx(EventDetailsContent_default, { event })
|
|
531
|
+
] });
|
|
532
|
+
}
|
|
533
|
+
var EventDetails_default2 = EventDetails;
|
|
534
|
+
|
|
535
|
+
// src/components/timeline/Timeline.utils.ts
|
|
536
|
+
function isFilterActive(filter) {
|
|
537
|
+
if (filter.search.length > 0 || filter.scopes.length > 0) {
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
if (filter.actions.length !== DEFAULT_FILTER.actions.length) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
return !DEFAULT_FILTER.actions.every((action) => filter.actions.includes(action));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/components/timeline/Timeline.module.css
|
|
547
|
+
var Timeline_default = {};
|
|
548
|
+
function TimelineContent(props) {
|
|
549
|
+
const { events, selectedEventId, onSelectEvent } = props;
|
|
550
|
+
return /* @__PURE__ */ jsxs(Content_default, { children: [
|
|
551
|
+
events.length === 0 && /* @__PURE__ */ jsx(EmptyState_default, { children: "No matching events" }),
|
|
552
|
+
events.length > 0 && /* @__PURE__ */ jsx("ul", { className: Timeline_default.eventList, children: events.map((event) => /* @__PURE__ */ jsx(
|
|
553
|
+
EventItem_default2,
|
|
554
|
+
{
|
|
555
|
+
event,
|
|
556
|
+
selected: selectedEventId === event.id,
|
|
557
|
+
onSelect: onSelectEvent
|
|
558
|
+
},
|
|
559
|
+
event.id
|
|
560
|
+
)) })
|
|
561
|
+
] });
|
|
562
|
+
}
|
|
563
|
+
var TimelineContent_default = TimelineContent;
|
|
564
|
+
function TimelineEmptyState() {
|
|
565
|
+
return /* @__PURE__ */ jsxs(EmptyState_default, { children: [
|
|
566
|
+
/* @__PURE__ */ jsx("p", { children: "No events recorded yet." }),
|
|
567
|
+
/* @__PURE__ */ jsx("p", { className: Timeline_default.emptyHint, children: "Events will appear here as blockers are added/removed." })
|
|
568
|
+
] });
|
|
569
|
+
}
|
|
570
|
+
var TimelineEmptyState_default = TimelineEmptyState;
|
|
571
|
+
function TimelineToolbar(props) {
|
|
572
|
+
const { search, onSearchChange } = props;
|
|
573
|
+
return /* @__PURE__ */ jsx("div", { className: Timeline_default.toolbar, children: /* @__PURE__ */ jsx(
|
|
574
|
+
"input",
|
|
575
|
+
{
|
|
576
|
+
type: "text",
|
|
577
|
+
placeholder: "Search by ID or reason...",
|
|
578
|
+
value: search,
|
|
579
|
+
className: Timeline_default.searchInput,
|
|
580
|
+
onChange: onSearchChange
|
|
581
|
+
}
|
|
582
|
+
) });
|
|
583
|
+
}
|
|
584
|
+
var TimelineToolbar_default = TimelineToolbar;
|
|
585
|
+
function Timeline() {
|
|
586
|
+
const events = useDevtoolsStore(selectFilteredEvents);
|
|
587
|
+
const allEvents = useDevtoolsStore(selectAllEvents);
|
|
588
|
+
const { selectedEventId, selectEvent, filter, setFilter } = useDevtoolsStore(
|
|
589
|
+
useShallow((state) => ({
|
|
590
|
+
selectedEventId: state.selectedEventId,
|
|
591
|
+
selectEvent: state.selectEvent,
|
|
592
|
+
filter: state.filter,
|
|
593
|
+
setFilter: state.setFilter
|
|
594
|
+
}))
|
|
595
|
+
);
|
|
596
|
+
const selectedEvent = selectedEventId ? events.find((e) => e.id === selectedEventId) : null;
|
|
597
|
+
useEffect(() => {
|
|
598
|
+
if (selectedEventId && !allEvents.some((e) => e.id === selectedEventId)) {
|
|
599
|
+
selectEvent(null);
|
|
600
|
+
}
|
|
601
|
+
}, [selectedEventId, allEvents, selectEvent]);
|
|
602
|
+
const handleSearchChange = useCallback(
|
|
603
|
+
(e) => {
|
|
604
|
+
setFilter({ search: e.target.value });
|
|
605
|
+
},
|
|
606
|
+
[setFilter]
|
|
607
|
+
);
|
|
608
|
+
const handleCloseDetails = useCallback(() => {
|
|
609
|
+
selectEvent(null);
|
|
610
|
+
}, [selectEvent]);
|
|
611
|
+
if (events.length === 0 && !isFilterActive(filter)) {
|
|
612
|
+
return /* @__PURE__ */ jsx(TimelineEmptyState_default, {});
|
|
613
|
+
}
|
|
614
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
615
|
+
/* @__PURE__ */ jsx(TimelineToolbar_default, { search: filter.search, onSearchChange: handleSearchChange }),
|
|
616
|
+
/* @__PURE__ */ jsx(
|
|
617
|
+
TimelineContent_default,
|
|
618
|
+
{
|
|
619
|
+
events,
|
|
620
|
+
selectedEventId,
|
|
621
|
+
onSelectEvent: selectEvent
|
|
622
|
+
}
|
|
623
|
+
),
|
|
624
|
+
selectedEvent && /* @__PURE__ */ jsx(EventDetails_default2, { event: selectedEvent, onClose: handleCloseDetails })
|
|
625
|
+
] });
|
|
626
|
+
}
|
|
627
|
+
var Timeline_default2 = Timeline;
|
|
628
|
+
function DevtoolsPanelContent(props) {
|
|
629
|
+
const { activeTab, store } = props;
|
|
630
|
+
return activeTab === "timeline" ? /* @__PURE__ */ jsx(Timeline_default2, {}) : /* @__PURE__ */ jsx(ActiveBlockers_default2, { store });
|
|
631
|
+
}
|
|
632
|
+
var DevtoolsPanelContent_default = DevtoolsPanelContent;
|
|
633
|
+
var MaximizeIcon = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M3 3h18v2H3z" }));
|
|
634
|
+
function getPauseButtonTitle(isPaused) {
|
|
635
|
+
return isPaused ? "Resume recording" : "Pause recording";
|
|
636
|
+
}
|
|
637
|
+
function getMinimizeButtonTitle(isMinimized) {
|
|
638
|
+
return isMinimized ? "Maximize" : "Minimize";
|
|
639
|
+
}
|
|
640
|
+
function getPauseButtonClassName(isPaused) {
|
|
641
|
+
return clsx(isPaused && DevtoolsPanel_default.pauseButtonActive);
|
|
642
|
+
}
|
|
643
|
+
function DevtoolsPanelHeader(props) {
|
|
644
|
+
const {
|
|
645
|
+
eventsCount,
|
|
646
|
+
isPaused,
|
|
647
|
+
isMinimized,
|
|
648
|
+
onTogglePause,
|
|
649
|
+
onClearEvents,
|
|
650
|
+
onToggleMinimized,
|
|
651
|
+
onClose
|
|
652
|
+
} = props;
|
|
653
|
+
return /* @__PURE__ */ jsxs("div", { className: DevtoolsPanel_default.header, children: [
|
|
654
|
+
/* @__PURE__ */ jsxs("div", { className: DevtoolsPanel_default.headerTitle, children: [
|
|
655
|
+
/* @__PURE__ */ jsx(ShieldIcon, { size: 16, color: COLORS.primary }),
|
|
656
|
+
/* @__PURE__ */ jsx("span", { children: "Action Guard" }),
|
|
657
|
+
/* @__PURE__ */ jsx(Badge_default, { className: DevtoolsPanel_default.headerCount, children: eventsCount })
|
|
658
|
+
] }),
|
|
659
|
+
/* @__PURE__ */ jsxs("div", { className: DevtoolsPanel_default.headerActions, children: [
|
|
660
|
+
/* @__PURE__ */ jsx(
|
|
661
|
+
IconButton_default,
|
|
662
|
+
{
|
|
663
|
+
className: getPauseButtonClassName(isPaused),
|
|
664
|
+
title: getPauseButtonTitle(isPaused),
|
|
665
|
+
onClick: onTogglePause,
|
|
666
|
+
children: isPaused ? /* @__PURE__ */ jsx(PlayIcon, {}) : /* @__PURE__ */ jsx(PauseIcon, {})
|
|
667
|
+
}
|
|
668
|
+
),
|
|
669
|
+
/* @__PURE__ */ jsx(IconButton_default, { title: "Clear events", onClick: onClearEvents, children: /* @__PURE__ */ jsx(TrashIcon, {}) }),
|
|
670
|
+
/* @__PURE__ */ jsx(IconButton_default, { title: getMinimizeButtonTitle(isMinimized), onClick: onToggleMinimized, children: isMinimized ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(MaximizeIcon, {}) }),
|
|
671
|
+
/* @__PURE__ */ jsx(IconButton_default, { title: "Close", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
672
|
+
] })
|
|
673
|
+
] });
|
|
674
|
+
}
|
|
675
|
+
var DevtoolsPanelHeader_default = DevtoolsPanelHeader;
|
|
676
|
+
|
|
677
|
+
// src/components/devtoolsPanel/DevtoolsPanelTabs.utils.ts
|
|
678
|
+
var DEVTOOLS_TABS = [
|
|
679
|
+
{ id: "timeline", label: "Timeline" },
|
|
680
|
+
{ id: "blockers", label: "Active Blockers" }
|
|
681
|
+
];
|
|
682
|
+
function DevtoolsPanelTabs(props) {
|
|
683
|
+
const { activeTab, onSelectTab } = props;
|
|
684
|
+
return /* @__PURE__ */ jsx("div", { className: DevtoolsPanel_default.tabs, children: DEVTOOLS_TABS.map((tab) => /* @__PURE__ */ jsx(
|
|
685
|
+
"button",
|
|
686
|
+
{
|
|
687
|
+
onClick: () => {
|
|
688
|
+
onSelectTab(tab.id);
|
|
689
|
+
},
|
|
690
|
+
className: clsx(DevtoolsPanel_default.tab, activeTab === tab.id && DevtoolsPanel_default.tabActive),
|
|
691
|
+
children: tab.label
|
|
692
|
+
},
|
|
693
|
+
tab.id
|
|
694
|
+
)) });
|
|
695
|
+
}
|
|
696
|
+
var DevtoolsPanelTabs_default = DevtoolsPanelTabs;
|
|
697
|
+
function DevtoolsPanel(props) {
|
|
698
|
+
const { position, store } = props;
|
|
699
|
+
const {
|
|
700
|
+
isOpen,
|
|
701
|
+
isMinimized,
|
|
702
|
+
activeTab,
|
|
703
|
+
setActiveTab,
|
|
704
|
+
toggleOpen,
|
|
705
|
+
toggleMinimized,
|
|
706
|
+
clearEvents,
|
|
707
|
+
isPaused,
|
|
708
|
+
togglePause,
|
|
709
|
+
events
|
|
710
|
+
} = useDevtoolsStore();
|
|
711
|
+
if (!isOpen) {
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
return /* @__PURE__ */ jsxs("div", { className: getPanelClassName(position, isMinimized), children: [
|
|
715
|
+
/* @__PURE__ */ jsx(
|
|
716
|
+
DevtoolsPanelHeader_default,
|
|
717
|
+
{
|
|
718
|
+
eventsCount: events.length,
|
|
719
|
+
isPaused,
|
|
720
|
+
isMinimized,
|
|
721
|
+
onTogglePause: togglePause,
|
|
722
|
+
onClearEvents: clearEvents,
|
|
723
|
+
onToggleMinimized: toggleMinimized,
|
|
724
|
+
onClose: toggleOpen
|
|
725
|
+
}
|
|
726
|
+
),
|
|
727
|
+
!isMinimized && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
728
|
+
/* @__PURE__ */ jsx(DevtoolsPanelTabs_default, { activeTab, onSelectTab: setActiveTab }),
|
|
729
|
+
/* @__PURE__ */ jsx(DevtoolsPanelContent_default, { activeTab, store })
|
|
730
|
+
] })
|
|
731
|
+
] });
|
|
732
|
+
}
|
|
733
|
+
var DevtoolsPanel_default2 = DevtoolsPanel;
|
|
734
|
+
|
|
735
|
+
// src/components/toggleButton/ToggleButton.module.css
|
|
736
|
+
var ToggleButton_default = {};
|
|
737
|
+
|
|
738
|
+
// src/components/toggleButton/ToggleButton.utils.ts
|
|
739
|
+
function getPositionClass2(position) {
|
|
740
|
+
return position === "left" ? position_default.positionLeft : position_default.positionRight;
|
|
741
|
+
}
|
|
742
|
+
function getToggleButtonClassName(position) {
|
|
743
|
+
return clsx(
|
|
744
|
+
ToggleButton_default.toggleButton,
|
|
745
|
+
position_default.positionBase,
|
|
746
|
+
getPositionClass2(position),
|
|
747
|
+
position_default.overlayLayer
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
function shouldShowBadge(count) {
|
|
751
|
+
return count > 0;
|
|
752
|
+
}
|
|
753
|
+
function getBadgeClassName(isPaused) {
|
|
754
|
+
return clsx(ToggleButton_default.badgePosition, isPaused ? ToggleButton_default.badgePaused : ToggleButton_default.badgeActive);
|
|
755
|
+
}
|
|
756
|
+
function ToggleButtonBadge(props) {
|
|
757
|
+
const { count, isPaused } = props;
|
|
758
|
+
if (!shouldShowBadge(count)) {
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
return /* @__PURE__ */ jsx(Badge_default, { className: getBadgeClassName(isPaused), children: count });
|
|
762
|
+
}
|
|
763
|
+
var ToggleButtonBadge_default = ToggleButtonBadge;
|
|
764
|
+
function ToggleButton(props) {
|
|
765
|
+
const { position, store } = props;
|
|
766
|
+
const { isOpen, toggleOpen, isPaused } = useDevtoolsStore();
|
|
767
|
+
const targetStore = store ?? uiBlockingStoreApi;
|
|
768
|
+
const activeBlockers = useStore(targetStore, (state) => state.activeBlockers);
|
|
769
|
+
const activeCount = activeBlockers.size;
|
|
770
|
+
if (isOpen) {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
return /* @__PURE__ */ jsxs(
|
|
774
|
+
"button",
|
|
775
|
+
{
|
|
776
|
+
className: getToggleButtonClassName(position),
|
|
777
|
+
title: "Open Action Guard Devtools",
|
|
778
|
+
onClick: toggleOpen,
|
|
779
|
+
children: [
|
|
780
|
+
/* @__PURE__ */ jsx(ShieldIcon, { size: 22 }),
|
|
781
|
+
/* @__PURE__ */ jsx(ToggleButtonBadge_default, { count: activeCount, isPaused })
|
|
782
|
+
]
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
var ToggleButton_default2 = ToggleButton;
|
|
787
|
+
function ActionGuardDevtoolsContent(props) {
|
|
788
|
+
const { position, store } = props;
|
|
789
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
790
|
+
/* @__PURE__ */ jsx(ToggleButton_default2, { position, store }),
|
|
791
|
+
/* @__PURE__ */ jsx(DevtoolsPanel_default2, { position, store })
|
|
792
|
+
] });
|
|
793
|
+
}
|
|
794
|
+
var ActionGuardDevtoolsContent_default = ActionGuardDevtoolsContent;
|
|
795
|
+
|
|
796
|
+
// src/components/actionGuardDevtools/ActionGuardDevtools.utils.ts
|
|
797
|
+
function isTypingTarget(target) {
|
|
798
|
+
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
|
|
799
|
+
}
|
|
800
|
+
function getDevtoolsKeyboardAction(event, isOpen) {
|
|
801
|
+
if (!isOpen) {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
if (isTypingTarget(event.target)) {
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
switch (event.key) {
|
|
808
|
+
case "Escape":
|
|
809
|
+
return { action: "close", preventDefault: false };
|
|
810
|
+
case " ":
|
|
811
|
+
return { action: "togglePause", preventDefault: true };
|
|
812
|
+
case "c":
|
|
813
|
+
case "C":
|
|
814
|
+
if (!event.metaKey && !event.ctrlKey) {
|
|
815
|
+
return { action: "clearEvents", preventDefault: false };
|
|
816
|
+
}
|
|
817
|
+
return null;
|
|
818
|
+
default:
|
|
819
|
+
return null;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
function ActionGuardDevtools(props) {
|
|
823
|
+
const {
|
|
824
|
+
position = "right",
|
|
825
|
+
defaultOpen = false,
|
|
826
|
+
maxEvents = 200,
|
|
827
|
+
showInProduction = false,
|
|
828
|
+
store: customStore
|
|
829
|
+
} = props;
|
|
830
|
+
const { setOpen, setMaxEvents, isOpen, togglePause, clearEvents } = useDevtoolsStore();
|
|
831
|
+
const targetStore = useMemo(() => customStore ?? uiBlockingStoreApi, [customStore]);
|
|
832
|
+
useEffect(() => {
|
|
833
|
+
const storeState = targetStore.getState();
|
|
834
|
+
const middleware = createDevtoolsMiddleware();
|
|
835
|
+
storeState.registerMiddleware(DEVTOOLS_MIDDLEWARE_NAME, middleware);
|
|
836
|
+
return () => {
|
|
837
|
+
storeState.unregisterMiddleware(DEVTOOLS_MIDDLEWARE_NAME);
|
|
838
|
+
};
|
|
839
|
+
}, [targetStore]);
|
|
840
|
+
useEffect(() => {
|
|
841
|
+
setOpen(defaultOpen);
|
|
842
|
+
setMaxEvents(maxEvents);
|
|
843
|
+
}, [defaultOpen, maxEvents, setOpen, setMaxEvents]);
|
|
844
|
+
const handleKeyDown = useCallback(
|
|
845
|
+
(event) => {
|
|
846
|
+
const action = getDevtoolsKeyboardAction(event, isOpen);
|
|
847
|
+
if (!action) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (action.preventDefault) {
|
|
851
|
+
event.preventDefault();
|
|
852
|
+
}
|
|
853
|
+
switch (action.action) {
|
|
854
|
+
case "close":
|
|
855
|
+
setOpen(false);
|
|
856
|
+
break;
|
|
857
|
+
case "togglePause":
|
|
858
|
+
togglePause();
|
|
859
|
+
break;
|
|
860
|
+
case "clearEvents":
|
|
861
|
+
clearEvents();
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
},
|
|
865
|
+
[isOpen, setOpen, togglePause, clearEvents]
|
|
866
|
+
);
|
|
867
|
+
useEffect(() => {
|
|
868
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
869
|
+
return () => {
|
|
870
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
871
|
+
};
|
|
872
|
+
}, [handleKeyDown]);
|
|
873
|
+
if (process.env.NODE_ENV === "production" && !showInProduction) {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
876
|
+
return /* @__PURE__ */ jsx(ActionGuardDevtoolsContent_default, { position, store: customStore });
|
|
877
|
+
}
|
|
878
|
+
var ActionGuardDevtools_default = ActionGuardDevtools;
|
|
879
|
+
|
|
880
|
+
export { ActionGuardDevtools_default as ActionGuardDevtools, DEVTOOLS_MIDDLEWARE_NAME, createDevtoolsMiddleware, selectFilteredEvents, selectUniqueScopes, useDevtoolsStore };
|
|
881
|
+
//# sourceMappingURL=index.js.map
|
|
882
|
+
//# sourceMappingURL=index.js.map
|