@arcanejs/react-toolkit 0.1.2 → 0.1.4

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
@@ -3,7 +3,7 @@
3
3
  [![NPM Version](https://img.shields.io/npm/v/%40arcanejs%2Freact-toolkit)](https://www.npmjs.com/package/@arcanejs/react-toolkit)
4
4
 
5
5
  `@arcanejs/react-toolkit` Allows you to quickly create real-time control panels
6
- for your JavaScript / TypeScript single-server apps,
6
+ for your single-process Node.js apps,
7
7
  using a custom react renderer, and WebSockets.
8
8
 
9
9
  Control panels can be accessed by any number of
@@ -14,20 +14,21 @@ clients.
14
14
  The UI has also been designed primarily with touch devices in mind,
15
15
  but also works well with a cursor and keyboard.
16
16
 
17
- ## Status / Suitability / Security Disclaimer
17
+ <p align="center">
18
+ <img src="./docs/architecture.svg" alt="Architecture Diagram">
19
+ </p>
18
20
 
19
- This project is **experimental**,
20
- and takes advantage of unstable `react` APIs exposed via `react-render`.
21
- It's not suitable for production or commercial projects yet,
22
- especially those that rely on regular updates of dependencies
23
- for security reasons,
24
- as usage of this project may make it difficult to keep `react` up-to-date
25
- (that being said, the license does not prohibit this,
26
- so feel free to at-your-own-risk).
21
+ ## What
27
22
 
28
- There are also no authentication mechanisms implemented yet,
29
- so be careful when exposing your control panels over the network,
30
- as this will allow anyone to interact with your processes.
23
+ - Easily create controller UIs for Node.js processes
24
+
25
+ - Uses server-side **React** for state management and UI composition
26
+
27
+ - This is not SSR, you can use `useState()` hooks etc...
28
+
29
+ - Instantly updates all clients using WebSockets
30
+
31
+ - Collection of 9+ components to build your UIs
31
32
 
32
33
  ## Why
33
34
 
@@ -287,3 +288,18 @@ TODO
287
288
  For a comprehensive list of examples,
288
289
  please see the example directory in the arcane monorepo:
289
290
  <https://github.com/arcanejs/arcanejs/tree/main/examples/react>
291
+
292
+ ## Status / Suitability / Security Disclaimer
293
+
294
+ This project is **experimental**,
295
+ and takes advantage of unstable `react` APIs exposed via `react-render`.
296
+ It's not suitable for production or commercial projects yet,
297
+ especially those that rely on regular updates of dependencies
298
+ for security reasons,
299
+ as usage of this project may make it difficult to keep `react` up-to-date
300
+ (that being said, the license does not prohibit this,
301
+ so feel free to at-your-own-risk).
302
+
303
+ There are also no authentication mechanisms implemented yet,
304
+ so be careful when exposing your control panels over the network,
305
+ as this will allow anyone to interact with your processes.
@@ -0,0 +1,271 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg"
2
+ xmlns:xlink="http://www.w3.org/1999/xlink" id="svg8" version="1.1" viewBox="0 0 800 200" width="800" height="200">
3
+ <style>
4
+ * {
5
+ font-size: 14px;
6
+ font-family: sans-serif;
7
+ }
8
+
9
+ #labels * {
10
+ font-size: 14px;
11
+ font-weight: bold;
12
+ }
13
+
14
+ #code * {
15
+ font-size: 12px;
16
+ font-family: monospace;
17
+ }
18
+
19
+ .black-border {
20
+ stroke: #151516;
21
+ stroke-width: 1;
22
+ }
23
+
24
+ @keyframes btn-move-keyframes {
25
+ 5% {
26
+ transform: translate(0, 0);
27
+ }
28
+ 10% {
29
+ transform: translate(40px, 0);
30
+ }
31
+ 55% {
32
+ transform: translate(40px, 0);
33
+ }
34
+ 60% {
35
+ transform: translate(0, 0);
36
+ }
37
+ }
38
+
39
+ .btn-move {
40
+ animation: 6s linear 0s infinite normal none running btn-move-keyframes;
41
+ }
42
+
43
+ @keyframes mouse-anim-keyframes {
44
+ 0% {
45
+ opacity: 1;
46
+ transform: scale(1);
47
+ }
48
+ 2.5% {
49
+ opacity: 1;
50
+ transform: scale(0.8);
51
+ }
52
+ 5% {
53
+ opacity: 1;
54
+ transform: scale(1);
55
+ }
56
+ 7.5% {
57
+ opacity: 1;
58
+ transform: scale(1);
59
+ }
60
+ 10% {
61
+ opacity: 0;
62
+ transform: scale(1);
63
+ }
64
+ 90% {
65
+ opacity: 0;
66
+ transform: scale(1);
67
+ }
68
+ 100% {
69
+ opacity: 1;
70
+ transform: scale(1);
71
+ }
72
+ }
73
+
74
+ @keyframes highlight-keyframes {
75
+ 0% {
76
+ opacity: 0;
77
+ }
78
+ 2.45% {
79
+ opacity: 0;
80
+ }
81
+ 2.5% {
82
+ opacity: 1;
83
+ }
84
+ 10% {
85
+ opacity: 0;
86
+ }
87
+ 100% {
88
+ opacity: 0;
89
+ }
90
+ }
91
+
92
+ .mouse-anim-1 {
93
+ opacity: 0;
94
+ transform-origin: 60px 75px;
95
+ animation: 6s linear 0s infinite normal none running mouse-anim-keyframes;
96
+ }
97
+
98
+ .highlight-anim-1 {
99
+ opacity: 0;
100
+ animation: 6s linear 0s infinite normal none running highlight-keyframes;
101
+ }
102
+
103
+ .mouse-anim-2 {
104
+ opacity: 0;
105
+ transform-origin: 620px 75px;
106
+ animation: 6s linear 3s infinite normal none running mouse-anim-keyframes;
107
+ }
108
+
109
+ .highlight-anim-2 {
110
+ opacity: 0;
111
+ animation: 6s linear 3s infinite normal none running highlight-keyframes;
112
+ }
113
+
114
+ @keyframes state-keyframes {
115
+ 4.9% {
116
+ opacity: 0;
117
+ fill: #aaa;
118
+ }
119
+ 5% {
120
+ opacity: 1;
121
+ fill: #4286f4;
122
+ }
123
+ 10% {
124
+ opacity: 1;
125
+ fill: #aaa;
126
+ }
127
+ 54.9% {
128
+ opacity: 1;
129
+ fill: #aaa;
130
+ }
131
+ 55% {
132
+ opacity: 0;
133
+ fill: #aaa;
134
+ }
135
+ }
136
+
137
+ .text-off {
138
+ font-weight: bold;
139
+ opacity: 0;
140
+ animation: 6s linear 3s infinite normal none running state-keyframes;
141
+ }
142
+
143
+ .text-on {
144
+ font-weight: bold;
145
+ opacity: 0;
146
+ animation: 6s linear 0s infinite normal none running state-keyframes;
147
+ }
148
+ </style>
149
+ <defs>
150
+ <linearGradient id="buttonOnGrad" x1="0%" y1="0%" x2="0%" y2="100%">
151
+ <stop offset="0%" style="stop-color:#2a77f3;stop-opacity:1" />
152
+ <stop offset="100%" style="stop-color:#4286f4;stop-opacity:1" />
153
+ </linearGradient>
154
+ <linearGradient id="buttonOffGrad" x1="0%" y1="0%" x2="0%" y2="100%">
155
+ <stop offset="0%" style="stop-color:#242525;stop-opacity:1" />
156
+ <stop offset="100%" style="stop-color:#37383a;stop-opacity:1" />
157
+ </linearGradient>
158
+ <linearGradient id="buttonGrad" x1="0%" y1="0%" x2="0%" y2="100%">
159
+ <stop offset="0%" style="stop-color:#4f5053;stop-opacity:1" />
160
+ <stop offset="100%" style="stop-color:#343436;stop-opacity:1" />
161
+ </linearGradient>
162
+ <filter id="textShadow" x="-50%" y="-50%" width="200%" height="200%">
163
+ <feGaussianBlur in="SourceAlpha" stdDeviation="1"/>
164
+ <feOffset dx="0" dy="-1" result="offsetblur"/>
165
+ <feFlood flood-color="rgba(0,0,0,0.4)"/>
166
+ <feComposite in2="offsetblur" operator="in"/>
167
+ <feMerge>
168
+ <feMergeNode/>
169
+ <feMergeNode in="SourceGraphic"/>
170
+ </feMerge>
171
+ </filter>
172
+ <filter id="inset-shadow" x="-50%" y="-50%" width="200%" height="200%">
173
+ <feComponentTransfer in="SourceAlpha">
174
+ <feFuncA type="table" tableValues="1 0" />
175
+ </feComponentTransfer>
176
+ <feGaussianBlur stdDeviation="5" />
177
+ <feOffset dx="0" dy="0" result="offsetblur" />
178
+ <feFlood flood-color="black" result="color" />
179
+ <feComposite in2="offsetblur" operator="in" />
180
+ <feComposite in2="SourceAlpha" operator="in" />
181
+ <feMerge>
182
+ <feMergeNode in="SourceGraphic" />
183
+ <feMergeNode />
184
+ </feMerge>
185
+ </filter>
186
+ <marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
187
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#777" />
188
+ </marker>
189
+ <g id="button_slider">
190
+ <rect x="-40" y="0" width="40" height="30" fill="url(#buttonOnGrad)" />
191
+ <text x="-20" y="15" width="40" height="30" dy="0.35em" text-anchor="middle" fill="white" filter="url(#textShadow)">ON</text>
192
+ <rect x="29" y="0" width="41" height="30" fill="url(#buttonOffGrad)" />
193
+ <text x="50" y="15" width="40" height="30" dy="0.35em" text-anchor="middle" fill="white" filter="url(#textShadow)">OFF</text>
194
+ <rect x="-1" y="0" class="black-border" width="31" height="30" fill="url(#buttonGrad)" rx="3" ry="3" />
195
+ </g>
196
+ <g id="screen">
197
+ <rect x="0" y="0" width="200" height="100" fill="#252524" filter="url(#inset-shadow)" rx="3" ry="3" />
198
+ <mask id="button_slider_1_mask">
199
+ <rect x="10.5" y="10.5" width="70" height="30" fill="#ffffff" rx="3" ry="3" />
200
+ </mask>
201
+ <g mask="url(#button_slider_1_mask)">
202
+ <g class="btn-move">
203
+ <use x="10.5" y="10.5" href="#button_slider" />
204
+ </g>
205
+ </g>
206
+ <rect class="black-border" x="10.5" y="10.5" width="70" height="30" fill="none" rx="3" ry="3" />
207
+ </g>
208
+ <g id="browser">
209
+ <rect x="-10" y="0" width="220" height="150" fill="#ccc" rx="5" ry="5" stroke-width="2" stroke="#aaa" />
210
+ <rect x="40.5" y="10.5" width="160" height="20" fill="#fff" rx="3" ry="3" stroke-width="1" stroke="#aaa" />
211
+ <path d="M 10 15 L 0 20 L 10 25 Z" fill="#777" />
212
+ <path d="M 20 15 L 30 20 L 20 25 Z" fill="#777" />
213
+ <text x="120" y="20" height="30" dy="0.35em" text-anchor="middle" fill="#777">10.10.10.10:8080</text>
214
+ </g>
215
+ <g id="switch_highlight">
216
+ <rect x="0.5" y="0.5" width="82" height="42" fill="none" stroke="#4286f4" stroke-width="2" rx="6" ry="6" />
217
+ </g>
218
+ <g id="mouse">
219
+ <g style="transform: scale(3)">
220
+ <path fill="#fefefe" d="M5.986 21.07v-2.155h-.958V17H4.07v-1.915h-.957V12.93H1.915v-.958H.958v-1.916h2.155v.958h.957v2.873h.958V.957h1.916v9.1H7.9V5.985h2.155v4.07h.958V6.944h1.916v4.07h.957V7.901h1.198V9.1h.957v6.943h-.957v2.873h-1.198v2.155H5.986z"/>
221
+ <path d="M5.028 22.028v-3.113H4.07V17h-.957v-1.915H1.915V12.93H.958v-.958H0V9.099h3.113v.957h.957V.958h.958V0h1.916v.958H7.9v4.07h2.155v.958h2.874v.958h2.155V7.9h.957V9.1H17v6.943h-.958v2.873h-.957v3.113H5.028zm8.86-.958v-2.155h1.197v-2.873h.957V9.1h-.957V7.9h-1.198v3.113h-.957v-4.07h-1.916v3.112h-.958v-4.07H7.901v4.07h-.957V.958H5.028v12.93H4.07v-2.874h-.957v-.958H.958v1.916h.957v.958h1.198v2.155h.957V17h.958v1.915h.958v2.155h7.901z" />
222
+ </g>
223
+ </g>
224
+ </defs>
225
+
226
+ <g>
227
+ <use y="10" x="20" href="#browser" />
228
+ <use y="50" x="20" href="#screen" />
229
+
230
+ <use y="10" x="580" href="#browser" />
231
+ <use y="50" x="580" href="#screen" />
232
+
233
+ <use y="54" x="24" href="#switch_highlight" class="highlight-anim-1" />
234
+ <use y="75" x="50.5" href="#mouse" class="mouse-anim-1" />
235
+ <use y="54" x="584" href="#switch_highlight" class="highlight-anim-2" />
236
+ <use y="75" x="610.5" href="#mouse" class="mouse-anim-2" />
237
+ </g>
238
+
239
+ <g>
240
+ <rect x="290" y="10" width="220" height="150" fill="#333" rx="5" ry="5" stroke-width="2" stroke="#050505" />
241
+ <g id="code">
242
+ <text x="300" y="30" text-anchor="start" fill="#f5f5f5">const &#91;state, setState&#93; &#61;</text>
243
+ <text x="300" y="50" text-anchor="start" fill="#f5f5f5">&#160;&#160;useState&#40;&#39;off&#39;&#41;&#59;</text>
244
+ <text x="300" y="80" text-anchor="start" fill="#aaa" class="text-off">&#47;&#47; state &#61;&#61; &#39;off&#39;</text>
245
+ <text x="300" y="80" text-anchor="start" fill="#aaa" class="text-on">&#47;&#47; state &#61;&#61; &#39;on&#39;</text>
246
+ <text x="300" y="110" text-anchor="start" fill="#f5f5f5">&lt;Switch</text>
247
+ <text x="300" y="130" text-anchor="start" fill="#f5f5f5">&#160;&#160;state&#61;&#123;state&#125;</text>
248
+ <text x="300" y="150" text-anchor="start" fill="#f5f5f5">&#160;&#160;onChange&#61;&#123;setState&#125; &#47;&#62;</text>
249
+ </g>
250
+ </g>
251
+
252
+ <g id="labels">
253
+ <!-- WS -->
254
+ <line x1="235" y1="90" x2="285" y2="90" stroke="#777" stroke-width="2" marker-start="url(#arrow)" marker-end="url(#arrow)" />
255
+ <rect x="235" y="52.5" width="50" height="25" fill="#f5f5f5" rx="6" ry="6" />
256
+ <text x="260" y="70" height="30" text-anchor="middle" fill="#333">WS</text>
257
+
258
+ <line x1="515" y1="90" x2="565" y2="90" stroke="#777" stroke-width="2" marker-start="url(#arrow)" marker-end="url(#arrow)" />
259
+ <rect x="515" y="52.5" width="50" height="25" fill="#f5f5f5" rx="6" ry="6" />
260
+ <text x="540" y="70" height="30" text-anchor="middle" fill="#333">WS</text>
261
+
262
+ <!-- Bottom -->
263
+ <rect x="35" y="167.5" width="170" height="25" fill="#f5f5f5" rx="6" ry="6" />
264
+ <text x="120" y="185" height="30" text-anchor="middle" fill="#333">Browser Client 1</text>
265
+ <rect x="315" y="167.5" width="170" height="25" fill="#f5f5f5" rx="6" ry="6" />
266
+ <text x="400" y="185" height="30" text-anchor="middle" fill="#333">Node.js Process</text>
267
+ <rect x="595" y="167.5" width="170" height="25" fill="#f5f5f5" rx="6" ry="6" />
268
+ <text x="680" y="185" height="30" text-anchor="middle" fill="#333">Browser Client 2</text>
269
+ </g>
270
+
271
+ </svg>
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcanejs/react-toolkit",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "description": "Build web-accessible control interfaces for your long-running Node.js processes",
6
6
  "keywords": [
@@ -35,15 +35,16 @@
35
35
  "react-reconciler": "^0.28.0",
36
36
  "tsup": "^8.1.0",
37
37
  "typescript": "^5.3.3",
38
- "@arcanejs/eslint-config": "^0.0.0",
39
- "@arcanejs/typescript-config": "^0.0.0"
38
+ "@arcanejs/typescript-config": "^0.0.0",
39
+ "@arcanejs/eslint-config": "^0.0.0"
40
40
  },
41
41
  "dependencies": {
42
42
  "react": "^18",
43
43
  "@arcanejs/toolkit": "^0.2.0"
44
44
  },
45
45
  "files": [
46
- "dist"
46
+ "dist",
47
+ "docs"
47
48
  ],
48
49
  "publishConfig": {
49
50
  "access": "public"