@valbuild/ui 0.26.0 → 0.28.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.
Files changed (145) hide show
  1. package/dist/valbuild-ui.cjs.js +41 -15
  2. package/dist/valbuild-ui.esm.js +41 -15
  3. package/package.json +7 -3
  4. package/server/.tmp/assets/index-18cfa26c.css +1 -0
  5. package/server/.tmp/assets/index-513f7a9c.js +197 -0
  6. package/{index.html → server/.tmp/index.html} +3 -1
  7. package/server/dist/style.css +0 -3
  8. package/server/dist/valbuild-ui-main.cjs.js +60 -34
  9. package/server/dist/valbuild-ui-main.esm.js +60 -34
  10. package/server/dist/valbuild-ui-server.cjs.js +1 -1
  11. package/server/dist/valbuild-ui-server.esm.js +1 -1
  12. package/.babelrc.json +0 -10
  13. package/.storybook/main.js +0 -25
  14. package/.storybook/preview-head.html +0 -6
  15. package/.storybook/preview.js +0 -33
  16. package/.storybook/theme.css +0 -34
  17. package/CHANGELOG.md +0 -0
  18. package/components.json +0 -16
  19. package/fix-server-hack.js +0 -54
  20. package/fullscreen.vite.config.ts +0 -9
  21. package/jest.config.js +0 -4
  22. package/postcss.config.js +0 -6
  23. package/rollup.config.js +0 -23
  24. package/server.vite.config.ts +0 -31
  25. package/src/App.tsx +0 -73
  26. package/src/assets/icons/Bold.tsx +0 -23
  27. package/src/assets/icons/Chevron.tsx +0 -28
  28. package/src/assets/icons/FontColor.tsx +0 -30
  29. package/src/assets/icons/ImageIcon.tsx +0 -29
  30. package/src/assets/icons/Italic.tsx +0 -24
  31. package/src/assets/icons/Logo.tsx +0 -103
  32. package/src/assets/icons/Section.tsx +0 -41
  33. package/src/assets/icons/Strikethrough.tsx +0 -22
  34. package/src/assets/icons/TextIcon.tsx +0 -20
  35. package/src/assets/icons/Underline.tsx +0 -22
  36. package/src/assets/icons/Undo.tsx +0 -20
  37. package/src/components/Button.tsx +0 -68
  38. package/src/components/Checkbox.tsx +0 -51
  39. package/src/components/DraggableList.stories.tsx +0 -20
  40. package/src/components/DraggableList.tsx +0 -95
  41. package/src/components/Dropdown.tsx +0 -101
  42. package/src/components/EditButton.tsx +0 -10
  43. package/src/components/ErrorText.tsx +0 -3
  44. package/src/components/ExpandLogo.tsx +0 -72
  45. package/src/components/Grid.stories.tsx +0 -43
  46. package/src/components/Grid.tsx +0 -139
  47. package/src/components/RichTextEditor/ContentEditable.tsx +0 -117
  48. package/src/components/RichTextEditor/Nodes/ImageNode.tsx +0 -100
  49. package/src/components/RichTextEditor/Plugins/AutoFocus.tsx +0 -12
  50. package/src/components/RichTextEditor/Plugins/ImagePlugin.tsx +0 -45
  51. package/src/components/RichTextEditor/Plugins/LinkEditorPlugin.tsx +0 -58
  52. package/src/components/RichTextEditor/Plugins/Toolbar.tsx +0 -412
  53. package/src/components/RichTextEditor/RichTextEditor.tsx +0 -105
  54. package/src/components/UploadModal.tsx +0 -109
  55. package/src/components/User.tsx +0 -17
  56. package/src/components/ValFormField.tsx +0 -574
  57. package/src/components/ValFullscreen.tsx +0 -1278
  58. package/src/components/ValMenu.tsx +0 -92
  59. package/src/components/ValOverlay.tsx +0 -488
  60. package/src/components/ValOverlayContext.tsx +0 -80
  61. package/src/components/ValWindow.stories.tsx +0 -146
  62. package/src/components/ValWindow.tsx +0 -220
  63. package/src/components/dashboard/DashboardButton.tsx +0 -25
  64. package/src/components/dashboard/DashboardDropdown.tsx +0 -59
  65. package/src/components/dashboard/Dropdown.stories.tsx +0 -11
  66. package/src/components/dashboard/Dropdown.tsx +0 -70
  67. package/src/components/dashboard/FormGroup.stories.tsx +0 -37
  68. package/src/components/dashboard/FormGroup.tsx +0 -42
  69. package/src/components/dashboard/Grid2.stories.tsx +0 -56
  70. package/src/components/dashboard/Grid2.tsx +0 -72
  71. package/src/components/dashboard/Tree.stories.tsx +0 -91
  72. package/src/components/dashboard/Tree.tsx +0 -72
  73. package/src/components/dashboard/ValDashboardEditor.tsx +0 -269
  74. package/src/components/dashboard/ValDashboardGrid.tsx +0 -142
  75. package/src/components/dashboard/ValTreeNavigator.tsx +0 -253
  76. package/src/components/forms/Form.tsx +0 -126
  77. package/src/components/forms/FormContainer.tsx +0 -24
  78. package/src/components/forms/ImageForm.tsx +0 -195
  79. package/src/components/forms/TextArea.tsx +0 -24
  80. package/src/components/ui/accordion.tsx +0 -58
  81. package/src/components/ui/alert-dialog.tsx +0 -139
  82. package/src/components/ui/avatar.tsx +0 -48
  83. package/src/components/ui/button.tsx +0 -56
  84. package/src/components/ui/calendar.tsx +0 -62
  85. package/src/components/ui/card.tsx +0 -86
  86. package/src/components/ui/checkbox.tsx +0 -28
  87. package/src/components/ui/command.tsx +0 -153
  88. package/src/components/ui/dialog.tsx +0 -120
  89. package/src/components/ui/dropdown-menu.tsx +0 -198
  90. package/src/components/ui/form.tsx +0 -177
  91. package/src/components/ui/input.tsx +0 -24
  92. package/src/components/ui/label.tsx +0 -24
  93. package/src/components/ui/popover.tsx +0 -29
  94. package/src/components/ui/progress.tsx +0 -26
  95. package/src/components/ui/radio-group.tsx +0 -42
  96. package/src/components/ui/scroll-area.tsx +0 -51
  97. package/src/components/ui/select.tsx +0 -119
  98. package/src/components/ui/switch.tsx +0 -27
  99. package/src/components/ui/tabs.tsx +0 -53
  100. package/src/components/ui/toggle.tsx +0 -43
  101. package/src/components/ui/tooltip.tsx +0 -28
  102. package/src/components/usePatch.ts +0 -86
  103. package/src/components/useTheme.ts +0 -45
  104. package/src/dto/SerializedSchema.ts +0 -69
  105. package/src/dto/Session.ts +0 -12
  106. package/src/dto/SessionMode.ts +0 -5
  107. package/src/dto/Tree.ts +0 -18
  108. package/src/exports.ts +0 -6
  109. package/src/index.css +0 -115
  110. package/src/index.tsx +0 -14
  111. package/src/lib/IValStore.ts +0 -6
  112. package/src/lib/utils.ts +0 -6
  113. package/src/main.jsx +0 -10
  114. package/src/richtext/conversion/conversion.test.ts +0 -146
  115. package/src/richtext/conversion/lexicalToRichTextSource.test.ts +0 -89
  116. package/src/richtext/conversion/lexicalToRichTextSource.ts +0 -285
  117. package/src/richtext/conversion/parseRichTextSource.test.ts +0 -469
  118. package/src/richtext/conversion/parseRichTextSource.ts +0 -233
  119. package/src/richtext/conversion/richTextSourceToLexical.test.ts +0 -381
  120. package/src/richtext/conversion/richTextSourceToLexical.ts +0 -293
  121. package/src/richtext/shadowRootPolyFill.js +0 -115
  122. package/src/server.ts +0 -70
  123. package/src/stories/Button.stories.tsx +0 -20
  124. package/src/stories/Checkbox.stories.tsx +0 -14
  125. package/src/stories/Dropdown.stories.tsx +0 -23
  126. package/src/stories/Introduction.mdx +0 -221
  127. package/src/stories/RichTextEditor.stories.tsx +0 -24
  128. package/src/stories/assets/code-brackets.svg +0 -1
  129. package/src/stories/assets/colors.svg +0 -1
  130. package/src/stories/assets/comments.svg +0 -1
  131. package/src/stories/assets/direction.svg +0 -1
  132. package/src/stories/assets/flow.svg +0 -1
  133. package/src/stories/assets/plugin.svg +0 -1
  134. package/src/stories/assets/repo.svg +0 -1
  135. package/src/stories/assets/stackalt.svg +0 -1
  136. package/src/utils/Remote.ts +0 -15
  137. package/src/utils/imageMimeType.ts +0 -23
  138. package/src/utils/readImage.ts +0 -54
  139. package/src/utils/resolvePath.ts +0 -32
  140. package/src/vite-env.d.ts +0 -1
  141. package/src/vite-index.tsx +0 -7
  142. package/src/vite-server.ts +0 -42
  143. package/tailwind.config.js +0 -83
  144. package/tsconfig.json +0 -19
  145. package/vite.config.ts +0 -43
