@valbuild/ui 0.19.0 → 0.20.2

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.
@@ -12,12 +12,13 @@ import { ImageNode } from "./Nodes/ImageNode";
12
12
  import { AutoFocus } from "./Plugins/AutoFocus";
13
13
  import ImagesPlugin from "./Plugins/ImagePlugin";
14
14
  import Toolbar from "./Plugins/Toolbar";
15
- import { AnyRichTextOptions, RichText } from "@valbuild/core";
15
+ import { AnyRichTextOptions, RichTextSource } from "@valbuild/core";
16
16
  import { HeadingNode } from "@lexical/rich-text";
17
17
  import { toLexical } from "./conversion";
18
+ import { useValOverlayContext } from "../ValOverlayContext";
18
19
 
19
20
  export interface RichTextEditorProps {
20
- richtext: RichText<AnyRichTextOptions>;
21
+ richtext: RichTextSource<AnyRichTextOptions>;
21
22
  onEditor?: (editor: LexicalEditor) => void; // Not the ideal way of passing the editor to the upper context, we need it to be able to save
22
23
  }
23
24
 
@@ -25,10 +26,13 @@ function onError(error: any) {
25
26
  console.error(error);
26
27
  }
27
28
 
29
+ const TOOLBAR_HEIGHT = 28;
30
+
28
31
  export const RichTextEditor: FC<RichTextEditorProps> = ({
29
32
  richtext,
30
33
  onEditor,
31
34
  }) => {
35
+ const { windowSize } = useValOverlayContext();
32
36
  const prePopulatedState = (editor: LexicalEditor) => {
33
37
  editor.setEditorState(
34
38
  editor.parseEditorState({ root: toLexical(richtext) })
@@ -39,7 +43,6 @@ export const RichTextEditor: FC<RichTextEditorProps> = ({
39
43
  editorState: prePopulatedState,
40
44
  nodes: [HeadingNode, ImageNode, ListNode, ListItemNode],
41
45
  theme: {
42
- root: "p-4 bg-fill text-white font-roboto border-b border-highlight",
43
46
  text: {
44
47
  bold: "font-semibold",
45
48
  underline: "underline",
@@ -68,7 +71,18 @@ export const RichTextEditor: FC<RichTextEditorProps> = ({
68
71
  <AutoFocus />
69
72
  <Toolbar onEditor={onEditor} />
70
73
  <RichTextPlugin
71
- contentEditable={<LexicalContentEditable className="outline-none" />}
74
+ contentEditable={
75
+ <div
76
+ className="text-white border-b border-highlight font-roboto"
77
+ style={{
78
+ minHeight: windowSize?.innerHeight
79
+ ? windowSize?.innerHeight - TOOLBAR_HEIGHT
80
+ : undefined,
81
+ }}
82
+ >
83
+ <LexicalContentEditable className="p-4 outline-none bg-fill" />
84
+ </div>
85
+ }
72
86
  placeholder={<div className="">Enter some text...</div>}
73
87
  ErrorBoundary={LexicalErrorBoundary}
74
88
  />
@@ -154,7 +154,7 @@ function getFileExtFromUrl(url: string): string | undefined {
154
154
  }
155
155
 
156
156
  export function toLexical(
157
- richtext: RichTextSource<AnyRichTextOptions> | RichText<AnyRichTextOptions>
157
+ richtext: RichTextSource<AnyRichTextOptions>
158
158
  ): LexicalRootNode {
159
159
  return {
160
160
  ...COMMON_LEXICAL_PROPS,
@@ -8,7 +8,12 @@ import {
8
8
  } from "react";
9
9
  import { Session } from "../dto/Session";
10
10
  import { ValMenu } from "./ValMenu";
11
- import { EditMode, Theme, ValOverlayContext } from "./ValOverlayContext";
11
+ import {
12
+ EditMode,
13
+ Theme,
14
+ ValOverlayContext,
15
+ WindowSize,
16
+ } from "./ValOverlayContext";
12
17
  import { Remote } from "../utils/Remote";
13
18
  import { ValWindow } from "./ValWindow";
14
19
  import { result } from "@valbuild/core/fp";
@@ -17,6 +22,7 @@ import {
17
22
  FileSource,
18
23
  Internal,
19
24
  RichText,
25
+ RichTextSource,
20
26
  SerializedSchema,
21
27
  SourcePath,
22
28
  VAL_EXTENSION,
@@ -83,6 +89,8 @@ export function ValOverlay({ defaultTheme, api }: ValOverlayProps) {
83
89
  });
84
90
  }, [windowTarget?.path]);
85
91
 
92
+ const [windowSize, setWindowSize] = useState<WindowSize>();
93
+
86
94
  return (
87
95
  <ValOverlayContext.Provider
88
96
  value={{
@@ -94,6 +102,8 @@ export function ValOverlay({ defaultTheme, api }: ValOverlayProps) {
94
102
  highlight,
95
103
  setHighlight,
96
104
  setTheme,
105
+ windowSize,
106
+ setWindowSize,
97
107
  }}
98
108
  >
99
109
  <div data-mode={theme}>
@@ -137,7 +147,9 @@ export function ValOverlay({ defaultTheme, api }: ValOverlayProps) {
137
147
  selectedSource[VAL_EXTENSION] === "richtext" && (
138
148
  <RichTextField
139
149
  registerPatchCallback={initPatchCallback(windowTarget.path)}
140
- defaultValue={selectedSource as RichText<AnyRichTextOptions>}
150
+ defaultValue={
151
+ selectedSource as RichTextSource<AnyRichTextOptions>
152
+ }
141
153
  />
142
154
  )}
143
155
  {selectedSource &&
@@ -256,7 +268,7 @@ function RichTextField({
256
268
  registerPatchCallback,
257
269
  }: {
258
270
  registerPatchCallback: (callback: PatchCallback) => void;
259
- defaultValue?: RichText<AnyRichTextOptions>;
271
+ defaultValue?: RichTextSource<AnyRichTextOptions>;
260
272
  }) {
261
273
  const [editor, setEditor] = useState<LexicalEditor | null>(null);
262
274
  useEffect(() => {
@@ -301,7 +313,7 @@ function RichTextField({
301
313
  ({
302
314
  children: [],
303
315
  [VAL_EXTENSION]: "root",
304
- } as unknown as RichText<AnyRichTextOptions>)
316
+ } as unknown as RichTextSource<AnyRichTextOptions>)
305
317
  }
306
318
  />
307
319
  );
@@ -5,6 +5,11 @@ import { ValApi } from "@valbuild/core";
5
5
 
6
6
  export type Theme = "dark" | "light";
7
7
  export type EditMode = "off" | "hover" | "window" | "full";
8
+ export type WindowSize = {
9
+ width: number;
10
+ height: number;
11
+ innerHeight: number;
12
+ };
8
13
 
9
14
  export const ValOverlayContext = React.createContext<{
10
15
  api: ValApi;
@@ -15,6 +20,8 @@ export const ValOverlayContext = React.createContext<{
15
20
  setEditMode: Dispatch<SetStateAction<EditMode>>;
16
21
  theme: Theme;
17
22
  setTheme: (theme: Theme) => void;
23
+ setWindowSize: (size: WindowSize) => void;
24
+ windowSize?: WindowSize;
18
25
  }>({
19
26
  get api(): never {
20
27
  throw Error(
@@ -56,6 +63,16 @@ export const ValOverlayContext = React.createContext<{
56
63
  "ValOverlayContext not found. Ensure components are wrapped by ValOverlayProvider!"
57
64
  );
58
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
+ },
59
76
  });
60
77
 
61
78
  export function useValOverlayContext() {
@@ -1,5 +1,8 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { AnyRichTextOptions, RichText as RichTextType } from "@valbuild/core";
2
+ import {
3
+ AnyRichTextOptions,
4
+ RichTextSource as RichTextSourceType,
5
+ } from "@valbuild/core";
3
6
  import { RichTextEditor } from "../exports";
4
7
  import { FormContainer } from "./forms/FormContainer";
5
8
  import { ImageForm } from "./forms/ImageForm";
@@ -123,7 +126,7 @@ export const RichText: Story = {
123
126
  ],
124
127
  },
125
128
  ],
126
- } as RichTextType<AnyRichTextOptions>
129
+ } as RichTextSourceType<AnyRichTextOptions>
127
130
  }
128
131
  />
129
132
  </FormContainer>
@@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
2
2
  import { AlignJustify, X } from "react-feather";
3
3
  import classNames from "classnames";
4
4
  import { Resizable } from "react-resizable";
5
+ import { useValOverlayContext } from "./ValOverlayContext";
5
6
 
6
7
  export type ValWindowProps = {
7
8
  children:
@@ -35,17 +36,34 @@ export function ValWindow({
35
36
  document.removeEventListener("keyup", closeOnEscape);
36
37
  };
37
38
  }, []);
38
-
39
39
  //
40
- const [size, setSize] = useState<{ height: number; width: number }>();
40
+ const { windowSize, setWindowSize } = useValOverlayContext();
41
+ useEffect(() => {
42
+ if (!windowSize) {
43
+ setWindowSize({
44
+ height: MIN_HEIGHT,
45
+ width: MIN_WIDTH,
46
+ innerHeight:
47
+ MIN_HEIGHT -
48
+ (64 + (bottomRef.current?.getBoundingClientRect()?.height || 0)),
49
+ });
50
+ }
51
+ }, [windowSize]);
41
52
  //
42
53
  const bottomRef = useRef<HTMLDivElement>(null);
43
54
 
44
55
  return (
45
56
  <Resizable
46
- width={size?.width || MIN_WIDTH}
47
- height={size?.height || MIN_HEIGHT}
48
- onResize={(_, { size }) => setSize(size)}
57
+ width={windowSize?.width || MIN_WIDTH}
58
+ height={windowSize?.height || MIN_HEIGHT}
59
+ onResize={(_, { size }) =>
60
+ setWindowSize({
61
+ ...size,
62
+ innerHeight:
63
+ (windowSize?.height || MIN_HEIGHT) -
64
+ (64 + (bottomRef.current?.getBoundingClientRect()?.height || 0)),
65
+ })
66
+ }
49
67
  handle={
50
68
  <div className="fixed bottom-0 right-0 cursor-se-resize">
51
69
  <svg
@@ -63,7 +81,7 @@ export function ValWindow({
63
81
  }
64
82
  draggableOpts={{}}
65
83
  className={classNames(
66
- "absolute inset-0 w-full tablet:w-auto tablet:h-auto tablet:min-h-fit tablet:rounded bg-base text-primary drop-shadow-2xl min-w-[320px] transition-opacity duration-300 delay-75 max-w-full",
84
+ "absolute inset-0 tablet:w-auto tablet:h-auto tablet:min-h-fit tablet:rounded bg-base text-primary drop-shadow-2xl min-w-[320px] transition-opacity duration-300 delay-75",
67
85
  {
68
86
  "opacity-0": !isInitialized,
69
87
  "opacity-100": isInitialized,
@@ -72,8 +90,8 @@ export function ValWindow({
72
90
  >
73
91
  <div
74
92
  style={{
75
- width: size?.width || MIN_WIDTH,
76
- height: size?.height || MIN_HEIGHT,
93
+ width: windowSize?.width || MIN_WIDTH,
94
+ height: windowSize?.height || MIN_HEIGHT,
77
95
  left: draggedPosition.left,
78
96
  top: draggedPosition.top,
79
97
  }}
@@ -108,10 +126,7 @@ export function ValWindow({
108
126
  <div
109
127
  className="relative overflow-scroll"
110
128
  style={{
111
- height:
112
- (size?.height || MIN_HEIGHT) -
113
- (64 +
114
- (bottomRef.current?.getBoundingClientRect()?.height || 0)),
129
+ height: windowSize?.innerHeight,
115
130
  }}
116
131
  >
117
132
  {Array.isArray(children) ? children.slice(1, -1) : children}
@@ -1,4 +1,4 @@
1
- import { AnyRichTextOptions, RichText } from "@valbuild/core";
1
+ import { AnyRichTextOptions, RichTextSource } from "@valbuild/core";
2
2
  import { LexicalEditor } from "lexical";
3
3
  import { useEffect, useState } from "react";
4
4
  import { RichTextEditor } from "../RichTextEditor/RichTextEditor";
@@ -18,7 +18,7 @@ export type Inputs = {
18
18
  | {
19
19
  status: "completed";
20
20
  type: "richtext";
21
- data: RichText<AnyRichTextOptions>;
21
+ data: RichTextSource<AnyRichTextOptions>;
22
22
  };
23
23
  };
24
24
 
@@ -3,7 +3,7 @@ import {
3
3
  RichTextEditorProps,
4
4
  } from "../components/RichTextEditor/RichTextEditor";
5
5
  import { Meta, Story } from "@storybook/react";
6
- import { AnyRichTextOptions, RichText } from "@valbuild/core";
6
+ import { AnyRichTextOptions, RichTextSource } from "@valbuild/core";
7
7
 
8
8
  export default {
9
9
  title: "RichTextEditor",
@@ -64,5 +64,5 @@ DropdownStory.args = {
64
64
  ],
65
65
  },
66
66
  ],
67
- } as RichText<AnyRichTextOptions>,
67
+ } as RichTextSource<AnyRichTextOptions>,
68
68
  };