@valbuild/react 0.12.0 → 0.13.3

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.
Files changed (60) hide show
  1. package/dist/ValProvider-52f2fa13.esm.js +731 -0
  2. package/dist/ValProvider-7364ec46.cjs.dev.js +746 -0
  3. package/dist/ValProvider-a45a47b9.worker.esm.js +726 -0
  4. package/dist/ValProvider-c7a8476b.browser.esm.js +731 -0
  5. package/dist/ValProvider-e1d5ffbe.cjs.js +7 -0
  6. package/dist/ValProvider-e1d5ffbe.cjs.prod.js +746 -0
  7. package/dist/ValUI-0fbdafd4.cjs.prod.js +398 -0
  8. package/dist/ValUI-371e9bf4.cjs.dev.js +398 -0
  9. package/dist/ValUI-51404232.browser.esm.js +396 -0
  10. package/dist/ValUI-9a3eb570.esm.js +396 -0
  11. package/dist/declarations/src/AuthStatus.d.ts +6 -0
  12. package/dist/declarations/src/ShadowRoot.d.ts +4 -0
  13. package/dist/declarations/src/ValProvider.d.ts +1 -1
  14. package/dist/declarations/src/ValProviderWrapper.d.ts +3 -0
  15. package/dist/declarations/src/ValUI.d.ts +8 -0
  16. package/dist/declarations/src/index.d.ts +1 -1
  17. package/dist/{slicedToArray-0ead6329.cjs.dev.js → slicedToArray-0eb0bcdb.cjs.prod.js} +3 -17
  18. package/dist/{slicedToArray-bf9b195a.worker.esm.js → slicedToArray-1a246338.browser.esm.js} +3 -16
  19. package/dist/{slicedToArray-236143cd.browser.esm.js → slicedToArray-9e7d1407.worker.esm.js} +3 -16
  20. package/dist/{slicedToArray-57b117df.cjs.prod.js → slicedToArray-b7cf26e0.cjs.dev.js} +3 -17
  21. package/dist/{slicedToArray-390fde8c.esm.js → slicedToArray-d846e1d2.esm.js} +3 -16
  22. package/dist/unsupportedIterableToArray-51bb61c2.esm.js +16 -0
  23. package/dist/unsupportedIterableToArray-738344ef.worker.esm.js +16 -0
  24. package/dist/unsupportedIterableToArray-9e97e24a.cjs.dev.js +18 -0
  25. package/dist/unsupportedIterableToArray-afbea1dd.cjs.prod.js +18 -0
  26. package/dist/unsupportedIterableToArray-d3087ed5.browser.esm.js +16 -0
  27. package/dist/valbuild-react.browser.esm.js +9 -1083
  28. package/dist/valbuild-react.cjs.dev.js +24 -1074
  29. package/dist/valbuild-react.cjs.prod.js +24 -1074
  30. package/dist/valbuild-react.esm.js +13 -1079
  31. package/dist/valbuild-react.worker.esm.js +13 -1079
  32. package/jest.config.js +5 -0
  33. package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.browser.esm.js +2 -1
  34. package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.cjs.dev.js +2 -1
  35. package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.cjs.prod.js +2 -1
  36. package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.esm.js +2 -1
  37. package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.worker.esm.js +2 -1
  38. package/jsx-runtime/dist/valbuild-react-jsx-runtime.browser.esm.js +2 -1
  39. package/jsx-runtime/dist/valbuild-react-jsx-runtime.cjs.dev.js +2 -1
  40. package/jsx-runtime/dist/valbuild-react-jsx-runtime.cjs.prod.js +2 -1
  41. package/jsx-runtime/dist/valbuild-react-jsx-runtime.esm.js +2 -1
  42. package/jsx-runtime/dist/valbuild-react-jsx-runtime.worker.esm.js +2 -1
  43. package/package.json +9 -6
  44. package/src/AuthStatus.tsx +13 -0
  45. package/src/ShadowRoot.tsx +32 -0
  46. package/src/ValApi.ts +65 -0
  47. package/src/ValProvider.tsx +51 -0
  48. package/src/ValProviderWrapper.tsx +15 -0
  49. package/src/ValRichText.tsx +141 -0
  50. package/src/ValStore.ts +62 -0
  51. package/src/ValUI.tsx +353 -0
  52. package/src/assets.ts +124 -0
  53. package/src/hooks/useVal.test.tsx +57 -0
  54. package/src/hooks/useVal.ts +35 -0
  55. package/src/index.ts +6 -0
  56. package/src/jsx-dev-runtime.js +47 -0
  57. package/src/jsx-namespace.d.ts +46 -0
  58. package/src/jsx-runtime.d.ts +1 -0
  59. package/src/jsx-runtime.dev.d.ts +1 -0
  60. package/src/jsx-runtime.js +52 -0
