@stanko/kaplay-inspector 0.1.0 → 0.1.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 CHANGED
@@ -52,6 +52,12 @@ if (
52
52
  }
53
53
  ```
54
54
 
55
+ If typescript is complaining about importing CSS files, you probably need to add this to one of your `.d.ts` files.
56
+
57
+ ```ts
58
+ declare module '*.scss';
59
+ ```
60
+
55
61
  ### Options
56
62
 
57
63
  You can pass options object to the init method as a second parameter:
@@ -127,4 +133,3 @@ Same as with colors, be sure to have a higher specificity selector if inspector'
127
133
  * [ ] Filter/search
128
134
  * [ ] Persist search in URL or local storage
129
135
  * [ ] Collapse/Expand all button
130
- * [ ] Clean up `inspect-comps.tsx`
@@ -0,0 +1,11 @@
1
+ import type { GameObj } from "kaplay";
2
+ type CheckboxCompProps = {
3
+ obj: GameObj;
4
+ propName: string;
5
+ };
6
+ export declare const useObjectBoolean: (obj: GameObj, propName: string) => {
7
+ checked: any;
8
+ onChange: (checked: boolean) => void;
9
+ };
10
+ export declare const BooleanComp: ({ obj, propName }: CheckboxCompProps) => import("preact").JSX.Element;
11
+ export {};
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { useEffect, useState } from "preact/hooks";
3
+ export const useObjectBoolean = (obj, propName) => {
4
+ const [checked, setChecked] = useState(obj[propName]);
5
+ useEffect(() => {
6
+ setChecked(obj[propName]);
7
+ }, [obj[propName]]);
8
+ const onChange = (checked) => {
9
+ setChecked(checked);
10
+ obj[propName] = checked;
11
+ };
12
+ return {
13
+ checked,
14
+ onChange,
15
+ };
16
+ };
17
+ export const BooleanComp = ({ obj, propName }) => {
18
+ const id = `${propName}-${obj.id}`;
19
+ const { checked, onChange } = useObjectBoolean(obj, propName);
20
+ return (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: id, children: _jsx("b", { children: propName }) }), _jsx("div", { children: _jsx("input", { id: id, type: "checkbox", checked: checked, onChange: (e) => onChange(e.target.checked) }) })] }));
21
+ };
@@ -0,0 +1,6 @@
1
+ import type { GameObj } from "kaplay";
2
+ export interface ColorProps {
3
+ className?: string;
4
+ obj: GameObj;
5
+ }
6
+ export declare const Color: ({ obj }: ColorProps) => import("preact").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { useEffect, useState } from "preact/hooks";
3
+ import { cx } from "../lib/cx";
4
+ const ColorSlider = ({ onChange, value, channel }) => {
5
+ const handleChange = (e) => {
6
+ const target = e.target;
7
+ onChange(channel, parseInt(target.value));
8
+ };
9
+ return (_jsx("input", { className: cx("color-controls__slider-input", `color-controls__slider-input--${channel}`), type: "range", min: "0", max: "255", value: value, onInput: handleChange }));
10
+ };
11
+ export const Color = ({ obj }) => {
12
+ const object = obj;
13
+ const { r, g, b } = object.color;
14
+ const [color, setColor] = useState({ r, g, b });
15
+ useEffect(() => {
16
+ setColor({ r, g, b });
17
+ }, [r, g, b]);
18
+ const updateColor = (channel, value) => {
19
+ const newColor = { ...color, [channel]: value };
20
+ setColor(newColor);
21
+ object.color[channel] = value;
22
+ };
23
+ return (_jsxs("div", { class: "color-controls", children: [_jsx("div", { class: "color-controls__swatch", style: { background: `rgb(${color.r} ${color.g} ${color.b})` } }), _jsxs("div", { children: [_jsx(ColorSlider, { value: color.r, onChange: updateColor, channel: "r" }), _jsx(ColorSlider, { value: color.g, onChange: updateColor, channel: "g" }), _jsx(ColorSlider, { value: color.b, onChange: updateColor, channel: "b" })] }), _jsxs("div", { children: ["rgb(", color.r, ", ", color.g, ", ", color.b, ")"] })] }));
24
+ };
@@ -5,6 +5,7 @@ import { cx } from "../lib/cx";
5
5
  import { drawBoundingBox } from "../lib/draw-bbox";
6
6
  import { getObjectInfo } from "../lib/get-object-info";
7
7
  import { Breadcrumbs } from "./breadcrumbs";
8
+ import { BooleanComp } from "./boolean-comp";
8
9
  export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal = false, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }) => {
9
10
  const [isExpanded, setIsExpanded] = useState(isExpandedExternal);
10
11
  const updateControllers = useRef([]);
@@ -54,5 +55,5 @@ export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal
54
55
  "game-object--no-children": !hasChildren,
55
56
  }), children: [isInspecting && _jsx(Breadcrumbs, { setRenderRoot: setRenderRoot, obj: obj }), _jsxs("div", { class: "game-object__content", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsxs("button", { class: cx("game-object__header", {
56
57
  "game-object__header--expandable": showExpandTree,
57
- }), onClick: handleToggleClick, children: [_jsx("span", { class: "game-object__expand-icon", children: isExpanded ? _jsx(MinusIcon, {}) : _jsx(PlusIcon, {}) }), _jsxs("div", { class: "game-object__id", children: ["ID ", obj.id, ":"] }), tags ? (_jsx("div", { class: "game-object__tags", children: isRootObject ? "Root" : tags })) : (_jsx("div", { class: "game-object__comp-names", children: compsLabel })), obj.children.length > 0 && _jsxs("div", { children: ["(", obj.children.length, ")"] }), isObjectDestroyed && (_jsx("div", { class: "game-object__destroyed", children: "DESTROYED" }))] }), _jsxs("div", { class: "game-object__buttons", children: [!isRenderRoot && (_jsx("button", { class: "ki-btn", onClick: () => setRenderRoot(obj), children: "inspect" })), _jsx("button", { class: "ki-btn ", onClick: () => console.log(obj), children: "log" })] }), isExpanded && (_jsx("div", { class: "game-object__comps-wrapper", children: _jsxs("div", { class: "game-object__comps", children: [_jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: `paused-${obj.id}`, children: _jsx("b", { children: "paused" }) }), _jsx("div", { children: _jsx("input", { id: `paused-${obj.id}`, type: "checkbox", defaultChecked: obj.paused, onChange: () => (obj.paused = !obj.paused) }) })] }), _jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: `hidden-${obj.id}`, children: _jsx("b", { children: "hidden" }) }), _jsx("div", { children: _jsx("input", { id: `hidden-${obj.id}`, type: "checkbox", defaultChecked: obj.hidden, onChange: () => (obj.hidden = !obj.hidden) }) })] }), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("div", { children: _jsx("b", { children: comp.tag }) }), _jsx("div", { children: comp.value })] }, comp.tag)))] }) }))] }), isExpanded && hasChildren && (_jsx("div", { class: "game-object__children", style: { display: isExpanded ? "block" : "none" }, children: obj.children.map((child) => (_jsx(GameObject, { k: k, obj: child, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }, child.id))) }))] }, obj.id));
58
+ }), onClick: handleToggleClick, children: [isExpanded ? (_jsx(MinusIcon, { className: "game-object__expand-icon" })) : (_jsx(PlusIcon, { className: "game-object__expand-icon" })), _jsxs("div", { class: "game-object__id", children: ["ID ", obj.id, ":"] }), tags ? (_jsx("div", { class: "game-object__tags", children: isRootObject ? "Root" : tags })) : (_jsx("div", { class: "game-object__comp-names", children: compsLabel })), obj.children.length > 0 && _jsxs("div", { children: ["(", obj.children.length, ")"] }), isObjectDestroyed && (_jsx("div", { class: "game-object__destroyed", children: "DESTROYED" }))] }), _jsxs("div", { class: "game-object__buttons", children: [!isRenderRoot && (_jsx("button", { class: "ki-btn", onClick: () => setRenderRoot(obj), children: "inspect" })), _jsx("button", { class: "ki-btn ", onClick: () => console.log(obj), children: "log" })] }), isExpanded && (_jsx("div", { class: "game-object__comps-wrapper", children: _jsxs("div", { class: "game-object__comps", children: [_jsx(BooleanComp, { obj: obj, propName: "paused" }), _jsx(BooleanComp, { obj: obj, propName: "hidden" }), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("div", { children: _jsx("b", { children: comp.tag }) }), _jsx("div", { children: comp.value })] }, comp.tag)))] }) }))] }), isExpanded && hasChildren && (_jsx("div", { class: "game-object__children", style: { display: isExpanded ? "block" : "none" }, children: obj.children.map((child) => (_jsx(GameObject, { k: k, obj: child, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }, child.id))) }))] }, obj.id));
58
59
  };
@@ -0,0 +1,9 @@
1
+ import type { JSX } from "preact/jsx-runtime";
2
+ export type HoldButtonProps = {
3
+ children?: JSX.Element | string | number;
4
+ className?: string;
5
+ onClickAndHold: () => void;
6
+ interval?: number;
7
+ startRepeatingDelay?: number;
8
+ };
9
+ export declare const HoldButton: ({ children, className, onClickAndHold, interval, startRepeatingDelay, }: HoldButtonProps) => JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "preact/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "preact/hooks";
3
+ export const HoldButton = ({ children, className, onClickAndHold, interval = 50, startRepeatingDelay = 200, }) => {
4
+ const intervalRef = useRef();
5
+ const timeoutRef = useRef();
6
+ const [isMouseDown, setIsMouseDown] = useState(false);
7
+ useEffect(() => {
8
+ document.addEventListener("mouseup", handleMouseUp);
9
+ return () => {
10
+ clearTimeout(timeoutRef.current);
11
+ clearInterval(intervalRef.current);
12
+ document.removeEventListener("mouseup", handleMouseUp);
13
+ };
14
+ }, []);
15
+ useEffect(() => {
16
+ clearTimeout(timeoutRef.current);
17
+ clearInterval(intervalRef.current);
18
+ if (isMouseDown) {
19
+ timeoutRef.current = setTimeout(() => {
20
+ intervalRef.current = setInterval(() => {
21
+ onClickAndHold();
22
+ }, interval);
23
+ }, startRepeatingDelay);
24
+ }
25
+ }, [isMouseDown]);
26
+ const handleMouseDown = () => {
27
+ setIsMouseDown(true);
28
+ };
29
+ const handleMouseUp = () => {
30
+ setIsMouseDown(false);
31
+ };
32
+ return (_jsx("button", { className: className, onMouseDown: handleMouseDown, onClick: onClickAndHold, children: children }));
33
+ };
@@ -1,6 +1,10 @@
1
- export declare const PlusIcon: () => import("preact").JSX.Element;
2
- export declare const MinusIcon: () => import("preact").JSX.Element;
3
- export declare const ArrowUpIcon: () => import("preact").JSX.Element;
4
- export declare const ArrowDownIcon: () => import("preact").JSX.Element;
5
- export declare const ArrowLeftIcon: () => import("preact").JSX.Element;
6
- export declare const ArrowRightIcon: () => import("preact").JSX.Element;
1
+ type IconProps = {
2
+ className?: string;
3
+ };
4
+ export declare const PlusIcon: ({ className }: IconProps) => import("preact").JSX.Element;
5
+ export declare const MinusIcon: ({ className }: IconProps) => import("preact").JSX.Element;
6
+ export declare const ArrowUpIcon: ({ className }: IconProps) => import("preact").JSX.Element;
7
+ export declare const ArrowDownIcon: ({ className }: IconProps) => import("preact").JSX.Element;
8
+ export declare const ArrowLeftIcon: ({ className }: IconProps) => import("preact").JSX.Element;
9
+ export declare const ArrowRightIcon: ({ className }: IconProps) => import("preact").JSX.Element;
10
+ export {};
@@ -1,19 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
- export const PlusIcon = () => {
3
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 8 4 V 12 M 4 8 H12" })] }) }));
2
+ export const PlusIcon = ({ className = "" }) => {
3
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 8 4 V 12 M 4 8 H12" })] }) }));
4
4
  };
5
- export const MinusIcon = () => {
6
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 4 8 H 12" })] }) }));
5
+ export const MinusIcon = ({ className = "" }) => {
6
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 4 8 H 12" })] }) }));
7
7
  };
8
- export const ArrowUpIcon = () => {
9
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 10 L 8 6 L 13 10" }) }) }));
8
+ export const ArrowUpIcon = ({ className = "" }) => {
9
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 10 L 8 6 L 13 10" }) }) }));
10
10
  };
11
- export const ArrowDownIcon = () => {
12
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 6 L 8 10 L 13 6" }) }) }));
11
+ export const ArrowDownIcon = ({ className = "" }) => {
12
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 6 L 8 10 L 13 6" }) }) }));
13
13
  };
14
- export const ArrowLeftIcon = () => {
15
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 10 3 L 6 8 L 10 13" }) }) }));
14
+ export const ArrowLeftIcon = ({ className = "" }) => {
15
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 10 3 L 6 8 L 10 13" }) }) }));
16
16
  };
17
- export const ArrowRightIcon = () => {
18
- return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 6 3 L 10 8 L 6 13" }) }) }));
17
+ export const ArrowRightIcon = ({ className = "" }) => {
18
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 6 3 L 10 8 L 6 13" }) }) }));
19
19
  };
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
2
  import { useEffect, useState } from "preact/hooks";
3
3
  import { GameObject } from "./game-object";
4
+ import { useObjectBoolean } from "./boolean-comp";
4
5
  const INTERVAL_OPTIONS = [
5
6
  { value: 100, label: "100ms" },
6
7
  { value: 250, label: "250ms" },
@@ -13,6 +14,7 @@ export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, ini
13
14
  const [root, setRoot] = useState(k.getTreeRoot());
14
15
  const [renderIndex, setRenderIndex] = useState(0);
15
16
  const [isVisible, setIsVisible] = useState(isVisibleOnLoad);
17
+ const paused = useObjectBoolean(k.getTreeRoot(), "paused");
16
18
  // Force re-render every updateTimeout milliseconds
17
19
  useEffect(() => {
18
20
  const interval = setInterval(() => {
@@ -20,15 +22,15 @@ export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, ini
20
22
  }, updateTimeout);
21
23
  return () => clearInterval(interval);
22
24
  }, [renderIndex, updateTimeout]);
23
- const handlePauseClick = () => {
24
- const root = k.getTreeRoot();
25
- root.paused = !root.paused;
26
- };
25
+ // const handlePauseClick = () => {
26
+ // const root = k.getTreeRoot();
27
+ // root.paused = !root.paused;
28
+ // };
27
29
  const toggleVisibility = () => {
28
30
  setIsVisible(!isVisible);
29
31
  };
30
32
  if (!isVisible) {
31
33
  return (_jsx("button", { class: "ki-btn k-inspector__show", onClick: toggleVisibility, children: "Show Inspector" }));
32
34
  }
33
- return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: handlePauseClick, children: "Pause/Resume" }), "\u2022", _jsxs("div", { children: [k.get("*", { recursive: true }).length, " objects"] }), "\u2022", _jsxs("div", { children: [Math.round(k.debug.fps()), " fps"] }), "\u2022", _jsxs("div", { class: "k-inspector__interval", children: ["Update:", INTERVAL_OPTIONS.map((option) => (_jsxs("label", { children: [_jsx("input", { type: "radio", name: "interval", value: option.value, checked: updateTimeout === option.value, onChange: () => setUpdateTimeout(option.value) }), option.label] }, option.value)))] }), "\u2022", _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: shouldDrawInspect, onChange: () => setShouldDrawInspect(!shouldDrawInspect) }), "Draw bbox on hover"] }), _jsx("button", { class: "ki-btn k-inspector__hide", onClick: toggleVisibility, children: "Hide" })] }), _jsx("div", { class: "k-inspector__objects", children: _jsx(GameObject, { k: k, className: "game-object--root", obj: root, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect, isExpanded: true, isRenderRoot: true }) })] }));
35
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: () => paused.onChange(!paused.checked), children: paused.checked ? "Resume Game" : "Pause Game" }), "\u2022", _jsxs("div", { children: [k.get("*", { recursive: true }).length, " objects"] }), "\u2022", _jsxs("div", { children: [Math.round(k.debug.fps()), " fps"] }), "\u2022", _jsxs("div", { class: "k-inspector__interval", children: ["Update:", INTERVAL_OPTIONS.map((option) => (_jsxs("label", { children: [_jsx("input", { type: "radio", name: "interval", value: option.value, checked: updateTimeout === option.value, onChange: () => setUpdateTimeout(option.value) }), option.label] }, option.value)))] }), "\u2022", _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: shouldDrawInspect, onChange: () => setShouldDrawInspect(!shouldDrawInspect) }), "Draw bbox on hover"] }), _jsx("button", { class: "ki-btn k-inspector__hide", onClick: toggleVisibility, children: "Hide" })] }), _jsx("div", { class: "k-inspector__objects", children: _jsx(GameObject, { k: k, className: "game-object--root", obj: root, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect, isExpanded: true, isRenderRoot: true }) })] }));
34
36
  };
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  import { roundToDecimal } from "../lib/round-to-decimal";
3
+ import { HoldButton } from "./hold-button";
3
4
  import { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, } from "./icons";
4
5
  export const PositionControls = ({ obj }) => {
5
6
  if (!obj.pos) {
6
7
  return null;
7
8
  }
8
- return (_jsxs("div", { class: "pos-controls", children: [_jsx("button", { class: "ki-btn", onClick: () => (obj.pos.x -= 1), children: _jsx(ArrowLeftIcon, {}) }), _jsx("button", { class: "ki-btn", onClick: () => (obj.pos.x += 1), children: _jsx(ArrowRightIcon, {}) }), _jsxs("div", { class: "pos-controls__value", children: ["x: ", roundToDecimal(obj.pos.x, 2)] }), _jsxs("div", { class: "pos-controls__value", children: ["y: ", roundToDecimal(obj.pos.y, 2)] }), _jsx("button", { class: "ki-btn", onClick: () => (obj.pos.y -= 1), children: _jsx(ArrowUpIcon, {}) }), _jsx("button", { class: "ki-btn", onClick: () => (obj.pos.y += 1), children: _jsx(ArrowDownIcon, {}) })] }));
9
+ return (_jsxs("div", { class: "pos-controls", children: [_jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.x -= 1), children: _jsx(ArrowLeftIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.x += 1), children: _jsx(ArrowRightIcon, {}) }), _jsxs("div", { class: "pos-controls__value", children: ["x: ", roundToDecimal(obj.pos.x, 2)] }), _jsxs("div", { class: "pos-controls__value", children: ["y: ", roundToDecimal(obj.pos.y, 2)] }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.y -= 1), children: _jsx(ArrowUpIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.y += 1), children: _jsx(ArrowDownIcon, {}) })] }));
9
10
  };
@@ -0,0 +1,6 @@
1
+ import type { GameObj } from "kaplay";
2
+ export interface SpriteControlsProps {
3
+ className?: string;
4
+ obj: GameObj;
5
+ }
6
+ export declare const SpriteControls: ({ obj }: SpriteControlsProps) => import("preact").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ export const SpriteControls = ({ obj }) => {
3
+ const object = obj;
4
+ const animation = object.getCurAnim();
5
+ return (_jsxs("div", { class: "sprite-controls", children: [_jsx("b", { children: object.sprite }), _jsxs("div", { children: ["frame: ", object.frame] }), animation && (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["animation: ", animation.name] }), _jsxs("div", { children: ["animation frame: ", animation?.frameIndex] })] }))] }));
6
+ };
@@ -1,9 +1,16 @@
1
1
  import { jsx as _jsx } from "preact/jsx-runtime";
2
+ import { useEffect, useState } from "preact/hooks";
2
3
  export const TextControls = ({ obj }) => {
4
+ const [text, setText] = useState(obj.text);
5
+ useEffect(() => {
6
+ setText(obj.text);
7
+ }, [obj.text]);
3
8
  if (typeof obj.text !== "string") {
4
9
  return null;
5
10
  }
6
- return (_jsx("div", { class: "text-controls", children: _jsx("input", { class: "text-controls__input", type: "text", placeholder: "Enter text", defaultValue: obj.text, onInput: (e) => {
7
- obj.text = e.target.value;
8
- } }) }));
11
+ const handleInput = (e) => {
12
+ obj.text = e.target.value;
13
+ setText(text);
14
+ };
15
+ return (_jsx("div", { class: "text-controls", children: _jsx("input", { class: "text-controls__input", type: "text", placeholder: "Enter text", value: text, onInput: handleInput }) }));
9
16
  };
@@ -2,11 +2,13 @@ import { jsx as _jsx } from "preact/jsx-runtime";
2
2
  import { stringify } from "./stringify";
3
3
  import { PositionControls } from "../components/position-controls";
4
4
  import { TextControls } from "../components/text-controls";
5
- import { Sprite } from "../components/sprite";
5
+ import { SpriteControls } from "../components/sprite-controls";
6
+ import { Color } from "../components/color-controls";
6
7
  const componentMap = {
7
8
  pos: PositionControls,
8
9
  text: TextControls,
9
- sprite: Sprite,
10
+ sprite: SpriteControls,
11
+ color: Color,
10
12
  };
11
13
  export const inspectComps = (obj) => {
12
14
  const object = obj;
@@ -30,6 +32,15 @@ export const inspectComps = (obj) => {
30
32
  value: value ? value.replace(`${tag}: `, "") : "",
31
33
  });
32
34
  }
35
+ else {
36
+ data.push({
37
+ tag,
38
+ // Commented out on purpose
39
+ // For now, only the name of the component is shown,
40
+ // until I try it out and figure if it would be useful to display the full component state
41
+ // value: stringify(comp),
42
+ });
43
+ }
33
44
  }
34
45
  for (const [i, comp] of object._anonymousCompStates.entries()) {
35
46
  if (comp.inspect) {
@@ -1,6 +1,6 @@
1
1
  export const stringify = (obj, maxDepth = 1, currentDepth = 0) => {
2
2
  if (typeof obj !== "object" || obj === null) {
3
- return obj.toString();
3
+ return JSON.stringify(obj);
4
4
  }
5
5
  const lines = Object.entries(obj).map(([key, value]) => {
6
6
  if (typeof value === "function") {
package/dist/styles.css CHANGED
@@ -326,14 +326,49 @@
326
326
  outline: none;
327
327
  border-color: var(--ki-primary);
328
328
  }
329
- }
330
329
 
331
- /* Breadcrumbs */
330
+ /* Color */
331
+
332
+ .color-controls {
333
+ display: flex;
334
+ align-items: center;
335
+ gap: 0.5rem;
336
+ width: fit-content;
337
+ min-width: 12rem;
338
+ }
332
339
 
333
- .breadcrumbs {
334
- font-size: 0.75rem;
335
- display: flex;
336
- margin-bottom: 0.5rem;
337
- gap: 0.5rem;
338
- align-items: center;
340
+ .color-controls__swatch {
341
+ width: 2rem;
342
+ height: 2rem;
343
+ border-radius: 8px;
344
+ border: 1px solid var(--ki-border-light);
345
+ }
346
+
347
+ .color-controls__slider {
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 0.25rem;
351
+ }
352
+
353
+ .color-controls__slider-input--r {
354
+ accent-color: red;
355
+ }
356
+
357
+ .color-controls__slider-input--g {
358
+ accent-color: green;
359
+ }
360
+
361
+ .color-controls__slider-input--b {
362
+ accent-color: blue;
363
+ }
364
+
365
+ /* Breadcrumbs */
366
+
367
+ .breadcrumbs {
368
+ font-size: 0.75rem;
369
+ display: flex;
370
+ margin-bottom: 0.5rem;
371
+ gap: 0.5rem;
372
+ align-items: center;
373
+ }
339
374
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stanko/kaplay-inspector",
3
3
  "description": "A dev tool for Kaplay which allows you to explore and inspect the game object tree real time.",
4
4
  "private": false,
5
- "version": "0.1.0",
5
+ "version": "0.1.1",
6
6
  "type": "module",
7
7
  "main": "./dist/init.js",
8
8
  "types": "./dist/init.d.ts",
@@ -1,6 +0,0 @@
1
- import type { GameObj } from "kaplay";
2
- export interface SpriteProps {
3
- className?: string;
4
- obj: GameObj;
5
- }
6
- export declare const Sprite: ({ obj }: SpriteProps) => import("preact").JSX.Element;
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
2
- export const Sprite = ({ obj }) => {
3
- const object = obj;
4
- const animation = object.getCurAnim();
5
- return (_jsxs("div", { class: "sprite", children: [_jsx("b", { children: object.sprite }), _jsxs("div", { children: ["frame: ", object.frame] }), animation && (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["animation: ", animation.name] }), _jsxs("div", { children: ["animation frame: ", animation?.frameIndex] })] }))] }));
6
- };