react-zeugma 6.9.6 → 6.9.8
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 +36 -41
- package/dist/devtools.cjs +1 -1
- package/dist/devtools.cjs.map +1 -1
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +1 -1
- package/dist/devtools.js.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/{render-counter-footer-CYe6-Atc.d.cts → render-counter-footer-rAKCzuRX.d.cts} +2 -2
- package/dist/{render-counter-footer-CYe6-Atc.d.ts → render-counter-footer-rAKCzuRX.d.ts} +2 -2
- package/dist/{types-DQICRtw1.d.cts → types-DFl4yzkP.d.cts} +9 -0
- package/dist/{types-DQICRtw1.d.ts → types-DFl4yzkP.d.ts} +9 -0
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,28 +96,29 @@ import { Zeugma } from 'react-zeugma'
|
|
|
96
96
|
|
|
97
97
|
##### Props
|
|
98
98
|
|
|
99
|
-
| Property | Description
|
|
100
|
-
| ------------------------ |
|
|
101
|
-
| `controller` | The layout state controller returned by `useZeugma(options)`.
|
|
102
|
-
| `children` | Children components rendered inside the context provider.
|
|
103
|
-
| `renderPane` | Callback function to map active pane IDs to custom pane structures. Required in standalone mode (without children) and must not be passed in provider mode.
|
|
104
|
-
| `renderDragOverlay` | Custom overlay renderer function for the drag-under-cursor preview.
|
|
105
|
-
| `classNames` | CSS class name mapping overrides for custom dashboard and overlay styling.
|
|
106
|
-
| `resizerSize` | Thickness of the split resizer bars in pixels.
|
|
107
|
-
| `dragActivationDistance` | Minimum pointer drag distance (in pixels) required to activate dragging.
|
|
108
|
-
| `snapThreshold` | Threshold in pixels to snap layout resizers to adjacent edges.
|
|
109
|
-
| `minSplitPercentage` | Minimum split limit percentage allowed for resized panes.
|
|
110
|
-
| `maxSplitPercentage` | Maximum split limit percentage allowed for resized panes.
|
|
111
|
-
| `enableDragToDismiss` | Enables drag-out-to-dismiss gesture for widgets.
|
|
112
|
-
| `dismissThreshold` | Distance in pixels outside container bounds required to trigger dismissal.
|
|
113
|
-
| `onRemove` | Callback triggered when a pane is removed.
|
|
114
|
-
| `onDragStart` | Callback triggered when a drag gesture begins.
|
|
115
|
-
| `onDragEnd` | Callback triggered when a drag gesture ends, containing active pane, target pane, and action metadata.
|
|
116
|
-
| `onResizeStart` | Callback triggered when resizing begins.
|
|
117
|
-
| `onResize` | Callback triggered during pane resizing.
|
|
118
|
-
| `onResizeEnd` | Callback triggered when pane resizing completes.
|
|
119
|
-
| `onDismissIntentChange` | Callback triggered when drag-out dismiss intent changes.
|
|
120
|
-
| `persist` | Layout persistence configuration in localStorage. If true, uses default options.
|
|
99
|
+
| Property | Description | Type | Default |
|
|
100
|
+
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
|
101
|
+
| `controller` | The layout state controller returned by `useZeugma(options)`. | `ZeugmaController` | - |
|
|
102
|
+
| `children` | Children components rendered inside the context provider. | `ReactNode` | - |
|
|
103
|
+
| `renderPane` | Callback function to map active pane IDs to custom pane structures. Required in standalone mode (without children) and must not be passed in provider mode. | `(paneId: string) => ReactNode` | - |
|
|
104
|
+
| `renderDragOverlay` | Custom overlay renderer function for the drag-under-cursor preview. | `(active: DragOverlayActiveItem) => ReactNode` | - |
|
|
105
|
+
| `classNames` | CSS class name mapping overrides for custom dashboard and overlay styling. | `ZeugmaClassNames` | - |
|
|
106
|
+
| `resizerSize` | Thickness of the split resizer bars in pixels. | `number` | `4` |
|
|
107
|
+
| `dragActivationDistance` | Minimum pointer drag distance (in pixels) required to activate dragging. | `number` | `8` |
|
|
108
|
+
| `snapThreshold` | Threshold in pixels to snap layout resizers to adjacent edges. | `number` | `8` |
|
|
109
|
+
| `minSplitPercentage` | Minimum split limit percentage allowed for resized panes. | `number` | `5` |
|
|
110
|
+
| `maxSplitPercentage` | Maximum split limit percentage allowed for resized panes. | `number` | `95` |
|
|
111
|
+
| `enableDragToDismiss` | Enables drag-out-to-dismiss gesture for widgets. | `boolean` | `false` |
|
|
112
|
+
| `dismissThreshold` | Distance in pixels outside container bounds required to trigger dismissal. | `number` | `60` |
|
|
113
|
+
| `onRemove` | Callback triggered when a pane is removed. | `(paneId: string) => void` | - |
|
|
114
|
+
| `onDragStart` | Callback triggered when a drag gesture begins. | `(activeId: string) => void` | - |
|
|
115
|
+
| `onDragEnd` | Callback triggered when a drag gesture ends, containing active pane, target pane, and action metadata. | `(activeId: string, overId: string \| null, dropAction: { type: 'split' \| 'move'; direction?: SplitDirection; position?: 'top' \| 'bottom' \| 'left' \| 'right' \| 'center' } \| null) => void` | - |
|
|
116
|
+
| `onResizeStart` | Callback triggered when resizing begins. | `(currentNode: SplitNode) => void` | - |
|
|
117
|
+
| `onResize` | Callback triggered during pane resizing. | `(currentNode: SplitNode, percentage: number) => void` | - |
|
|
118
|
+
| `onResizeEnd` | Callback triggered when pane resizing completes. | `(currentNode: SplitNode, percentage: number) => void` | - |
|
|
119
|
+
| `onDismissIntentChange` | Callback triggered when drag-out dismiss intent changes. | `(paneId: string \| null) => void` | - |
|
|
120
|
+
| `persist` | Layout persistence configuration in localStorage. If true, uses default options. | `boolean \| ZeugmaPersistOptions` | `false` |
|
|
121
|
+
| `renderPopoutWrapper` | **[Experimental]** Custom wrapper to inject context or style managers (e.g. `styled-components`' `StyleSheetManager` or `antd`'s `StyleProvider`/`ConfigProvider`) into popout windows. | `(props: { tabId: string; document: Document; window: Window; children: React.ReactNode }) => React.ReactNode` | - |
|
|
121
122
|
|
|
122
123
|
##### `ZeugmaPersistOptions`
|
|
123
124
|
|
|
@@ -507,9 +508,7 @@ const parentPane = findPaneContainingTab(currentTree, 'new-file.js')
|
|
|
507
508
|
|
|
508
509
|
When using CSS-in-JS libraries like `styled-components` or `antd` (Ant Design) inside your widgets, dynamic styles are injected into the main document's `<head>` by default. In popped-out tabs, these dynamic styles will not apply because they render inside a separate window. Additionally, shared JS context caches will prevent styles from being re-emitted unless a separate cache instance is created.
|
|
509
510
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
Because React Zeugma globally intercepts and patches `document` references (like `document.head` and `document.body`) during the portal rendering phase, you can pass the global `document` reference directly to the providers. It will automatically resolve to the correct active window's document.
|
|
511
|
+
You can use the `renderPopoutWrapper` callback prop on the `<Zeugma>` component to wrap popped-out widgets with the required style managers and providers targeting the child window's DOM.
|
|
513
512
|
|
|
514
513
|
##### Example (`styled-components` & `antd`):
|
|
515
514
|
|
|
@@ -519,8 +518,8 @@ import { StyleSheetManager } from 'styled-components'
|
|
|
519
518
|
import { StyleProvider, createCache } from '@ant-design/cssinjs'
|
|
520
519
|
import { ConfigProvider } from 'antd'
|
|
521
520
|
|
|
522
|
-
//
|
|
523
|
-
const
|
|
521
|
+
// Using a wrapper component is recommended to safely instantiate a style cache per popout window
|
|
522
|
+
const PopoutStyleManager = ({ document, children }) => {
|
|
524
523
|
const cache = useMemo(() => createCache(), [])
|
|
525
524
|
|
|
526
525
|
return (
|
|
@@ -532,18 +531,14 @@ const StableStyleManager = ({ children }) => {
|
|
|
532
531
|
)
|
|
533
532
|
}
|
|
534
533
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
<
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
)}
|
|
544
|
-
</Pane.Content>
|
|
545
|
-
</Pane>
|
|
546
|
-
)
|
|
534
|
+
;<Zeugma
|
|
535
|
+
controller={controller}
|
|
536
|
+
renderPopoutWrapper={({ document, children }) => (
|
|
537
|
+
<PopoutStyleManager document={document}>{children}</PopoutStyleManager>
|
|
538
|
+
)}
|
|
539
|
+
>
|
|
540
|
+
{/* Dashboard grid structure */}
|
|
541
|
+
</Zeugma>
|
|
547
542
|
```
|
|
548
543
|
|
|
549
544
|
---
|
|
@@ -578,5 +573,5 @@ function MyDashboardWidget({ id }: { id: string }) {
|
|
|
578
573
|
### Components & Hooks
|
|
579
574
|
|
|
580
575
|
- `useRenderCounter(idOrOptions?, options?)`: React 18/19 StrictMode-safe hook returning `{ mounts, renders, reset }`.
|
|
581
|
-
- `<RenderCounterBadge id={id} position="top-right" />`:
|
|
582
|
-
- `<RenderCounterFooter id={id} label="Widget Name">`:
|
|
576
|
+
- `<RenderCounterBadge id={id} position="top-right" className="..." />`: Unstyled overlay badge for any panel or component.
|
|
577
|
+
- `<RenderCounterFooter id={id} label="Widget Name" className="..." footerClassName="...">`: Unstyled wrapper component rendering a bottom status footer for tabbed widgets.
|
package/dist/devtools.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var a=new Map;function i(r){let e=a.get(r);return e||(e={mounts:0,renders:0,listeners:new Set},a.set(r,e)),e}function N(r,e){let n=i(r);return n.listeners.add(e),()=>{n.listeners.delete(e);}}function g(r){let e=a.get(r);e&&e.listeners.forEach(n=>n());}function v(r){let e=a.get(r);e&&(e.mounts=0,e.renders=0,g(r));}function S(){a.clear();}function p(r,e){let n=react.useId(),c=typeof r=="string"?{id:r,...e}:r||{},{id:t=n,logToConsole:u=false,disabled:o=false}=c,s=react.useRef(0),l=react.useRef(false),[,R]=react.useState(0);if(o||(s.current+=1),react.useEffect(()=>{if(o)return;let C=N(t,()=>{R(P=>P+1);}),b=i(t);return b.mounts+=1,l.current=true,u&&console.log(`[DevTools:${t}] Mounted: ${b.mounts} | Rendered: ${s.current}`),g(t),()=>{l.current=false,C();}},[t,o,u]),!o){let C=i(t);C.renders=Math.max(C.renders,s.current);}let m=react.useCallback(()=>{s.current=0,v(t);},[t]);return o?{mounts:0,renders:0,reset:m}:{mounts:i(t).mounts,renders:s.current,reset:m}}function G({id:r,className:e,style:n,logToConsole:c=false,disabled:t=false}){let{mounts:u,renders:o}=p(r,{logToConsole:c,disabled:t});return t?null:jsxRuntime.jsxs("div",{className:e,style:n,children:[jsxRuntime.jsxs("span",{children:["M: ",jsxRuntime.jsx("strong",{children:u})]}),jsxRuntime.jsx("span",{children:"|"}),jsxRuntime.jsxs("span",{children:["R: ",jsxRuntime.jsx("strong",{children:o})]})]})}function I({id:r,label:e,children:n,className:c,footerClassName:t,style:u,logToConsole:o=false,disabled:s=false}){let l=e||r||"widget",{mounts:R,renders:m}=p(r,{logToConsole:o,disabled:s});return s?jsxRuntime.jsx(jsxRuntime.Fragment,{children:n}):jsxRuntime.jsxs("div",{className:c,style:u,children:[n&&jsxRuntime.jsx("div",{className:"flex-1 overflow-hidden relative min-h-0",children:n}),jsxRuntime.jsxs("div",{className:t,children:[jsxRuntime.jsx("span",{className:"truncate",children:l}),jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsxs("span",{children:["Mounts: ",jsxRuntime.jsx("strong",{className:"counter-mounts",children:R})]}),jsxRuntime.jsx("span",{children:"|"}),jsxRuntime.jsxs("span",{children:["Renders: ",jsxRuntime.jsx("strong",{className:"counter-renders",children:m})]})]})]})]})}exports.RenderCounterBadge=G;exports.RenderCounterFooter=I;exports.clearAllCounters=S;exports.resetCounterRecord=v;exports.useRenderCounter=p;//# sourceMappingURL=devtools.cjs.map
|
|
2
2
|
//# sourceMappingURL=devtools.cjs.map
|
package/dist/devtools.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools/store.ts","../src/devtools/use-render-counter.ts","../src/devtools/render-counter-badge.tsx","../src/devtools/render-counter-footer.tsx"],"names":["store","getCounterRecord","id","record","subscribeCounter","listener","notifyCounter","fn","resetCounterRecord","clearAllCounters","useRenderCounter","idOrOptions","maybeOptions","defaultAutoId","useId","options","logToConsole","disabled","renderCountRef","useRef","isMountedRef","forceUpdate","useState","useEffect","unsubscribe","c","reset","useCallback","POSITION_STYLES","RenderCounterBadge","position","className","style","mounts","renders","posClass","jsxs","jsx","RenderCounterFooter","label","children","footerClassName","displayId","Fragment"],"mappings":"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","file":"devtools.cjs","sourcesContent":["type Listener = () => void\n\ninterface GlobalCounterRecord {\n mounts: number\n renders: number\n listeners: Set<Listener>\n}\n\nconst store = new Map<string, GlobalCounterRecord>()\n\nexport function getCounterRecord(id: string): GlobalCounterRecord {\n let record = store.get(id)\n if (!record) {\n record = { mounts: 0, renders: 0, listeners: new Set() }\n store.set(id, record)\n }\n return record\n}\n\nexport function subscribeCounter(id: string, listener: Listener): () => void {\n const record = getCounterRecord(id)\n record.listeners.add(listener)\n return () => {\n record.listeners.delete(listener)\n }\n}\n\nexport function notifyCounter(id: string) {\n const record = store.get(id)\n if (record) {\n record.listeners.forEach((fn) => fn())\n }\n}\n\nexport function resetCounterRecord(id: string) {\n const record = store.get(id)\n if (record) {\n record.mounts = 0\n record.renders = 0\n notifyCounter(id)\n }\n}\n\nexport function clearAllCounters() {\n store.clear()\n}\n","'use client'\n\nimport { useRef, useEffect, useState, useCallback, useId } from 'react'\nimport type { RenderCounterOptions, RenderCounterState } from './types'\nimport { getCounterRecord, subscribeCounter, notifyCounter, resetCounterRecord } from './store'\n\n/**\n * A React hook that tracks component mount and render counts in a React 18/19 StrictMode safe manner.\n * Supports optional global ID sharing, console logging, and manual reset.\n */\nexport function useRenderCounter(\n idOrOptions?: string | RenderCounterOptions,\n maybeOptions?: RenderCounterOptions,\n): RenderCounterState {\n const defaultAutoId = useId()\n\n const options: RenderCounterOptions =\n typeof idOrOptions === 'string' ? { id: idOrOptions, ...maybeOptions } : idOrOptions || {}\n\n const { id = defaultAutoId, logToConsole = false, disabled = false } = options\n\n const renderCountRef = useRef<number>(0)\n const isMountedRef = useRef<boolean>(false)\n const [, forceUpdate] = useState<number>(0)\n\n if (!disabled) {\n renderCountRef.current += 1\n }\n\n useEffect(() => {\n if (disabled) return\n\n const unsubscribe = subscribeCounter(id, () => {\n forceUpdate((c) => c + 1)\n })\n\n const record = getCounterRecord(id)\n record.mounts += 1\n isMountedRef.current = true\n\n if (logToConsole) {\n console.log(\n `[DevTools:${id}] Mounted: ${record.mounts} | Rendered: ${renderCountRef.current}`,\n )\n }\n\n notifyCounter(id)\n\n return () => {\n isMountedRef.current = false\n unsubscribe()\n }\n }, [id, disabled, logToConsole])\n\n if (!disabled) {\n const record = getCounterRecord(id)\n record.renders = Math.max(record.renders, renderCountRef.current)\n }\n\n const reset = useCallback(() => {\n renderCountRef.current = 0\n resetCounterRecord(id)\n }, [id])\n\n if (disabled) {\n return { mounts: 0, renders: 0, reset }\n }\n\n const record = getCounterRecord(id)\n\n return {\n mounts: record.mounts,\n renders: renderCountRef.current,\n reset,\n }\n}\n","'use client'\n\nimport type { RenderCounterBadgeProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\nconst POSITION_STYLES: Record<NonNullable<RenderCounterBadgeProps['position']>, string> = {\n 'top-right': 'top-2 right-2',\n 'top-left': 'top-2 left-2',\n 'bottom-right': 'bottom-2 right-2',\n 'bottom-left': 'bottom-2 left-2',\n}\n\n/**\n * A floating overlay badge displaying mount and render counters for debugging component lifecycles.\n */\nexport function RenderCounterBadge({\n id,\n position = 'top-right',\n className = '',\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterBadgeProps) {\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return null\n }\n\n const posClass = POSITION_STYLES[position] || POSITION_STYLES['top-right']\n\n return (\n <div\n className={`absolute ${posClass} z-50 pointer-events-none flex items-center gap-2 rounded px-2 py-1 text-[11px] font-mono bg-zinc-900/90 text-zinc-200 border border-zinc-700/80 shadow-md backdrop-blur-xs select-none ${className}`}\n style={style}\n >\n <span>\n M: <strong className=\"text-emerald-400 font-semibold\">{mounts}</strong>\n </span>\n <span className=\"opacity-30\">|</span>\n <span>\n R: <strong className=\"text-indigo-400 font-semibold\">{renders}</strong>\n </span>\n </div>\n )\n}\n","'use client'\n\nimport type { RenderCounterFooterProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A container footer component for displaying mount and render counters at the bottom of widgets or panels.\n */\nexport function RenderCounterFooter({\n id,\n label,\n children,\n className = '',\n footerClassName = '',\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterFooterProps) {\n const displayId = label || id || 'widget'\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return <>{children}</>\n }\n\n return (\n <div\n className={`h-full w-full flex flex-col overflow-hidden min-h-0 ${className}`}\n style={style}\n >\n {children && <div className=\"flex-1 overflow-hidden relative min-h-0\">{children}</div>}\n <div\n className={`bg-zinc-900/90 border-t border-zinc-800 px-3 py-1.5 flex items-center justify-between text-[11px] text-zinc-400 font-mono shrink-0 select-none ${footerClassName}`}\n >\n <span className=\"truncate max-w-[140px] text-zinc-300 font-semibold\">{displayId}</span>\n <div className=\"flex items-center gap-3\">\n <span>\n Mounts: <strong className=\"text-emerald-400 font-semibold\">{mounts}</strong>\n </span>\n <span className=\"opacity-20\">|</span>\n <span>\n Renders: <strong className=\"text-indigo-400 font-semibold\">{renders}</strong>\n </span>\n </div>\n </div>\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/devtools/store.ts","../src/devtools/use-render-counter.ts","../src/devtools/render-counter-badge.tsx","../src/devtools/render-counter-footer.tsx"],"names":["store","getCounterRecord","id","record","subscribeCounter","listener","notifyCounter","fn","resetCounterRecord","clearAllCounters","useRenderCounter","idOrOptions","maybeOptions","defaultAutoId","useId","options","logToConsole","disabled","renderCountRef","useRef","isMountedRef","forceUpdate","useState","useEffect","unsubscribe","c","reset","useCallback","RenderCounterBadge","className","style","mounts","renders","jsxs","jsx","RenderCounterFooter","label","children","footerClassName","displayId","Fragment"],"mappings":"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","file":"devtools.cjs","sourcesContent":["type Listener = () => void\n\ninterface GlobalCounterRecord {\n mounts: number\n renders: number\n listeners: Set<Listener>\n}\n\nconst store = new Map<string, GlobalCounterRecord>()\n\nexport function getCounterRecord(id: string): GlobalCounterRecord {\n let record = store.get(id)\n if (!record) {\n record = { mounts: 0, renders: 0, listeners: new Set() }\n store.set(id, record)\n }\n return record\n}\n\nexport function subscribeCounter(id: string, listener: Listener): () => void {\n const record = getCounterRecord(id)\n record.listeners.add(listener)\n return () => {\n record.listeners.delete(listener)\n }\n}\n\nexport function notifyCounter(id: string) {\n const record = store.get(id)\n if (record) {\n record.listeners.forEach((fn) => fn())\n }\n}\n\nexport function resetCounterRecord(id: string) {\n const record = store.get(id)\n if (record) {\n record.mounts = 0\n record.renders = 0\n notifyCounter(id)\n }\n}\n\nexport function clearAllCounters() {\n store.clear()\n}\n","'use client'\n\nimport { useRef, useEffect, useState, useCallback, useId } from 'react'\nimport type { RenderCounterOptions, RenderCounterState } from './types'\nimport { getCounterRecord, subscribeCounter, notifyCounter, resetCounterRecord } from './store'\n\n/**\n * A React hook that tracks component mount and render counts in a React 18/19 StrictMode safe manner.\n * Supports optional global ID sharing, console logging, and manual reset.\n */\nexport function useRenderCounter(\n idOrOptions?: string | RenderCounterOptions,\n maybeOptions?: RenderCounterOptions,\n): RenderCounterState {\n const defaultAutoId = useId()\n\n const options: RenderCounterOptions =\n typeof idOrOptions === 'string' ? { id: idOrOptions, ...maybeOptions } : idOrOptions || {}\n\n const { id = defaultAutoId, logToConsole = false, disabled = false } = options\n\n const renderCountRef = useRef<number>(0)\n const isMountedRef = useRef<boolean>(false)\n const [, forceUpdate] = useState<number>(0)\n\n if (!disabled) {\n renderCountRef.current += 1\n }\n\n useEffect(() => {\n if (disabled) return\n\n const unsubscribe = subscribeCounter(id, () => {\n forceUpdate((c) => c + 1)\n })\n\n const record = getCounterRecord(id)\n record.mounts += 1\n isMountedRef.current = true\n\n if (logToConsole) {\n console.log(\n `[DevTools:${id}] Mounted: ${record.mounts} | Rendered: ${renderCountRef.current}`,\n )\n }\n\n notifyCounter(id)\n\n return () => {\n isMountedRef.current = false\n unsubscribe()\n }\n }, [id, disabled, logToConsole])\n\n if (!disabled) {\n const record = getCounterRecord(id)\n record.renders = Math.max(record.renders, renderCountRef.current)\n }\n\n const reset = useCallback(() => {\n renderCountRef.current = 0\n resetCounterRecord(id)\n }, [id])\n\n if (disabled) {\n return { mounts: 0, renders: 0, reset }\n }\n\n const record = getCounterRecord(id)\n\n return {\n mounts: record.mounts,\n renders: renderCountRef.current,\n reset,\n }\n}\n","'use client'\n\nimport type { RenderCounterBadgeProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A badge displaying mount and render counters for debugging component lifecycles.\n */\nexport function RenderCounterBadge({\n id,\n className,\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterBadgeProps) {\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={className} style={style}>\n <span>\n M: <strong>{mounts}</strong>\n </span>\n <span>|</span>\n <span>\n R: <strong>{renders}</strong>\n </span>\n </div>\n )\n}\n","'use client'\n\nimport type { RenderCounterFooterProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A container footer component for displaying mount and render counters at the bottom of widgets or panels.\n */\nexport function RenderCounterFooter({\n id,\n label,\n children,\n className,\n footerClassName,\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterFooterProps) {\n const displayId = label || id || 'widget'\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return <>{children}</>\n }\n\n return (\n <div className={className} style={style}>\n {children && <div className=\"flex-1 overflow-hidden relative min-h-0\">{children}</div>}\n <div className={footerClassName}>\n <span className=\"truncate\">{displayId}</span>\n <div className=\"flex items-center gap-3\">\n <span>\n Mounts: <strong className=\"counter-mounts\">{mounts}</strong>\n </span>\n <span>|</span>\n <span>\n Renders: <strong className=\"counter-renders\">{renders}</strong>\n </span>\n </div>\n </div>\n </div>\n )\n}\n"]}
|
package/dist/devtools.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { R as RenderCounterBadge, a as RenderCounterBadgeProps, b as RenderCounterFooter, c as RenderCounterFooterProps, d as RenderCounterOptions, e as RenderCounterState, u as useRenderCounter } from './render-counter-footer-
|
|
1
|
+
export { R as RenderCounterBadge, a as RenderCounterBadgeProps, b as RenderCounterFooter, c as RenderCounterFooterProps, d as RenderCounterOptions, e as RenderCounterState, u as useRenderCounter } from './render-counter-footer-rAKCzuRX.cjs';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
declare function resetCounterRecord(id: string): void;
|
package/dist/devtools.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { R as RenderCounterBadge, a as RenderCounterBadgeProps, b as RenderCounterFooter, c as RenderCounterFooterProps, d as RenderCounterOptions, e as RenderCounterState, u as useRenderCounter } from './render-counter-footer-
|
|
1
|
+
export { R as RenderCounterBadge, a as RenderCounterBadgeProps, b as RenderCounterFooter, c as RenderCounterFooterProps, d as RenderCounterOptions, e as RenderCounterState, u as useRenderCounter } from './render-counter-footer-rAKCzuRX.js';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
declare function resetCounterRecord(id: string): void;
|
package/dist/devtools.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {useId,useRef,useState,useEffect,useCallback}from'react';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var
|
|
1
|
+
import {useId,useRef,useState,useEffect,useCallback}from'react';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var a=new Map;function i(r){let e=a.get(r);return e||(e={mounts:0,renders:0,listeners:new Set},a.set(r,e)),e}function N(r,e){let n=i(r);return n.listeners.add(e),()=>{n.listeners.delete(e);}}function g(r){let e=a.get(r);e&&e.listeners.forEach(n=>n());}function v(r){let e=a.get(r);e&&(e.mounts=0,e.renders=0,g(r));}function S(){a.clear();}function p(r,e){let n=useId(),c=typeof r=="string"?{id:r,...e}:r||{},{id:t=n,logToConsole:u=false,disabled:o=false}=c,s=useRef(0),l=useRef(false),[,R]=useState(0);if(o||(s.current+=1),useEffect(()=>{if(o)return;let C=N(t,()=>{R(P=>P+1);}),b=i(t);return b.mounts+=1,l.current=true,u&&console.log(`[DevTools:${t}] Mounted: ${b.mounts} | Rendered: ${s.current}`),g(t),()=>{l.current=false,C();}},[t,o,u]),!o){let C=i(t);C.renders=Math.max(C.renders,s.current);}let m=useCallback(()=>{s.current=0,v(t);},[t]);return o?{mounts:0,renders:0,reset:m}:{mounts:i(t).mounts,renders:s.current,reset:m}}function G({id:r,className:e,style:n,logToConsole:c=false,disabled:t=false}){let{mounts:u,renders:o}=p(r,{logToConsole:c,disabled:t});return t?null:jsxs("div",{className:e,style:n,children:[jsxs("span",{children:["M: ",jsx("strong",{children:u})]}),jsx("span",{children:"|"}),jsxs("span",{children:["R: ",jsx("strong",{children:o})]})]})}function I({id:r,label:e,children:n,className:c,footerClassName:t,style:u,logToConsole:o=false,disabled:s=false}){let l=e||r||"widget",{mounts:R,renders:m}=p(r,{logToConsole:o,disabled:s});return s?jsx(Fragment,{children:n}):jsxs("div",{className:c,style:u,children:[n&&jsx("div",{className:"flex-1 overflow-hidden relative min-h-0",children:n}),jsxs("div",{className:t,children:[jsx("span",{className:"truncate",children:l}),jsxs("div",{className:"flex items-center gap-3",children:[jsxs("span",{children:["Mounts: ",jsx("strong",{className:"counter-mounts",children:R})]}),jsx("span",{children:"|"}),jsxs("span",{children:["Renders: ",jsx("strong",{className:"counter-renders",children:m})]})]})]})]})}export{G as RenderCounterBadge,I as RenderCounterFooter,S as clearAllCounters,v as resetCounterRecord,p as useRenderCounter};//# sourceMappingURL=devtools.js.map
|
|
2
2
|
//# sourceMappingURL=devtools.js.map
|
package/dist/devtools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools/store.ts","../src/devtools/use-render-counter.ts","../src/devtools/render-counter-badge.tsx","../src/devtools/render-counter-footer.tsx"],"names":["store","getCounterRecord","id","record","subscribeCounter","listener","notifyCounter","fn","resetCounterRecord","clearAllCounters","useRenderCounter","idOrOptions","maybeOptions","defaultAutoId","useId","options","logToConsole","disabled","renderCountRef","useRef","isMountedRef","forceUpdate","useState","useEffect","unsubscribe","c","reset","useCallback","POSITION_STYLES","RenderCounterBadge","position","className","style","mounts","renders","posClass","jsxs","jsx","RenderCounterFooter","label","children","footerClassName","displayId","Fragment"],"mappings":"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","file":"devtools.js","sourcesContent":["type Listener = () => void\n\ninterface GlobalCounterRecord {\n mounts: number\n renders: number\n listeners: Set<Listener>\n}\n\nconst store = new Map<string, GlobalCounterRecord>()\n\nexport function getCounterRecord(id: string): GlobalCounterRecord {\n let record = store.get(id)\n if (!record) {\n record = { mounts: 0, renders: 0, listeners: new Set() }\n store.set(id, record)\n }\n return record\n}\n\nexport function subscribeCounter(id: string, listener: Listener): () => void {\n const record = getCounterRecord(id)\n record.listeners.add(listener)\n return () => {\n record.listeners.delete(listener)\n }\n}\n\nexport function notifyCounter(id: string) {\n const record = store.get(id)\n if (record) {\n record.listeners.forEach((fn) => fn())\n }\n}\n\nexport function resetCounterRecord(id: string) {\n const record = store.get(id)\n if (record) {\n record.mounts = 0\n record.renders = 0\n notifyCounter(id)\n }\n}\n\nexport function clearAllCounters() {\n store.clear()\n}\n","'use client'\n\nimport { useRef, useEffect, useState, useCallback, useId } from 'react'\nimport type { RenderCounterOptions, RenderCounterState } from './types'\nimport { getCounterRecord, subscribeCounter, notifyCounter, resetCounterRecord } from './store'\n\n/**\n * A React hook that tracks component mount and render counts in a React 18/19 StrictMode safe manner.\n * Supports optional global ID sharing, console logging, and manual reset.\n */\nexport function useRenderCounter(\n idOrOptions?: string | RenderCounterOptions,\n maybeOptions?: RenderCounterOptions,\n): RenderCounterState {\n const defaultAutoId = useId()\n\n const options: RenderCounterOptions =\n typeof idOrOptions === 'string' ? { id: idOrOptions, ...maybeOptions } : idOrOptions || {}\n\n const { id = defaultAutoId, logToConsole = false, disabled = false } = options\n\n const renderCountRef = useRef<number>(0)\n const isMountedRef = useRef<boolean>(false)\n const [, forceUpdate] = useState<number>(0)\n\n if (!disabled) {\n renderCountRef.current += 1\n }\n\n useEffect(() => {\n if (disabled) return\n\n const unsubscribe = subscribeCounter(id, () => {\n forceUpdate((c) => c + 1)\n })\n\n const record = getCounterRecord(id)\n record.mounts += 1\n isMountedRef.current = true\n\n if (logToConsole) {\n console.log(\n `[DevTools:${id}] Mounted: ${record.mounts} | Rendered: ${renderCountRef.current}`,\n )\n }\n\n notifyCounter(id)\n\n return () => {\n isMountedRef.current = false\n unsubscribe()\n }\n }, [id, disabled, logToConsole])\n\n if (!disabled) {\n const record = getCounterRecord(id)\n record.renders = Math.max(record.renders, renderCountRef.current)\n }\n\n const reset = useCallback(() => {\n renderCountRef.current = 0\n resetCounterRecord(id)\n }, [id])\n\n if (disabled) {\n return { mounts: 0, renders: 0, reset }\n }\n\n const record = getCounterRecord(id)\n\n return {\n mounts: record.mounts,\n renders: renderCountRef.current,\n reset,\n }\n}\n","'use client'\n\nimport type { RenderCounterBadgeProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\nconst POSITION_STYLES: Record<NonNullable<RenderCounterBadgeProps['position']>, string> = {\n 'top-right': 'top-2 right-2',\n 'top-left': 'top-2 left-2',\n 'bottom-right': 'bottom-2 right-2',\n 'bottom-left': 'bottom-2 left-2',\n}\n\n/**\n * A floating overlay badge displaying mount and render counters for debugging component lifecycles.\n */\nexport function RenderCounterBadge({\n id,\n position = 'top-right',\n className = '',\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterBadgeProps) {\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return null\n }\n\n const posClass = POSITION_STYLES[position] || POSITION_STYLES['top-right']\n\n return (\n <div\n className={`absolute ${posClass} z-50 pointer-events-none flex items-center gap-2 rounded px-2 py-1 text-[11px] font-mono bg-zinc-900/90 text-zinc-200 border border-zinc-700/80 shadow-md backdrop-blur-xs select-none ${className}`}\n style={style}\n >\n <span>\n M: <strong className=\"text-emerald-400 font-semibold\">{mounts}</strong>\n </span>\n <span className=\"opacity-30\">|</span>\n <span>\n R: <strong className=\"text-indigo-400 font-semibold\">{renders}</strong>\n </span>\n </div>\n )\n}\n","'use client'\n\nimport type { RenderCounterFooterProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A container footer component for displaying mount and render counters at the bottom of widgets or panels.\n */\nexport function RenderCounterFooter({\n id,\n label,\n children,\n className = '',\n footerClassName = '',\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterFooterProps) {\n const displayId = label || id || 'widget'\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return <>{children}</>\n }\n\n return (\n <div\n className={`h-full w-full flex flex-col overflow-hidden min-h-0 ${className}`}\n style={style}\n >\n {children && <div className=\"flex-1 overflow-hidden relative min-h-0\">{children}</div>}\n <div\n className={`bg-zinc-900/90 border-t border-zinc-800 px-3 py-1.5 flex items-center justify-between text-[11px] text-zinc-400 font-mono shrink-0 select-none ${footerClassName}`}\n >\n <span className=\"truncate max-w-[140px] text-zinc-300 font-semibold\">{displayId}</span>\n <div className=\"flex items-center gap-3\">\n <span>\n Mounts: <strong className=\"text-emerald-400 font-semibold\">{mounts}</strong>\n </span>\n <span className=\"opacity-20\">|</span>\n <span>\n Renders: <strong className=\"text-indigo-400 font-semibold\">{renders}</strong>\n </span>\n </div>\n </div>\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/devtools/store.ts","../src/devtools/use-render-counter.ts","../src/devtools/render-counter-badge.tsx","../src/devtools/render-counter-footer.tsx"],"names":["store","getCounterRecord","id","record","subscribeCounter","listener","notifyCounter","fn","resetCounterRecord","clearAllCounters","useRenderCounter","idOrOptions","maybeOptions","defaultAutoId","useId","options","logToConsole","disabled","renderCountRef","useRef","isMountedRef","forceUpdate","useState","useEffect","unsubscribe","c","reset","useCallback","RenderCounterBadge","className","style","mounts","renders","jsxs","jsx","RenderCounterFooter","label","children","footerClassName","displayId","Fragment"],"mappings":"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","file":"devtools.js","sourcesContent":["type Listener = () => void\n\ninterface GlobalCounterRecord {\n mounts: number\n renders: number\n listeners: Set<Listener>\n}\n\nconst store = new Map<string, GlobalCounterRecord>()\n\nexport function getCounterRecord(id: string): GlobalCounterRecord {\n let record = store.get(id)\n if (!record) {\n record = { mounts: 0, renders: 0, listeners: new Set() }\n store.set(id, record)\n }\n return record\n}\n\nexport function subscribeCounter(id: string, listener: Listener): () => void {\n const record = getCounterRecord(id)\n record.listeners.add(listener)\n return () => {\n record.listeners.delete(listener)\n }\n}\n\nexport function notifyCounter(id: string) {\n const record = store.get(id)\n if (record) {\n record.listeners.forEach((fn) => fn())\n }\n}\n\nexport function resetCounterRecord(id: string) {\n const record = store.get(id)\n if (record) {\n record.mounts = 0\n record.renders = 0\n notifyCounter(id)\n }\n}\n\nexport function clearAllCounters() {\n store.clear()\n}\n","'use client'\n\nimport { useRef, useEffect, useState, useCallback, useId } from 'react'\nimport type { RenderCounterOptions, RenderCounterState } from './types'\nimport { getCounterRecord, subscribeCounter, notifyCounter, resetCounterRecord } from './store'\n\n/**\n * A React hook that tracks component mount and render counts in a React 18/19 StrictMode safe manner.\n * Supports optional global ID sharing, console logging, and manual reset.\n */\nexport function useRenderCounter(\n idOrOptions?: string | RenderCounterOptions,\n maybeOptions?: RenderCounterOptions,\n): RenderCounterState {\n const defaultAutoId = useId()\n\n const options: RenderCounterOptions =\n typeof idOrOptions === 'string' ? { id: idOrOptions, ...maybeOptions } : idOrOptions || {}\n\n const { id = defaultAutoId, logToConsole = false, disabled = false } = options\n\n const renderCountRef = useRef<number>(0)\n const isMountedRef = useRef<boolean>(false)\n const [, forceUpdate] = useState<number>(0)\n\n if (!disabled) {\n renderCountRef.current += 1\n }\n\n useEffect(() => {\n if (disabled) return\n\n const unsubscribe = subscribeCounter(id, () => {\n forceUpdate((c) => c + 1)\n })\n\n const record = getCounterRecord(id)\n record.mounts += 1\n isMountedRef.current = true\n\n if (logToConsole) {\n console.log(\n `[DevTools:${id}] Mounted: ${record.mounts} | Rendered: ${renderCountRef.current}`,\n )\n }\n\n notifyCounter(id)\n\n return () => {\n isMountedRef.current = false\n unsubscribe()\n }\n }, [id, disabled, logToConsole])\n\n if (!disabled) {\n const record = getCounterRecord(id)\n record.renders = Math.max(record.renders, renderCountRef.current)\n }\n\n const reset = useCallback(() => {\n renderCountRef.current = 0\n resetCounterRecord(id)\n }, [id])\n\n if (disabled) {\n return { mounts: 0, renders: 0, reset }\n }\n\n const record = getCounterRecord(id)\n\n return {\n mounts: record.mounts,\n renders: renderCountRef.current,\n reset,\n }\n}\n","'use client'\n\nimport type { RenderCounterBadgeProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A badge displaying mount and render counters for debugging component lifecycles.\n */\nexport function RenderCounterBadge({\n id,\n className,\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterBadgeProps) {\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={className} style={style}>\n <span>\n M: <strong>{mounts}</strong>\n </span>\n <span>|</span>\n <span>\n R: <strong>{renders}</strong>\n </span>\n </div>\n )\n}\n","'use client'\n\nimport type { RenderCounterFooterProps } from './types'\nimport { useRenderCounter } from './use-render-counter'\n\n/**\n * A container footer component for displaying mount and render counters at the bottom of widgets or panels.\n */\nexport function RenderCounterFooter({\n id,\n label,\n children,\n className,\n footerClassName,\n style,\n logToConsole = false,\n disabled = false,\n}: RenderCounterFooterProps) {\n const displayId = label || id || 'widget'\n const { mounts, renders } = useRenderCounter(id, { logToConsole, disabled })\n\n if (disabled) {\n return <>{children}</>\n }\n\n return (\n <div className={className} style={style}>\n {children && <div className=\"flex-1 overflow-hidden relative min-h-0\">{children}</div>}\n <div className={footerClassName}>\n <span className=\"truncate\">{displayId}</span>\n <div className=\"flex items-center gap-3\">\n <span>\n Mounts: <strong className=\"counter-mounts\">{mounts}</strong>\n </span>\n <span>|</span>\n <span>\n Renders: <strong className=\"counter-renders\">{renders}</strong>\n </span>\n </div>\n </div>\n </div>\n )\n}\n"]}
|