@zikojs/console 0.1.0 → 0.3.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 ZAKARIA ELALAOUI
3
+ Copyright (c) 2025 ZAKARIA ELALAOUI
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "@zikojs/console",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/zikojs/console.git",
12
+ "directory": "packages/console"
13
+ },
9
14
  "keywords": [
10
15
  "zikojs",
11
16
  "console",
@@ -16,7 +21,7 @@
16
21
  "license": "MIT",
17
22
  "type": "module",
18
23
  "dependencies": {
19
- "ziko": "^2.0.0-beta.16.0"
24
+ "ziko": "latest"
20
25
  },
21
26
  "scripts": {
22
27
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -1,28 +1,32 @@
1
1
  import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
2
+ const { div } = van.tags;
3
+ import { nodeEntry, makeEntry } from "./nodeEntry.js";
4
+ import { Row } from "./Row.js";
2
5
 
3
- import { entryNode, nodeEntry } from "../entries/entryNode.js";
6
+ const entryNode =
7
+ (method) =>
8
+ (...args) => {
9
+ const e = makeEntry(method, args);
10
+ const node = div(
11
+ { class: () => "cf cf-solo " + Console.theme }, // <-- using a function or string
12
+ Row(e),
13
+ );
14
+ nodeEntry.set(node, e);
15
+ return node;
16
+ };
4
17
 
5
18
  export const Console = {
6
- theme: van.state("light")
7
- };
8
-
9
- Console.log = entryNode("log", Console.theme);
10
- Console.info = entryNode("info", Console.theme);
11
- Console.debug = entryNode("debug", Console.theme);
12
- Console.warn = entryNode("warn", Console.theme);
13
- Console.error = entryNode("error", Console.theme);
14
- Console.table = entryNode("table", Console.theme);
15
-
16
- Console.group = entryNode("group", Console.theme);
17
-
18
- Console.groupEnd = () => {
19
- const node =
20
- document.createComment("groupEnd");
21
-
22
- nodeEntry.set(node, {
23
- method: "groupEnd",
24
- args: []
25
- });
26
-
27
- return node;
19
+ theme: { val: "dark" },
20
+ log: entryNode("log"),
21
+ info: entryNode("info"),
22
+ debug: entryNode("debug"),
23
+ warn: entryNode("warn"),
24
+ error: entryNode("error"),
25
+ table: entryNode("table"),
26
+ group: entryNode("group"),
27
+ groupEnd: () => {
28
+ const node = document.createComment("groupEnd");
29
+ nodeEntry.set(node, { method: "groupEnd", args: [] });
30
+ return node;
31
+ },
28
32
  };
@@ -1,46 +1,58 @@
1
- import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
2
- import { Row } from "./Row.js";
1
+ import { tags } from "ziko/dom";
2
+ const { div } = tags;
3
+ import { Row, cache } from "./Row.js";
4
+
5
+ export function ConsoleBody(feed) {
6
+ const listContainer = div();
7
+
8
+ const renderLogs = () => {
9
+ const visible = feed.getVisibleLogs();
10
+ listContainer.element.replaceChildren(
11
+ (
12
+ visible.length
13
+ ? div(...visible.map((e) => Row(e)))
14
+ : div(
15
+ { class: "cf-empty" },
16
+ "No messages yet. Anything sent to console.* shows up here.",
17
+ )
18
+ ).element
3
19
 
4
- const { div } = van.tags;
20
+ );
21
+ };
5
22
 
6
- export function ConsoleBody(visible) {
7
23
  let stick = true;
8
-
9
24
  const body = div(
10
25
  {
11
26
  class: "cf-body",
12
-
13
27
  onscroll: () => {
14
- stick =
15
- body.scrollHeight -
16
- body.scrollTop -
17
- body.clientHeight < 24;
18
- }
28
+ stick = body.scrollHeight - body.scrollTop - body.clientHeight < 24;
29
+ },
19
30
  },
31
+ listContainer
32
+ ).element;
33
+
34
+ feed.addEventListener("logs-change", () => {
35
+ renderLogs();
36
+ if (stick) {
37
+ requestAnimationFrame(() => {
38
+ body.scrollTop = body.scrollHeight;
39
+ });
40
+ }
41
+ });
20
42
 
21
- () =>
22
- visible.val.length
23
- ? div(
24
- visible.val.map(entry =>
25
- Row(entry)
26
- )
27
- )
28
- : div(
29
- { class: "cf-empty" },
30
- "No messages yet. Anything sent to console.* shows up here."
31
- )
32
- );
33
-
34
- van.derive(() => {
35
- visible.val;
43
+ feed.addEventListener("clear", () => {
44
+ renderLogs();
45
+ });
36
46
 
37
- requestAnimationFrame(() => {
38
- if (stick) {
39
- body.scrollTop =
40
- body.scrollHeight;
41
- }
42
- });
47
+ feed.addEventListener("row-update", (e) => {
48
+ const rowEl = cache.get(e.detail);
49
+ if (rowEl) {
50
+ const badge = rowEl.querySelector(".cf-badge");
51
+ if (badge && badge.updateBadge) badge.updateBadge();
52
+ }
43
53
  });
44
54
 
55
+ renderLogs();
56
+
45
57
  return body;
46
58
  }
@@ -1,141 +1,45 @@
1
- import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
1
+ import { tags } from 'ziko/dom'
2
2
 
3
- import { createFeed } from "../feed/createFeed.js";
4
- import { nodeEntry } from "../entries/entryNode.js";
5
-
6
- import { ConsoleToolbar } from "./ConsoleToolbar.js";
7
- import { ConsoleBody } from "./ConsoleBody.js";
8
- import { ConsolePrompt } from "./ConsolePrompt.js";
3
+ const { div } = tags;
9
4
 
5
+ import { isProps } from "../utils/index.js";
10
6
  import { Hook } from "../hook/index.js";
11
- import {
12
- fmt,
13
- safe
14
- } from "../utils/index.js";
15
-
16
- const { div } = van.tags;
17
-
18
- const LEVEL = {
19
- log: "log",
20
- dir: "log",
21
- table: "log",
22
- group: "log",
23
-
24
- info: "info",
25
- debug: "debug",
26
- warn: "warn",
27
- error: "error"
28
- };
29
-
30
- const LEVELS = [
31
- "log",
32
- "info",
33
- "warn",
34
- "error",
35
- "debug"
36
- ];
37
-
38
- const isProps = value =>
39
- value &&
40
- typeof value === "object" &&
41
- !(value instanceof Node) &&
42
- Object.getPrototypeOf(value) === Object.prototype;
7
+ import { createFeed } from "../feed/index.js";
8
+ import { nodeEntry } from "./nodeEntry.js";
9
+ import { cache } from "./Row.js";
10
+ import { ConsoleBody } from "./ConsoleBody.js";
43
11
 
44
12
  export function ConsoleFeed(...args) {
45
- const [props, ...children] =
46
- isProps(args[0])
47
- ? args
48
- : [{}, ...args];
49
-
13
+ const [props, ...kids] = isProps(args[0]) ? args : [{}, ...args];
14
+ const feed = props.feed || createFeed(1000, cache);
50
15
  const {
51
- feed = createFeed(),
52
16
  variant = "dark",
53
- repl = true,
54
- hook = false
17
+ hook = false,
55
18
  } = props;
56
19
 
57
- if (hook) {
58
- Hook(console, feed.push);
59
- }
60
-
61
- children
62
- .flat(Infinity)
63
- .forEach(child => {
64
- const entry = nodeEntry.get(child);
65
-
66
- if (entry) {
67
- feed.push(entry);
68
- }
69
- });
70
-
71
- const theme =
72
- typeof variant === "string"
73
- ? van.state(variant)
74
- : variant;
75
-
76
- const levels = Object.fromEntries(
77
- LEVELS.map(level => [
78
- level,
79
- van.state(true)
80
- ])
81
- );
82
-
83
- const query = van.state("");
84
-
85
- const count = level =>
86
- van.derive(() =>
87
- feed.logs.val.filter(
88
- entry =>
89
- LEVEL[entry.method] === level
90
- ).length
91
- );
92
-
93
- const visible = van.derive(() => {
94
- const search =
95
- query.val.toLowerCase();
96
-
97
- return feed.logs.val.filter(entry => {
98
- const level =
99
- LEVEL[entry.method];
100
-
101
- if (
102
- level &&
103
- !levels[level].val
104
- ) {
105
- return false;
106
- }
107
-
108
- if (!search) {
109
- return true;
110
- }
111
-
112
- return fmt(entry.args)
113
- .map(safe)
114
- .join(" ")
115
- .toLowerCase()
116
- .includes(search);
117
- });
20
+ if (hook) Hook(console, (e) => feed.push(e));
21
+ kids.flat(Infinity).forEach((c) => {
22
+ const e = nodeEntry.get(c);
23
+ if (e) feed.push(e);
118
24
  });
119
25
 
120
- return div(
121
- {
122
- class: () =>
123
- "cf " + theme.val,
26
+ const initialTheme = typeof variant === "string" ? variant : (variant.val || "dark");
27
+ feed.setTheme(initialTheme);
124
28
 
125
- style: "flex:1"
126
- },
29
+ const body = ConsoleBody(feed);
127
30
 
128
- ConsoleToolbar({
129
- levels,
130
- query,
131
- count,
132
- clear: feed.clear
133
- }),
31
+ const container = div(
32
+ { class: "cf " + feed.theme },
33
+ // bar,
34
+ body,
35
+ // prompt,
36
+ ).style({
37
+ flex : 1
38
+ });
134
39
 
135
- ConsoleBody(visible),
40
+ feed.addEventListener("theme-change", (e) => {
41
+ container.className = "cf " + e.detail + " flex:1";
42
+ });
136
43
 
137
- repl
138
- ? ConsolePrompt({ feed })
139
- : ""
140
- );
44
+ return container;
141
45
  }
@@ -1,64 +1,41 @@
1
1
  import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
2
-
3
- import {
4
- fmt,
5
- isObj
6
- } from "../utils/index.js";
7
-
8
- import { Inspect } from "./Inspect.js";
9
- import { Table } from "./Table.js";
10
-
11
2
  const { div, span } = van.tags;
3
+ import { fmt, isObj } from "../utils/index.js";
4
+ import { Inspect, Table } from "./index.js";
12
5
 
13
6
  const cache = new WeakMap();
14
7
 
15
- const buildRow = entry => {
16
- const [a0, ...rest] = entry.args;
17
-
8
+ const buildRow = (e) => {
9
+ const [a0, ...rest] = e.args;
18
10
  const items =
19
- entry.method === "table" && isObj(a0)
20
- ? [
21
- Table(a0),
22
- ...rest.map(x =>
23
- Inspect(x, undefined, [], true).element
24
- )
25
- ]
26
- : fmt(entry.args).map(a =>
27
- Inspect(a, undefined, [], true).element
28
- );
11
+ e.method === "table" && isObj(a0)
12
+ ? [Table(a0), rest.map((x) => Inspect(x, undefined, [], true)).element]
13
+ : fmt(e.args).map((a) => Inspect(a, undefined, [], true).element);
14
+
15
+ const badgeSpan = span({ class: "cf-badge" }, () => (e.count > 1 ? e.count : ""));
16
+ const updateBadge = () => {
17
+ badgeSpan.textContent = e.count > 1 ? e.count : "";
18
+ badgeSpan.style.display = e.count > 1 ? "inline-block" : "none";
19
+ };
20
+ badgeSpan.updateBadge = updateBadge;
21
+ updateBadge();
29
22
 
30
23
  return div(
31
- {
32
- class: `cf-row ${entry.method}`,
33
- style: `--d:${entry.depth}`
34
- },
35
-
36
- () =>
37
- entry.count.val > 1
38
- ? span(
39
- { class: "cf-badge" },
40
- entry.count.val
41
- )
42
- : "",
43
-
24
+ { class: `cf-row ${e.method}`, style: `--d:${e.depth}` },
25
+ badgeSpan,
44
26
  span(
45
27
  { class: "cf-time" },
46
- entry.time.toLocaleTimeString([], {
47
- hour12: false
48
- })
28
+ e.time.toLocaleTimeString([], { hour12: false }),
49
29
  ),
50
-
51
- div(
52
- { class: "cf-msg" },
53
- items
54
- )
30
+ div({ class: "cf-msg" }, items),
55
31
  );
56
32
  };
57
33
 
58
- export const Row = entry =>
59
- cache.get(entry) ||
60
- (() => {
61
- const node = buildRow(entry);
62
- cache.set(entry, node);
63
- return node;
64
- })();
34
+ export const Row = (e) => {
35
+ if (cache.has(e)) return cache.get(e);
36
+ const n = buildRow(e);
37
+ cache.set(e, n);
38
+ return n;
39
+ };
40
+
41
+ export { cache };
@@ -1,8 +1,6 @@
1
1
  export * from './Inspect.js'
2
2
  export * from './Table.js'
3
3
  export * from './Row.js'
4
- export * from './ConsoleToolbar.js'
5
4
  export * from './ConsoleBody.js'
6
- export * from './ConsolePrompt.js'
7
5
  export * from './ConsoleFeed.js'
8
6
  export * from './Console.js'
@@ -0,0 +1,10 @@
1
+ export const nodeEntry = new WeakMap();
2
+
3
+ export const makeEntry = (method, args) => ({
4
+ id: 0,
5
+ method,
6
+ args,
7
+ depth: 0,
8
+ count: 1,
9
+ time: new Date(),
10
+ });
@@ -0,0 +1,96 @@
1
+ import { LEVEL, LEVELS, same, fmt, safe } from "../utils/index.js";
2
+
3
+ export class ConsoleStore extends EventTarget {
4
+ constructor(max = 1000, cacheRef = null) {
5
+ super();
6
+ this.logs = [];
7
+ this.max = max;
8
+ this.depth = 0;
9
+ this.id = 0;
10
+ this.levels = Object.fromEntries(LEVELS.map((l) => [l, true]));
11
+ this.query = "";
12
+ this.theme = "dark";
13
+ this.cache = cacheRef;
14
+ }
15
+
16
+ setTheme(theme) {
17
+ this.theme = theme;
18
+ this.dispatchEvent(new CustomEvent("theme-change", { detail: theme }));
19
+ }
20
+
21
+ toggleLevel(level) {
22
+ this.levels[level] = !this.levels[level];
23
+ this.dispatchEvent(new CustomEvent("filter-change"));
24
+ }
25
+
26
+ setQuery(query) {
27
+ this.query = query;
28
+ this.dispatchEvent(new CustomEvent("filter-change"));
29
+ }
30
+
31
+ push(src) {
32
+ const { method, args = [] } = src;
33
+ if (method === "clear") {
34
+ this.depth = 0;
35
+ this.logs = [];
36
+ this.dispatchEvent(new CustomEvent("clear"));
37
+ this.dispatchEvent(new CustomEvent("logs-change"));
38
+ return;
39
+ }
40
+ if (method === "groupEnd") {
41
+ this.depth = Math.max(0, this.depth - 1);
42
+ return;
43
+ }
44
+ const isGroup = method === "group" || method === "groupCollapsed";
45
+ const e = src.count
46
+ ? Object.assign(src, { id: ++this.id, depth: this.depth })
47
+ : {
48
+ id: ++this.id,
49
+ method: isGroup ? "group" : method,
50
+ args,
51
+ depth: this.depth,
52
+ count: 1,
53
+ time: new Date(),
54
+ };
55
+
56
+ if (src.count && this.cache) {
57
+ this.cache.get(e)?.style.setProperty("--d", this.depth);
58
+ }
59
+
60
+ const last = this.logs.at(-1);
61
+ if (last && !isGroup && same(last, e)) {
62
+ last.count++;
63
+ this.dispatchEvent(new CustomEvent("row-update", { detail: last }));
64
+ return;
65
+ }
66
+
67
+ this.logs.push(e);
68
+ if (this.logs.length > this.max) {
69
+ this.logs.shift();
70
+ }
71
+
72
+ this.dispatchEvent(new CustomEvent("logs-change", { detail: e }));
73
+ if (isGroup) this.depth++;
74
+ }
75
+
76
+ clear() {
77
+ this.push({ method: "clear" });
78
+ }
79
+
80
+ getCount(level) {
81
+ return this.logs.filter((e) => LEVEL[e.method] === level).length;
82
+ }
83
+
84
+ getVisibleLogs() {
85
+ const s = this.query.toLowerCase();
86
+ return this.logs.filter(
87
+ (e) =>
88
+ (!(e.method in LEVEL) || this.levels[LEVEL[e.method]]) &&
89
+ (!s || fmt(e.args).map(safe).join(" ").toLowerCase().includes(s))
90
+ );
91
+ }
92
+ }
93
+
94
+ export function createFeed(max = 1000, cache) {
95
+ return new ConsoleStore(max, cache);
96
+ }
package/src/index.css CHANGED
@@ -15,67 +15,15 @@ body {
15
15
  display: flex;
16
16
  flex-direction: column;
17
17
  }
18
- header {
19
- padding: 14px 20px 4px;
20
- }
21
- header h1 {
22
- margin: 0;
23
- font-size: 17px;
24
- font-weight: 650;
25
- }
26
- header p {
27
- margin: 2px 0 0;
28
- color: #5c6578;
29
- font-size: 13px;
30
- }
31
- main {
32
- flex: 1;
33
- min-height: 0;
34
- display: grid;
35
- grid-template-columns: 230px 1fr;
36
- gap: 14px;
37
- padding: 12px 20px 20px;
38
- }
18
+
39
19
  @media (max-width: 720px) {
40
20
  main {
41
21
  grid-template-columns: 1fr;
42
22
  grid-template-rows: auto 1fr;
43
23
  }
44
24
  }
45
- aside {
46
- display: flex;
47
- flex-wrap: wrap;
48
- align-content: flex-start;
49
- gap: 6px;
50
- }
51
- aside h2 {
52
- width: 100%;
53
- margin: 6px 0 0;
54
- font-size: 12px;
55
- font-weight: 600;
56
- color: #5c6578;
57
- }
58
- aside button {
59
- font: inherit;
60
- font-size: 13px;
61
- padding: 5px 10px;
62
- border: 1px solid #c9cedb;
63
- background: #f6f7fa;
64
- color: inherit;
65
- border-radius: 5px;
66
- cursor: pointer;
67
- }
68
- aside button:hover {
69
- background: #fff;
70
- border-color: #8a93a8;
71
- }
72
- button:focus-visible,
73
- input:focus-visible {
74
- outline: 2px solid #3b82f6;
75
- outline-offset: 1px;
76
- }
77
25
 
78
- /* ---------- Console component ---------- */
26
+ /* ---------- Console feed ---------- */
79
27
  .cf {
80
28
  --bg: #171b24;
81
29
  --bar: #1e2330;
@@ -119,49 +67,7 @@ input:focus-visible {
119
67
  --err-fg: #b3261e;
120
68
  --hover: #f3f5f9;
121
69
  }
122
- .cf-bar {
123
- display: flex;
124
- gap: 6px;
125
- align-items: center;
126
- padding: 6px 8px;
127
- background: var(--bar);
128
- border-bottom: 1px solid var(--line);
129
- flex-wrap: wrap;
130
- }
131
- .cf-bar input {
132
- flex: 1;
133
- min-width: 120px;
134
- font: inherit;
135
- background: var(--bg);
136
- color: var(--fg);
137
- border: 1px solid var(--line);
138
- border-radius: 4px;
139
- padding: 3px 8px;
140
- }
141
- .cf-bar button {
142
- font: inherit;
143
- background: none;
144
- color: var(--dim);
145
- border: 1px solid transparent;
146
- border-radius: 4px;
147
- padding: 2px 8px;
148
- cursor: pointer;
149
- }
150
- .cf-bar button:hover {
151
- color: var(--fg);
152
- border-color: var(--line);
153
- }
154
- .cf-bar button.cf-chip.on {
155
- color: var(--fg);
156
- border-color: var(--line);
157
- background: var(--bg);
158
- }
159
- .cf-chip.warn.on {
160
- color: var(--warn-fg) !important;
161
- }
162
- .cf-chip.error.on {
163
- color: var(--err-fg) !important;
164
- }
70
+
165
71
  .cf-body {
166
72
  flex: 1;
167
73
  overflow: auto;
@@ -288,23 +194,4 @@ input:focus-visible {
288
194
  .cf-table th {
289
195
  background: var(--bar);
290
196
  font-weight: 600;
291
- }
292
- .cf-prompt {
293
- display: flex;
294
- align-items: center;
295
- gap: 8px;
296
- padding: 5px 10px;
297
- border-top: 1px solid var(--line);
298
- background: var(--bar);
299
- }
300
- .cf-prompt span {
301
- color: var(--key);
302
- }
303
- .cf-prompt input {
304
- flex: 1;
305
- font: inherit;
306
- background: none;
307
- border: 0;
308
- color: var(--fg);
309
- outline: 0;
310
- }
197
+ }
package/src/index.js CHANGED
@@ -1,51 +1,4 @@
1
- import './index.css'
2
- import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js"
3
- import {
4
- ConsoleFeed,
5
- Console
6
- } from './components'
7
- import { createFeed } from './feed/createFeed'
8
- import { Hook } from './hook/index.js'
9
-
10
- Object.assign(window, {ConsoleFeed: {Hook, createFeed, ConsoleFeed, Console}})
11
-
12
- /* =====================================================================
13
- Demo
14
- ===================================================================== */
15
-
16
- const theme = van.state("light")
17
-
18
- // 1) Declarative: children only, or props first then children
19
- document.body.append(
20
- ConsoleFeed({variant: theme, repl: false},
21
- Console.log("Hello from VanJS", 42, true, null, undefined),
22
- Console.info("Server listening on :3000"),
23
- Console.group("Request"),
24
- Console.log("parsing"),
25
- Console.warn("token expires soon"),
26
- Console.groupEnd(),
27
- Console.error(new Error("Something broke")),
28
- Console.table([{id: 1, name: "Ada"}, {id: 2, name: "Linus"}]),
29
- )
30
- )
31
-
32
- // 2) Standalone: a single row, no toolbar
33
- document.body.append(Console.log("Just one line", {a: 1, b : 1}))
34
- document.body.append(Console.warn("Standalone warning"))
35
- document.body.append(Console.table([1,2,3]))
36
-
37
-
38
- // 3) Live: hook the real console into a feed
39
- Console.theme = theme
40
- const feed = createFeed()
41
- Hook(console, e => feed.push(e))
42
- globalThis.c = ConsoleFeed({feed})
43
- document.body.append(c)
44
-
45
- console.log("Hello from VanJS", 42, true, null, undefined)
46
- console.log({a: 1})
47
- console.group("Request")
48
- console.log("parsing")
49
- console.group("Auth")
50
- console.warn("token expires soon")
51
- console.groupEnd()
1
+ import "./index.css";
2
+ export { Hook } from "./hook/index.js";
3
+ export { createFeed } from "./feed/index.js";
4
+ export { ConsoleFeed, Console } from "./components/index.js";
@@ -0,0 +1,11 @@
1
+ export const LEVEL = {
2
+ log: "log",
3
+ dir: "log",
4
+ table: "log",
5
+ group: "log",
6
+ info: "info",
7
+ debug: "debug",
8
+ warn: "warn",
9
+ error: "error",
10
+ };
11
+ export const LEVELS = ["log", "info", "warn", "error", "debug"];
@@ -0,0 +1,5 @@
1
+ export const same = (a, b) =>
2
+ a.method === b.method &&
3
+ a.depth === b.depth &&
4
+ a.args.length === b.args.length &&
5
+ a.args.every((x, i) => !isObj(x) && Object.is(x, b.args[i])); // is v f
@@ -1,2 +1,4 @@
1
1
  export * from './value-formatting.js'
2
- export * from './fmt.js'
2
+ export * from './fmt.js'
3
+ export * from './feed.js'
4
+ export * from './const.js'
@@ -1,4 +1,5 @@
1
1
  export const isObj = v => v !== null && typeof v === "object"
2
+ export const isProps = a => a && typeof a === "object" && !(a instanceof Node) && Object.getPrototypeOf(a) === Object.prototype
2
3
  export const cname = v => { try { return Object.getPrototypeOf(v)?.constructor?.name || "" } catch { return "" } }
3
4
  export const prim = v => typeof v === "string" ? JSON.stringify(v) : typeof v === "bigint" ? v + "n" : String(v)
4
5
  export const primCls = v => v == null ? "nul" : typeof v === "string" ? "str" : typeof v === "boolean" ? "bool" : "num"
@@ -1,74 +0,0 @@
1
- import { tags } from "ziko/dom";
2
- const { div, span, input } = tags;
3
- export function ConsolePrompt({
4
- feed
5
- }) {
6
- const history = [];
7
- let index = 0;
8
-
9
- const run = code => {
10
- feed.push({
11
- method: "command",
12
- args: [code]
13
- });
14
-
15
- try {
16
- feed.push({
17
- method: "result",
18
- args: [(0, eval)(code)]
19
- });
20
- } catch (error) {
21
- feed.push({
22
- method: "error",
23
- args: [error]
24
- });
25
- }
26
- };
27
-
28
- const inp = input({
29
- placeholder: "Run JavaScript",
30
- "aria-label": "Run JavaScript",
31
- spellcheck: false,
32
- autocomplete: "off",
33
-
34
- onKeyDown: __e__ => {
35
- const e = __e__.event
36
- const el = e.target;
37
-
38
- if (
39
- e.key === "Enter" &&
40
- el.value.trim()
41
- ) {
42
- history.push(el.value);
43
- index = history.length;
44
-
45
- run(el.value);
46
-
47
- el.value = "";
48
- }
49
-
50
- else if (
51
- e.key === "ArrowUp" &&
52
- index > 0
53
- ) {
54
- el.value = history[--index];
55
- e.preventDefault();
56
- }
57
-
58
- else if (e.key === "ArrowDown") {
59
- el.value =
60
- index < history.length - 1
61
- ? history[++index]
62
- : (index = history.length, "");
63
- }
64
- }
65
- })
66
-
67
- return div(
68
- { class: "cf-prompt" },
69
-
70
- span("\u203A"),
71
- inp
72
-
73
- ).element;
74
- }
@@ -1,61 +0,0 @@
1
- import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
2
-
3
- const {
4
- div,
5
- button,
6
- input
7
- } = van.tags;
8
-
9
- export function ConsoleToolbar({
10
- levels,
11
- query,
12
- count,
13
- clear
14
- }) {
15
- const LEVELS = [
16
- "log",
17
- "info",
18
- "warn",
19
- "error",
20
- "debug"
21
- ];
22
-
23
- return div(
24
- { class: "cf-bar" },
25
-
26
- LEVELS.map(level =>
27
- button(
28
- {
29
- class: () =>
30
- `cf-chip ${level}` +
31
- (levels[level].val ? " on" : ""),
32
-
33
- "aria-pressed": () =>
34
- levels[level].val,
35
-
36
- onclick: () =>
37
- levels[level].val =
38
- !levels[level].val
39
- },
40
-
41
- level,
42
- " ",
43
- count(level)
44
- )
45
- ),
46
-
47
- input({
48
- type: "search",
49
- placeholder: "Filter messages",
50
- "aria-label": "Filter messages",
51
-
52
- oninput: e =>
53
- query.val = e.target.value
54
- }),
55
-
56
- button(
57
- { onclick: clear },
58
- "Clear"
59
- )
60
- );
61
- }
@@ -1,67 +0,0 @@
1
- import van from "https://cdn.jsdelivr.net/npm/vanjs-core@1.5.3/src/van.js";
2
- import { isObj } from "../utils/index.js";
3
-
4
- export function createFeed(max = 1000) {
5
- const logs = van.state([]);
6
-
7
- let depth = 0;
8
- let id = 0;
9
-
10
- const same = (a, b) =>
11
- a.method === b.method &&
12
- a.depth === b.depth &&
13
- a.args.length === b.args.length &&
14
- a.args.every(
15
- (x, i) => !isObj(x) && Object.is(x, b.args[i])
16
- );
17
-
18
- const push = src => {
19
- const { method, args = [] } = src;
20
-
21
- if (method === "clear") {
22
- depth = 0;
23
- logs.val = [];
24
- return;
25
- }
26
-
27
- if (method === "groupEnd") {
28
- depth = Math.max(0, depth - 1);
29
- return;
30
- }
31
-
32
- const isGroup =
33
- method === "group" ||
34
- method === "groupCollapsed";
35
-
36
- const entry = src.count
37
- ? Object.assign(src, {
38
- id: ++id,
39
- depth
40
- })
41
- : {
42
- id: ++id,
43
- method: isGroup ? "group" : method,
44
- args,
45
- depth,
46
- count: van.state(1),
47
- time: new Date()
48
- };
49
-
50
- const last = logs.val.at(-1);
51
-
52
- if (last && !isGroup && same(last, entry)) {
53
- last.count.val++;
54
- return;
55
- }
56
-
57
- logs.val = [...logs.val, entry].slice(-max);
58
-
59
- if (isGroup) depth++;
60
- };
61
-
62
- return {
63
- logs,
64
- push,
65
- clear: () => push({ method: "clear" })
66
- };
67
- }