package/jest.config.js ADDED
@@ -0,0 +1,5 @@
1
+ /** @type {import("jest").Config} */
2
+ module.exports = {
3
+ preset: "../../jest.preset",
4
+ testEnvironment: "./jest-environment.mjs",
5
+ };
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-236143cd.browser.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-1a246338.browser.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime';
4
4
  export * from 'react/jsx-dev-runtime';
5
+ import '../../dist/unsupportedIterableToArray-d3087ed5.browser.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
@@ -2,9 +2,10 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var slicedToArray = require('../../dist/slicedToArray-0ead6329.cjs.dev.js');
5
+ var slicedToArray = require('../../dist/slicedToArray-b7cf26e0.cjs.dev.js');
6
6
  var core = require('@valbuild/core');
7
7
  var ReactJSXRuntimeDev = require('react/jsx-dev-runtime');
8
+ require('../../dist/unsupportedIterableToArray-9e97e24a.cjs.dev.js');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -2,9 +2,10 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var slicedToArray = require('../../dist/slicedToArray-57b117df.cjs.prod.js');
5
+ var slicedToArray = require('../../dist/slicedToArray-0eb0bcdb.cjs.prod.js');
6
6
  var core = require('@valbuild/core');
7
7
  var ReactJSXRuntimeDev = require('react/jsx-dev-runtime');
8
+ require('../../dist/unsupportedIterableToArray-afbea1dd.cjs.prod.js');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-390fde8c.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-d846e1d2.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime';
4
4
  export * from 'react/jsx-dev-runtime';
5
+ import '../../dist/unsupportedIterableToArray-51bb61c2.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-bf9b195a.worker.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-9e7d1407.worker.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime';
4
4
  export * from 'react/jsx-dev-runtime';
5
+ import '../../dist/unsupportedIterableToArray-738344ef.worker.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-236143cd.browser.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-1a246338.browser.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntime from 'react/jsx-runtime';
4
4
  export * from 'react/jsx-runtime';
5
+ import '../../dist/unsupportedIterableToArray-d3087ed5.browser.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
@@ -2,9 +2,10 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var slicedToArray = require('../../dist/slicedToArray-0ead6329.cjs.dev.js');
5
+ var slicedToArray = require('../../dist/slicedToArray-b7cf26e0.cjs.dev.js');
6
6
  var core = require('@valbuild/core');
7
7
  var ReactJSXRuntime = require('react/jsx-runtime');
8
+ require('../../dist/unsupportedIterableToArray-9e97e24a.cjs.dev.js');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -2,9 +2,10 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var slicedToArray = require('../../dist/slicedToArray-57b117df.cjs.prod.js');
5
+ var slicedToArray = require('../../dist/slicedToArray-0eb0bcdb.cjs.prod.js');
6
6
  var core = require('@valbuild/core');
7
7
  var ReactJSXRuntime = require('react/jsx-runtime');
8
+ require('../../dist/unsupportedIterableToArray-afbea1dd.cjs.prod.js');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-390fde8c.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-d846e1d2.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntime from 'react/jsx-runtime';
4
4
  export * from 'react/jsx-runtime';
5
+ import '../../dist/unsupportedIterableToArray-51bb61c2.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
@@ -1,7 +1,8 @@
1
- import { a as _slicedToArray, b as _typeof } from '../../dist/slicedToArray-bf9b195a.worker.esm.js';
1
+ import { _ as _slicedToArray, a as _typeof } from '../../dist/slicedToArray-9e7d1407.worker.esm.js';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import * as ReactJSXRuntime from 'react/jsx-runtime';
4
4
  export * from 'react/jsx-runtime';
5
+ import '../../dist/unsupportedIterableToArray-738344ef.worker.esm.js';
5
6
 
