@valbuild/ui 0.13.4 → 0.17.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 (46) hide show
  1. package/dist/valbuild-ui.cjs.d.ts +13 -18
  2. package/dist/valbuild-ui.cjs.js +7624 -1718
  3. package/dist/valbuild-ui.esm.js +7625 -1719
  4. package/package.json +5 -2
  5. package/src/assets/icons/ImageIcon.tsx +15 -7
  6. package/src/assets/icons/Section.tsx +41 -0
  7. package/src/assets/icons/TextIcon.tsx +20 -0
  8. package/src/components/Button.tsx +18 -7
  9. package/src/components/DraggableList.stories.tsx +20 -0
  10. package/src/components/DraggableList.tsx +95 -0
  11. package/src/components/Dropdown.tsx +2 -0
  12. package/src/components/ExpandLogo.tsx +72 -0
  13. package/src/components/RichTextEditor/Plugins/Toolbar.tsx +1 -16
  14. package/src/components/RichTextEditor/RichTextEditor.tsx +2 -2
  15. package/src/components/User.tsx +17 -0
  16. package/src/components/ValMenu.tsx +40 -0
  17. package/src/components/ValOverlay.tsx +513 -29
  18. package/src/components/ValOverlayContext.tsx +63 -0
  19. package/src/components/ValWindow.stories.tsx +3 -3
  20. package/src/components/ValWindow.tsx +26 -18
  21. package/src/components/dashboard/DashboardButton.tsx +25 -0
  22. package/src/components/dashboard/DashboardDropdown.tsx +59 -0
  23. package/src/components/dashboard/Dropdown.stories.tsx +11 -0
  24. package/src/components/dashboard/Dropdown.tsx +70 -0
  25. package/src/components/dashboard/FormGroup.stories.tsx +37 -0
  26. package/src/components/dashboard/FormGroup.tsx +36 -0
  27. package/src/components/dashboard/Grid.stories.tsx +52 -0
  28. package/src/components/dashboard/Grid.tsx +126 -0
  29. package/src/components/dashboard/Grid2.stories.tsx +56 -0
  30. package/src/components/dashboard/Grid2.tsx +72 -0
  31. package/src/components/dashboard/Tree.stories.tsx +91 -0
  32. package/src/components/dashboard/Tree.tsx +72 -0
  33. package/src/components/dashboard/ValDashboard.tsx +148 -0
  34. package/src/components/dashboard/ValDashboardEditor.tsx +269 -0
  35. package/src/components/dashboard/ValDashboardGrid.tsx +142 -0
  36. package/src/components/dashboard/ValTreeNavigator.tsx +253 -0
  37. package/src/components/forms/Form.tsx +2 -2
  38. package/src/components/forms/{TextForm.tsx → TextArea.tsx} +5 -3
  39. package/src/dto/SerializedSchema.ts +69 -0
  40. package/src/dto/Session.ts +12 -0
  41. package/src/dto/SessionMode.ts +5 -0
  42. package/src/dto/Tree.ts +18 -0
  43. package/src/exports.ts +1 -0
  44. package/src/utils/Remote.ts +15 -0
  45. package/src/utils/resolvePath.ts +33 -0
  46. package/tailwind.config.js +20 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/ui",
3
- "version": "0.13.4",
3
+ "version": "0.17.0",
4
4
  "sideEffects": false,
5
5
  "scripts": {
6
6
  "typecheck": "tsc --noEmit",
@@ -17,11 +17,14 @@
17
17
  "@types/express": "^4.17.17",
18
18
  "@types/react": "^18.0.26",
19
19
  "classnames": "^2.3.2",
20
+ "esbuild": "^0.17.19",
20
21
  "lexical": "^0.10.0",
21
22
  "react-feather": "^2.0.10",
22
23
  "rollup-plugin-peer-deps-external": "^2.2.4",
23
24
  "rollup-plugin-postcss": "^4.0.2",
24
- "rollup-plugin-typescript2": "^0.34.1"
25
+ "rollup-plugin-typescript2": "^0.34.1",
26
+ "zod": "^3.22.2",
27
+ "@valbuild/core": "~0.17.0"
25
28
  },
