@arcanejs/react-toolkit 0.12.5 → 0.13.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/README.md +273 -193
- package/dist/{chunk-Q54JXYCV.js → chunk-EJVUDIQP.js} +94 -38
- package/dist/{chunk-CAHNLXTY.mjs → chunk-TP2BI3OM.mjs} +93 -37
- package/dist/colors.js +7 -7
- package/dist/colors.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -2,309 +2,389 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@arcanejs/react-toolkit)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
for your single-process Node.js apps,
|
|
7
|
-
using a custom react renderer, and WebSockets.
|
|
5
|
+
React renderer for ArcaneJS server-side control panels.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
browsers / devices / clients simultaneously,
|
|
11
|
-
and changes caused by any client will be immediately propagated to all other
|
|
12
|
-
clients.
|
|
13
|
-
|
|
14
|
-
The UI has also been designed primarily with touch devices in mind,
|
|
15
|
-
but also works well with a cursor and keyboard.
|
|
7
|
+
This package lets you build toolkit component trees using React state/hooks on the server, then synchronize them to connected browser clients in real time.
|
|
16
8
|
|
|
17
9
|
<p align="center">
|
|
18
10
|
<img src="https://raw.githubusercontent.com/ArcaneWizards/arcanejs/main/packages/react-toolkit/docs/architecture.svg" alt="Architecture Diagram">
|
|
19
11
|
</p>
|
|
20
12
|
|
|
21
|
-
##
|
|
13
|
+
## Why Use `@arcanejs/react-toolkit`
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
This package is useful when you want a control panel for a long-running Node.js process without building a full web app stack.
|
|
24
16
|
|
|
25
|
-
|
|
17
|
+
It gives you:
|
|
26
18
|
|
|
27
|
-
|
|
19
|
+
- server-side React state/hooks for control logic
|
|
20
|
+
- realtime multi-client sync over WebSockets
|
|
21
|
+
- a ready set of control-oriented UI components (switches, sliders, groups, tabs, timelines)
|
|
22
|
+
- an extension path for custom components when core components are not enough
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
Typical use cases:
|
|
30
25
|
|
|
31
|
-
-
|
|
26
|
+
- home/lab automation control surfaces
|
|
27
|
+
- AV/lighting/operations dashboards on a local network
|
|
28
|
+
- internal tooling for stateful services/scripts that need live operator controls
|
|
32
29
|
|
|
33
|
-
##
|
|
30
|
+
## When It Fits (And When It Doesn't)
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
and would like to have a way to interact with the state or configuration
|
|
37
|
-
of these applications in real-time,
|
|
38
|
-
for example:
|
|
32
|
+
Good fit:
|
|
39
33
|
|
|
40
|
-
-
|
|
41
|
-
-
|
|
34
|
+
- single-process Node.js apps with in-memory state
|
|
35
|
+
- trusted/internal networks where operators need live controls
|
|
36
|
+
- projects where React composition is preferred over manual tree mutation
|
|
42
37
|
|
|
43
|
-
|
|
38
|
+
Not a fit:
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
- internet-exposed apps requiring built-in auth/authz
|
|
41
|
+
- horizontally scaled/multi-process architectures needing shared state coordination
|
|
42
|
+
- general-purpose public web apps that need standard React DOM/SSR patterns
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
- Is stateless _(It's explicitly designed to manage in-memory state)_
|
|
50
|
-
- Will be exposed over the internet _(no authentication has been implemented)_
|
|
44
|
+
## Install
|
|
51
45
|
|
|
52
|
-
|
|
46
|
+
```bash
|
|
47
|
+
npm install react@^19.2.0 @arcanejs/toolkit @arcanejs/react-toolkit
|
|
48
|
+
```
|
|
53
49
|
|
|
54
|
-
|
|
50
|
+
Version compatibility:
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
npm install --save react@^18 @arcanejs/toolkit @arcanejs/react-toolkit
|
|
58
|
-
```
|
|
52
|
+
- `@arcanejs/react-toolkit` is tested against React 19 and `react-reconciler` 0.33.x.
|
|
59
53
|
|
|
60
|
-
|
|
54
|
+
Optional helper dependencies:
|
|
61
55
|
|
|
62
|
-
-
|
|
63
|
-
- We don't need `react-dom` or any react native libraries,
|
|
64
|
-
`@arcanejs/react-toolkit` is the react renderer.
|
|
56
|
+
- `zod` is required if you use `@arcanejs/react-toolkit/data`
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
server-side state like this:
|
|
58
|
+
## Quick Start
|
|
68
59
|
|
|
69
|
-
```
|
|
60
|
+
```tsx
|
|
70
61
|
import { useState } from 'react';
|
|
71
62
|
import { Toolkit } from '@arcanejs/toolkit';
|
|
72
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
ToolkitRenderer,
|
|
65
|
+
Group,
|
|
66
|
+
Switch,
|
|
67
|
+
SliderButton,
|
|
68
|
+
} from '@arcanejs/react-toolkit';
|
|
73
69
|
|
|
74
70
|
const toolkit = new Toolkit();
|
|
71
|
+
toolkit.start({ mode: 'automatic', port: 3000 });
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
toolkit.start({
|
|
80
|
-
mode: 'automatic',
|
|
81
|
-
port: 3000,
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const ControlPanel = () => {
|
|
85
|
-
const [switchState, setSwitchState] = useState<'off' | 'on'>('off');
|
|
86
|
-
const [sliderValue, setSliderValue] = useState(50);
|
|
73
|
+
function App() {
|
|
74
|
+
const [enabled, setEnabled] = useState<'on' | 'off'>('off');
|
|
75
|
+
const [level, setLevel] = useState(50);
|
|
87
76
|
|
|
88
77
|
return (
|
|
89
|
-
<Group direction=
|
|
78
|
+
<Group direction="vertical" title="Controller">
|
|
90
79
|
<Group>
|
|
91
|
-
{`
|
|
92
|
-
<Switch
|
|
93
|
-
value={switchState}
|
|
94
|
-
onChange={setSwitchState}
|
|
95
|
-
/>
|
|
80
|
+
{`Enabled: ${enabled}`}
|
|
81
|
+
<Switch value={enabled} onChange={setEnabled} />
|
|
96
82
|
</Group>
|
|
97
83
|
<Group>
|
|
98
|
-
{`
|
|
99
|
-
<SliderButton
|
|
100
|
-
value={sliderValue}
|
|
101
|
-
onChange={setSliderValue}
|
|
102
|
-
min={0}
|
|
103
|
-
max={100}
|
|
104
|
-
/>
|
|
84
|
+
{`Level: ${level}`}
|
|
85
|
+
<SliderButton value={level} onChange={setLevel} min={0} max={100} />
|
|
105
86
|
</Group>
|
|
106
87
|
</Group>
|
|
107
88
|
);
|
|
108
|
-
}
|
|
89
|
+
}
|
|
109
90
|
|
|
110
|
-
|
|
111
|
-
ToolkitRenderer.render(<ControlPanel />, toolkit);
|
|
91
|
+
ToolkitRenderer.render(<App />, toolkit);
|
|
112
92
|
```
|
|
113
93
|
|
|
114
|
-
|
|
115
|
-
from [localhost:3000](http://localhost:3000):
|
|
94
|
+
## Core Exports
|
|
116
95
|
|
|
117
|
-
|
|
96
|
+
### From `@arcanejs/react-toolkit`
|
|
118
97
|
|
|
119
|
-
|
|
98
|
+
- `ToolkitRenderer`
|
|
99
|
+
- `render(element, toolkit, rootGroupProps?, config?)`
|
|
100
|
+
- `renderGroup(element, group, config?)`
|
|
101
|
+
- Core React components:
|
|
102
|
+
- `Button`, `Group`, `GroupHeader`, `Label`, `Rect`, `SliderButton`, `Switch`, `Tab`, `Tabs`, `TextInput`, `Timeline`
|
|
103
|
+
- Extension helpers:
|
|
104
|
+
- `prepareComponents(namespace, components)`
|
|
105
|
+
- `CoreComponents`
|
|
120
106
|
|
|
121
|
-
|
|
122
|
-
or components, only `@arcanejs` components are supported.
|
|
107
|
+
Core component props/events map directly to the corresponding classes in `@arcanejs/toolkit`.
|
|
123
108
|
|
|
124
|
-
|
|
125
|
-
in the same manner that you would any `react-dom` or `react-native` project.
|
|
109
|
+
## Core Component API
|
|
126
110
|
|
|
127
|
-
|
|
111
|
+
These are the React components most users consume directly from `@arcanejs/react-toolkit`.
|
|
128
112
|
|
|
129
|
-
|
|
130
|
-
and does not accurately represent the HTML used on the frontend.
|
|
131
|
-
Your `@arcanejs` tree is converted to a JSON representation,
|
|
132
|
-
and then sent to clients / browsers over a WebSocket.
|
|
133
|
-
There is then a separate `react-dom` application
|
|
134
|
-
that is loaded in the browser,
|
|
135
|
-
and then used to render the JSON representation of the `@arcanejs` tree.
|
|
136
|
-
|
|
137
|
-
- It's possible to define your own custom components,
|
|
138
|
-
however this functionality is not documented.
|
|
139
|
-
|
|
140
|
-
You can see code examples of this functionality here in the
|
|
141
|
-
[custom components example app](https://github.com/ArcaneWizards/arcanejs/tree/main/examples/custom-components).
|
|
113
|
+
### `Button`
|
|
142
114
|
|
|
143
|
-
|
|
115
|
+
Props:
|
|
144
116
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
117
|
+
- `text?: string | null`
|
|
118
|
+
- `icon?: string | null` (Material Symbols Outlined icon name)
|
|
119
|
+
- `mode?: 'normal' | 'pressed'`
|
|
120
|
+
- `error?: string | null`
|
|
121
|
+
- `onClick?: (connection) => void | Promise<void>`
|
|
148
122
|
|
|
149
|
-
|
|
123
|
+
Notes:
|
|
150
124
|
|
|
151
|
-
|
|
125
|
+
- `onClick` uses request/response semantics and can be async.
|
|
126
|
+
- Throwing (or rejecting) in `onClick` surfaces an error state in the UI.
|
|
152
127
|
|
|
153
|
-
|
|
128
|
+
```tsx
|
|
129
|
+
<Button
|
|
130
|
+
text="Run"
|
|
131
|
+
icon="play_arrow"
|
|
132
|
+
onClick={async () => {
|
|
133
|
+
await runTask();
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
```
|
|
154
137
|
|
|
155
|
-
|
|
138
|
+
### `Group`
|
|
156
139
|
|
|
157
|
-
|
|
140
|
+
Props:
|
|
158
141
|
|
|
159
|
-
|
|
160
|
-
|
|
142
|
+
- `direction?: 'horizontal' | 'vertical'`
|
|
143
|
+
- `wrap?: boolean`
|
|
144
|
+
- `border?: true`
|
|
145
|
+
- `title?: string | null`
|
|
146
|
+
- `labels?: Array<{ text: string }> | null`
|
|
147
|
+
- `editableTitle?: boolean`
|
|
148
|
+
- `defaultCollapsibleState?: 'open' | 'closed' | 'auto'`
|
|
149
|
+
- `onTitleChanged?: (title, connection) => void`
|
|
161
150
|
|
|
162
|
-
|
|
151
|
+
Use `Group` as the primary layout primitive and nest groups freely.
|
|
163
152
|
|
|
164
|
-
|
|
165
|
-
|
|
153
|
+
```tsx
|
|
154
|
+
<Group
|
|
155
|
+
direction="vertical"
|
|
156
|
+
title="Fixture Settings"
|
|
157
|
+
border
|
|
158
|
+
editableTitle
|
|
159
|
+
onTitleChanged={(title) => setPanelTitle(title)}
|
|
160
|
+
>
|
|
161
|
+
<Label text="Master Intensity" />
|
|
162
|
+
<SliderButton value={master} min={0} max={100} onChange={setMaster} />
|
|
163
|
+
</Group>
|
|
164
|
+
```
|
|
166
165
|
|
|
167
|
-
|
|
166
|
+
### `GroupHeader`
|
|
168
167
|
|
|
169
|
-
|
|
168
|
+
`GroupHeader` lets you place controls in a group's header area.
|
|
170
169
|
|
|
171
|
-
|
|
170
|
+
```tsx
|
|
171
|
+
<Group title="Playlist">
|
|
172
|
+
<GroupHeader>
|
|
173
|
+
<Button text="Add" onClick={addItem} />
|
|
174
|
+
<Button text="Shuffle" onClick={shuffle} />
|
|
175
|
+
</GroupHeader>
|
|
176
|
+
<Label text="Current Queue" />
|
|
177
|
+
</Group>
|
|
178
|
+
```
|
|
172
179
|
|
|
173
|
-
|
|
180
|
+
### `Label`
|
|
174
181
|
|
|
175
|
-
|
|
176
|
-
to indicate an error and propagate an error message to the user,
|
|
177
|
-
similar to setting the `error` property.
|
|
182
|
+
Props:
|
|
178
183
|
|
|
179
|
-
|
|
184
|
+
- `text: string | null`
|
|
185
|
+
- `bold?: boolean`
|
|
180
186
|
|
|
181
187
|
```tsx
|
|
182
|
-
|
|
183
|
-
<Button text="Stop" onClick={() => doAThing()} icon="close" />
|
|
184
|
-
);
|
|
188
|
+
<Label text={`Connected: ${isConnected ? 'yes' : 'no'}`} bold />
|
|
185
189
|
```
|
|
186
190
|
|
|
187
|
-
### `
|
|
191
|
+
### `Rect`
|
|
192
|
+
|
|
193
|
+
Props:
|
|
188
194
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
and nest them to achieve the desired layout.
|
|
195
|
+
- `color?: string`
|
|
196
|
+
- `grow?: boolean`
|
|
192
197
|
|
|
193
|
-
|
|
198
|
+
Useful for color/state swatches.
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
<Group>
|
|
202
|
+
<Label text="Current Color" />
|
|
203
|
+
<Rect color={`hsl(${hue}deg 100% 50%)`} grow />
|
|
204
|
+
</Group>
|
|
205
|
+
```
|
|
194
206
|
|
|
195
|
-
|
|
207
|
+
### `SliderButton`
|
|
196
208
|
|
|
197
|
-
|
|
209
|
+
Props:
|
|
198
210
|
|
|
199
|
-
|
|
211
|
+
- `value: number` (required)
|
|
212
|
+
- `min?: number` (default `0`)
|
|
213
|
+
- `max?: number` (default `255`)
|
|
214
|
+
- `step?: number` (default `5`)
|
|
215
|
+
- `defaultValue?: number` (for uncontrolled style workflows)
|
|
216
|
+
- `gradient?: Array<{ color: string; position: number }>`
|
|
217
|
+
- `grow?: boolean`
|
|
218
|
+
- `onChange?: (value, connection) => void | Promise<void>`
|
|
200
219
|
|
|
201
|
-
|
|
220
|
+
```tsx
|
|
221
|
+
<SliderButton
|
|
222
|
+
value={temperature}
|
|
223
|
+
min={2700}
|
|
224
|
+
max={6500}
|
|
225
|
+
step={100}
|
|
226
|
+
onChange={setTemperature}
|
|
227
|
+
/>
|
|
228
|
+
```
|
|
202
229
|
|
|
203
|
-
|
|
204
|
-
components will be wrapped, and start to be arranged on additional columns
|
|
205
|
-
or rows.
|
|
230
|
+
### `Switch`
|
|
206
231
|
|
|
207
|
-
|
|
232
|
+
Props:
|
|
208
233
|
|
|
209
|
-
|
|
210
|
-
|
|
234
|
+
- `value?: 'on' | 'off'`
|
|
235
|
+
- `defaultValue?: 'on' | 'off'`
|
|
236
|
+
- `onChange?: (state, connection) => void | Promise<void>`
|
|
211
237
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
238
|
+
```tsx
|
|
239
|
+
<Switch value={enabled} onChange={setEnabled} />
|
|
240
|
+
```
|
|
215
241
|
|
|
216
|
-
|
|
242
|
+
### `Tabs` and `Tab`
|
|
217
243
|
|
|
218
|
-
|
|
244
|
+
`Tabs` only accepts `Tab` children. Each `Tab` should contain one child component subtree.
|
|
219
245
|
|
|
220
|
-
|
|
246
|
+
```tsx
|
|
247
|
+
<Tabs>
|
|
248
|
+
<Tab name="Input">
|
|
249
|
+
<Group>
|
|
250
|
+
<TextInput value={input} onChange={setInput} />
|
|
251
|
+
</Group>
|
|
252
|
+
</Tab>
|
|
253
|
+
<Tab name="Output">
|
|
254
|
+
<Group>
|
|
255
|
+
<Label text={output} />
|
|
256
|
+
</Group>
|
|
257
|
+
</Tab>
|
|
258
|
+
</Tabs>
|
|
259
|
+
```
|
|
221
260
|
|
|
222
|
-
|
|
223
|
-
will allow the user to click on the title to change it,
|
|
224
|
-
which will trigger a callback to the listener `onTitleChanged`.
|
|
261
|
+
### `TextInput`
|
|
225
262
|
|
|
226
|
-
|
|
227
|
-
(optional, default: `undefined`)
|
|
263
|
+
Props:
|
|
228
264
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
by default set to the given state.
|
|
265
|
+
- `value?: string | null`
|
|
266
|
+
- `onChange?: (value, connection) => void | Promise<void>`
|
|
232
267
|
|
|
233
|
-
|
|
234
|
-
|
|
268
|
+
```tsx
|
|
269
|
+
<TextInput value={name} onChange={setName} />
|
|
270
|
+
```
|
|
235
271
|
|
|
236
|
-
|
|
272
|
+
### `Timeline`
|
|
237
273
|
|
|
238
|
-
|
|
274
|
+
Props:
|
|
239
275
|
|
|
240
|
-
|
|
276
|
+
- `state?`:
|
|
277
|
+
- `{ state: 'playing'; totalTimeMillis; effectiveStartTime; speed }`
|
|
278
|
+
- `{ state: 'stopped'; totalTimeMillis; currentTimeMillis }`
|
|
279
|
+
- `title?: string | null`
|
|
280
|
+
- `subtitles?: string[] | null`
|
|
281
|
+
- `source?: { name: string } | null`
|
|
241
282
|
|
|
242
|
-
|
|
283
|
+
```tsx
|
|
284
|
+
<Timeline
|
|
285
|
+
title="Show Timeline"
|
|
286
|
+
subtitles={[`Cue ${cue}`, `BPM ${bpm}`]}
|
|
287
|
+
source={{ name: activeTrack }}
|
|
288
|
+
state={
|
|
289
|
+
playing
|
|
290
|
+
? {
|
|
291
|
+
state: 'playing',
|
|
292
|
+
totalTimeMillis: duration,
|
|
293
|
+
effectiveStartTime: startedAt,
|
|
294
|
+
speed: 1,
|
|
295
|
+
}
|
|
296
|
+
: {
|
|
297
|
+
state: 'stopped',
|
|
298
|
+
totalTimeMillis: duration,
|
|
299
|
+
currentTimeMillis: pausedAt,
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/>
|
|
303
|
+
```
|
|
243
304
|
|
|
244
|
-
|
|
245
|
-
`<GroupHeader/>` component directly under the `<Group/>`.
|
|
305
|
+
## Helper Modules
|
|
246
306
|
|
|
247
|
-
|
|
248
|
-
a `<Group>` component's direct children,
|
|
249
|
-
and all nested components will be placed in the header.
|
|
307
|
+
### `@arcanejs/react-toolkit/connections`
|
|
250
308
|
|
|
251
|
-
|
|
309
|
+
Connection-awareness for server-side React trees:
|
|
252
310
|
|
|
253
|
-
|
|
311
|
+
- `ConnectionsContext`
|
|
312
|
+
- `ConnectionsContextProvider`
|
|
254
313
|
|
|
255
|
-
|
|
314
|
+
Use this to render connection-specific UI or track per-connection state.
|
|
256
315
|
|
|
257
|
-
### `
|
|
316
|
+
### `@arcanejs/react-toolkit/data`
|
|
258
317
|
|
|
259
|
-
|
|
318
|
+
JSON file persistence helpers backed by Zod validation:
|
|
260
319
|
|
|
261
|
-
|
|
320
|
+
- `createDataFileDefinition`
|
|
321
|
+
- `useDataFileContext`
|
|
322
|
+
- `useDataFileData`
|
|
323
|
+
- `useDataFileUpdater`
|
|
324
|
+
- `useDataFile`
|
|
325
|
+
- `useDataFileCore`
|
|
262
326
|
|
|
263
|
-
|
|
327
|
+
Supports:
|
|
264
328
|
|
|
265
|
-
|
|
329
|
+
- lazy file creation with defaults
|
|
330
|
+
- schema validation on load
|
|
331
|
+
- throttled disk writes
|
|
332
|
+
- path switching behavior (`onPathChange: 'transfer' | 'defaultValue'`)
|
|
266
333
|
|
|
267
|
-
|
|
334
|
+
### `@arcanejs/react-toolkit/colors`
|
|
268
335
|
|
|
269
|
-
|
|
336
|
+
- `HslColor` type
|
|
337
|
+
- `HslColorPicker` component
|
|
270
338
|
|
|
271
|
-
|
|
339
|
+
### `@arcanejs/react-toolkit/logging`
|
|
272
340
|
|
|
273
|
-
|
|
341
|
+
- `LoggerContext`
|
|
342
|
+
- `useLogger()`
|
|
274
343
|
|
|
275
|
-
|
|
344
|
+
## Custom Component Namespaces
|
|
276
345
|
|
|
277
|
-
|
|
346
|
+
Use `prepareComponents(...)` + `ToolkitRenderer` config to add custom namespaces:
|
|
278
347
|
|
|
279
|
-
|
|
348
|
+
```tsx
|
|
349
|
+
import {
|
|
350
|
+
prepareComponents,
|
|
351
|
+
CoreComponents,
|
|
352
|
+
ToolkitRenderer,
|
|
353
|
+
} from '@arcanejs/react-toolkit';
|
|
354
|
+
|
|
355
|
+
const Custom = prepareComponents('custom', {
|
|
356
|
+
MyComponent,
|
|
357
|
+
});
|
|
280
358
|
|
|
281
|
-
|
|
359
|
+
ToolkitRenderer.render(
|
|
360
|
+
<App />,
|
|
361
|
+
toolkit,
|
|
362
|
+
{},
|
|
363
|
+
{
|
|
364
|
+
componentNamespaces: [CoreComponents, Custom],
|
|
365
|
+
},
|
|
366
|
+
);
|
|
367
|
+
```
|
|
282
368
|
|
|
283
|
-
|
|
369
|
+
You must also implement matching protocol/backend/frontend layers. See:
|
|
284
370
|
|
|
285
|
-
|
|
371
|
+
- <https://github.com/ArcaneWizards/arcanejs/tree/main/examples/custom-components>
|
|
286
372
|
|
|
287
|
-
|
|
288
|
-
please see the example directory in the arcane monorepo:
|
|
289
|
-
<https://github.com/ArcaneWizards/arcanejs/tree/main/examples/react>
|
|
373
|
+
## Important Constraints
|
|
290
374
|
|
|
291
|
-
|
|
375
|
+
- This is a custom renderer, not React DOM. Standard HTML elements are not supported.
|
|
376
|
+
- React state/hooks run on the server process.
|
|
377
|
+
- Toolkit root can only be set once.
|
|
378
|
+
- Architecture is single-process and intentionally stateful.
|
|
379
|
+
- No built-in authentication/authorization.
|
|
292
380
|
|
|
293
|
-
|
|
294
|
-
to create an app that can be used to control a Philips Hue Bridge
|
|
295
|
-
on your local network.
|
|
381
|
+
## Stability / Suitability
|
|
296
382
|
|
|
297
|
-
|
|
383
|
+
ArcaneJS uses `react-reconciler` APIs and is considered experimental. It is best suited for trusted-network/internal control applications.
|
|
298
384
|
|
|
299
|
-
|
|
300
|
-
and takes advantage of unstable `react` APIs exposed via `react-render`.
|
|
301
|
-
It's not suitable for production or commercial projects yet,
|
|
302
|
-
especially those that rely on regular updates of dependencies
|
|
303
|
-
for security reasons,
|
|
304
|
-
as usage of this project may make it difficult to keep `react` up-to-date
|
|
305
|
-
(that being said, the license does not prohibit this,
|
|
306
|
-
so feel free to at-your-own-risk).
|
|
385
|
+
## Examples
|
|
307
386
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
387
|
+
- React examples: <https://github.com/ArcaneWizards/arcanejs/tree/main/examples/react>
|
|
388
|
+
- Main readme example: <https://github.com/ArcaneWizards/arcanejs/blob/main/examples/react/src/readme.tsx>
|
|
389
|
+
- Connections example: <https://github.com/ArcaneWizards/arcanejs/blob/main/examples/react/src/connections.tsx>
|
|
390
|
+
- Data file example: <https://github.com/ArcaneWizards/arcanejs/blob/main/examples/react/src/data-file.tsx>
|
|
@@ -4,12 +4,13 @@ var _chunkRT2VSMJLjs = require('./chunk-RT2VSMJL.js');
|
|
|
4
4
|
|
|
5
5
|
// src/index.tsx
|
|
6
6
|
var _reactreconciler = require('react-reconciler'); var _reactreconciler2 = _interopRequireDefault(_reactreconciler);
|
|
7
|
+
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
7
8
|
var _constants = require('react-reconciler/constants');
|
|
8
9
|
var _toolkit = require('@arcanejs/toolkit'); var ld = _interopRequireWildcard(_toolkit);
|
|
9
10
|
var _base = require('@arcanejs/toolkit/components/base');
|
|
10
11
|
|
|
11
12
|
// src/registry.ts
|
|
12
|
-
|
|
13
|
+
|
|
13
14
|
var prepareComponents = (namespace, defn) => {
|
|
14
15
|
const entries = Object.entries(defn);
|
|
15
16
|
const _creators = entries.reduce((acc, [key, cls]) => {
|
|
@@ -67,9 +68,48 @@ var CoreComponents = prepareComponents("core", {
|
|
|
67
68
|
// src/index.tsx
|
|
68
69
|
var _jsxruntime = require('react/jsx-runtime');
|
|
69
70
|
var canSetProps = (instance) => instance instanceof _base.Base;
|
|
70
|
-
var
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
var getPropsToSet = (props) => {
|
|
72
|
+
const updates = {};
|
|
73
|
+
for (const [key, val] of Object.entries(props)) {
|
|
74
|
+
if (key !== "children") {
|
|
75
|
+
updates[key] = val;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return updates;
|
|
79
|
+
};
|
|
80
|
+
var setInstanceProps = (instance, props) => {
|
|
81
|
+
if (canSetProps(instance)) {
|
|
82
|
+
instance.setProps(props);
|
|
83
|
+
} else {
|
|
84
|
+
throw new Error(`Unexpected Instance: ${instance}`);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var scheduleMicrotaskCompat = typeof queueMicrotask === "function" ? queueMicrotask : (cb) => {
|
|
88
|
+
Promise.resolve().then(cb);
|
|
89
|
+
};
|
|
90
|
+
var reportRendererError = (error) => {
|
|
91
|
+
console.error(error);
|
|
92
|
+
};
|
|
93
|
+
var createContainerCompat = (reconciler, container) => {
|
|
94
|
+
const createContainer = reconciler.createContainer;
|
|
95
|
+
if (createContainer.length <= 4) {
|
|
96
|
+
return createContainer(container, 0, false, null);
|
|
97
|
+
}
|
|
98
|
+
return createContainer(
|
|
99
|
+
container,
|
|
100
|
+
0,
|
|
101
|
+
null,
|
|
102
|
+
false,
|
|
103
|
+
null,
|
|
104
|
+
"",
|
|
105
|
+
reportRendererError,
|
|
106
|
+
reportRendererError,
|
|
107
|
+
reportRendererError,
|
|
108
|
+
null
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
var ROOT_HOST_CONTEXT = {};
|
|
112
|
+
var hostConfig = ({ componentNamespaces }) => {
|
|
73
113
|
const processedNamespaces = {};
|
|
74
114
|
for (const namespace of componentNamespaces) {
|
|
75
115
|
if (processedNamespaces[namespace._namespace]) {
|
|
@@ -77,12 +117,17 @@ var hostConfig = ({
|
|
|
77
117
|
}
|
|
78
118
|
processedNamespaces[namespace._namespace] = namespace;
|
|
79
119
|
}
|
|
80
|
-
|
|
120
|
+
const hostTransitionContext = _react2.default.createContext(null);
|
|
121
|
+
let currentUpdatePriority = _constants.DefaultEventPriority;
|
|
122
|
+
const config = {
|
|
81
123
|
supportsMutation: true,
|
|
82
124
|
supportsPersistence: false,
|
|
83
125
|
noTimeout: -1,
|
|
84
126
|
isPrimaryRenderer: true,
|
|
85
127
|
supportsHydration: false,
|
|
128
|
+
supportsMicrotasks: true,
|
|
129
|
+
NotPendingTransition: null,
|
|
130
|
+
HostTransitionContext: hostTransitionContext,
|
|
86
131
|
afterActiveInstanceBlur: () => null,
|
|
87
132
|
appendChild: (parentInstance, child) => {
|
|
88
133
|
if (parentInstance instanceof _base.BaseParent) {
|
|
@@ -104,14 +149,23 @@ var hostConfig = ({
|
|
|
104
149
|
beforeActiveInstanceBlur: () => null,
|
|
105
150
|
cancelTimeout: (id) => clearTimeout(id),
|
|
106
151
|
clearContainer: (container) => container.removeAllChildren(),
|
|
107
|
-
commitMount: () => {
|
|
152
|
+
commitMount: (_instance, _type, _props) => {
|
|
108
153
|
throw new Error(`Unexpected call to commitMount()`);
|
|
109
154
|
},
|
|
110
|
-
commitUpdate(instance,
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
155
|
+
commitUpdate(instance, ...args) {
|
|
156
|
+
if (typeof args[0] === "string") {
|
|
157
|
+
const nextProps2 = args[2];
|
|
158
|
+
setInstanceProps(instance, getPropsToSet(nextProps2));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const updatePayload = args[0];
|
|
162
|
+
if (updatePayload) {
|
|
163
|
+
setInstanceProps(instance, updatePayload);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const nextProps = args[3];
|
|
167
|
+
if (nextProps) {
|
|
168
|
+
setInstanceProps(instance, getPropsToSet(nextProps));
|
|
115
169
|
}
|
|
116
170
|
},
|
|
117
171
|
commitTextUpdate: (textInstance, _oldText, newText) => textInstance.setText(newText),
|
|
@@ -137,6 +191,7 @@ var hostConfig = ({
|
|
|
137
191
|
detachDeletedInstance: () => null,
|
|
138
192
|
getChildHostContext: (parentHostContext) => parentHostContext,
|
|
139
193
|
getCurrentEventPriority: () => _constants.DefaultEventPriority,
|
|
194
|
+
getCurrentUpdatePriority: () => currentUpdatePriority,
|
|
140
195
|
getInstanceFromNode: () => {
|
|
141
196
|
throw new Error("Not yet implemented.");
|
|
142
197
|
},
|
|
@@ -144,7 +199,7 @@ var hostConfig = ({
|
|
|
144
199
|
throw new Error("Not yet implemented.");
|
|
145
200
|
},
|
|
146
201
|
getPublicInstance: (instance) => instance,
|
|
147
|
-
getRootHostContext: () =>
|
|
202
|
+
getRootHostContext: () => ROOT_HOST_CONTEXT,
|
|
148
203
|
insertBefore: (parentInstance, child, beforeChild) => {
|
|
149
204
|
if (parentInstance instanceof _base.BaseParent) {
|
|
150
205
|
parentInstance.insertBefore(child, beforeChild);
|
|
@@ -154,21 +209,17 @@ var hostConfig = ({
|
|
|
154
209
|
},
|
|
155
210
|
insertInContainerBefore: (container, child, beforeChild) => container.insertBefore(child, beforeChild),
|
|
156
211
|
finalizeInitialChildren: () => false,
|
|
212
|
+
maySuspendCommit: () => false,
|
|
213
|
+
preloadInstance: () => false,
|
|
157
214
|
prepareForCommit: () => null,
|
|
158
215
|
preparePortalMount: () => null,
|
|
159
216
|
prepareScopeUpdate: () => null,
|
|
160
217
|
prepareUpdate: (_instance, _type, _oldProps, newProps, _rootContainer, _hostContext) => {
|
|
161
|
-
const updates =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
if (Object.keys(updates).length) {
|
|
168
|
-
return updates;
|
|
169
|
-
} else {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
218
|
+
const updates = getPropsToSet(newProps);
|
|
219
|
+
return Object.keys(updates).length ? updates : null;
|
|
220
|
+
},
|
|
221
|
+
requestPostPaintCallback: (callback) => {
|
|
222
|
+
setTimeout(() => callback(Date.now()), 0);
|
|
172
223
|
},
|
|
173
224
|
removeChild(parentInstance, child) {
|
|
174
225
|
if (parentInstance instanceof _base.BaseParent) {
|
|
@@ -182,31 +233,36 @@ var hostConfig = ({
|
|
|
182
233
|
resetTextContent: () => {
|
|
183
234
|
throw new Error(`Unexpected call to resetTextContent()`);
|
|
184
235
|
},
|
|
236
|
+
resetFormInstance: () => null,
|
|
237
|
+
resolveEventTimeStamp: () => Date.now(),
|
|
238
|
+
resolveEventType: () => null,
|
|
239
|
+
resolveUpdatePriority: () => currentUpdatePriority,
|
|
185
240
|
scheduleTimeout: (fn, delay) => setTimeout(fn, delay),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.log("Not-implemented: hideInstance");
|
|
190
|
-
},
|
|
191
|
-
hideTextInstance: () => {
|
|
192
|
-
console.log("Not-implemented: hideTextInstance");
|
|
241
|
+
scheduleMicrotask: scheduleMicrotaskCompat,
|
|
242
|
+
setCurrentUpdatePriority: (newPriority) => {
|
|
243
|
+
currentUpdatePriority = newPriority;
|
|
193
244
|
},
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
245
|
+
shouldAttemptEagerTransition: () => false,
|
|
246
|
+
shouldSetTextContent: () => false,
|
|
247
|
+
startSuspendingCommit: () => null,
|
|
248
|
+
suspendInstance: () => null,
|
|
249
|
+
trackSchedulerEvent: () => null,
|
|
250
|
+
waitForCommitToBeReady: () => null,
|
|
251
|
+
hideInstance: () => null,
|
|
252
|
+
hideTextInstance: () => null,
|
|
253
|
+
unhideInstance: () => null,
|
|
254
|
+
unhideTextInstance: () => null
|
|
200
255
|
};
|
|
256
|
+
return config;
|
|
201
257
|
};
|
|
202
258
|
var ToolkitRenderer = {
|
|
203
259
|
renderGroup: (component, container, config = {
|
|
204
260
|
componentNamespaces: [CoreComponents]
|
|
205
261
|
}) => {
|
|
206
262
|
const reconciler = _reactreconciler2.default.call(void 0, hostConfig(config));
|
|
207
|
-
const root = reconciler
|
|
263
|
+
const root = createContainerCompat(reconciler, container);
|
|
208
264
|
const componentWithContexts = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRT2VSMJLjs.LoggerContext.Provider, { value: container.log, children: component });
|
|
209
|
-
reconciler.updateContainer(componentWithContexts, root, null);
|
|
265
|
+
reconciler.updateContainer(componentWithContexts, root, null, void 0);
|
|
210
266
|
},
|
|
211
267
|
render: (component, container, rootGroupProps, config = {
|
|
212
268
|
componentNamespaces: [CoreComponents]
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// src/index.tsx
|
|
6
6
|
import Reconciler from "react-reconciler";
|
|
7
|
+
import React2 from "react";
|
|
7
8
|
import { DefaultEventPriority } from "react-reconciler/constants";
|
|
8
9
|
import * as ld from "@arcanejs/toolkit";
|
|
9
10
|
import { Base, BaseParent } from "@arcanejs/toolkit/components/base";
|
|
@@ -67,9 +68,48 @@ var CoreComponents = prepareComponents("core", {
|
|
|
67
68
|
// src/index.tsx
|
|
68
69
|
import { jsx } from "react/jsx-runtime";
|
|
69
70
|
var canSetProps = (instance) => instance instanceof Base;
|
|
70
|
-
var
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
var getPropsToSet = (props) => {
|
|
72
|
+
const updates = {};
|
|
73
|
+
for (const [key, val] of Object.entries(props)) {
|
|
74
|
+
if (key !== "children") {
|
|
75
|
+
updates[key] = val;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return updates;
|
|
79
|
+
};
|
|
80
|
+
var setInstanceProps = (instance, props) => {
|
|
81
|
+
if (canSetProps(instance)) {
|
|
82
|
+
instance.setProps(props);
|
|
83
|
+
} else {
|
|
84
|
+
throw new Error(`Unexpected Instance: ${instance}`);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var scheduleMicrotaskCompat = typeof queueMicrotask === "function" ? queueMicrotask : (cb) => {
|
|
88
|
+
Promise.resolve().then(cb);
|
|
89
|
+
};
|
|
90
|
+
var reportRendererError = (error) => {
|
|
91
|
+
console.error(error);
|
|
92
|
+
};
|
|
93
|
+
var createContainerCompat = (reconciler, container) => {
|
|
94
|
+
const createContainer = reconciler.createContainer;
|
|
95
|
+
if (createContainer.length <= 4) {
|
|
96
|
+
return createContainer(container, 0, false, null);
|
|
97
|
+
}
|
|
98
|
+
return createContainer(
|
|
99
|
+
container,
|
|
100
|
+
0,
|
|
101
|
+
null,
|
|
102
|
+
false,
|
|
103
|
+
null,
|
|
104
|
+
"",
|
|
105
|
+
reportRendererError,
|
|
106
|
+
reportRendererError,
|
|
107
|
+
reportRendererError,
|
|
108
|
+
null
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
var ROOT_HOST_CONTEXT = {};
|
|
112
|
+
var hostConfig = ({ componentNamespaces }) => {
|
|
73
113
|
const processedNamespaces = {};
|
|
74
114
|
for (const namespace of componentNamespaces) {
|
|
75
115
|
if (processedNamespaces[namespace._namespace]) {
|
|
@@ -77,12 +117,17 @@ var hostConfig = ({
|
|
|
77
117
|
}
|
|
78
118
|
processedNamespaces[namespace._namespace] = namespace;
|
|
79
119
|
}
|
|
80
|
-
|
|
120
|
+
const hostTransitionContext = React2.createContext(null);
|
|
121
|
+
let currentUpdatePriority = DefaultEventPriority;
|
|
122
|
+
const config = {
|
|
81
123
|
supportsMutation: true,
|
|
82
124
|
supportsPersistence: false,
|
|
83
125
|
noTimeout: -1,
|
|
84
126
|
isPrimaryRenderer: true,
|
|
85
127
|
supportsHydration: false,
|
|
128
|
+
supportsMicrotasks: true,
|
|
129
|
+
NotPendingTransition: null,
|
|
130
|
+
HostTransitionContext: hostTransitionContext,
|
|
86
131
|
afterActiveInstanceBlur: () => null,
|
|
87
132
|
appendChild: (parentInstance, child) => {
|
|
88
133
|
if (parentInstance instanceof BaseParent) {
|
|
@@ -104,14 +149,23 @@ var hostConfig = ({
|
|
|
104
149
|
beforeActiveInstanceBlur: () => null,
|
|
105
150
|
cancelTimeout: (id) => clearTimeout(id),
|
|
106
151
|
clearContainer: (container) => container.removeAllChildren(),
|
|
107
|
-
commitMount: () => {
|
|
152
|
+
commitMount: (_instance, _type, _props) => {
|
|
108
153
|
throw new Error(`Unexpected call to commitMount()`);
|
|
109
154
|
},
|
|
110
|
-
commitUpdate(instance,
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
155
|
+
commitUpdate(instance, ...args) {
|
|
156
|
+
if (typeof args[0] === "string") {
|
|
157
|
+
const nextProps2 = args[2];
|
|
158
|
+
setInstanceProps(instance, getPropsToSet(nextProps2));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const updatePayload = args[0];
|
|
162
|
+
if (updatePayload) {
|
|
163
|
+
setInstanceProps(instance, updatePayload);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const nextProps = args[3];
|
|
167
|
+
if (nextProps) {
|
|
168
|
+
setInstanceProps(instance, getPropsToSet(nextProps));
|
|
115
169
|
}
|
|
116
170
|
},
|
|
117
171
|
commitTextUpdate: (textInstance, _oldText, newText) => textInstance.setText(newText),
|
|
@@ -137,6 +191,7 @@ var hostConfig = ({
|
|
|
137
191
|
detachDeletedInstance: () => null,
|
|
138
192
|
getChildHostContext: (parentHostContext) => parentHostContext,
|
|
139
193
|
getCurrentEventPriority: () => DefaultEventPriority,
|
|
194
|
+
getCurrentUpdatePriority: () => currentUpdatePriority,
|
|
140
195
|
getInstanceFromNode: () => {
|
|
141
196
|
throw new Error("Not yet implemented.");
|
|
142
197
|
},
|
|
@@ -144,7 +199,7 @@ var hostConfig = ({
|
|
|
144
199
|
throw new Error("Not yet implemented.");
|
|
145
200
|
},
|
|
146
201
|
getPublicInstance: (instance) => instance,
|
|
147
|
-
getRootHostContext: () =>
|
|
202
|
+
getRootHostContext: () => ROOT_HOST_CONTEXT,
|
|
148
203
|
insertBefore: (parentInstance, child, beforeChild) => {
|
|
149
204
|
if (parentInstance instanceof BaseParent) {
|
|
150
205
|
parentInstance.insertBefore(child, beforeChild);
|
|
@@ -154,21 +209,17 @@ var hostConfig = ({
|
|
|
154
209
|
},
|
|
155
210
|
insertInContainerBefore: (container, child, beforeChild) => container.insertBefore(child, beforeChild),
|
|
156
211
|
finalizeInitialChildren: () => false,
|
|
212
|
+
maySuspendCommit: () => false,
|
|
213
|
+
preloadInstance: () => false,
|
|
157
214
|
prepareForCommit: () => null,
|
|
158
215
|
preparePortalMount: () => null,
|
|
159
216
|
prepareScopeUpdate: () => null,
|
|
160
217
|
prepareUpdate: (_instance, _type, _oldProps, newProps, _rootContainer, _hostContext) => {
|
|
161
|
-
const updates =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
if (Object.keys(updates).length) {
|
|
168
|
-
return updates;
|
|
169
|
-
} else {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
218
|
+
const updates = getPropsToSet(newProps);
|
|
219
|
+
return Object.keys(updates).length ? updates : null;
|
|
220
|
+
},
|
|
221
|
+
requestPostPaintCallback: (callback) => {
|
|
222
|
+
setTimeout(() => callback(Date.now()), 0);
|
|
172
223
|
},
|
|
173
224
|
removeChild(parentInstance, child) {
|
|
174
225
|
if (parentInstance instanceof BaseParent) {
|
|
@@ -182,31 +233,36 @@ var hostConfig = ({
|
|
|
182
233
|
resetTextContent: () => {
|
|
183
234
|
throw new Error(`Unexpected call to resetTextContent()`);
|
|
184
235
|
},
|
|
236
|
+
resetFormInstance: () => null,
|
|
237
|
+
resolveEventTimeStamp: () => Date.now(),
|
|
238
|
+
resolveEventType: () => null,
|
|
239
|
+
resolveUpdatePriority: () => currentUpdatePriority,
|
|
185
240
|
scheduleTimeout: (fn, delay) => setTimeout(fn, delay),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.log("Not-implemented: hideInstance");
|
|
190
|
-
},
|
|
191
|
-
hideTextInstance: () => {
|
|
192
|
-
console.log("Not-implemented: hideTextInstance");
|
|
193
|
-
},
|
|
194
|
-
unhideInstance: () => {
|
|
195
|
-
console.log("Not-implemented: unhideInstance");
|
|
241
|
+
scheduleMicrotask: scheduleMicrotaskCompat,
|
|
242
|
+
setCurrentUpdatePriority: (newPriority) => {
|
|
243
|
+
currentUpdatePriority = newPriority;
|
|
196
244
|
},
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
245
|
+
shouldAttemptEagerTransition: () => false,
|
|
246
|
+
shouldSetTextContent: () => false,
|
|
247
|
+
startSuspendingCommit: () => null,
|
|
248
|
+
suspendInstance: () => null,
|
|
249
|
+
trackSchedulerEvent: () => null,
|
|
250
|
+
waitForCommitToBeReady: () => null,
|
|
251
|
+
hideInstance: () => null,
|
|
252
|
+
hideTextInstance: () => null,
|
|
253
|
+
unhideInstance: () => null,
|
|
254
|
+
unhideTextInstance: () => null
|
|
200
255
|
};
|
|
256
|
+
return config;
|
|
201
257
|
};
|
|
202
258
|
var ToolkitRenderer = {
|
|
203
259
|
renderGroup: (component, container, config = {
|
|
204
260
|
componentNamespaces: [CoreComponents]
|
|
205
261
|
}) => {
|
|
206
262
|
const reconciler = Reconciler(hostConfig(config));
|
|
207
|
-
const root = reconciler
|
|
263
|
+
const root = createContainerCompat(reconciler, container);
|
|
208
264
|
const componentWithContexts = /* @__PURE__ */ jsx(LoggerContext.Provider, { value: container.log, children: component });
|
|
209
|
-
reconciler.updateContainer(componentWithContexts, root, null);
|
|
265
|
+
reconciler.updateContainer(componentWithContexts, root, null, void 0);
|
|
210
266
|
},
|
|
211
267
|
render: (component, container, rootGroupProps, config = {
|
|
212
268
|
componentNamespaces: [CoreComponents]
|
package/dist/colors.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkEJVUDIQPjs = require('./chunk-EJVUDIQP.js');
|
|
6
6
|
require('./chunk-RT2VSMJL.js');
|
|
7
7
|
|
|
8
8
|
// src/colors.tsx
|
|
@@ -56,10 +56,10 @@ var HslColorPicker = ({
|
|
|
56
56
|
},
|
|
57
57
|
[onChange]
|
|
58
58
|
);
|
|
59
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
60
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
59
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkEJVUDIQPjs.Group, { ...DEFAULT_GROUP_PROPS, ...groupProps, children: [
|
|
60
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEJVUDIQPjs.Rect, { color: `hsl(${hue}deg ${saturation}% ${lightness}% / ${alpha})` }),
|
|
61
61
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
62
|
-
|
|
62
|
+
_chunkEJVUDIQPjs.SliderButton,
|
|
63
63
|
{
|
|
64
64
|
value: hue,
|
|
65
65
|
onChange: setHue,
|
|
@@ -71,7 +71,7 @@ var HslColorPicker = ({
|
|
|
71
71
|
}
|
|
72
72
|
),
|
|
73
73
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
74
|
-
|
|
74
|
+
_chunkEJVUDIQPjs.SliderButton,
|
|
75
75
|
{
|
|
76
76
|
value: saturation,
|
|
77
77
|
onChange: setSat,
|
|
@@ -87,7 +87,7 @@ var HslColorPicker = ({
|
|
|
87
87
|
}
|
|
88
88
|
),
|
|
89
89
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
90
|
-
|
|
90
|
+
_chunkEJVUDIQPjs.SliderButton,
|
|
91
91
|
{
|
|
92
92
|
value: lightness,
|
|
93
93
|
onChange: setLightness,
|
|
@@ -103,7 +103,7 @@ var HslColorPicker = ({
|
|
|
103
103
|
}
|
|
104
104
|
),
|
|
105
105
|
showAlpha && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
106
|
-
|
|
106
|
+
_chunkEJVUDIQPjs.SliderButton,
|
|
107
107
|
{
|
|
108
108
|
value: alpha,
|
|
109
109
|
onChange: setAlpha,
|
package/dist/colors.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -51,8 +51,8 @@ type ReactToolkitConfig = {
|
|
|
51
51
|
componentNamespaces: Array<PreparedComponents<any>>;
|
|
52
52
|
};
|
|
53
53
|
declare const ToolkitRenderer: {
|
|
54
|
-
renderGroup: (component:
|
|
55
|
-
render: (component:
|
|
54
|
+
renderGroup: (component: React__default.ReactElement, container: ld.Group, config?: ReactToolkitConfig) => void;
|
|
55
|
+
render: (component: React__default.ReactElement, container: ld.Toolkit, rootGroupProps?: Props, config?: ReactToolkitConfig) => void;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
declare const Button: React__default.ForwardRefExoticComponent<Partial<Partial<_arcanejs_toolkit_components_button.InternalProps>> & React__default.RefAttributes<ld.Button>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -51,8 +51,8 @@ type ReactToolkitConfig = {
|
|
|
51
51
|
componentNamespaces: Array<PreparedComponents<any>>;
|
|
52
52
|
};
|
|
53
53
|
declare const ToolkitRenderer: {
|
|
54
|
-
renderGroup: (component:
|
|
55
|
-
render: (component:
|
|
54
|
+
renderGroup: (component: React__default.ReactElement, container: ld.Group, config?: ReactToolkitConfig) => void;
|
|
55
|
+
render: (component: React__default.ReactElement, container: ld.Toolkit, rootGroupProps?: Props, config?: ReactToolkitConfig) => void;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
declare const Button: React__default.ForwardRefExoticComponent<Partial<Partial<_arcanejs_toolkit_components_button.InternalProps>> & React__default.RefAttributes<ld.Button>>;
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var _chunkEJVUDIQPjs = require('./chunk-EJVUDIQP.js');
|
|
17
17
|
require('./chunk-RT2VSMJL.js');
|
|
18
18
|
|
|
19
19
|
|
|
@@ -30,4 +30,4 @@ require('./chunk-RT2VSMJL.js');
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
exports.Button =
|
|
33
|
+
exports.Button = _chunkEJVUDIQPjs.Button; exports.CoreComponents = _chunkEJVUDIQPjs.CoreComponents; exports.Group = _chunkEJVUDIQPjs.Group; exports.GroupHeader = _chunkEJVUDIQPjs.GroupHeader; exports.Label = _chunkEJVUDIQPjs.Label; exports.Rect = _chunkEJVUDIQPjs.Rect; exports.SliderButton = _chunkEJVUDIQPjs.SliderButton; exports.Switch = _chunkEJVUDIQPjs.Switch; exports.Tab = _chunkEJVUDIQPjs.Tab; exports.Tabs = _chunkEJVUDIQPjs.Tabs; exports.TextInput = _chunkEJVUDIQPjs.TextInput; exports.Timeline = _chunkEJVUDIQPjs.Timeline; exports.ToolkitRenderer = _chunkEJVUDIQPjs.ToolkitRenderer; exports.prepareComponents = _chunkEJVUDIQPjs.prepareComponents;
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcanejs/react-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Build web-accessible control interfaces for your long-running Node.js processes",
|
|
6
6
|
"keywords": [
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"@types/eslint": "^8.56.5",
|
|
56
56
|
"@types/lodash": "^4.17.10",
|
|
57
57
|
"@types/node": "^20.11.24",
|
|
58
|
-
"@types/react": "^
|
|
59
|
-
"@types/react-reconciler": "^0.
|
|
58
|
+
"@types/react": "^19.2.2",
|
|
59
|
+
"@types/react-reconciler": "^0.32.2",
|
|
60
60
|
"check-export-map": "^1.3.1",
|
|
61
61
|
"eslint": "^8.57.0",
|
|
62
62
|
"tsup": "^8.1.0",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"@arcanejs/typescript-config": "^0.0.0"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"lodash": "^4.17.
|
|
70
|
-
"react": "^
|
|
71
|
-
"react-reconciler": "0.
|
|
72
|
-
"@arcanejs/
|
|
73
|
-
"@arcanejs/
|
|
69
|
+
"lodash": "^4.17.23",
|
|
70
|
+
"react": "^19.2.0",
|
|
71
|
+
"react-reconciler": "0.33.0",
|
|
72
|
+
"@arcanejs/protocol": "^0.8.0",
|
|
73
|
+
"@arcanejs/toolkit": "^7.0.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"zod": "^3.23.8"
|