@@ -1,92 +0,0 @@
1
- import { useValOverlayContext } from "./ValOverlayContext";
2
- import { ValApi } from "@valbuild/core";
3
- import classNames from "classnames";
4
- import {
5
- Maximize,
6
- Minimize,
7
- Moon,
8
- Pause,
9
- Play,
10
- Power,
11
- Sun,
12
- } from "lucide-react";
13
- import React from "react";
14
-
15
- const className = "p-1 border rounded-full shadow border-accent";
16
- const PREV_URL_KEY = "valbuild:urlBeforeNavigation";
17
-
18
- export function ValMenu({ api }: { api: ValApi }) {
19
- const { theme, setTheme, editMode, setEditMode } = useValOverlayContext();
20
- return (
21
- <div className="flex flex-row items-center justify-center w-full h-full px-1 py-2 border-2 rounded-full gap-x-3 text-primary bg-background border-fill">
22
- <MenuButton
23
- active={editMode === "hover"}
24
- onClick={() => {
25
- setEditMode((prev) => (prev === "hover" ? "off" : "hover"));
26
- }}
27
- >
28
- <div className="h-[24px] w-[24px] flex justify-center items-center">
29
- {editMode === "hover" ? <Pause size={18} /> : <Play size={18} />}
30
- </div>
31
- </MenuButton>
32
- <MenuButton
33
- onClick={() => {
34
- setTheme(theme === "dark" ? "light" : "dark");
35
- }}
36
- >
37
- <div className="h-[24px] w-[24px] flex justify-center items-center">
38
- {theme === "dark" && <Sun size={15} />}
39
- {theme === "light" && <Moon size={15} />}
40
- </div>
41
- </MenuButton>
42
- <MenuButton
43
- active={editMode === "full"}
44
- onClick={() => {
45
- // Save the current url so we can go back to it when returning from fullscreen mode
46
- if (editMode !== "full") {
47
- localStorage.setItem(PREV_URL_KEY, window.location.href);
48
- window.location.href = api.getEditUrl();
49
- } else if (editMode === "full") {
50
- const prevUrl = localStorage.getItem(PREV_URL_KEY);
51
- window.location.href = prevUrl || "/";
52
- }
53
- }}
54
- >
55
- <div className="h-[24px] w-[24px] flex justify-center items-center">
56
- {editMode === "full" ? (
57
- <Minimize size={15} />
58
- ) : (
59
- <Maximize size={15} />
60
- )}
61
- </div>
62
- </MenuButton>
63
-
64
- <a className={className} href={api.getDisableUrl()}>
65
- <div className="h-[24px] w-[24px] flex justify-center items-center">
66
- <Power size={18} />
67
- </div>
68
- </a>
69
- </div>
70
- );
71
- }
72
-
73
- function MenuButton({
74
- active,
75
- onClick,
76
- children,
77
- }: {
78
- active?: boolean;
79
- children: React.ReactNode;
80
- onClick: () => void;
81
- }) {
82
- return (
83
- <button
84
- className={classNames(className, {
85
- "bg-accent drop-shadow-[0px_0px_12px_rgba(56,205,152,0.60)]": active,
86
- })}
87
- onClick={onClick}
88
- >
89
- {children}
90
- </button>
91
- );
92
- }
@@ -1,488 +0,0 @@
1
- "use client";
2
-
3
- import {
4
- Dispatch,
5
- SetStateAction,
6
- useCallback,
7
- useEffect,
8
- useState,
9
- } from "react";
10
- import { Session } from "../dto/Session";
11
- import { ValMenu } from "./ValMenu";
12
- import { EditMode, ValOverlayContext, WindowSize } from "./ValOverlayContext";
13
- import { Remote } from "../utils/Remote";
14
- import { ValWindow } from "./ValWindow";
15
- import { result } from "@valbuild/core/fp";
16
- import { Internal, SerializedSchema, SourcePath } from "@valbuild/core";
17
- import { Modules, resolvePath } from "../utils/resolvePath";
18
- import { ValApi } from "@valbuild/core";
19
- import { ValFormField } from "./ValFormField";
20
- import { usePatch } from "./usePatch";
21
- import { Button } from "./ui/button";
22
- import { useTheme } from "./useTheme";
23
- import { IValStore } from "../lib/IValStore";
24
-
25
- export type ValOverlayProps = {
26
- defaultTheme?: "dark" | "light";
27
- api: ValApi;
28
- store: IValStore;
29
- };
30
-
31
- export function ValOverlay({ defaultTheme, api, store }: ValOverlayProps) {
32
- const [theme, setTheme] = useTheme(defaultTheme);
33
- const session = useSession(api);
34
-
35
- const [editMode, setEditMode] = useInitEditMode();
36
- const [hoverTarget, setHoverTarget] = useHoverTarget(editMode);
37
- const [windowTarget, setWindowTarget] = useState<WindowTarget | null>(null);
38
- const [highlight, setHighlight] = useState(false);
39
- const { selectedSchema, selectedSource, error, loading } = useValModules(
40
- api,
41
- windowTarget?.path
42
- );
43
-
44
- const { initPatchCallback, onSubmitPatch } = usePatch(
45
- windowTarget?.path ? [windowTarget.path] : [],
46
- api,
47
- store
48
- );
49
-
50
- const [windowSize, setWindowSize] = useState<WindowSize>();
51
- useEffect(() => {
52
- store.updateAll();
53
- }, []);
54
-
55
- return (
56
- <ValOverlayContext.Provider
57
- value={{
58
- api,
59
- theme,
60
- session,
61
- editMode,
62
- setEditMode,
63
- highlight,
64
- setHighlight,
65
- setTheme,
66
- windowSize,
67
- setWindowSize,
68
- }}
69
- >
70
- <div data-mode={theme} className="antialiased">
71
- <div className="fixed -translate-x-1/2 z-overlay left-1/2 bottom-4">
72
- <ValMenu api={api} />
73
- </div>
74
- {editMode === "hover" && hoverTarget && (
75
- <ValHover
76
- hoverTarget={hoverTarget}
77
- setHoverTarget={setHoverTarget}
78
- setEditMode={setEditMode}
79
- setWindowTarget={setWindowTarget}
80
- />
81
- )}
82
- {editMode === "window" && windowTarget && (
83
- <ValWindow
84
- onClose={() => {
85
- setWindowTarget(null);
86
- setEditMode("hover");
87
- }}
88
- >
89
- <div className="px-4 py-2 text-sm border-b border-highlight">
90
- <WindowHeader
91
- path={windowTarget.path}
92
- type={selectedSchema?.type}
93
- />
94
- </div>
95
- {loading && <div className="text-primary">Loading...</div>}
96
- {error && <div className="text-red">{error}</div>}
97
- {selectedSchema !== undefined && selectedSource !== undefined && (
98
- <ValFormField
99
- path={windowTarget.path}
100
- disabled={loading}
101
- source={selectedSource}
102
- schema={selectedSchema}
103
- registerPatchCallback={initPatchCallback(windowTarget.path)}
104
- />
105
- )}
106
- <div className="flex items-end justify-end py-2">
107
- <SubmitButton disabled={false} onClick={onSubmitPatch} />
108
- </div>
109
- </ValWindow>
110
- )}
111
- </div>
112
- </ValOverlayContext.Provider>
113
- );
114
- }
115
-
116
- function SubmitButton({
117
- disabled,
118
- onClick,
119
- }: {
120
- disabled?: boolean;
121
- onClick?: () => void;
122
- }) {
123
- return (
124
- <Button
125
- className="px-4 py-2 border border-highlight disabled:border-border"
126
- disabled={disabled}
127
- onClick={onClick}
128
- >
129
- Submit
130
- </Button>
131
- );
132
- }
133
-
134
- function useValModules(api: ValApi, path: string | undefined) {
135
- const [modules, setModules] = useState<Remote<Modules>>();
136
- const moduleId =
137
- path && Internal.splitModuleIdAndModulePath(path as SourcePath)[0];
138
-
139
- useEffect(() => {
140
- if (path) {
141
- setModules({ status: "loading" });
142
- api
143
- .getModules({
144
- patch: true,
145
- includeSchema: true,
146
- includeSource: true,
147
- treePath: moduleId,
148
- })
149
- .then((res) => {
150
- if (result.isOk(res)) {
151
- setModules({ status: "success", data: res.value.modules });
152
- } else {
153
- console.error({ status: "error", error: res.error });
154
- setModules({ status: "error", error: res.error.message });
155
- }
156
- });
157
- }
158
- }, [path]);
159
- if (!path || modules?.status === "not-asked") {
160
- return {
161
- error: null,
162
- selectedSource: undefined,
163
- selectedSchema: undefined,
164
- loading: false,
165
- };
166
- }
167
- if (modules?.status === "loading") {
168
- return {
169
- error: null,
170
- selectedSource: undefined,
171
- selectedSchema: undefined,
172
- loading: true,
173
- };
174
- }
175
- if (modules?.status === "error") {
176
- return {
177
- error: modules.error,
178
- selectedSource: undefined,
179
- selectedSchema: undefined,
180
- loading: false,
181
- };
182
- }
183
- if (!modules?.data) {
184
- return {
185
- error: "No modules",
186
- selectedSource: undefined,
187
- selectedSchema: undefined,
188
- loading: false,
189
- };
190
- }
191
-
192
- const resolvedModulePath = resolvePath(path as SourcePath, modules.data);
193
-
194
- const {
195
- error,
196
- source: selectedSource,
197
- schema: selectedSchema,
198
- } = resolvedModulePath && result.isOk(resolvedModulePath)
199
- ? {
200
- ...resolvedModulePath.value,
201
- error: null,
202
- }
203
- : {
204
- error:
205
- resolvedModulePath && result.isErr(resolvedModulePath)
206
- ? resolvedModulePath.error.message
207
- : null,
208
- source: undefined,
209
- schema: undefined,
210
- };
211
- return {
212
- error,
213
- selectedSource,
214
- selectedSchema,
215
- loading: false,
216
- };
217
- }
218
-
219
- type WindowTarget = {
220
- element?: HTMLElement | undefined;
221
- mouse: { x: number; y: number };
222
- path: SourcePath;
223
- };
224
-
225
- type HoverTarget = {
226
- element?: HTMLElement | undefined;
227
- path: SourcePath;
228
- };
229
- function ValHover({
230
- hoverTarget,
231
- setEditMode,
232
- setWindowTarget,
233
- setHoverTarget,
234
- }: {
235
- hoverTarget: HoverTarget;
236
- setEditMode: Dispatch<EditMode>;
237
- setHoverTarget: Dispatch<HoverTarget | null>;
238
- setWindowTarget: Dispatch<WindowTarget | null>;
239
- }) {
240
- const rect = hoverTarget.element?.getBoundingClientRect();
241
- return (
242
- <div
243
- id="val-hover"
244
- className="fixed border-2 cursor-pointer z-overlay-hover border-highlight drop-shadow-[0px_0px_12px_rgba(56,205,152,0.60)]"
245
- style={{
246
- top: rect?.top,
247
- left: rect?.left,
248
- width: rect?.width,
249
- height: rect?.height,
250
- }}
251
- onClick={(ev) => {
252
- setWindowTarget({
253
- ...hoverTarget,
254
- mouse: { x: ev.pageX, y: ev.pageY },
255
- });
256
- setEditMode("window");
257
- setHoverTarget(null);
258
- }}
259
- >
260
- <div className="flex items-center justify-end w-full text-xs">
261
- <div
262
- className="flex items-center justify-center px-3 py-1 text-primary bg-highlight"
263
- style={{
264
- maxHeight: rect?.height && rect.height - 4,
265
- fontSize:
266
- rect?.height && rect.height <= 16 ? rect.height - 4 : undefined,
267
- }}
268
- >
269
- Edit
270
- </div>
271
- </div>
272
- </div>
273
- );
274
- }
275
-
276
- function useHoverTarget(editMode: EditMode) {
277
- const [targetElement, setTargetElement] = useState<HTMLElement>();
278
- const [targetPath, setTargetPath] = useState<SourcePath>();
279
- const [targetRect, setTargetRect] = useState<DOMRect>();
280
- useEffect(() => {
281
- if (editMode === "hover") {
282
- let curr: HTMLElement | null = null;
283
- const mouseOverListener = (e: MouseEvent) => {
284
- const target = e.target as HTMLElement | null;
285
- curr = target;
286
- // TODO: use .contains?
287
- do {
288
- if (curr?.dataset.valPath) {
289
- setTargetElement(curr);
290
- setTargetPath(curr.dataset.valPath as SourcePath);
291
- setTargetRect(curr.getBoundingClientRect());
292
- break;
293
- }
294
- } while ((curr = curr?.parentElement || null));
295
- };
296
-
297
- document.addEventListener("mouseover", mouseOverListener);
298
-
299
- return () => {
300
- setTargetElement(undefined);
301
- setTargetPath(undefined);
302
- document.removeEventListener("mouseover", mouseOverListener);
303
- };
304
- }
305
- }, [editMode]);
306
- useEffect(() => {
307
- const scrollListener = () => {
308
- if (targetElement) {
309
- setTargetRect(targetElement.getBoundingClientRect());
310
- }
311
- };
312
- document.addEventListener("scroll", scrollListener, { passive: true });
313
- return () => {
314
- document.removeEventListener("scroll", scrollListener);
315
- };
316
- }, [targetElement]);
317
-
318
- return [
319
- {
320
- path: targetPath,
321
- element: targetElement,
322
- rect: targetRect,
323
- } as HoverTarget,
324
- (target: HoverTarget | null) => {
325
- setTargetElement(target?.element);
326
- setTargetPath(target?.path);
327
- setTargetRect(target?.element?.getBoundingClientRect());
328
- },
329
- ] as const;
330
- }
331
-
332
- // TODO: do something fun on highlight?
333
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
334
- function useHighlight(
335
- highlight: boolean,
336
- setTarget: Dispatch<HoverTarget | null>
337
- ) {
338
- useEffect(() => {
339
- if (highlight) {
340
- const elements =
341
- document.querySelectorAll<HTMLElement>("[data-val-path]");
342
- let index = 0;
343
- let timeout: NodeJS.Timeout | null = null;
344
-
345
- const highlight = () => {
346
- const element = elements[index];
347
- const path = element.dataset.valPath as SourcePath;
348
- if (path) {
349
- setTarget({
350
- path,
351
- element,
352
- });
353
- }
354
- index++;
355
- if (index >= elements.length) {
356
- index = 0;
357
- }
358
- timeout = setTimeout(highlight, 1000);
359
- };
360
- highlight();
361
- return () => {
362
- if (timeout) {
363
- clearTimeout(timeout);
364
- }
365
- };
366
- }
367
- }, [highlight]);
368
- }
369
-
370
- const LOCAL_STORAGE_EDIT_MODE_KEY = "val-edit-mode";
371
-
372
- function useInitEditMode() {
373
- const [editMode, setEditModeRaw] = useState<EditMode>("off");
374
- useEffect(() => {
375
- try {
376
- const storedEditMode = localStorage.getItem(LOCAL_STORAGE_EDIT_MODE_KEY);
377
- if (
378
- storedEditMode === "off" ||
379
- storedEditMode === "hover" ||
380
- storedEditMode === "window" ||
381
- storedEditMode === "full"
382
- ) {
383
- setEditModeRaw(storedEditMode === "window" ? "hover" : storedEditMode);
384
- } else {
385
- localStorage.removeItem(LOCAL_STORAGE_EDIT_MODE_KEY);
386
- setEditModeRaw("off");
387
- }
388
- } catch (err) {
389
- setEditModeRaw("off");
390
- }
391
- }, []);
392
-
393
- const setEditMode: Dispatch<SetStateAction<EditMode>> = useCallback((v) => {
394
- if (typeof v === "function") {
395
- setEditModeRaw((prev) => {
396
- const next = v(prev);
397
- localStorage.setItem(LOCAL_STORAGE_EDIT_MODE_KEY, next);
398
- return next;
399
- });
400
- } else {
401
- localStorage.setItem(LOCAL_STORAGE_EDIT_MODE_KEY, v);
402
- setEditModeRaw(v);
403
- }
404
- }, []);
405
- return [editMode, setEditMode] as const;
406
- }
407
-
408
- function useSession(api: ValApi) {
409
- const [session, setSession] = useState<Remote<Session>>({
410
- status: "not-asked",
411
- });
412
- const [sessionResetId, setSessionResetId] = useState(0);
413
- useEffect(() => {
414
- setSession({ status: "loading" });
415
- api.getSession().then(async (res) => {
416
- try {
417
- if (result.isOk(res)) {
418
- const session = res.value;
419
- setSession({ status: "success", data: Session.parse(session) });
420
- } else {
421
- if (sessionResetId < 3) {
422
- setTimeout(() => {
423
- setSessionResetId(sessionResetId + 1);
424
- }, 200 * sessionResetId);
425
- } else {
426
- setSession({ status: "error", error: "Could not fetch session" });
427
- }
428
- }
429
- } catch (e) {
430
- setSession({
431
- status: "error",
432
- error: "Got an error while trying to get session",
433
- });
434
- }
435
- });
436
- }, [sessionResetId]);
437
- return session;
438
- }
439
-
440
- function WindowHeader({
441
- path,
442
- type,
443
- }: {
444
- path: SourcePath;
445
- type?: SerializedSchema["type"];
446
- }) {
447
- const segments = path.split("/").slice(1);
448
- return (
449
- <span className="flex items-center justify-between">
450
- <span>
451
- <span className="pr-1 text-xs opacity-50">/</span>
452
- {segments.map((segment, i) => {
453
- if (i === segments.length - 1) {
454
- return (
455
- <span key={i} className="text-primary">
456
- {segment.split(".").map((s, i) => {
457
- let name = s;
458
- if (i === 0) {
459
- return (
460
- <span key={i + "."}>
461
- <span>{name}</span>
462
- </span>
463
- );
464
- } else {
465
- name = JSON.parse(s);
466
- }
467
- return (
468
- <span key={i + "."}>
469
- <span className="px-1 text-xs text-highlight">/</span>
470
- <span>{name}</span>
471
- </span>
472
- );
473
- })}
474
- </span>
475
- );
476
- }
477
- return (
478
- <span key={i}>
479
- <span>{segment}</span>
480
- <span className="px-1 text-xs opacity-50">/</span>
481
- </span>
482
- );
483
- })}
484
- </span>
485
- {type && <span className="ml-4">({type})</span>}
486
- </span>
487
- );
488
- }
@@ -1,80 +0,0 @@
1
- import React, { Dispatch, SetStateAction } from "react";
2
- import type { Remote } from "../utils/Remote";
3
- import type { Session } from "../dto/Session";
4
- import { ValApi } from "@valbuild/core";
5
-
6
- export type Theme = "dark" | "light";
7
- export type EditMode = "off" | "hover" | "window" | "full";
8
- export type WindowSize = {
9
- width: number;
10
- height: number;
11
- innerHeight: number;
12
- };
13
-
14
- export const ValOverlayContext = React.createContext<{
15
- api: ValApi;
16
- session: Remote<Session>;
17
- editMode: EditMode;
18
- highlight: boolean;
19
- setHighlight: Dispatch<SetStateAction<boolean>>;
20
- setEditMode: Dispatch<SetStateAction<EditMode>>;
21
- theme: Theme;
22
- setTheme: (theme: Theme) => void;
23
- setWindowSize: (size: WindowSize) => void;
24
- windowSize?: WindowSize;
25
- }>({
26
- get api(): never {
27
- throw Error(
28
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
29
- );
30
- },
31
- get session(): never {
32
- throw Error(
33
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
34
- );
35
- },
36
- get theme(): never {
37
- throw Error(
38
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
39
- );
40
- },
41
- get setTheme(): never {
42
- throw Error(
43
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
44
- );
45
- },
46
- get editMode(): never {
47
- throw Error(
48
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
49
- );
50
- },
51
- get setEditMode(): never {
52
- throw Error(
53
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
54
- );
55
- },
56
- get highlight(): never {
57
- throw Error(
58
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
59
- );
60
- },
61
- get setHighlight(): never {
62
- throw Error(
63
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
64
- );
65
- },
66
- get setWindowSize(): never {
67
- throw Error(
68
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
69
- );
70
- },
71
- get windowSize(): never {
72
- throw Error(
73
- "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
74
- );
75
- },
76
- });
77
-
78
- export function useValOverlayContext() {
79
- return React.useContext(ValOverlayContext);
80
- }