26
29
  "devDependencies": {
27
30
  "@storybook/addon-essentials": "^7.0.12",
@@ -3,17 +3,25 @@ import { FC } from "react";
3
3
  const ImageIcon: FC<{ className?: string }> = ({ className }) => {
4
4
  return (
5
5
  <svg
6
+ width="9"
7
+ height="10"
8
+ viewBox="0 0 9 10"
9
+ fill="none"
6
10
  xmlns="http://www.w3.org/2000/svg"
7
- viewBox="0 0 32 32"
8
11
  className={className}
9
- width={25}
10
- height={25}
11
- strokeWidth="4"
12
12
  >
13
- <g>
14
- <path d="M25,2H7A5,5,0,0,0,2,7V25a5,5,0,0,0,5,5H25a5,5,0,0,0,5-5V7A5,5,0,0,0,25,2ZM7,4H25a3,3,0,0,1,3,3v5.59l-1.88-1.88a3,3,0,0,0-4.24,0l-7.95,8-3-2.42a3,3,0,0,0-3.8,0L4,18.86V7A3,3,0,0,1,7,4ZM25,28H7a3,3,0,0,1-3-3V21.47l4.38-3.66a1,1,0,0,1,1.27,0l3.73,3a1,1,0,0,0,1.33-.07l8.58-8.59a1,1,0,0,1,1.42,0L28,15.41V25A3,3,0,0,1,25,28Z" />
15
- <path d="M10,13a3,3,0,1,0-3-3A3,3,0,0,0,10,13Zm0-4a1,1,0,1,1-1,1A1,1,0,0,1,10,9Z" />
13
+ <g clipPath="url(#clip0_1225_1638)">
14
+ <rect y="0.5" width="9" height="9" />
15
+
16
+ <path d="M0 7L8.5 5" stroke="currentColor" />
17
+ <circle cx="3" cy="3.5" r="1" fill="currentColor" />
16
18
  </g>
19
+ <rect x="0.5" y="1" width="8" height="8" stroke="currentColor" />
20
+ <defs>
21
+ <clipPath id="clip0_1225_1638">
22
+ <rect y="0.5" width="9" height="9" fill="white" />
23
+ </clipPath>
24
+ </defs>
17
25
  </svg>
18
26
  );
19
27
  };
@@ -0,0 +1,41 @@
1
+ import { FC } from "react";
2
+
3
+ const Section: FC<{ className?: string }> = ({ className }) => {
4
+ return (
5
+ <svg
6
+ width="9"
7
+ height="10"
8
+ viewBox="0 0 9 10"
9
+ className={className}
10
+ fill="currentColor"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ >
13
+ <g clipPath="url(#clip0_1222_1618)">
14
+ <path
15
+ fillRule="evenodd"
16
+ clipRule="evenodd"
17
+ d="M9 1.5H0V0.5H9V1.5Z"
18
+ fill="currentColor"
19
+ />
20
+ <path
21
+ fillRule="evenodd"
22
+ clipRule="evenodd"
23
+ d="M9 9.5H0V8.5H9V9.5Z"
24
+ fill="currentColor"
25
+ />
26
+ </g>
27
+ <defs>
28
+ <clipPath id="clip0_1222_1618">
29
+ <rect
30
+ width="9"
31
+ height="9"
32
+ fill="white"
33
+ transform="translate(0 0.5)"
34
+ />
35
+ </clipPath>
36
+ </defs>
37
+ </svg>
38
+ );
39
+ };
40
+
41
+ export default Section;
@@ -0,0 +1,20 @@
1
+ import { FC } from "react";
2
+
3
+ const TextIcon: FC<{ className?: string }> = ({ className }) => {
4
+ return (
5
+ <svg
6
+ width="9"
7
+ height="10"
8
+ viewBox="0 0 9 10"
9
+ fill="currentColor"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ className={className}
12
+ >
13
+ <g clipPath="url(#clip0_1229_1625)">
14
+ <path d="M0.0145513 0.5H8.98545L9 3.18569H8.57074C8.43007 2.2276 8.02749 1.57948 7.36298 1.24133C6.98949 1.05491 6.43169 0.953035 5.68957 0.935694V7.94581C5.68957 8.43569 5.78416 8.76084 5.97332 8.92124C6.16734 9.08165 6.5675 9.16185 7.17381 9.16185V9.5H1.86257V9.16185C2.44462 9.16185 2.83023 9.08165 3.0194 8.92124C3.21342 8.7565 3.31043 8.43136 3.31043 7.94581V0.935694C2.58286 0.953035 2.02506 1.05491 1.63703 1.24133C0.92401 1.58815 0.521423 2.23627 0.429264 3.18569H0L0.0145513 0.5Z" />
15
+ </g>
16
+ </svg>
17
+ );
18
+ };
19
+
20
+ export default TextIcon;
@@ -9,6 +9,24 @@ export interface ButtonProps
9
9
  disabled?: boolean;
10
10
  tooltip?: string;
11
11
  }
