streamator-react 0.1.0 → 0.1.2

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 ADDED
@@ -0,0 +1,94 @@
1
+ # streamator-react
2
+
3
+ Frontend primitives for displaying live log streams in React. Handles SSE connection,
4
+ entry formatting, auto-scroll, and rendering.
5
+
6
+ Pairs with [`streamator`](https://pypi.org/project/streamator/) on the backend.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install streamator-react
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```jsx
17
+ import { useLogStream, LogPanel } from "streamator-react"
18
+ import "streamator-react/log.css"
19
+
20
+ const { logs, active } = useLogStream(`/api/log/${jobId}/stream`)
21
+
22
+ <LogPanel logs={logs} active={active} />
23
+ ```
24
+
25
+ ## `useLogStream(url, options)`
26
+
27
+ ```js
28
+ const { logs, active } = useLogStream(url, {
29
+ mode: "sse", // "sse" (default) | "poll"
30
+ interval: 3000, // poll interval ms — poll mode only
31
+ formatEvent: fn, // (rawEvent) => string | null
32
+ })
33
+ ```
34
+
35
+ - `logs` — `Array<{ text, t, level }>` — ready to render
36
+ - `active` — `true` while stream is open / polling
37
+ - Passing `null` or `undefined` as `url` is a no-op
38
+
39
+ ## `LogPanel` props
40
+
41
+ ```jsx
42
+ <LogPanel
43
+ logs={logs}
44
+ active={active}
45
+ waitingText="⏳ Starting…" // shown while active but no logs yet
46
+ maxHeight="200px" // default: 160px
47
+ className="my-log" // appended to root class
48
+ style={{}}
49
+ renderEntry={(entry, i) => <div />} // fully custom row renderer
50
+ autoScroll={true} // set false to disable auto-scroll
51
+ />
52
+ ```
53
+
54
+ Returns `null` when not active and no logs. Auto-scrolls to latest entry.
55
+
56
+ ## `makeFormatEvent(overrides)`
57
+
58
+ Map structured backend events to display strings:
59
+
60
+ ```js
61
+ import { makeFormatEvent } from "streamator-react"
62
+
63
+ const formatEvent = makeFormatEvent({
64
+ scraping: e => `🔍 Scraping ${e.url}`,
65
+ done: () => `✅ Finished`,
66
+ })
67
+
68
+ const { logs } = useLogStream(url, { formatEvent })
69
+ ```
70
+
71
+ Return `null` from a handler to suppress that entry entirely.
72
+
73
+ ## Styling
74
+
75
+ Default styles via CSS custom properties — override any of them:
76
+
77
+ ```css
78
+ --streamator-bg: #f8f8f8;
79
+ --streamator-border: #e0e0e0;
80
+ --streamator-color: #444;
81
+ --streamator-time-color: #aaa;
82
+ --streamator-radius: 6px;
83
+ --streamator-font-size: 0.8rem;
84
+ --streamator-max-height: 160px;
85
+ --streamator-success-color: #2e7d32;
86
+ --streamator-warning-color: #f59e0b;
87
+ --streamator-error-color: #c62828;
88
+ ```
89
+
90
+ Migrating from old `.log` / `.log-time` / `.log-waiting` class names?
91
+
92
+ ```js
93
+ import "streamator-react/log-compat.css"
94
+ ```
package/dist/index.cjs.js CHANGED
@@ -85,20 +85,20 @@ function LogPanel({
85
85
  maxHeight,
86
86
  className,
87
87
  style,
88
- renderEntry
88
+ renderEntry,
89
+ autoScroll = true
89
90
  }) {
90
- const bottomRef = react.useRef(null);
91
+ const panelRef = react.useRef(null);
91
92
  react.useEffect(() => {
92
- bottomRef.current?.scrollIntoView({
93
- behavior: "smooth"
94
- });
95
- }, [logs]);
93
+ if (autoScroll && panelRef.current) panelRef.current.scrollTop = panelRef.current.scrollHeight;
94
+ }, [logs, autoScroll]);
96
95
  if (!active && logs.length === 0) return null;
97
96
  const rootStyle = maxHeight ? {
98
97
  ...style,
99
98
  "--streamator-max-height": maxHeight
100
99
  } : style;
101
100
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
101
+ ref: panelRef,
102
102
  className: ["streamator-log", className].filter(Boolean).join(" "),
103
103
  style: rootStyle,
104
104
  children: [active && logs.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -112,9 +112,7 @@ function LogPanel({
112
112
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
113
113
  children: entry.text
114
114
  })]
115
- }, i)), /*#__PURE__*/jsxRuntime.jsx("div", {
116
- ref: bottomRef
117
- })]
115
+ }, i))]
118
116
  });
119
117
  }
120
118
 
package/dist/index.esm.js CHANGED
@@ -83,20 +83,20 @@ function LogPanel({
83
83
  maxHeight,
84
84
  className,
85
85
  style,
86
- renderEntry
86
+ renderEntry,
87
+ autoScroll = true
87
88
  }) {
88
- const bottomRef = useRef(null);
89
+ const panelRef = useRef(null);
89
90
  useEffect(() => {
90
- bottomRef.current?.scrollIntoView({
91
- behavior: "smooth"
92
- });
93
- }, [logs]);
91
+ if (autoScroll && panelRef.current) panelRef.current.scrollTop = panelRef.current.scrollHeight;
92
+ }, [logs, autoScroll]);
94
93
  if (!active && logs.length === 0) return null;
95
94
  const rootStyle = maxHeight ? {
96
95
  ...style,
97
96
  "--streamator-max-height": maxHeight
98
97
  } : style;
99
98
  return /*#__PURE__*/jsxs("div", {
99
+ ref: panelRef,
100
100
  className: ["streamator-log", className].filter(Boolean).join(" "),
101
101
  style: rootStyle,
102
102
  children: [active && logs.length === 0 && /*#__PURE__*/jsx("div", {
@@ -110,9 +110,7 @@ function LogPanel({
110
110
  }), /*#__PURE__*/jsx("span", {
111
111
  children: entry.text
112
112
  })]
113
- }, i)), /*#__PURE__*/jsx("div", {
114
- ref: bottomRef
115
- })]
113
+ }, i))]
116
114
  });
117
115
  }
118
116
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "streamator-react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Frontend primitives for displaying live log streams",
5
5
  "author": "Arved Klöhn <arved.kloehn@gmail.com>",
6
6
  "license": "MIT",