@rtk-devtools/ui 0.1.0 → 0.3.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/README.md ADDED
@@ -0,0 +1,89 @@
1
+ <p align="center">
2
+ <a href="https://lilohq.com">
3
+ <img src="../../lilo-logo.svg" alt="Lilo" width="200" />
4
+ </a>
5
+ <br />
6
+ This project couldn't be possible without <a href="https://lilohq.com">lilohq.com</a>.
7
+ </p>
8
+
9
+ ---
10
+
11
+ # @rtk-devtools/ui
12
+
13
+ Shared React UI components and panels for RTK Devtools. This package provides the themed panel views and reusable components used by `@rtk-devtools/react`.
14
+
15
+ This package is part of [RTK Devtools](https://github.com/enBonnet/rtk-devtools). For the full devtools experience, install all three packages:
16
+
17
+ ```bash
18
+ npm install @rtk-devtools/core @rtk-devtools/ui @rtk-devtools/react
19
+ ```
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @rtk-devtools/ui
25
+ # or
26
+ pnpm add @rtk-devtools/ui
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### Panels
32
+
33
+ | Panel | Description |
34
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35
+ | `QueriesPanel` | Browse cached queries with status, timing, subscriber count, and cache expiration countdowns. Master-detail view with data inspection, filtering, and sorting |
36
+ | `MutationsPanel` | Track mutation lifecycle with arguments, results, errors, and which tags each mutation invalidated |
37
+ | `TagsPanel` | Three-column visualization of tag relationships: tag types, provider queries, and invalidator mutations |
38
+ | `SubscriptionsPanel` | Table view of subscriber counts per cache entry, polling intervals, and expiring cache entries with countdown timers |
39
+ | `TimelinePanel` | Chronological event log of all RTK Query activity: starts, completions, failures, invalidations, and subscription changes |
40
+
41
+ ### Components
42
+
43
+ | Component | Description |
44
+ | ----------------- | --------------------------------------------------------------------------------------- |
45
+ | `StatusBadge` | Query/mutation status indicator (pending, fulfilled, rejected) |
46
+ | `TagChip` | Tag type display chip |
47
+ | `CacheKeyDisplay` | Formatted cache key display |
48
+ | `DataExplorer` | Collapsible JSON data inspector |
49
+ | `PanelTabs` | Tab navigation for panels. Accepts `TabItem[]` with `id`, `label`, and optional `count` |
50
+ | `SearchFilter` | Search and filter input |
51
+ | `TimeAgo` | Relative timestamp display |
52
+ | `TimingBar` | Visual timing indicator |
53
+
54
+ ### Theme
55
+
56
+ Built-in dark and light themes using [goober](https://github.com/cristianbote/goober) for CSS-in-JS.
57
+
58
+ | Export | Description |
59
+ | ----------------------- | --------------------------------------------------------------------------------- |
60
+ | `DevtoolsThemeProvider` | Theme context provider. Accepts a `mode` prop: `"light"`, `"dark"`, or `"system"` |
61
+ | `useTheme()` | Hook to access the current `Theme` object inside the provider |
62
+ | `lightTheme` | Light theme token set |
63
+ | `darkTheme` | Dark theme token set |
64
+
65
+ ```tsx
66
+ import {
67
+ DevtoolsThemeProvider,
68
+ lightTheme,
69
+ darkTheme,
70
+ useTheme,
71
+ } from "@rtk-devtools/ui";
72
+ ```
73
+
74
+ ### Exported Types
75
+
76
+ `ThemeMode`, `Theme`, `TabItem`
77
+
78
+ ## Peer Dependencies
79
+
80
+ - `react` >= 18.0.0
81
+ - `react-dom` >= 18.0.0
82
+
83
+ ## Inspiration
84
+
85
+ This project is inspired by [TanStack DevTools](https://github.com/tanstack/devtools).
86
+
87
+ ## License
88
+
89
+ MIT
package/dist/index.cjs CHANGED
@@ -449,9 +449,14 @@ function ExpandToggle({
449
449
  }
450
450
  );
451
451
  }
452
- function PanelTabs({ tabs, activeTab, onTabChange }) {
452
+ function PanelTabs({
453
+ tabs,
454
+ activeTab,
455
+ onTabChange,
456
+ onClose
457
+ }) {
453
458
  const { theme } = useTheme();
454
- return /* @__PURE__ */ jsxRuntime.jsx(
459
+ return /* @__PURE__ */ jsxRuntime.jsxs(
455
460
  "div",
456
461
  {
457
462
  className: goober.css({
@@ -459,44 +464,86 @@ function PanelTabs({ tabs, activeTab, onTabChange }) {
459
464
  alignItems: "center",
460
465
  borderBottom: `1px solid ${theme.border.primary}`,
461
466
  backgroundColor: theme.bg.secondary,
462
- padding: "0 8px",
463
- gap: "2px",
464
- overflowX: "auto",
465
467
  flexShrink: 0
466
468
  }),
467
- children: tabs.map((tab) => {
468
- const isActive = tab.id === activeTab;
469
- return /* @__PURE__ */ jsxRuntime.jsxs(
469
+ children: [
470
+ /* @__PURE__ */ jsxRuntime.jsx(
471
+ "div",
472
+ {
473
+ className: goober.css({
474
+ display: "flex",
475
+ alignItems: "center",
476
+ padding: "0 8px",
477
+ gap: "2px",
478
+ overflowX: "auto",
479
+ flex: 1,
480
+ minWidth: 0
481
+ }),
482
+ children: tabs.map((tab) => {
483
+ const isActive = tab.id === activeTab;
484
+ return /* @__PURE__ */ jsxRuntime.jsxs(
485
+ "button",
486
+ {
487
+ onClick: () => onTabChange(tab.id),
488
+ className: goober.css({
489
+ display: "inline-flex",
490
+ alignItems: "center",
491
+ gap: "4px",
492
+ padding: "8px 12px",
493
+ border: "none",
494
+ background: "none",
495
+ color: isActive ? theme.text.link : theme.text.secondary,
496
+ fontSize: "12px",
497
+ fontWeight: isActive ? 600 : 400,
498
+ cursor: "pointer",
499
+ borderBottom: isActive ? `2px solid ${theme.brand[500]}` : "2px solid transparent",
500
+ marginBottom: "-1px",
501
+ whiteSpace: "nowrap",
502
+ transition: "color 0.15s, border-color 0.15s",
503
+ ":hover": {
504
+ color: theme.text.primary
505
+ }
506
+ }),
507
+ children: [
508
+ tab.label,
509
+ tab.count !== void 0 && tab.count > 0 && /* @__PURE__ */ jsxRuntime.jsx(CountBadge, { count: tab.count, active: isActive })
510
+ ]
511
+ },
512
+ tab.id
513
+ );
514
+ })
515
+ }
516
+ ),
517
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(
470
518
  "button",
471
519
  {
472
- onClick: () => onTabChange(tab.id),
520
+ onClick: onClose,
521
+ "aria-label": "Close devtools",
473
522
  className: goober.css({
474
523
  display: "inline-flex",
475
524
  alignItems: "center",
476
- gap: "4px",
477
- padding: "8px 12px",
525
+ justifyContent: "center",
526
+ width: "28px",
527
+ height: "28px",
528
+ margin: "0 4px",
478
529
  border: "none",
479
530
  background: "none",
480
- color: isActive ? theme.text.link : theme.text.secondary,
481
- fontSize: "12px",
482
- fontWeight: isActive ? 600 : 400,
531
+ color: theme.text.secondary,
532
+ fontSize: "14px",
533
+ lineHeight: 1,
483
534
  cursor: "pointer",
484
- borderBottom: isActive ? `2px solid ${theme.brand[500]}` : "2px solid transparent",
485
- marginBottom: "-1px",
486
- whiteSpace: "nowrap",
487
- transition: "color 0.15s, border-color 0.15s",
535
+ borderRadius: "4px",
536
+ flexShrink: 0,
537
+ transition: "color 0.15s, background-color 0.15s",
488
538
  ":hover": {
489
- color: theme.text.primary
539
+ color: theme.text.primary,
540
+ backgroundColor: theme.bg.tertiary
490
541
  }
491
542
  }),
492
- children: [
493
- tab.label,
494
- tab.count !== void 0 && tab.count > 0 && /* @__PURE__ */ jsxRuntime.jsx(CountBadge, { count: tab.count, active: isActive })
495
- ]
496
- },
497
- tab.id
498
- );
499
- })
543
+ children: "\u2715"
544
+ }
545
+ )
546
+ ]
500
547
  }
501
548
  );
502
549
  }