12
+
13
+ export function PrimaryButton({
14
+ children,
15
+ onClick,
16
+ }: {
17
+ children: React.ReactNode;
18
+ onClick?: () => void;
19
+ }) {
20
+ return (
21
+ <button
22
+ onClick={onClick}
23
+ className="px-4 py-[2px] font-serif border rounded-sm border-border bg-fill text-primary hover:dark:bg-yellow hover:bg-warm-black hover:dark:text-dark-gray hover:text-white focus-visible:border-highlight focus:outline-none"
24
+ >
25
+ {children}
26
+ </button>
27
+ );
28
+ }
29
+
12
30
  const Button: FC<ButtonProps> = ({
13
31
  variant = "primary",
14
32
  onClick,
@@ -49,10 +67,3 @@ const Button: FC<ButtonProps> = ({
49
67
  };
50
68
 
51
69
  export default Button;
52
- export function PrimaryButton({ children }: { children: React.ReactNode }) {
53
- return (
54
- <button className="px-4 py-[2px] font-serif border rounded-sm border-border bg-fill text-primary hover:dark:bg-yellow hover:bg-warm-black hover:dark:text-dark-gray hover:text-white focus-visible:border-highlight focus:outline-none">
55
- {children}
56
- </button>
57
- );
58
- }
@@ -0,0 +1,20 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+
3
+ import { DraggableList } from "./DraggableList";
4
+
5
+ const meta: Meta<typeof DraggableList> = { component: DraggableList };
6
+
7
+ export default meta;
8
+ type Story = StoryObj<typeof DraggableList>;
9
+
10
+ export const Default: Story = {
11
+ args: {
12
+ children: [
13
+ <div className="p-4 bg-white w-fit">test 1</div>,
14
+ <div className="p-4 bg-white w-fit">test 2</div>,
15
+ <div className="p-4 bg-white w-fit">test 3</div>,
16
+ <div className="p-4 bg-white w-fit">test 4</div>,
17
+ <div className="p-4 bg-white w-fit">test 5</div>,
18
+ ],
19
+ },
20
+ };
@@ -0,0 +1,95 @@
1
+ import classNames from "classnames";
2
+ import { createRef, useEffect, useState } from "react";
3
+
4
+ export type DraggableResult = {
5
+ from: number;
6
+ to: number;
7
+ };
8
+
9
+ export type DraggableListProps = {
10
+ children: React.ReactNode | React.ReactNode[];
11
+ onDragEnd?: (result: DraggableResult) => void;
12
+ };
13
+
14
+ export const DraggableList = ({
15
+ children: rawChildren,
16
+ onDragEnd,
17
+ }: DraggableListProps): React.ReactElement => {
18
+ const [from, setFrom] = useState<number | undefined>();
19
+ const [dragOver, setDragOver] = useState<number | undefined>();
20
+ const [children, setChildren] = useState<React.ReactNode[]>([]);
21
+ const [dropHappened, setDropHappened] = useState<boolean>(false);
22
+ useEffect(() => {
23
+ setChildren(Array.isArray(rawChildren) ? rawChildren : [rawChildren]);
24
+ }, [rawChildren]);
25
+
26
+ return (
27
+ <div className="bg-transparent">
28
+ {[...children, <div className="h-[1px]"></div>].map((child, idx) => {
29
+ const ref = createRef<HTMLDivElement>();
30
+ return (
31
+ <div key={idx} className="relative">
32
+ {dragOver === idx && (
33
+ <div className="flex items-center">
34
+ <div className="border-[2px] border-yellow w-3 h-3 rounded-full" />
35
+ <div className="bg-yellow border-yellow w-full h-[1px]" />
36
+ <div className="border-[2px] border-yellow w-3 h-3 rounded-full" />
37
+ </div>
38
+ )}
39
+ <div
40
+ ref={ref}
41
+ draggable
42
+ className={classNames("cursor-grab transition-opacity")}
43
+ onDragStart={(ev) => {
44
+ ev.dataTransfer.setDragImage(new Image(), 0, 0);
45
+ setFrom(idx);
46
+ }}
47
+ onDragOver={(ev) => {
48
+ ev.preventDefault();
49
+ setDragOver(idx);
50
+ }}
51
+ onDragEnd={(ev) => {
52
+ ev.preventDefault();
53
+ if (
54
+ from !== undefined &&
55
+ !dropHappened &&
56
+ dragOver !== undefined
57
+ ) {
58
+ const copy = [...children];
59
+ const end = Math.min(dragOver, children.length - 1);
60
+ copy.splice(from, 1);
61
+ copy.splice(end, 0, children[from]);
62
+ setChildren(copy);
63
+ if (onDragEnd) {
64
+ onDragEnd({ from: from, to: end });
65
+ }
66
+ }
67
+ setDropHappened(false);
68
+ setFrom(undefined);
69
+ setDragOver(undefined);
70
+ }}
71
+ onDrop={(ev) => {
72
+ ev.preventDefault();
73
+ if (from !== undefined) {
74
+ const copy = [...children];
75
+ copy.splice(from, 1);
76
+ const end = Math.min(idx, children.length - 1);
77
+ copy.splice(end, 0, children[from]);
78
+ if (onDragEnd) {
79
+ onDragEnd({ from: from, to: end });
80
+ }
81
+ setChildren(copy);
82
+ setDragOver(undefined);
83
+ setFrom(undefined);
84
+ setDropHappened(true);
85
+ }
86
+ }}
87
+ >
88
+ {child}
89
+ </div>
90
+ </div>
91
+ );
92
+ })}
93
+ </div>
94
+ );
95
+ };
@@ -7,6 +7,7 @@ export interface DropdownProps {
7
7
  label: string;
8
8
  onChange: (selectedOption: string) => void;
9
9
  icon?: React.ReactElement<SVGProps<SVGSVGElement>>;
10
+ variant?: "primary" | "secondary";
10
11
  }
11
12
 
12
13
  const Dropdown: React.FC<DropdownProps> = ({
@@ -14,6 +15,7 @@ const Dropdown: React.FC<DropdownProps> = ({
14
15
  onChange,
15
16
  label,
16
17
  icon,
18
+ // variant = "primary",
17
19
  }) => {
18
20
  const [isOpen, setIsOpen] = useState<boolean>(false);
19
21
  const dropdownRef = useRef<HTMLDivElement>(null);
@@ -0,0 +1,72 @@
1
+ import { FC } from "react";
2
+
3
+ const ExpandLogo: FC<{ expanded: boolean; className?: string }> = ({
4
+ expanded,
5
+ className,
6
+ }) => {
7
+ return (
8
+ <div>
9
+ {expanded ? (
10
+ <svg
11
+ width="11"
12
+ height="11"
13
+ viewBox="0 0 11 11"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ className={className}
16
+ >
17
+ <path
18
+ fillRule="evenodd"
19
+ clipRule="evenodd"
20
+ d="M0.606061 9.39394V6.25H0V10H3.75V9.39394H0.606061Z"
21
+ />
22
+ <path
23
+ fillRule="evenodd"
24
+ clipRule="evenodd"
25
+ d="M9.4319 0.644146L9.4319 3.78809L10.038 3.78809L10.038 0.0380859L6.28796 0.0380863L6.28796 0.644146L9.4319 0.644146Z"
26
+ />
27
+ <path
28
+ fillRule="evenodd"
29
+ clipRule="evenodd"
30
+ d="M3.11371e-05 9.59583L3.34602 6.24995L3.78796 6.6919L0.441965 10.0378L3.11371e-05 9.59583Z"
31
+ />
32
+ <path
33
+ fillRule="evenodd"
34
+ clipRule="evenodd"
35
+ d="M10.0379 0.441766L6.69194 3.78764L6.25001 3.3457L9.596 -0.000183055L10.0379 0.441766Z"
36
+ />
37
+ </svg>
38
+ ) : (
39
+ <svg
40
+ width="11"
41
+ height="11"
42
+ viewBox="0 0 11 11"
43
+ fill="none"
44
+ xmlns="http://www.w3.org/2000/svg"
45
+ className={className}
46
+ >
47
+ <path
48
+ fillRule="evenodd"
49
+ clipRule="evenodd"
50
+ d="M3.14394 6.85606L3.14394 10L3.75 10L3.75 6.25L-3.27835e-07 6.25L-2.74852e-07 6.85606L3.14394 6.85606Z"
51
+ />
52
+ <path
53
+ fillRule="evenodd"
54
+ clipRule="evenodd"
55
+ d="M6.89402 3.18203V0.0380859L6.28796 0.0380859L6.28796 3.78809L10.038 3.78809V3.18203L6.89402 3.18203Z"
56
+ />
57
+ <path
58
+ fillRule="evenodd"
59
+ clipRule="evenodd"
60
+ d="M3.11371e-05 9.59583L3.34602 6.24995L3.78796 6.6919L0.441965 10.0378L3.11371e-05 9.59583Z"
61
+ />
62
+ <path
63
+ fillRule="evenodd"
64
+ clipRule="evenodd"
65
+ d="M10.0379 0.441766L6.69194 3.78764L6.25001 3.3457L9.596 -0.000183055L10.0379 0.441766Z"
66
+ />
67
+ </svg>
68
+ )}
69
+ </div>
70
+ );
71
+ };
72
+ export default ExpandLogo;
@@ -284,22 +284,7 @@ const Toolbar: FC<ToolbarSettingsProps> = ({
284
284
  };
285
285
 
286
286
  return (
287
- <div className="flex flex-row items-center gap-6 p-2 overflow-scroll">
288
- {/* <div className="flex flex-row gap-2">
289
- <button className="hidden w-0 h-0 " disabled></button>
290
- <Button
291
- icon={<Undo />}
292
- onClick={() => {
293
- editor.dispatchCommand(UNDO_COMMAND, undefined);
294
- }}
295
- ></Button>
296
- <Button
297
- icon={<Undo className="transform -scale-x-100" />}
298
- onClick={() => {
299
- editor.dispatchCommand(REDO_COMMAND, undefined);
300
- }}
301
- />
302
- </div> */}
287
+ <div className="flex flex-row items-center gap-6 p-2 overflow-clip">
303
288
  <div className="flex flex-row gap-2">
304
289
  <Dropdown
305
290
  options={Object.values(blockTypes)}
@@ -152,13 +152,13 @@ export const RichTextEditor: FC<RichTextEditorProps> = ({
152
152
  onError,
153
153
  };
154
154
  return (
155
- <div className=" relative bg-base min-h-[200px] mt-2 border border-highlight rounded">
155
+ <div className=" relative bg-base min-h-[200px] mt-2 border border-highlight rounded overflow-none resize">
156
156
  <LexicalComposer initialConfig={initialConfig}>
157
157
  <Toolbar onEditor={onEditor} />
158
158
  <ImagesPlugin />
159
159
  <RichTextPlugin
160
160
  contentEditable={
161
- <LexicalContentEditable className="relative bg-fill flex flex-col h-full w-full min-h-[200px] text-primary outline-none" />
161
+ <LexicalContentEditable className="relative bg-fill flex flex-col h-full w-full min-h-[200px] min-w-[566px] text-primary outline-none overflow-auto resize" />
162
162
  }
163
163
  placeholder={
164
164
  <div className="absolute top-[calc(58px+1rem)] left-4 text-base/25 text-primary">
@@ -0,0 +1,17 @@
1
+ import { FC } from "react";
2
+
3
+ const User: FC<{ name: string }> = ({ name }) => {
4
+ return (
5
+ <div className="flex flex-row items-center gap-2">
6
+ <div className="w-[32px] h-[32px] rounded-full bg-light-gray flex justify-center items-center">
7
+ {name
8
+ .split(" ")
9
+ .map((name) => name.charAt(0))
10
+ .join("")}
11
+ </div>
12
+ <div className="text-white">{name}</div>
13
+ </div>
14
+ );
15
+ };
16
+
17
+ export default User;
@@ -0,0 +1,40 @@
1
+ import { Edit2, Edit3, Moon, Power, Sun } from "react-feather";
2
+ import { useValOverlayContext } from "./ValOverlayContext";
3
+ import { ValApi } from "@valbuild/core";
4
+
5
+ export function ValMenu({ api }: { api: ValApi }) {
6
+ const { theme, setTheme, editMode, setEditMode } = useValOverlayContext();
7
+ return (
8
+ <div className="flex flex-row items-center justify-center w-full h-full space-x-4 text-primary">
9
+ <button
10
+ className="p-1 border rounded-full shadow bg-base border-highlight"
11
+ onClick={() => {
12
+ setEditMode((prev) => (prev === "off" ? "hover" : "off"));
13
+ }}
14
+ >
15
+ <div className="h-[24px] w-[24px] flex justify-center items-center">
16
+ {editMode === "off" ? <Edit2 size={18} /> : <Edit3 size={18} />}
17
+ </div>
18
+ </button>
19
+ <button
20
+ className="p-1 border rounded-full shadow bg-base border-highlight"
21
+ onClick={() => {
22
+ setTheme(theme === "dark" ? "light" : "dark");
23
+ }}
24
+ >
25
+ <div className="h-[24px] w-[24px] flex justify-center items-center">
26
+ {theme === "dark" && <Sun size={15} />}
27
+ {theme === "light" && <Moon size={15} />}
28
+ </div>
29
+ </button>
30
+ <a
31
+ className="p-1 border rounded-full shadow bg-base border-highlight"
32
+ href={api.getDisableUrl()}
33
+ >
34
+ <div className="h-[24px] w-[24px] flex justify-center items-center">
35
+ <Power size={18} />
36
+ </div>
37
+ </a>
38
+ </div>
39
+ );
40
+ }