reflex 0.4.2a1__py3-none-any.whl → 0.4.3a2__py3-none-any.whl

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.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (60) hide show
  1. reflex/.templates/apps/blank/code/blank.py +1 -1
  2. reflex/.templates/apps/sidebar/README.md +3 -2
  3. reflex/.templates/apps/sidebar/assets/reflex_white.svg +8 -0
  4. reflex/.templates/apps/sidebar/code/components/sidebar.py +26 -22
  5. reflex/.templates/apps/sidebar/code/pages/dashboard.py +6 -5
  6. reflex/.templates/apps/sidebar/code/pages/settings.py +45 -6
  7. reflex/.templates/apps/sidebar/code/styles.py +15 -17
  8. reflex/.templates/apps/sidebar/code/templates/__init__.py +1 -1
  9. reflex/.templates/apps/sidebar/code/templates/template.py +54 -40
  10. reflex/.templates/jinja/custom_components/README.md.jinja2 +9 -0
  11. reflex/.templates/jinja/custom_components/__init__.py.jinja2 +1 -0
  12. reflex/.templates/jinja/custom_components/demo_app.py.jinja2 +36 -0
  13. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +35 -0
  14. reflex/.templates/jinja/custom_components/src.py.jinja2 +57 -0
  15. reflex/.templates/jinja/web/utils/context.js.jinja2 +26 -6
  16. reflex/.templates/web/utils/state.js +206 -146
  17. reflex/app.py +21 -18
  18. reflex/compiler/compiler.py +6 -2
  19. reflex/compiler/templates.py +17 -0
  20. reflex/compiler/utils.py +2 -2
  21. reflex/components/core/__init__.py +2 -1
  22. reflex/components/core/banner.py +99 -11
  23. reflex/components/core/banner.pyi +215 -2
  24. reflex/components/el/elements/__init__.py +1 -0
  25. reflex/components/el/elements/forms.py +6 -0
  26. reflex/components/el/elements/forms.pyi +4 -0
  27. reflex/components/markdown/markdown.py +13 -25
  28. reflex/components/markdown/markdown.pyi +5 -5
  29. reflex/components/plotly/plotly.py +3 -0
  30. reflex/components/plotly/plotly.pyi +2 -0
  31. reflex/components/radix/primitives/drawer.py +3 -7
  32. reflex/components/radix/themes/components/select.py +4 -4
  33. reflex/components/radix/themes/components/text_field.pyi +4 -0
  34. reflex/constants/__init__.py +4 -0
  35. reflex/constants/colors.py +1 -0
  36. reflex/constants/compiler.py +4 -3
  37. reflex/constants/custom_components.py +30 -0
  38. reflex/custom_components/__init__.py +1 -0
  39. reflex/custom_components/custom_components.py +565 -0
  40. reflex/reflex.py +11 -2
  41. reflex/route.py +4 -0
  42. reflex/state.py +594 -124
  43. reflex/testing.py +6 -0
  44. reflex/utils/exec.py +9 -0
  45. reflex/utils/prerequisites.py +28 -2
  46. reflex/utils/telemetry.py +3 -1
  47. reflex/utils/types.py +23 -0
  48. reflex/vars.py +48 -17
  49. reflex/vars.pyi +8 -3
  50. {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/METADATA +4 -2
  51. {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/RECORD +55 -51
  52. {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/WHEEL +1 -1
  53. reflex/components/base/bare.pyi +0 -84
  54. reflex/constants/base.pyi +0 -94
  55. reflex/constants/event.pyi +0 -59
  56. reflex/constants/route.pyi +0 -50
  57. reflex/constants/style.pyi +0 -20
  58. /reflex/.templates/apps/sidebar/assets/{icon.svg → reflex_black.svg} +0 -0
  59. {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/LICENSE +0 -0
  60. {reflex-0.4.2a1.dist-info → reflex-0.4.3a2.dist-info}/entry_points.txt +0 -0
@@ -6,14 +6,19 @@ import env from "/env.json";
6
6
  import Cookies from "universal-cookie";
7
7
  import { useEffect, useReducer, useRef, useState } from "react";
8
8
  import Router, { useRouter } from "next/router";
9
- import { initialEvents, initialState, onLoadInternalEvent, state_name } from "utils/context.js"
9
+ import {
10
+ initialEvents,
11
+ initialState,
12
+ onLoadInternalEvent,
13
+ state_name,
14
+ } from "utils/context.js";
10
15
 
11
16
  // Endpoint URLs.
12
- const EVENTURL = env.EVENT
13
- const UPLOADURL = env.UPLOAD
17
+ const EVENTURL = env.EVENT;
18
+ const UPLOADURL = env.UPLOAD;
14
19
 
15
20
  // These hostnames indicate that the backend and frontend are reachable via the same domain.
16
- const SAME_DOMAIN_HOSTNAMES = ["localhost", "0.0.0.0", "::", "0:0:0:0:0:0:0:0"]
21
+ const SAME_DOMAIN_HOSTNAMES = ["localhost", "0.0.0.0", "::", "0:0:0:0:0:0:0:0"];
17
22
 
18
23
  // Global variable to hold the token.
19
24
  let token;
@@ -28,7 +33,7 @@ const cookies = new Cookies();
28
33
  export const refs = {};
29
34
 
30
35
  // Flag ensures that only one event is processing on the backend concurrently.
31
- let event_processing = false
36
+ let event_processing = false;
32
37
  // Array holding pending events to be processed.
33
38
  const event_queue = [];
34
39
 
@@ -64,7 +69,7 @@ export const getToken = () => {
64
69
  if (token) {
65
70
  return token;
66
71
  }
67
- if (typeof window !== 'undefined') {
72
+ if (typeof window !== "undefined") {
68
73
  if (!window.sessionStorage.getItem(TOKEN_KEY)) {
69
74
  window.sessionStorage.setItem(TOKEN_KEY, generateUUID());
70
75
  }
@@ -81,7 +86,10 @@ export const getToken = () => {
81
86
  export const getBackendURL = (url_str) => {
82
87
  // Get backend URL object from the endpoint.
83
88
  const endpoint = new URL(url_str);
84
- if ((typeof window !== 'undefined') && SAME_DOMAIN_HOSTNAMES.includes(endpoint.hostname)) {
89
+ if (
90
+ typeof window !== "undefined" &&
91
+ SAME_DOMAIN_HOSTNAMES.includes(endpoint.hostname)
92
+ ) {
85
93
  // Use the frontend domain to access the backend
86
94
  const frontend_hostname = window.location.hostname;
87
95
  endpoint.hostname = frontend_hostname;
@@ -91,11 +99,11 @@ export const getBackendURL = (url_str) => {
91
99
  } else if (endpoint.protocol === "http:") {
92
100
  endpoint.protocol = "https:";
93
101
  }
94
- endpoint.port = ""; // Assume websocket is on https port via load balancer.
102
+ endpoint.port = ""; // Assume websocket is on https port via load balancer.
95
103
  }
96
104
  }
97
- return endpoint
98
- }
105
+ return endpoint;
106
+ };
99
107
 
100
108
  /**
101
109
  * Apply a delta to the state.
@@ -103,10 +111,9 @@ export const getBackendURL = (url_str) => {
103
111
  * @param delta The delta to apply.
104
112
  */
105
113
  export const applyDelta = (state, delta) => {
106
- return { ...state, ...delta }
114
+ return { ...state, ...delta };
107
115
  };
108
116
 
109
-
110
117
  /**
111
118
  * Handle frontend event or send the event to the backend via Websocket.
112
119
  * @param event The event to send.
@@ -117,10 +124,8 @@ export const applyDelta = (state, delta) => {
117
124
  export const applyEvent = async (event, socket) => {
118
125
  // Handle special events
119
126
  if (event.name == "_redirect") {
120
- if (event.payload.external)
121
- window.open(event.payload.path, "_blank");
122
- else
123
- Router.push(event.payload.path);
127
+ if (event.payload.external) window.open(event.payload.path, "_blank");
128
+ else Router.push(event.payload.path);
124
129
  return false;
125
130
  }
126
131
 
@@ -130,20 +135,20 @@ export const applyEvent = async (event, socket) => {
130
135
  }
131
136
 
132
137
  if (event.name == "_remove_cookie") {
133
- cookies.remove(event.payload.key, { ...event.payload.options })
134
- queueEvents(initialEvents(), socket)
138
+ cookies.remove(event.payload.key, { ...event.payload.options });
139
+ queueEvents(initialEvents(), socket);
135
140
  return false;
136
141
  }
137
142
 
138
143
  if (event.name == "_clear_local_storage") {
139
144
  localStorage.clear();
140
- queueEvents(initialEvents(), socket)
145
+ queueEvents(initialEvents(), socket);
141
146
  return false;
142
147
  }
143
148
 
144
149
  if (event.name == "_remove_local_storage") {
145
150
  localStorage.removeItem(event.payload.key);
146
- queueEvents(initialEvents(), socket)
151
+ queueEvents(initialEvents(), socket);
147
152
  return false;
148
153
  }
149
154
 
@@ -154,9 +159,9 @@ export const applyEvent = async (event, socket) => {
154
159
  }
155
160
 
156
161
  if (event.name == "_download") {
157
- const a = document.createElement('a');
162
+ const a = document.createElement("a");
158
163
  a.hidden = true;
159
- a.href = event.payload.url
164
+ a.href = event.payload.url;
160
165
  a.download = event.payload.filename;
161
166
  a.click();
162
167
  a.remove();
@@ -178,7 +183,9 @@ export const applyEvent = async (event, socket) => {
178
183
  if (event.name == "_set_value") {
179
184
  const ref =
180
185
  event.payload.ref in refs ? refs[event.payload.ref] : event.payload.ref;
181
- ref.current.value = event.payload.value;
186
+ if (ref.current) {
187
+ ref.current.value = event.payload.value;
188
+ }
182
189
  return false;
183
190
  }
184
191
 
@@ -186,10 +193,10 @@ export const applyEvent = async (event, socket) => {
186
193
  try {
187
194
  const eval_result = eval(event.payload.javascript_code);
188
195
  if (event.payload.callback) {
189
- if (!!eval_result && typeof eval_result.then === 'function') {
190
- eval(event.payload.callback)(await eval_result)
196
+ if (!!eval_result && typeof eval_result.then === "function") {
197
+ eval(event.payload.callback)(await eval_result);
191
198
  } else {
192
- eval(event.payload.callback)(eval_result)
199
+ eval(event.payload.callback)(eval_result);
193
200
  }
194
201
  }
195
202
  } catch (e) {
@@ -199,14 +206,24 @@ export const applyEvent = async (event, socket) => {
199
206
  }
200
207
 
201
208
  // Update token and router data (if missing).
202
- event.token = getToken()
203
- if (event.router_data === undefined || Object.keys(event.router_data).length === 0) {
204
- event.router_data = (({ pathname, query, asPath }) => ({ pathname, query, asPath }))(Router)
209
+ event.token = getToken();
210
+ if (
211
+ event.router_data === undefined ||
212
+ Object.keys(event.router_data).length === 0
213
+ ) {
214
+ event.router_data = (({ pathname, query, asPath }) => ({
215
+ pathname,
216
+ query,
217
+ asPath,
218
+ }))(Router);
205
219
  }
206
220
 
207
221
  // Send the event to the server.
208
222
  if (socket) {
209
- socket.emit("event", JSON.stringify(event, (k, v) => v === undefined ? null : v));
223
+ socket.emit(
224
+ "event",
225
+ JSON.stringify(event, (k, v) => (v === undefined ? null : v))
226
+ );
210
227
  return true;
211
228
  }
212
229
 
@@ -242,17 +259,15 @@ export const applyRestEvent = async (event, socket) => {
242
259
  * @param socket The socket object to send the event on.
243
260
  */
244
261
  export const queueEvents = async (events, socket) => {
245
- event_queue.push(...events)
246
- await processEvent(socket.current)
247
- }
262
+ event_queue.push(...events);
263
+ await processEvent(socket.current);
264
+ };
248
265
 
249
266
  /**
250
267
  * Process an event off the event queue.
251
268
  * @param socket The socket object to send the event on.
252
269
  */
253
- export const processEvent = async (
254
- socket
255
- ) => {
270
+ export const processEvent = async (socket) => {
256
271
  // Only proceed if the socket is up, otherwise we throw the event into the void
257
272
  if (!socket) {
258
273
  return;
@@ -264,12 +279,12 @@ export const processEvent = async (
264
279
  }
265
280
 
266
281
  // Set processing to true to block other events from being processed.
267
- event_processing = true
282
+ event_processing = true;
268
283
 
269
284
  // Apply the next event in the queue.
270
285
  const event = event_queue.shift();
271
286
 
272
- let eventSent = false
287
+ let eventSent = false;
273
288
  // Process events with handlers via REST and all others via websockets.
274
289
  if (event.handler) {
275
290
  eventSent = await applyRestEvent(event, socket);
@@ -281,27 +296,27 @@ export const processEvent = async (
281
296
  event_processing = false;
282
297
  // recursively call processEvent to drain the queue, since there is
283
298
  // no state update to trigger the useEffect event loop.
284
- await processEvent(socket)
299
+ await processEvent(socket);
285
300
  }
286
- }
301
+ };
287
302
 
288
303
  /**
289
304
  * Connect to a websocket and set the handlers.
290
305
  * @param socket The socket object to connect.
291
306
  * @param dispatch The function to queue state update
292
307
  * @param transports The transports to use.
293
- * @param setConnectError The function to update connection error value.
308
+ * @param setConnectErrors The function to update connection error value.
294
309
  * @param client_storage The client storage object from context.js
295
310
  */
296
311
  export const connect = async (
297
312
  socket,
298
313
  dispatch,
299
314
  transports,
300
- setConnectError,
301
- client_storage = {},
315
+ setConnectErrors,
316
+ client_storage = {}
302
317
  ) => {
303
318
  // Get backend URL object from the endpoint.
304
- const endpoint = getBackendURL(EVENTURL)
319
+ const endpoint = getBackendURL(EVENTURL);
305
320
 
306
321
  // Create the socket.
307
322
  socket.current = io(endpoint.href, {
@@ -310,27 +325,39 @@ export const connect = async (
310
325
  autoUnref: false,
311
326
  });
312
327
 
328
+ function checkVisibility() {
329
+ if (document.visibilityState === "visible") {
330
+ if (!socket.current.connected) {
331
+ console.log("Socket is disconnected, attempting to reconnect ");
332
+ socket.current.connect();
333
+ } else {
334
+ console.log("Socket is reconnected ");
335
+ }
336
+ }
337
+ }
338
+
313
339
  // Once the socket is open, hydrate the page.
314
340
  socket.current.on("connect", () => {
315
- setConnectError(null)
341
+ setConnectErrors([]);
316
342
  });
317
343
 
318
- socket.current.on('connect_error', (error) => {
319
- setConnectError(error)
344
+ socket.current.on("connect_error", (error) => {
345
+ setConnectErrors((connectErrors) => [connectErrors.slice(-9), error]);
320
346
  });
321
-
322
347
  // On each received message, queue the updates and events.
323
- socket.current.on("event", message => {
324
- const update = JSON5.parse(message)
348
+ socket.current.on("event", (message) => {
349
+ const update = JSON5.parse(message);
325
350
  for (const substate in update.delta) {
326
- dispatch[substate](update.delta[substate])
351
+ dispatch[substate](update.delta[substate]);
327
352
  }
328
- applyClientStorageDelta(client_storage, update.delta)
329
- event_processing = !update.final
353
+ applyClientStorageDelta(client_storage, update.delta);
354
+ event_processing = !update.final;
330
355
  if (update.events) {
331
- queueEvents(update.events, socket)
356
+ queueEvents(update.events, socket);
332
357
  }
333
358
  });
359
+
360
+ document.addEventListener("visibilitychange", checkVisibility);
334
361
  };
335
362
 
336
363
  /**
@@ -344,38 +371,44 @@ export const connect = async (
344
371
  *
345
372
  * @returns The response from posting to the UPLOADURL endpoint.
346
373
  */
347
- export const uploadFiles = async (handler, files, upload_id, on_upload_progress, socket) => {
374
+ export const uploadFiles = async (
375
+ handler,
376
+ files,
377
+ upload_id,
378
+ on_upload_progress,
379
+ socket
380
+ ) => {
348
381
  // return if there's no file to upload
349
382
  if (files === undefined || files.length === 0) {
350
383
  return false;
351
384
  }
352
385
 
353
386
  if (upload_controllers[upload_id]) {
354
- console.log("Upload already in progress for ", upload_id)
387
+ console.log("Upload already in progress for ", upload_id);
355
388
  return false;
356
389
  }
357
390
 
358
391
  let resp_idx = 0;
359
392
  const eventHandler = (progressEvent) => {
360
393
  // handle any delta / event streamed from the upload event handler
361
- const chunks = progressEvent.event.target.responseText.trim().split("\n")
394
+ const chunks = progressEvent.event.target.responseText.trim().split("\n");
362
395
  chunks.slice(resp_idx).map((chunk) => {
363
396
  try {
364
397
  socket._callbacks.$event.map((f) => {
365
- f(chunk)
366
- })
367
- resp_idx += 1
398
+ f(chunk);
399
+ });
400
+ resp_idx += 1;
368
401
  } catch (e) {
369
402
  if (progressEvent.progress === 1) {
370
403
  // Chunk may be incomplete, so only report errors when full response is available.
371
- console.log("Error parsing chunk", chunk, e)
404
+ console.log("Error parsing chunk", chunk, e);
372
405
  }
373
- return
406
+ return;
374
407
  }
375
- })
376
- }
408
+ });
409
+ };
377
410
 
378
- const controller = new AbortController()
411
+ const controller = new AbortController();
379
412
  const config = {
380
413
  headers: {
381
414
  "Reflex-Client-Token": getToken(),
@@ -383,26 +416,22 @@ export const uploadFiles = async (handler, files, upload_id, on_upload_progress,
383
416
  },
384
417
  signal: controller.signal,
385
418
  onDownloadProgress: eventHandler,
386
- }
419
+ };
387
420
  if (on_upload_progress) {
388
- config["onUploadProgress"] = on_upload_progress
421
+ config["onUploadProgress"] = on_upload_progress;
389
422
  }
390
423
  const formdata = new FormData();
391
424
 
392
425
  // Add the token and handler to the file name.
393
426
  files.forEach((file) => {
394
- formdata.append(
395
- "files",
396
- file,
397
- file.path || file.name
398
- );
399
- })
427
+ formdata.append("files", file, file.path || file.name);
428
+ });
400
429
 
401
430
  // Send the file to the server.
402
- upload_controllers[upload_id] = controller
431
+ upload_controllers[upload_id] = controller;
403
432
 
404
433
  try {
405
- return await axios.post(getBackendURL(UPLOADURL), formdata, config)
434
+ return await axios.post(getBackendURL(UPLOADURL), formdata, config);
406
435
  } catch (error) {
407
436
  if (error.response) {
408
437
  // The request was made and the server responded with a status code
@@ -419,7 +448,7 @@ export const uploadFiles = async (handler, files, upload_id, on_upload_progress,
419
448
  }
420
449
  return false;
421
450
  } finally {
422
- delete upload_controllers[upload_id]
451
+ delete upload_controllers[upload_id];
423
452
  }
424
453
  };
425
454
 
@@ -441,30 +470,32 @@ export const Event = (name, payload = {}, handler = null) => {
441
470
  * @returns payload dict of client storage values
442
471
  */
443
472
  export const hydrateClientStorage = (client_storage) => {
444
- const client_storage_values = {}
473
+ const client_storage_values = {};
445
474
  if (client_storage.cookies) {
446
475
  for (const state_key in client_storage.cookies) {
447
- const cookie_options = client_storage.cookies[state_key]
448
- const cookie_name = cookie_options.name || state_key
449
- const cookie_value = cookies.get(cookie_name)
476
+ const cookie_options = client_storage.cookies[state_key];
477
+ const cookie_name = cookie_options.name || state_key;
478
+ const cookie_value = cookies.get(cookie_name);
450
479
  if (cookie_value !== undefined) {
451
- client_storage_values[state_key] = cookies.get(cookie_name)
480
+ client_storage_values[state_key] = cookies.get(cookie_name);
452
481
  }
453
482
  }
454
483
  }
455
- if (client_storage.local_storage && (typeof window !== 'undefined')) {
484
+ if (client_storage.local_storage && typeof window !== "undefined") {
456
485
  for (const state_key in client_storage.local_storage) {
457
- const options = client_storage.local_storage[state_key]
458
- const local_storage_value = localStorage.getItem(options.name || state_key)
486
+ const options = client_storage.local_storage[state_key];
487
+ const local_storage_value = localStorage.getItem(
488
+ options.name || state_key
489
+ );
459
490
  if (local_storage_value !== null) {
460
- client_storage_values[state_key] = local_storage_value
491
+ client_storage_values[state_key] = local_storage_value;
461
492
  }
462
493
  }
463
494
  }
464
495
  if (client_storage.cookies || client_storage.local_storage) {
465
- return client_storage_values
496
+ return client_storage_values;
466
497
  }
467
- return {}
498
+ return {};
468
499
  };
469
500
 
470
501
  /**
@@ -474,9 +505,11 @@ export const hydrateClientStorage = (client_storage) => {
474
505
  */
475
506
  const applyClientStorageDelta = (client_storage, delta) => {
476
507
  // find the main state and check for is_hydrated
477
- const unqualified_states = Object.keys(delta).filter((key) => key.split(".").length === 1);
508
+ const unqualified_states = Object.keys(delta).filter(
509
+ (key) => key.split(".").length === 1
510
+ );
478
511
  if (unqualified_states.length === 1) {
479
- const main_state = delta[unqualified_states[0]]
512
+ const main_state = delta[unqualified_states[0]];
480
513
  if (main_state.is_hydrated !== undefined && !main_state.is_hydrated) {
481
514
  // skip if the state is not hydrated yet, since all client storage
482
515
  // values are sent in the hydrate event
@@ -486,19 +519,23 @@ const applyClientStorageDelta = (client_storage, delta) => {
486
519
  // Save known client storage values to cookies and localStorage.
487
520
  for (const substate in delta) {
488
521
  for (const key in delta[substate]) {
489
- const state_key = `${substate}.${key}`
522
+ const state_key = `${substate}.${key}`;
490
523
  if (client_storage.cookies && state_key in client_storage.cookies) {
491
- const cookie_options = { ...client_storage.cookies[state_key] }
492
- const cookie_name = cookie_options.name || state_key
493
- delete cookie_options.name // name is not a valid cookie option
524
+ const cookie_options = { ...client_storage.cookies[state_key] };
525
+ const cookie_name = cookie_options.name || state_key;
526
+ delete cookie_options.name; // name is not a valid cookie option
494
527
  cookies.set(cookie_name, delta[substate][key], cookie_options);
495
- } else if (client_storage.local_storage && state_key in client_storage.local_storage && (typeof window !== 'undefined')) {
496
- const options = client_storage.local_storage[state_key]
528
+ } else if (
529
+ client_storage.local_storage &&
530
+ state_key in client_storage.local_storage &&
531
+ typeof window !== "undefined"
532
+ ) {
533
+ const options = client_storage.local_storage[state_key];
497
534
  localStorage.setItem(options.name || state_key, delta[substate][key]);
498
535
  }
499
536
  }
500
537
  }
501
- }
538
+ };
502
539
 
503
540
  /**
504
541
  * Establish websocket event loop for a NextJS page.
@@ -506,18 +543,18 @@ const applyClientStorageDelta = (client_storage, delta) => {
506
543
  * @param initial_events The initial app events.
507
544
  * @param client_storage The client storage object from context.js
508
545
  *
509
- * @returns [addEvents, connectError] -
546
+ * @returns [addEvents, connectErrors] -
510
547
  * addEvents is used to queue an event, and
511
- * connectError is a reactive js error from the websocket connection (or null if connected).
548
+ * connectErrors is an array of reactive js error from the websocket connection (or null if connected).
512
549
  */
513
550
  export const useEventLoop = (
514
551
  dispatch,
515
552
  initial_events = () => [],
516
- client_storage = {},
553
+ client_storage = {}
517
554
  ) => {
518
- const socket = useRef(null)
519
- const router = useRouter()
520
- const [connectError, setConnectError] = useState(null)
555
+ const socket = useRef(null);
556
+ const router = useRouter();
557
+ const [connectErrors, setConnectErrors] = useState([]);
521
558
 
522
559
  // Function to add new events to the event queue.
523
560
  const addEvents = (events, _e, event_actions) => {
@@ -527,22 +564,26 @@ export const useEventLoop = (
527
564
  if (event_actions?.stopPropagation && _e?.stopPropagation) {
528
565
  _e.stopPropagation();
529
566
  }
530
- queueEvents(events, socket)
531
- }
567
+ queueEvents(events, socket);
568
+ };
532
569
 
533
- const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode
570
+ const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode
534
571
  useEffect(() => {
535
572
  if (router.isReady && !sentHydrate.current) {
536
- const events = initial_events()
537
- addEvents(events.map((e) => (
538
- {
573
+ const events = initial_events();
574
+ addEvents(
575
+ events.map((e) => ({
539
576
  ...e,
540
- router_data: (({ pathname, query, asPath }) => ({ pathname, query, asPath }))(router)
541
- }
542
- )))
543
- sentHydrate.current = true
577
+ router_data: (({ pathname, query, asPath }) => ({
578
+ pathname,
579
+ query,
580
+ asPath,
581
+ }))(router),
582
+ }))
583
+ );
584
+ sentHydrate.current = true;
544
585
  }
545
- }, [router.isReady])
586
+ }, [router.isReady]);
546
587
 
547
588
  // Main event loop.
548
589
  useEffect(() => {
@@ -554,17 +595,22 @@ export const useEventLoop = (
554
595
  if (Object.keys(initialState).length > 1) {
555
596
  // Initialize the websocket connection.
556
597
  if (!socket.current) {
557
- connect(socket, dispatch, ['websocket', 'polling'], setConnectError, client_storage)
598
+ connect(
599
+ socket,
600
+ dispatch,
601
+ ["websocket", "polling"],
602
+ setConnectErrors,
603
+ client_storage
604
+ );
558
605
  }
559
606
  (async () => {
560
607
  // Process all outstanding events.
561
608
  while (event_queue.length > 0 && !event_processing) {
562
- await processEvent(socket.current)
609
+ await processEvent(socket.current);
563
610
  }
564
- })()
611
+ })();
565
612
  }
566
- })
567
-
613
+ });
568
614
 
569
615
  // localStorage event handling
570
616
  useEffect(() => {
@@ -583,9 +629,12 @@ export const useEventLoop = (
583
629
  // e is StorageEvent
584
630
  const handleStorage = (e) => {
585
631
  if (storage_to_state_map[e.key]) {
586
- const vars = {}
587
- vars[storage_to_state_map[e.key]] = e.newValue
588
- const event = Event(`${state_name}.update_vars_internal`, {vars: vars})
632
+ const vars = {};
633
+ vars[storage_to_state_map[e.key]] = e.newValue;
634
+ const event = Event(
635
+ `${state_name}.update_vars_internal_state.update_vars_internal`,
636
+ { vars: vars }
637
+ );
589
638
  addEvents([event], e);
590
639
  }
591
640
  };
@@ -594,18 +643,17 @@ export const useEventLoop = (
594
643
  return () => window.removeEventListener("storage", handleStorage);
595
644
  });
596
645
 
597
-
598
646
  // Route after the initial page hydration.
599
647
  useEffect(() => {
600
- const change_complete = () => addEvents(onLoadInternalEvent())
601
- router.events.on('routeChangeComplete', change_complete)
648
+ const change_complete = () => addEvents(onLoadInternalEvent());
649
+ router.events.on("routeChangeComplete", change_complete);
602
650
  return () => {
603
- router.events.off('routeChangeComplete', change_complete)
604
- }
605
- }, [router])
651
+ router.events.off("routeChangeComplete", change_complete);
652
+ };
653
+ }, [router]);
606
654
 
607
- return [addEvents, connectError]
608
- }
655
+ return [addEvents, connectErrors];
656
+ };
609
657
 
610
658
  /***
611
659
  * Check if a value is truthy in python.
@@ -626,17 +674,25 @@ export const getRefValue = (ref) => {
626
674
  return;
627
675
  }
628
676
  if (ref.current.type == "checkbox") {
629
- return ref.current.checked; // chakra
630
- } else if (ref.current.className.includes("rt-CheckboxButton") || ref.current.className.includes("rt-SwitchButton")) {
631
- return ref.current.ariaChecked == "true"; // radix
632
- } else if (ref.current.className.includes("rt-SliderRoot")) {
677
+ return ref.current.checked; // chakra
678
+ } else if (
679
+ ref.current.className?.includes("rt-CheckboxButton") ||
680
+ ref.current.className?.includes("rt-SwitchButton")
681
+ ) {
682
+ return ref.current.ariaChecked == "true"; // radix
683
+ } else if (ref.current.className?.includes("rt-SliderRoot")) {
633
684
  // find the actual slider
634
- return ref.current.querySelector(".rt-SliderThumb").ariaValueNow;
685
+ return ref.current.querySelector(".rt-SliderThumb")?.ariaValueNow;
635
686
  } else {
636
687
  //querySelector(":checked") is needed to get value from radio_group
637
- return ref.current.value || (ref.current.querySelector(':checked') && ref.current.querySelector(':checked').value);
688
+ return (
689
+ ref.current.value ||
690
+ (ref.current.querySelector &&
691
+ ref.current.querySelector(":checked") &&
692
+ ref.current.querySelector(":checked")?.value)
693
+ );
638
694
  }
639
- }
695
+ };
640
696
 
641
697
  /**
642
698
  * Get the values from a ref array.
@@ -648,21 +704,25 @@ export const getRefValues = (refs) => {
648
704
  return;
649
705
  }
650
706
  // getAttribute is used by RangeSlider because it doesn't assign value
651
- return refs.map((ref) => ref.current ? ref.current.value || ref.current.getAttribute("aria-valuenow") : null);
652
- }
707
+ return refs.map((ref) =>
708
+ ref.current
709
+ ? ref.current.value || ref.current.getAttribute("aria-valuenow")
710
+ : null
711
+ );
712
+ };
653
713
 
654
714
  /**
655
- * Spread two arrays or two objects.
656
- * @param first The first array or object.
657
- * @param second The second array or object.
658
- * @returns The final merged array or object.
659
- */
715
+ * Spread two arrays or two objects.
716
+ * @param first The first array or object.
717
+ * @param second The second array or object.
718
+ * @returns The final merged array or object.
719
+ */
660
720
  export const spreadArraysOrObjects = (first, second) => {
661
721
  if (Array.isArray(first) && Array.isArray(second)) {
662
722
  return [...first, ...second];
663
- } else if (typeof first === 'object' && typeof second === 'object') {
723
+ } else if (typeof first === "object" && typeof second === "object") {
664
724
  return { ...first, ...second };
665
725
  } else {
666
- throw new Error('Both parameters must be either arrays or objects.');
726
+ throw new Error("Both parameters must be either arrays or objects.");
667
727
  }
668
- }
728
+ };