@tanstack/table-devtools
Version:
Devtools for TanStack Table.
247 lines (245 loc) • 8.44 kB
JavaScript
import { useTableDevtoolsContext } from "../TableContextProvider.js";
import { useStyles } from "../styles/use-styles.js";
import { useTableStore } from "../useTableStore.js";
import { NoTableConnected } from "./NoTableConnected.js";
import { ThreeWayResizableSplit } from "./ThreeWayResizableSplit.js";
import { For, Show, createMemo, createSignal } from "solid-js";
import { className, createComponent, delegateEvents, effect, insert, memo, template } from "solid-js/web";
import { JsonTree } from "@tanstack/devtools-ui";
import { batch as batch$1 } from "@tanstack/solid-store";
//#region src/components/StatePanel.tsx
var _tmpl$ = /*#__PURE__*/ template(`<div>`);
var _tmpl$2 = /*#__PURE__*/ template(`<div>initialState`);
var _tmpl$3 = /*#__PURE__*/ template(`<div><button type=button>`);
var _tmpl$4 = /*#__PURE__*/ template(`<div>Atoms`);
var _tmpl$5 = /*#__PURE__*/ template(`<div><button type=button>Reset to initialState`);
var _tmpl$6 = /*#__PURE__*/ template(`<div>Store`);
var _tmpl$7 = /*#__PURE__*/ template(`<div><button type=button></button><button type=button>Paste`);
var _tmpl$8 = /*#__PURE__*/ template(`<div><div><span></span><span></span></div><div>`);
function StatePanel() {
const styles = useStyles();
const { table } = useTableDevtoolsContext();
const [initialStateCopied, setInitialStateCopied] = createSignal(false);
const [storeCopied, setStoreCopied] = createSignal(false);
const [pasteError, setPasteError] = createSignal(null);
const tableState = useTableStore(() => table()?.store, (state) => state);
const optionsStoreValue = useTableStore(() => table()?.optionsStore, (options) => options);
const initialState = createMemo(() => {
const tableInstance = table();
if (!tableInstance) return void 0;
return tableInstance.initialState;
});
const storeState = createMemo(() => {
const tableInstance = table();
if (!tableInstance) return void 0;
return tableState() ?? tableInstance.store.get();
});
const tableOptions = createMemo(() => {
const tableInstance = table();
if (!tableInstance) return void 0;
return optionsStoreValue() ?? tableInstance.options;
});
const atomKeys = createMemo(() => Object.keys(storeState() ?? {}));
const getAtomSource = (key) => {
const options = tableOptions() ?? {};
const externalAtoms = options.atoms ?? {};
const externalState = options.state ?? {};
const hasExternalAtom = externalAtoms[key] != null;
const hasExternalState = !hasExternalAtom && key in externalState && externalState[key] !== void 0;
return hasExternalAtom ? "external-atom" : hasExternalState ? "external-state" : "internal";
};
const copyToClipboard = async (value, setCopied) => {
try {
await navigator.clipboard.writeText(JSON.stringify(value, null, 2));
setCopied(true);
setTimeout(() => setCopied(false), 1500);
} catch {}
};
const handlePaste = async () => {
const tableInstance = table();
if (!tableInstance) return;
setPasteError(null);
try {
const text = await navigator.clipboard.readText();
const parsed = JSON.parse(text);
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
setPasteError("Invalid state: must be a JSON object");
return;
}
const baseAtoms = tableInstance.baseAtoms;
batch$1(() => {
for (const [key, value] of Object.entries(parsed)) if (key in baseAtoms) baseAtoms[key].set(value);
});
} catch (e) {
setPasteError(e instanceof Error ? e.message : "Failed to parse clipboard");
}
};
const handleReset = () => {
table()?.reset();
};
return createComponent(Show, {
get fallback() {
return createComponent(NoTableConnected, { title: "State" });
},
get when() {
return table();
},
get children() {
var _el$ = _tmpl$();
insert(_el$, createComponent(ThreeWayResizableSplit, {
get left() {
return [
(() => {
var _el$2 = _tmpl$2();
effect(() => className(_el$2, styles().sectionTitle));
return _el$2;
})(),
(() => {
var _el$3 = _tmpl$3(), _el$4 = _el$3.firstChild;
_el$4.$$click = () => copyToClipboard(initialState(), setInitialStateCopied);
insert(_el$4, () => initialStateCopied() ? "Copied!" : "Copy");
effect((_p$) => {
var _v$ = styles().buttonRow, _v$2 = styles().copyButton;
_v$ !== _p$.e && className(_el$3, _p$.e = _v$);
_v$2 !== _p$.t && className(_el$4, _p$.t = _v$2);
return _p$;
}, {
e: void 0,
t: void 0
});
return _el$3;
})(),
createComponent(JsonTree, {
copyable: true,
get value() {
return initialState();
}
})
];
},
get middle() {
return [
(() => {
var _el$5 = _tmpl$4();
effect(() => className(_el$5, styles().sectionTitle));
return _el$5;
})(),
(() => {
var _el$6 = _tmpl$5(), _el$7 = _el$6.firstChild;
_el$7.$$click = handleReset;
effect((_p$) => {
var _v$3 = styles().buttonRow, _v$4 = styles().resetButton;
_v$3 !== _p$.e && className(_el$6, _p$.e = _v$3);
_v$4 !== _p$.t && className(_el$7, _p$.t = _v$4);
return _p$;
}, {
e: void 0,
t: void 0
});
return _el$6;
})(),
createComponent(For, {
get each() {
return atomKeys();
},
children: (key) => createComponent(AtomRow, {
atomKey: key,
source: () => getAtomSource(key),
styles,
value: () => storeState()?.[key]
})
})
];
},
get right() {
return [
(() => {
var _el$8 = _tmpl$6();
effect(() => className(_el$8, styles().sectionTitle));
return _el$8;
})(),
(() => {
var _el$9 = _tmpl$7(), _el$0 = _el$9.firstChild, _el$1 = _el$0.nextSibling;
_el$0.$$click = () => copyToClipboard(storeState(), setStoreCopied);
insert(_el$0, () => storeCopied() ? "Copied!" : "Copy");
_el$1.$$click = handlePaste;
effect((_p$) => {
var _v$5 = styles().buttonRow, _v$6 = styles().copyButton, _v$7 = styles().pasteButton;
_v$5 !== _p$.e && className(_el$9, _p$.e = _v$5);
_v$6 !== _p$.t && className(_el$0, _p$.t = _v$6);
_v$7 !== _p$.a && className(_el$1, _p$.a = _v$7);
return _p$;
}, {
e: void 0,
t: void 0,
a: void 0
});
return _el$9;
})(),
memo(() => memo(() => !!pasteError())() && (() => {
var _el$10 = _tmpl$();
insert(_el$10, pasteError);
effect(() => className(_el$10, styles().pasteError));
return _el$10;
})()),
createComponent(JsonTree, {
copyable: true,
get value() {
return storeState();
}
})
];
}
}));
effect(() => className(_el$, styles().panelScroll));
return _el$;
}
});
}
function AtomRow(props) {
const badgeLabel = () => {
switch (props.source()) {
case "external-atom": return "External Atom";
case "external-state": return "External State";
case "internal": return "Internal";
}
};
const badgeClass = () => {
const base = props.styles().atomBadge;
switch (props.source()) {
case "external-atom": return `${base} ${props.styles().atomBadgeExternalAtom}`;
case "external-state": return `${base} ${props.styles().atomBadgeExternalState}`;
case "internal": return `${base} ${props.styles().atomBadgeInternal}`;
}
};
return (() => {
var _el$11 = _tmpl$8(), _el$12 = _el$11.firstChild, _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, _el$15 = _el$12.nextSibling;
insert(_el$13, () => props.atomKey);
insert(_el$14, badgeLabel);
insert(_el$15, createComponent(JsonTree, {
copyable: true,
get value() {
return props.value();
}
}));
effect((_p$) => {
var _v$8 = props.styles().atomRow, _v$9 = props.styles().atomRowHeader, _v$0 = props.styles().atomKey, _v$1 = badgeClass(), _v$10 = props.styles().atomValue;
_v$8 !== _p$.e && className(_el$11, _p$.e = _v$8);
_v$9 !== _p$.t && className(_el$12, _p$.t = _v$9);
_v$0 !== _p$.a && className(_el$13, _p$.a = _v$0);
_v$1 !== _p$.o && className(_el$14, _p$.o = _v$1);
_v$10 !== _p$.i && className(_el$15, _p$.i = _v$10);
return _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
});
return _el$11;
})();
}
delegateEvents(["click"]);
//#endregion
export { StatePanel };