6
7
  var isIntrinsicElement = function isIntrinsicElement(type) {
7
8
  // TODO: think this is not correct, but good enough for now?
package/package.json CHANGED
@@ -1,26 +1,29 @@
1
1
  {
2
2
  "name": "@valbuild/react",
3
- "version": "0.12.0",
3
+ "version": "0.13.3",
4
+ "private": false,
5
+ "description": "Val - React",
4
6
  "sideEffects": false,
5
7
  "scripts": {
6
8
  "typecheck": "tsc --noEmit",
7
9
  "test": "jest"
8
10
  },
9
11
  "dependencies": {
10
- "@valbuild/core": "~0.12.0",
11
- "@valbuild/ui": "~0.12.0",
12
+ "@valbuild/core": "~0.13.3",
13
+ "@valbuild/ui": "~0.13.3",
12
14
  "base64-arraybuffer": "^1.0.2",
13
- "react-shadow": "^20.0.0",
14
15
  "style-to-object": "^0.4.1"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@testing-library/react": "^14.0.0",
18
19
  "@types/react": "^18.0.26",
19
20
  "jest-environment-jsdom": "^29.5.0",
20
- "react": "^18.2.0"
21
+ "react": "^18.2.0",
22
+ "react-dom": "^18.2.0"
21
23
  },
22
24
  "peerDependencies": {
23
- "react": ">=16.8.0"
25
+ "react": ">=16.8.0",
26
+ "react-dom": ">=16.8.0"
24
27
  },
25
28
  "peerDependenciesMeta": {
26
29
  "@types/react": {
@@ -0,0 +1,13 @@
1
+ export type AuthStatus =
2
+ | {
3
+ status:
4
+ | "not-asked"
5
+ | "authenticated"
6
+ | "unauthenticated"
7
+ | "loading"
8
+ | "local";
9
+ }
10
+ | {
11
+ status: "error";
12
+ message: string;
13
+ };
@@ -0,0 +1,32 @@
1
+ import { useState, useLayoutEffect, useRef } from "react";
2
+ import { createPortal } from "react-dom";
3
+
4
+ function ShadowContent({
5
+ root,
6
+ children,
7
+ }: {
8
+ children: React.ReactNode;
9
+ root: Element | DocumentFragment;
10
+ }) {
11
+ return createPortal(children, root);
12
+ }
13
+
14
+ export const ShadowRoot = ({ children }: { children: React.ReactNode }) => {
15
+ const node = useRef<HTMLDivElement>(null);
16
+ const [root, setRoot] = useState<ShadowRoot | null>(null);
17
+
18
+ useLayoutEffect(() => {
19
+ if (node.current) {
20
+ const root = node.current.attachShadow({
21
+ mode: "closed",
22
+ });
23
+ setRoot(root);
24
+ }
25
+ }, []);
26
+
27
+ return (
28
+ <div ref={node}>
29
+ {root && <ShadowContent root={root}>{children}</ShadowContent>}
30
+ </div>
31
+ );
32
+ };
package/src/ValApi.ts ADDED
@@ -0,0 +1,65 @@
1
+ import { SerializedModule } from "@valbuild/core";
2
+ import { PatchJSON } from "@valbuild/core/patch";
3
+
4
+ export class ValApi {
5
+ constructor(readonly host: string) {}
6
+
7
+ async getModule(sourcePath: string): Promise<SerializedModule> {
8
+ const res = await fetch(`${this.host}/ids${sourcePath}`);
9
+ if (res.ok) {
10
+ const serializedVal = await res.json(); // TODO: validate
11
+ return serializedVal;
12
+ } else {
13
+ throw Error(
14
+ `Failed to get content of module "${sourcePath}". Status: ${
15
+ res.status
16
+ }. Error: ${await res.text()}`
17
+ );
18
+ }
19
+ }
20
+
21
+ async patchModuleContent(
22
+ moduleId: string,
23
+ patch: PatchJSON
24
+ ): Promise<SerializedModule> {
25
+ const res = await fetch(`${this.host}/ids${moduleId}`, {
26
+ method: "PATCH",
27
+ headers: {
28
+ "Content-Type": "application/json-patch+json",
29
+ },
30
+ body: JSON.stringify(patch),
31
+ });
32
+ if (res.ok) {
33
+ return res.json(); // TODO: validate
34
+ } else {
35
+ throw Error(
36
+ `Failed to patch content of module "${moduleId}". Error: ${await res.text()}`
37
+ );
38
+ }
39
+ }
40
+
41
+ async commit(): Promise<void> {
42
+ const res = await fetch(`${this.host}/commit`, {
43
+ method: "POST",
44
+ });
45
+ if (res.ok) {
46
+ return;
47
+ } else {
48
+ throw Error(`Failed to commit. Error: ${await res.text()}`);
49
+ }
50
+ }
51
+
52
+ getSession() {
53
+ return fetch(`${this.host}/session`);
54
+ }
55
+
56
+ loginUrl() {
57
+ return `${this.host}/authorize?redirect_to=${encodeURIComponent(
58
+ location.href
59
+ )}`;
60
+ }
61
+
62
+ logout() {
63
+ return fetch(`${this.host}/logout`);
64
+ }
65
+ }
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import React, { lazy, useContext, useMemo } from "react";
4
+ import { ValApi } from "./ValApi";
5
+ import { ValStore } from "./ValStore";
6
+
7
+ export function useValStore() {
8
+ return useContext(ValContext).valStore;
9
+ }
10
+ export function useValApi() {
11
+ return useContext(ValContext).valApi;
12
+ }
13
+
14
+ export type ValContext = {
15
+ readonly valStore: ValStore;
16
+ readonly valApi: ValApi;
17
+ };
18
+
19
+ export const ValContext = React.createContext<ValContext>({
20
+ get valStore(): never {
21
+ throw Error(
22
+ "Val context not found. Ensure components are wrapped by ValProvider!"
23
+ );
24
+ },
25
+ get valApi(): never {
26
+ throw Error(
27
+ "Val context not found. Ensure components are wrapped by ValProvider!"
28
+ );
29
+ },
30
+ });
31
+
32
+ export type ValProviderProps = {
33
+ host?: string;
34
+ children?: React.ReactNode;
35
+ };
36
+ const ValUI =
37
+ typeof window !== "undefined" ? lazy(() => import("./ValUI")) : null;
38
+
39
+ export default function ValProvider({
40
+ host = "/api/val",
41
+ children,
42
+ }: ValProviderProps) {
43
+ const valApi = useMemo(() => new ValApi(host), [host]);
44
+ const valStore = useMemo(() => new ValStore(valApi), [valApi]);
45
+ return (
46
+ <ValContext.Provider value={{ valApi, valStore }}>
47
+ {children}
48
+ {ValUI && <ValUI valApi={valApi} valStore={valStore} />}
49
+ </ValContext.Provider>
50
+ );
51
+ }
@@ -0,0 +1,15 @@
1
+ import { lazy } from "react";
2
+ import { ValProviderProps } from "./ValProvider";
3
+
4
+ const ValProvider =
5
+ typeof window === "undefined" && lazy(() => import("./ValProvider"));
6
+
7
+ export function ValProviderWrapper({
8
+ host = "/api/val",
9
+ children,
10
+ }: ValProviderProps) {
11
+ if (!ValProvider) {
12
+ return null;
13
+ }
14
+ return <ValProvider host={host}>{children}</ValProvider>;
15
+ }
@@ -0,0 +1,141 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import {
3
+ HeadingNode,
4
+ ListItemNode,
5
+ ListNode,
6
+ ParagraphNode,
7
+ RichText,
8
+ TextNode,
9
+ Val,
10
+ } from "@valbuild/core";
11
+ import { Internal } from "@valbuild/core";
12
+ import { createElement } from "react";
13
+ import parse from "style-to-object";
14
+
15
+ const getValPath = Internal.getValPath;
16
+ export function ValRichText({ children }: { children: Val<RichText> }) {
17
+ return (
18
+ <div data-val-path={getValPath(children)}>
19
+ {children.children.map((child) => {
20
+ switch (child.type.val) {
21
+ case "heading":
22
+ return (
23
+ <HeadingNodeComponent
24
+ key={getValPath(child)}
25
+ node={child as Val<HeadingNode>}
26
+ />
27
+ );
28
+ case "paragraph":
29
+ return (
30
+ <ParagraphNodeComponent
31
+ key={getValPath(child)}
32
+ node={child as Val<ParagraphNode>}
33
+ />
34
+ );
35
+ case "list":
36
+ return (
37
+ <ListNodeComponent
38
+ key={getValPath(child)}
39
+ node={child as Val<ListNode>}
40
+ />
41
+ );
42
+ default:
43
+ throw Error("Unknown node type: " + (child as any)?.type);
44
+ }
45
+ })}
46
+ </div>
47
+ );
48
+ }
49
+
50
+ function TextNodeComponent({ node }: { node: Val<TextNode> }) {
51
+ const actualVal = node.val;
52
+ const styleProps = actualVal.style ? parse(actualVal.style) ?? {} : {};
53
+ // TODO: Ugly! We should do this before serializing instead
54
+ if (styleProps["font-family"]) {
55
+ styleProps["fontFamily"] = styleProps["font-family"];
56
+ delete styleProps["font-family"];
57
+ }
58
+ if (styleProps["font-size"]) {
59
+ styleProps["fontSize"] = styleProps["font-size"];
60
+ delete styleProps["font-size"];
61
+ }
62
+ const bitmask = actualVal.format.toString(2);
63
+ const bitmaskOffset = bitmask.length - 1;
64
+ function isBitOne(bit: number) {
65
+ return (
66
+ bitmask.length >= bitmaskOffset - bit &&
67
+ bitmask[bitmaskOffset - bit] === "1"
68
+ );
69
+ }
70
+ if (isBitOne(0)) {
71
+ styleProps["fontWeight"] = "bold";
72
+ }
73
+ if (isBitOne(1)) {
74
+ styleProps["fontStyle"] = "italic";
75
+ }
76
+ if (isBitOne(2)) {
77
+ if (!styleProps["textDecoration"]) {
78
+ styleProps["textDecoration"] = "line-through";
79
+ } else {
80
+ styleProps["textDecoration"] += " line-through";
81
+ }
82
+ }
83
+ if (isBitOne(3)) {
84
+ if (!styleProps["textDecoration"]) {
85
+ styleProps["textDecoration"] = "underline";
86
+ } else {
87
+ styleProps["textDecoration"] += " underline";
88
+ }
89
+ }
90
+ return <span style={styleProps}>{actualVal.text}</span>;
91
+ }
92
+
93
+ function HeadingNodeComponent({ node }: { node: Val<HeadingNode> }) {
94
+ return createElement(
95
+ node.tag.val,
96
+ {},
97
+ node.children.map((child) => (
98
+ <TextNodeComponent key={getValPath(child)} node={child} />
99
+ ))
100
+ );
101
+ }
102
+
103
+ function ParagraphNodeComponent({ node }: { node: Val<ParagraphNode> }) {
104
+ return (
105
+ <p>
106
+ {node.children.map((child) => {
107
+ switch (child.type.val) {
108
+ case "text":
109
+ return <TextNodeComponent key={getValPath(child)} node={child} />;
110
+ default:
111
+ throw Error("Unknown node type: " + (child as any)?.type);
112
+ }
113
+ })}
114
+ </p>
115
+ );
116
+ }
117
+
118
+ function ListNodeComponent({ node }: { node: Val<ListNode> }) {
119
+ return createElement(
120
+ node.val.tag,
121
+ {},
122
+ node.children.map((child) => (
123
+ <ListItemComponent key={getValPath(child)} node={child} />
124
+ ))
125
+ );
126
+ }
127
+
128
+ function ListItemComponent({ node }: { node: Val<ListItemNode> }) {
129
+ return (
130
+ <li>
131
+ {node.children.map((child, i) => {
132
+ switch (child.val.type) {
133
+ case "text":
134
+ return <TextNodeComponent key={i} node={child} />;
135
+ default:
136
+ throw Error("Unknown node type: " + (child as any)?.type);
137
+ }
138
+ })}
139
+ </li>
140
+ );
141
+ }
@@ -0,0 +1,62 @@
1
+ import { ValModule, SelectorSource } from "@valbuild/core";
2
+ import { ValApi } from "./ValApi";
3
+
4
+ export class ValStore {
5
+ private readonly vals: Map<string, ValModule<SelectorSource>>;
6
+ private readonly listeners: { [moduleId: string]: (() => void)[] };
7
+
8
+ constructor(private readonly api: ValApi) {
9
+ this.vals = new Map();
10
+ this.listeners = {};
11
+ }
12
+
13
+ async updateAll() {
14
+ await Promise.all(
15
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
+ Object.keys(this.listeners).map(async (moduleId) => {
17
+ // this.set(
18
+ // moduleId,
19
+ // await this.api.getModule(moduleId)
20
+ // // ModuleContent.deserialize(await this.api.getModule(moduleId))
21
+ // );
22
+ })
23
+ );
24
+ }
25
+
26
+ subscribe = (moduleId: string) => (listener: () => void) => {
27
+ const listeners = (this.listeners[moduleId] =
28
+ moduleId in this.listeners ? this.listeners[moduleId] : []);
29
+ listeners.push(listener);
30
+ return () => {
31
+ listeners.splice(listeners.indexOf(listener), 1);
32
+ if (listeners.length === 0) {
33
+ delete this.listeners[moduleId];
34
+ }
35
+ };
36
+ };
37
+
38
+ set(moduleId: string, val: ValModule<SelectorSource>) {
39
+ this.vals.set(moduleId, val);
40
+ this.emitChange(moduleId);
41
+ }
42
+
43
+ get(moduleId: string) {
44
+ return this.vals.get(moduleId);
45
+ }
46
+
47
+ emitChange(moduleId: string) {
48
+ const listeners = this.listeners[moduleId];
49
+ if (typeof listeners === "undefined") return;
50
+ for (const listener of listeners) {
51
+ listener();
52
+ }
53
+ }
54
+
55
+ getSnapshot = (moduleId: string) => () => {
56
+ return this.vals.get(moduleId);
57
+ };
58
+
59
+ getServerSnapshot = (moduleId: string) => () => {
60
+ return this.vals.get(moduleId);
61
+ };
62
+ }