@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.
- package/dist/valbuild-ui.cjs.d.ts +3 -3
- package/dist/valbuild-ui.cjs.js +141 -106
- package/dist/valbuild-ui.esm.js +141 -106
- package/package.json +2 -2
- package/src/components/Button.tsx +0 -9
- package/src/components/Dropdown.tsx +32 -25
- package/src/components/RichTextEditor/RichTextEditor.tsx +18 -4
- package/src/components/RichTextEditor/conversion.ts +1 -1
- package/src/components/ValOverlay.tsx +16 -4
- package/src/components/ValOverlayContext.tsx +17 -0
- package/src/components/ValWindow.stories.tsx +5 -2
- package/src/components/ValWindow.tsx +27 -12
- package/src/components/forms/Form.tsx +2 -2
- package/src/stories/RichTextEditor.stories.tsx +2 -2
|
@@ -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,
|
|
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:
|
|
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={
|
|
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>
|
|
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 {
|
|
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={
|
|
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?:
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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={
|
|
47
|
-
height={
|
|
48
|
-
onResize={(_, { 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
|
|
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:
|
|
76
|
-
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,
|
|
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:
|
|
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,
|
|
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
|
|
67
|
+
} as RichTextSource<AnyRichTextOptions>,
|
|
68
68
|
};
|