@okyrychenko-dev/react-action-guard-devtools 0.1.1 β 0.1.3
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/README.md +3 -6
- package/dist/index.cjs +261 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +22 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +143 -1
- package/dist/index.d.ts +143 -1
- package/dist/index.js +255 -196
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- π **Real-time Timeline** - Visual timeline of all blocking events with duration tracking
|
|
12
12
|
- π― **Active Blockers View** - See all currently active blockers at a glance
|
|
13
|
-
- π **Filtering** - Search by blocker ID or
|
|
13
|
+
- π **Filtering** - Search by blocker ID, reason, or scope (advanced filters via store API)
|
|
14
14
|
- βΈοΈ **Pause/Resume** - Pause event recording to inspect specific moments
|
|
15
15
|
- π **Detailed Event Info** - View full configuration, duration, and state changes
|
|
16
16
|
- π¨ **Customizable Position** - Place devtools panel on the left or right
|
|
@@ -31,7 +31,7 @@ pnpm add @okyrychenko-dev/react-action-guard-devtools
|
|
|
31
31
|
|
|
32
32
|
This package requires the following peer dependencies:
|
|
33
33
|
|
|
34
|
-
- [@okyrychenko-dev/react-action-guard](https://github.com/okyrychenko-dev/react-action-guard) ^0.
|
|
34
|
+
- [@okyrychenko-dev/react-action-guard](https://github.com/okyrychenko-dev/react-action-guard) ^0.6.0
|
|
35
35
|
- [React](https://react.dev/) ^17.0.0 || ^18.0.0 || ^19.0.0
|
|
36
36
|
|
|
37
37
|
## Quick Start
|
|
@@ -216,7 +216,7 @@ See all currently active blockers with:
|
|
|
216
216
|
|
|
217
217
|
Filter events by:
|
|
218
218
|
|
|
219
|
-
- **Search**: Search by blocker ID or
|
|
219
|
+
- **Search**: Search by blocker ID, reason, or scope
|
|
220
220
|
|
|
221
221
|
For action/scope filtering, use `useDevtoolsStore` and `setFilter` in your own UI.
|
|
222
222
|
|
|
@@ -241,9 +241,6 @@ The package is written in TypeScript and includes full type definitions:
|
|
|
241
241
|
|
|
242
242
|
```typescript
|
|
243
243
|
import type {
|
|
244
|
-
// Component types
|
|
245
|
-
ActionGuardDevtoolsProps,
|
|
246
|
-
|
|
247
244
|
// Event types
|
|
248
245
|
DevtoolsEvent,
|
|
249
246
|
DevtoolsFilter,
|
package/dist/index.cjs
CHANGED
|
@@ -3,135 +3,146 @@
|
|
|
3
3
|
var reactActionGuard = require('@okyrychenko-dev/react-action-guard');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var reactZustandToolkit = require('@okyrychenko-dev/react-zustand-toolkit');
|
|
6
|
-
var
|
|
6
|
+
var clsx = require('clsx');
|
|
7
7
|
var zustand = require('zustand');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var shallow = require('zustand/react/shallow');
|
|
10
10
|
|
|
11
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
-
|
|
13
|
-
var clsx2__default = /*#__PURE__*/_interopDefault(clsx2);
|
|
14
|
-
|
|
15
11
|
// src/components/actionGuardDevtools/ActionGuardDevtools.tsx
|
|
16
12
|
|
|
17
13
|
// src/store/devtoolsStore.constants.ts
|
|
18
14
|
var DEFAULT_FILTER = {
|
|
19
|
-
actions: ["add", "remove", "update", "
|
|
15
|
+
actions: ["add", "remove", "update", "timeout", "clear", "clear_scope"],
|
|
20
16
|
scopes: [],
|
|
21
17
|
search: ""
|
|
22
18
|
};
|
|
19
|
+
var createDefaultFilter = () => ({
|
|
20
|
+
actions: [...DEFAULT_FILTER.actions],
|
|
21
|
+
scopes: [...DEFAULT_FILTER.scopes],
|
|
22
|
+
search: DEFAULT_FILTER.search
|
|
23
|
+
});
|
|
23
24
|
var DEFAULT_MAX_EVENTS = 200;
|
|
24
25
|
var DEFAULT_TAB = "timeline";
|
|
25
26
|
|
|
26
27
|
// src/store/devtoolsStore.actions.ts
|
|
27
|
-
var createDevtoolsActions = (set, get) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
isPaused: false,
|
|
37
|
-
// Actions
|
|
38
|
-
/**
|
|
39
|
-
* Add a new event to history
|
|
40
|
-
*
|
|
41
|
-
* @param eventData - Event data without ID (auto-generated)
|
|
42
|
-
*/
|
|
43
|
-
addEvent: (eventData) => {
|
|
44
|
-
if (get().isPaused) {
|
|
45
|
-
return;
|
|
28
|
+
var createDevtoolsActions = (set, get) => {
|
|
29
|
+
let eventCounter = 0;
|
|
30
|
+
const createEventId = (eventData) => {
|
|
31
|
+
eventCounter += 1;
|
|
32
|
+
return `${String(eventData.timestamp)}-${eventData.blockerId}-${eventCounter.toString(36)}`;
|
|
33
|
+
};
|
|
34
|
+
const trimEvents = (events, maxEvents) => {
|
|
35
|
+
if (events.length <= maxEvents) {
|
|
36
|
+
return events;
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
return events.slice(0, maxEvents);
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
// Initial State
|
|
42
|
+
events: [],
|
|
43
|
+
maxEvents: DEFAULT_MAX_EVENTS,
|
|
44
|
+
isOpen: false,
|
|
45
|
+
isMinimized: false,
|
|
46
|
+
activeTab: DEFAULT_TAB,
|
|
47
|
+
filter: createDefaultFilter(),
|
|
48
|
+
selectedEventId: null,
|
|
49
|
+
isPaused: false,
|
|
50
|
+
// Actions
|
|
51
|
+
/**
|
|
52
|
+
* Add a new event to history
|
|
53
|
+
*
|
|
54
|
+
* @param eventData - Event data without ID (auto-generated)
|
|
55
|
+
*/
|
|
56
|
+
addEvent: (eventData) => {
|
|
57
|
+
if (get().isPaused) {
|
|
58
|
+
return;
|
|
55
59
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
60
|
+
const event = {
|
|
61
|
+
...eventData,
|
|
62
|
+
id: createEventId(eventData)
|
|
63
|
+
};
|
|
64
|
+
set((state) => {
|
|
65
|
+
const newEvents = [event, ...state.events];
|
|
66
|
+
return { events: trimEvents(newEvents, state.maxEvents) };
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Clear all events from history
|
|
71
|
+
*/
|
|
72
|
+
clearEvents: () => {
|
|
73
|
+
set({ events: [], selectedEventId: null });
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Toggle panel open/closed state
|
|
77
|
+
*/
|
|
78
|
+
toggleOpen: () => {
|
|
79
|
+
set((state) => ({ isOpen: !state.isOpen }));
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* Set panel open state
|
|
83
|
+
*
|
|
84
|
+
* @param open - Whether panel should be open
|
|
85
|
+
*/
|
|
86
|
+
setOpen: (open) => {
|
|
87
|
+
set({ isOpen: open });
|
|
88
|
+
},
|
|
89
|
+
/**
|
|
90
|
+
* Toggle minimized state
|
|
91
|
+
*/
|
|
92
|
+
toggleMinimized: () => {
|
|
93
|
+
set((state) => ({ isMinimized: !state.isMinimized }));
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Set active tab
|
|
97
|
+
*
|
|
98
|
+
* @param tab - Tab to activate
|
|
99
|
+
*/
|
|
100
|
+
setActiveTab: (tab) => {
|
|
101
|
+
set({ activeTab: tab, selectedEventId: null });
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Update filter settings (partial update)
|
|
105
|
+
*
|
|
106
|
+
* @param filterUpdate - Partial filter update
|
|
107
|
+
*/
|
|
108
|
+
setFilter: (filterUpdate) => {
|
|
109
|
+
set((state) => ({
|
|
110
|
+
filter: { ...state.filter, ...filterUpdate }
|
|
111
|
+
}));
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* Reset filters to default
|
|
115
|
+
*/
|
|
116
|
+
resetFilter: () => {
|
|
117
|
+
set({ filter: createDefaultFilter() });
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* Select an event for detail view
|
|
121
|
+
*
|
|
122
|
+
* @param eventId - Event ID to select (null to deselect)
|
|
123
|
+
*/
|
|
124
|
+
selectEvent: (eventId) => {
|
|
125
|
+
set({ selectedEventId: eventId });
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Toggle pause state (stops/resumes recording)
|
|
129
|
+
*/
|
|
130
|
+
togglePause: () => {
|
|
131
|
+
set((state) => ({ isPaused: !state.isPaused }));
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Set maximum events limit
|
|
135
|
+
*
|
|
136
|
+
* @param max - Maximum number of events to keep
|
|
137
|
+
*/
|
|
138
|
+
setMaxEvents: (max) => {
|
|
139
|
+
set((state) => ({
|
|
140
|
+
maxEvents: max,
|
|
141
|
+
events: trimEvents(state.events, max)
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
};
|
|
135
146
|
|
|
136
147
|
// src/store/devtoolsStore.store.ts
|
|
137
148
|
var {
|
|
@@ -140,40 +151,50 @@ var {
|
|
|
140
151
|
} = reactZustandToolkit.createShallowStore(createDevtoolsActions);
|
|
141
152
|
|
|
142
153
|
// src/store/devtoolsStore.selectors.ts
|
|
154
|
+
function normalizeScopes(scope) {
|
|
155
|
+
if (!scope) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
if (typeof scope === "string") {
|
|
159
|
+
return [scope];
|
|
160
|
+
}
|
|
161
|
+
return scope;
|
|
162
|
+
}
|
|
163
|
+
function matchesActionFilter(event, actions) {
|
|
164
|
+
return actions.length === 0 || actions.includes(event.action);
|
|
165
|
+
}
|
|
166
|
+
function matchesScopeFilter(event, scopes) {
|
|
167
|
+
if (scopes.length === 0) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
const eventScopes = normalizeScopes(event.config?.scope);
|
|
171
|
+
if (eventScopes.length === 0) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return eventScopes.some((scope) => scopes.includes(scope));
|
|
175
|
+
}
|
|
176
|
+
function matchesSearchQuery(event, search) {
|
|
177
|
+
if (!search) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
const searchLower = search.toLowerCase();
|
|
181
|
+
const matchesId = event.blockerId.toLowerCase().includes(searchLower);
|
|
182
|
+
const matchesReason = (event.config?.reason ?? "").toLowerCase().includes(searchLower);
|
|
183
|
+
const matchesScope = normalizeScopes(event.config?.scope).some(
|
|
184
|
+
(scope) => scope.toLowerCase().includes(searchLower)
|
|
185
|
+
);
|
|
186
|
+
return matchesId || matchesReason || matchesScope;
|
|
187
|
+
}
|
|
143
188
|
function selectFilteredEvents(state) {
|
|
144
189
|
const { events, filter } = state;
|
|
145
190
|
return events.filter((event) => {
|
|
146
|
-
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
if (filter.scopes.length > 0) {
|
|
150
|
-
if (!event.config?.scope) {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
const eventScopes = Array.isArray(event.config.scope) ? event.config.scope : [event.config.scope];
|
|
154
|
-
const hasMatchingScope = eventScopes.some((s) => filter.scopes.includes(s));
|
|
155
|
-
if (!hasMatchingScope) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (filter.search) {
|
|
160
|
-
const searchLower = filter.search.toLowerCase();
|
|
161
|
-
const matchesId = event.blockerId.toLowerCase().includes(searchLower);
|
|
162
|
-
const matchesReason = event.config?.reason?.toLowerCase().includes(searchLower);
|
|
163
|
-
if (!matchesId && !matchesReason) {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return true;
|
|
191
|
+
return matchesActionFilter(event, filter.actions) && matchesScopeFilter(event, filter.scopes) && matchesSearchQuery(event, filter.search);
|
|
168
192
|
});
|
|
169
193
|
}
|
|
170
194
|
function selectUniqueScopes(state) {
|
|
171
195
|
const scopes = /* @__PURE__ */ new Set();
|
|
172
196
|
state.events.forEach((event) => {
|
|
173
|
-
|
|
174
|
-
const eventScopes = Array.isArray(event.config.scope) ? event.config.scope : [event.config.scope];
|
|
175
|
-
eventScopes.forEach((s) => scopes.add(s));
|
|
176
|
-
}
|
|
197
|
+
normalizeScopes(event.config?.scope).forEach((scope) => scopes.add(scope));
|
|
177
198
|
});
|
|
178
199
|
return Array.from(scopes).sort();
|
|
179
200
|
}
|
|
@@ -185,19 +206,29 @@ function selectAllEvents(state) {
|
|
|
185
206
|
var DEVTOOLS_MIDDLEWARE_NAME = "action-guard-devtools";
|
|
186
207
|
function createDevtoolsMiddleware() {
|
|
187
208
|
const addTimestamps = /* @__PURE__ */ new Map();
|
|
209
|
+
const terminalActions = /* @__PURE__ */ new Set([
|
|
210
|
+
"remove",
|
|
211
|
+
"timeout",
|
|
212
|
+
"clear",
|
|
213
|
+
"clear_scope"
|
|
214
|
+
]);
|
|
215
|
+
const getDuration = (action, blockerId, timestamp) => {
|
|
216
|
+
if (!terminalActions.has(action)) {
|
|
217
|
+
return void 0;
|
|
218
|
+
}
|
|
219
|
+
const addTime = addTimestamps.get(blockerId);
|
|
220
|
+
if (addTime === void 0) {
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
addTimestamps.delete(blockerId);
|
|
224
|
+
return timestamp - addTime;
|
|
225
|
+
};
|
|
188
226
|
return (context) => {
|
|
189
227
|
const { addEvent } = devtoolsStoreApi.getState();
|
|
190
228
|
if (context.action === "add") {
|
|
191
229
|
addTimestamps.set(context.blockerId, context.timestamp);
|
|
192
230
|
}
|
|
193
|
-
|
|
194
|
-
if (context.action === "remove" || context.action === "timeout" || context.action === "cancel") {
|
|
195
|
-
const addTime = addTimestamps.get(context.blockerId);
|
|
196
|
-
if (addTime !== void 0) {
|
|
197
|
-
duration = context.timestamp - addTime;
|
|
198
|
-
addTimestamps.delete(context.blockerId);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
231
|
+
const duration = getDuration(context.action, context.blockerId, context.timestamp);
|
|
201
232
|
addEvent({
|
|
202
233
|
action: context.action,
|
|
203
234
|
blockerId: context.blockerId,
|
|
@@ -209,6 +240,33 @@ function createDevtoolsMiddleware() {
|
|
|
209
240
|
};
|
|
210
241
|
}
|
|
211
242
|
|
|
243
|
+
// src/components/actionGuardDevtools/ActionGuardDevtools.utils.ts
|
|
244
|
+
function isTypingTarget(target) {
|
|
245
|
+
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
|
|
246
|
+
}
|
|
247
|
+
function getDevtoolsKeyboardAction(event, isOpen) {
|
|
248
|
+
if (!isOpen) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
if (isTypingTarget(event.target)) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
switch (event.key) {
|
|
255
|
+
case "Escape":
|
|
256
|
+
return { action: "close", preventDefault: false };
|
|
257
|
+
case " ":
|
|
258
|
+
return { action: "togglePause", preventDefault: true };
|
|
259
|
+
case "c":
|
|
260
|
+
case "C":
|
|
261
|
+
if (!event.metaKey && !event.ctrlKey) {
|
|
262
|
+
return { action: "clearEvents", preventDefault: false };
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
default:
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
212
270
|
// src/styles/position.module.css
|
|
213
271
|
var position_default = {};
|
|
214
272
|
|
|
@@ -220,7 +278,7 @@ function getPositionClass(position) {
|
|
|
220
278
|
return position === "left" ? position_default.positionLeft : position_default.positionRight;
|
|
221
279
|
}
|
|
222
280
|
function getPanelClassName(position, isMinimized) {
|
|
223
|
-
return
|
|
281
|
+
return clsx.clsx(
|
|
224
282
|
DevtoolsPanel_default.panel,
|
|
225
283
|
position_default.positionBase,
|
|
226
284
|
getPositionClass(position),
|
|
@@ -280,28 +338,52 @@ var COLORS = {
|
|
|
280
338
|
var shared_default = {};
|
|
281
339
|
function Badge(props) {
|
|
282
340
|
const { children, className, style } = props;
|
|
283
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className:
|
|
341
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx.clsx(shared_default.badge, className), style, children });
|
|
284
342
|
}
|
|
285
343
|
var Badge_default = Badge;
|
|
286
344
|
function Content(props) {
|
|
287
345
|
const { children, className } = props;
|
|
288
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className:
|
|
346
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx.clsx(shared_default.content, className), children });
|
|
289
347
|
}
|
|
290
348
|
var Content_default = Content;
|
|
291
349
|
function EmptyState(props) {
|
|
292
350
|
const { children, className } = props;
|
|
293
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className:
|
|
351
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx.clsx(shared_default.emptyState, className), children });
|
|
294
352
|
}
|
|
295
353
|
var EmptyState_default = EmptyState;
|
|
354
|
+
var ErrorBoundary = class extends react.Component {
|
|
355
|
+
constructor(props) {
|
|
356
|
+
super(props);
|
|
357
|
+
this.state = { hasError: false, error: null };
|
|
358
|
+
}
|
|
359
|
+
static getDerivedStateFromError(error) {
|
|
360
|
+
return { hasError: true, error };
|
|
361
|
+
}
|
|
362
|
+
render() {
|
|
363
|
+
const { hasError, error } = this.state;
|
|
364
|
+
const { children, fallback } = this.props;
|
|
365
|
+
if (hasError) {
|
|
366
|
+
if (fallback) {
|
|
367
|
+
return fallback;
|
|
368
|
+
}
|
|
369
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: shared_default.errorBoundary, children: [
|
|
370
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: shared_default.errorTitle, children: "Devtools Error" }),
|
|
371
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: shared_default.errorMessage, children: error?.message ?? "Unknown error" })
|
|
372
|
+
] });
|
|
373
|
+
}
|
|
374
|
+
return children;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
var ErrorBoundary_default = ErrorBoundary;
|
|
296
378
|
function EventBadge(props) {
|
|
297
379
|
const { children, className, style, action } = props;
|
|
298
|
-
const classes =
|
|
380
|
+
const classes = clsx.clsx(shared_default.eventBadge, action && shared_default.eventBadgeAction, className);
|
|
299
381
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: classes, style, "data-action": action, children });
|
|
300
382
|
}
|
|
301
383
|
var EventBadge_default = EventBadge;
|
|
302
384
|
function IconButton(props) {
|
|
303
385
|
const { children, className, type = "button", ...others } = props;
|
|
304
|
-
return /* @__PURE__ */ jsxRuntime.jsx("button", { type, className:
|
|
386
|
+
return /* @__PURE__ */ jsxRuntime.jsx("button", { type, className: clsx.clsx(shared_default.iconButton, className), ...others, children });
|
|
305
387
|
}
|
|
306
388
|
var IconButton_default = IconButton;
|
|
307
389
|
|
|
@@ -428,7 +510,7 @@ function EventItem(props) {
|
|
|
428
510
|
const handleSelect = () => {
|
|
429
511
|
onSelect(selected ? null : event.id);
|
|
430
512
|
};
|
|
431
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className:
|
|
513
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: clsx.clsx(EventItem_default.eventItem, selected && EventItem_default.selected), onClick: handleSelect, children: [
|
|
432
514
|
/* @__PURE__ */ jsxRuntime.jsx(EventItemHeader_default, { event }),
|
|
433
515
|
/* @__PURE__ */ jsxRuntime.jsx(EventItemDetails_default, { event })
|
|
434
516
|
] });
|
|
@@ -601,7 +683,7 @@ function Timeline() {
|
|
|
601
683
|
);
|
|
602
684
|
const selectedEvent = selectedEventId ? events.find((e) => e.id === selectedEventId) : null;
|
|
603
685
|
react.useEffect(() => {
|
|
604
|
-
if (selectedEventId && !allEvents.some((
|
|
686
|
+
if (selectedEventId && !allEvents.some((event) => event.id === selectedEventId)) {
|
|
605
687
|
selectEvent(null);
|
|
606
688
|
}
|
|
607
689
|
}, [selectedEventId, allEvents, selectEvent]);
|
|
@@ -633,7 +715,7 @@ function Timeline() {
|
|
|
633
715
|
var Timeline_default2 = Timeline;
|
|
634
716
|
function DevtoolsPanelContent(props) {
|
|
635
717
|
const { activeTab, store } = props;
|
|
636
|
-
return activeTab === "timeline" ? /* @__PURE__ */ jsxRuntime.jsx(Timeline_default2, {}) : /* @__PURE__ */ jsxRuntime.jsx(ActiveBlockers_default2, { store });
|
|
718
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary_default, { children: activeTab === "timeline" ? /* @__PURE__ */ jsxRuntime.jsx(Timeline_default2, {}) : /* @__PURE__ */ jsxRuntime.jsx(ActiveBlockers_default2, { store }) });
|
|
637
719
|
}
|
|
638
720
|
var DevtoolsPanelContent_default = DevtoolsPanelContent;
|
|
639
721
|
var MaximizeIcon = createSvgIcon(/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 3h18v2H3z" }));
|
|
@@ -644,7 +726,7 @@ function getMinimizeButtonTitle(isMinimized) {
|
|
|
644
726
|
return isMinimized ? "Maximize" : "Minimize";
|
|
645
727
|
}
|
|
646
728
|
function getPauseButtonClassName(isPaused) {
|
|
647
|
-
return
|
|
729
|
+
return clsx.clsx(isPaused && DevtoolsPanel_default.pauseButtonActive);
|
|
648
730
|
}
|
|
649
731
|
function DevtoolsPanelHeader(props) {
|
|
650
732
|
const {
|
|
@@ -693,7 +775,7 @@ function DevtoolsPanelTabs(props) {
|
|
|
693
775
|
onClick: () => {
|
|
694
776
|
onSelectTab(tab.id);
|
|
695
777
|
},
|
|
696
|
-
className:
|
|
778
|
+
className: clsx.clsx(DevtoolsPanel_default.tab, activeTab === tab.id && DevtoolsPanel_default.tabActive),
|
|
697
779
|
children: tab.label
|
|
698
780
|
},
|
|
699
781
|
tab.id
|
|
@@ -746,7 +828,7 @@ function getPositionClass2(position) {
|
|
|
746
828
|
return position === "left" ? position_default.positionLeft : position_default.positionRight;
|
|
747
829
|
}
|
|
748
830
|
function getToggleButtonClassName(position) {
|
|
749
|
-
return
|
|
831
|
+
return clsx.clsx(
|
|
750
832
|
ToggleButton_default.toggleButton,
|
|
751
833
|
position_default.positionBase,
|
|
752
834
|
getPositionClass2(position),
|
|
@@ -757,7 +839,7 @@ function shouldShowBadge(count) {
|
|
|
757
839
|
return count > 0;
|
|
758
840
|
}
|
|
759
841
|
function getBadgeClassName(isPaused) {
|
|
760
|
-
return
|
|
842
|
+
return clsx.clsx(ToggleButton_default.badgePosition, isPaused ? ToggleButton_default.badgePaused : ToggleButton_default.badgeActive);
|
|
761
843
|
}
|
|
762
844
|
function ToggleButtonBadge(props) {
|
|
763
845
|
const { count, isPaused } = props;
|
|
@@ -798,41 +880,8 @@ function ActionGuardDevtoolsContent(props) {
|
|
|
798
880
|
] });
|
|
799
881
|
}
|
|
800
882
|
var ActionGuardDevtoolsContent_default = ActionGuardDevtoolsContent;
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
function isTypingTarget(target) {
|
|
804
|
-
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
|
|
805
|
-
}
|
|
806
|
-
function getDevtoolsKeyboardAction(event, isOpen) {
|
|
807
|
-
if (!isOpen) {
|
|
808
|
-
return null;
|
|
809
|
-
}
|
|
810
|
-
if (isTypingTarget(event.target)) {
|
|
811
|
-
return null;
|
|
812
|
-
}
|
|
813
|
-
switch (event.key) {
|
|
814
|
-
case "Escape":
|
|
815
|
-
return { action: "close", preventDefault: false };
|
|
816
|
-
case " ":
|
|
817
|
-
return { action: "togglePause", preventDefault: true };
|
|
818
|
-
case "c":
|
|
819
|
-
case "C":
|
|
820
|
-
if (!event.metaKey && !event.ctrlKey) {
|
|
821
|
-
return { action: "clearEvents", preventDefault: false };
|
|
822
|
-
}
|
|
823
|
-
return null;
|
|
824
|
-
default:
|
|
825
|
-
return null;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
function ActionGuardDevtools(props) {
|
|
829
|
-
const {
|
|
830
|
-
position = "right",
|
|
831
|
-
defaultOpen = false,
|
|
832
|
-
maxEvents = 200,
|
|
833
|
-
showInProduction = false,
|
|
834
|
-
store: customStore
|
|
835
|
-
} = props;
|
|
883
|
+
function ActionGuardDevtoolsInternal(props) {
|
|
884
|
+
const { position = "right", defaultOpen = false, maxEvents = 200, store: customStore } = props;
|
|
836
885
|
const { setOpen, setMaxEvents, isOpen, togglePause, clearEvents } = useDevtoolsStore();
|
|
837
886
|
const targetStore = react.useMemo(() => customStore ?? reactActionGuard.uiBlockingStoreApi, [customStore]);
|
|
838
887
|
react.useEffect(() => {
|
|
@@ -847,9 +896,14 @@ function ActionGuardDevtools(props) {
|
|
|
847
896
|
setOpen(defaultOpen);
|
|
848
897
|
setMaxEvents(maxEvents);
|
|
849
898
|
}, [defaultOpen, maxEvents, setOpen, setMaxEvents]);
|
|
850
|
-
const
|
|
851
|
-
|
|
852
|
-
|
|
899
|
+
const stateRef = react.useRef({ isOpen, setOpen, togglePause, clearEvents });
|
|
900
|
+
react.useEffect(() => {
|
|
901
|
+
stateRef.current = { isOpen, setOpen, togglePause, clearEvents };
|
|
902
|
+
}, [isOpen, setOpen, togglePause, clearEvents]);
|
|
903
|
+
react.useEffect(() => {
|
|
904
|
+
const handleKeyDown = (event) => {
|
|
905
|
+
const { isOpen: isOpen2, setOpen: setOpen2, togglePause: togglePause2, clearEvents: clearEvents2 } = stateRef.current;
|
|
906
|
+
const action = getDevtoolsKeyboardAction(event, isOpen2);
|
|
853
907
|
if (!action) {
|
|
854
908
|
return;
|
|
855
909
|
}
|
|
@@ -858,28 +912,29 @@ function ActionGuardDevtools(props) {
|
|
|
858
912
|
}
|
|
859
913
|
switch (action.action) {
|
|
860
914
|
case "close":
|
|
861
|
-
|
|
915
|
+
setOpen2(false);
|
|
862
916
|
break;
|
|
863
917
|
case "togglePause":
|
|
864
|
-
|
|
918
|
+
togglePause2();
|
|
865
919
|
break;
|
|
866
920
|
case "clearEvents":
|
|
867
|
-
|
|
921
|
+
clearEvents2();
|
|
868
922
|
break;
|
|
869
923
|
}
|
|
870
|
-
}
|
|
871
|
-
[isOpen, setOpen, togglePause, clearEvents]
|
|
872
|
-
);
|
|
873
|
-
react.useEffect(() => {
|
|
924
|
+
};
|
|
874
925
|
document.addEventListener("keydown", handleKeyDown);
|
|
875
926
|
return () => {
|
|
876
927
|
document.removeEventListener("keydown", handleKeyDown);
|
|
877
928
|
};
|
|
878
|
-
}, [
|
|
929
|
+
}, []);
|
|
930
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ActionGuardDevtoolsContent_default, { position, store: customStore });
|
|
931
|
+
}
|
|
932
|
+
function ActionGuardDevtools(props) {
|
|
933
|
+
const { showInProduction = false, ...others } = props;
|
|
879
934
|
if (process.env.NODE_ENV === "production" && !showInProduction) {
|
|
880
935
|
return null;
|
|
881
936
|
}
|
|
882
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
937
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ActionGuardDevtoolsInternal, { ...others });
|
|
883
938
|
}
|
|
884
939
|
var ActionGuardDevtools_default = ActionGuardDevtools;
|
|
885
940
|
|