New:Socket for Asana Is Now Available.Learn more
Get Started

Zustand DevTools

Package Overview
Versions
2
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zustand-devtools@extension - firefox Package Compare versions

Comparing version
1.8.0
to
1.10.0
+1
-1
manifest.json
{
"manifest_version": 2,
"name": "Zustand DevTools",
"version": "1.8.0",
"version": "1.10.0",
"description": "Inspect and debug Zustand state stores in real-time. View state snapshots, track actions, and time-travel through state changes.",

@@ -6,0 +6,0 @@ "author": "Your Name",

@@ -471,21 +471,73 @@ /**

// SVG icon strings — single source of truth for copy button states
const ICON_COPY = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`;
const ICON_CHECK = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
// ── SVG DOM builders (no innerHTML — AMO safe) ───────────────────────────────
const _SVG = 'http://www.w3.org/2000/svg';
function _mkSvg(w, h, fill, sw, children) {
const s = document.createElementNS(_SVG, 'svg');
s.setAttribute('width', String(w)); s.setAttribute('height', String(h));
s.setAttribute('viewBox', '0 0 24 24'); s.setAttribute('fill', fill);
if (sw) {
s.setAttribute('stroke', 'currentColor'); s.setAttribute('stroke-width', String(sw));
s.setAttribute('stroke-linecap', 'round'); s.setAttribute('stroke-linejoin', 'round');
}
children.forEach(([tag, attrs]) => {
const el = document.createElementNS(_SVG, tag);
Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
s.appendChild(el);
});
return s;
}
function iconCopy() {
return _mkSvg(14, 14, 'none', 2, [
['rect', { x:'9', y:'9', width:'13', height:'13', rx:'2' }],
['path', { d:'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' }],
]);
}
function iconCheck() {
return _mkSvg(14, 14, 'none', 2.5, [
['polyline', { points:'20 6 9 17 4 12' }],
]);
}
function iconPlay() {
return _mkSvg(12, 12, 'currentColor', null, [
['polygon', { points:'5 3 19 12 5 21 5 3' }],
]);
}
function iconPause() {
return _mkSvg(12, 12, 'currentColor', null, [
['rect', { x:'6', y:'5', width:'4', height:'14' }],
['rect', { x:'14', y:'5', width:'4', height:'14' }],
]);
}
function iconReset() {
return _mkSvg(12, 12, 'none', 2, [
['polyline', { points:'1 4 1 10 7 10' }],
['path', { d:'M3.51 15a9 9 0 1 0 .49-3.5' }],
]);
}
function iconLap() {
return _mkSvg(12, 12, 'none', 2, [
['path', { d:'M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z' }],
['line', { x1:'4', y1:'22', x2:'4', y2:'15' }],
]);
}
let _copyToastTimer = null;
function _setBtnIcon(btn, svgNode) {
btn.textContent = ''; // clears children safely
btn.appendChild(svgNode);
}
function showCopyToast() {
const toast = document.getElementById('copy-toast');
const btn = document.getElementById('btn-copy');
// Swap to checkmark icon
btn.innerHTML = ICON_CHECK;
_setBtnIcon(btn, iconCheck());
btn.classList.add('btn-copy-success');
// Toast
toast.classList.add('visible');
// Reset after 2 s
clearTimeout(_copyToastTimer);
_copyToastTimer = setTimeout(() => {
toast.classList.remove('visible');
btn.innerHTML = ICON_COPY;
_setBtnIcon(btn, iconCopy());
btn.classList.remove('btn-copy-success');

@@ -809,9 +861,3 @@ }, 2000);

// SVG icons used by the timer buttons
const T_ICON = {
play: `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>`,
pause: `<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14"/><rect x="14" y="5" width="4" height="14"/></svg>`,
reset: `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-3.5"/></svg>`,
lap: `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>`,
};
// Timer SVG icons are provided by iconPlay/iconPause/iconReset/iconLap (defined above)

@@ -841,9 +887,15 @@ function timerFormatMs(ms) {

const ssLabel = document.createElement('span');
if (timerState.isRunning) {
btnSS.innerHTML = T_ICON.pause + '<span>Stop</span>';
ssLabel.textContent = 'Stop';
btnSS.textContent = '';
btnSS.appendChild(iconPause());
btnSS.appendChild(ssLabel);
btnSS.className = 'timer-btn timer-btn-stop';
btnLap.disabled = false;
} else {
const hasTime = timerState.elapsed > 0;
btnSS.innerHTML = T_ICON.play + `<span>${hasTime ? 'Resume' : 'Start'}</span>`;
ssLabel.textContent = timerState.elapsed > 0 ? 'Resume' : 'Start';
btnSS.textContent = '';
btnSS.appendChild(iconPlay());
btnSS.appendChild(ssLabel);
btnSS.className = 'timer-btn timer-btn-start';

@@ -907,6 +959,14 @@ btnLap.disabled = true;

row.className = 'timer-lap-row' + (isLatest ? ' timer-lap-latest' : '');
row.innerHTML =
`<span class="timer-lap-num">Lap ${lap.num}</span>` +
`<span class="timer-lap-split">+${timerFormatMs(lap.split)}</span>` +
`<span class="timer-lap-total">${timerFormatMs(lap.total)}</span>`;
const numEl = document.createElement('span');
numEl.className = 'timer-lap-num';
numEl.textContent = `Lap ${lap.num}`;
const splitEl = document.createElement('span');
splitEl.className = 'timer-lap-split';
splitEl.textContent = `+${timerFormatMs(lap.split)}`;
const totalEl = document.createElement('span');
totalEl.className = 'timer-lap-total';
totalEl.textContent = timerFormatMs(lap.total);
row.appendChild(numEl);
row.appendChild(splitEl);
row.appendChild(totalEl);
list.appendChild(row);

@@ -928,21 +988,64 @@ });

$c.innerHTML = `
<div class="timer-wrap">
<div class="timer-display-wrap">
<div class="timer-label">ELAPSED</div>
<div id="timer-display" class="timer-display">00:00.00</div>
</div>
<div class="timer-controls">
<button id="timer-btn-ss" class="timer-btn timer-btn-start">${T_ICON.play}<span>Start</span></button>
<button id="timer-btn-reset" class="timer-btn timer-btn-reset">${T_ICON.reset}<span>Reset</span></button>
<button id="timer-btn-lap" class="timer-btn timer-btn-lap" disabled>${T_ICON.lap}<span>Lap</span></button>
</div>
<div id="timer-laps" class="timer-laps"></div>
</div>`;
// Build entire timer DOM with createElement — no innerHTML (AMO safe)
const wrap = document.createElement('div');
wrap.className = 'timer-wrap';
document.getElementById('timer-btn-ss').addEventListener('click', () => {
// Display
const dispWrap = document.createElement('div');
dispWrap.className = 'timer-display-wrap';
const labelEl = document.createElement('div');
labelEl.className = 'timer-label';
labelEl.textContent = 'ELAPSED';
const dispEl = document.createElement('div');
dispEl.id = 'timer-display';
dispEl.className = 'timer-display';
dispEl.textContent = '00:00.00';
dispWrap.appendChild(labelEl);
dispWrap.appendChild(dispEl);
// Controls
const controls = document.createElement('div');
controls.className = 'timer-controls';
const btnSS = document.createElement('button');
btnSS.id = 'timer-btn-ss';
btnSS.className = 'timer-btn timer-btn-start';
btnSS.appendChild(iconPlay());
const ssSpan = document.createElement('span'); ssSpan.textContent = 'Start';
btnSS.appendChild(ssSpan);
const btnReset = document.createElement('button');
btnReset.id = 'timer-btn-reset';
btnReset.className = 'timer-btn timer-btn-reset';
btnReset.appendChild(iconReset());
const resetSpan = document.createElement('span'); resetSpan.textContent = 'Reset';
btnReset.appendChild(resetSpan);
const btnLap = document.createElement('button');
btnLap.id = 'timer-btn-lap';
btnLap.className = 'timer-btn timer-btn-lap';
btnLap.disabled = true;
btnLap.appendChild(iconLap());
const lapSpan = document.createElement('span'); lapSpan.textContent = 'Lap';
btnLap.appendChild(lapSpan);
controls.appendChild(btnSS);
controls.appendChild(btnReset);
controls.appendChild(btnLap);
// Laps list
const lapsEl = document.createElement('div');
lapsEl.id = 'timer-laps';
lapsEl.className = 'timer-laps';
wrap.appendChild(dispWrap);
wrap.appendChild(controls);
wrap.appendChild(lapsEl);
$c.appendChild(wrap);
btnSS.addEventListener('click', () => {
timerState.isRunning ? timerStop() : timerStart();
});
document.getElementById('timer-btn-reset').addEventListener('click', timerReset);
document.getElementById('timer-btn-lap').addEventListener('click', timerLap);
btnReset.addEventListener('click', timerReset);
btnLap.addEventListener('click', timerLap);

@@ -949,0 +1052,0 @@ timerTick();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet