Skip to content

Commit

Permalink
Feat/tooltip (#95)
Browse files Browse the repository at this point in the history
* feat: add tooltip

* feat: add tooltip

* test: spannerDelegate

* optimize: font changed

* feat: react theme provider
  • Loading branch information
vincentdchan authored Dec 3, 2023
1 parent 5dba662 commit 26e21b6
Show file tree
Hide file tree
Showing 18 changed files with 457 additions and 62 deletions.
1 change: 1 addition & 0 deletions packages/blocky-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export {
type ParagraphStyle,
SearchContext,
darkTheme,
themeDataToCssVariables,
} from "./model";
export { TextBlock } from "./block/textBlock";
export * from "./data";
14 changes: 14 additions & 0 deletions packages/blocky-core/src/model/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,17 @@ export const darkTheme: ThemeData = {
color: "#c3c3bf",
},
};

export function themeDataToCssVariables(
themeData?: ThemeData
): Record<string, string> {
const result = Object.create(null);

const primaryColor = themeData?.primary?.color ?? null;
result["--blocky-primary-color"] = primaryColor;

const font = themeData?.font ?? blockyDefaultFonts;
result["--blocky-font"] = font;

return result;
}
39 changes: 16 additions & 23 deletions packages/blocky-core/src/view/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import {
BehaviorSubject,
timer,
filter,
Observable,
} from "rxjs";
import { debounce, isUndefined, isString, isNumber } from "lodash-es";
import { debounce, isUndefined, isNumber } from "lodash-es";
import { DocRenderer, RenderFlag, RenderOption } from "@pkg/view/renderer";
import {
EditorState,
NodeTraverser,
SearchContext,
blockyDefaultFonts,
themeDataToCssVariables,
} from "@pkg/model";
import {
type CursorStateUpdateEvent,
Expand Down Expand Up @@ -306,6 +308,10 @@ export class Editor {
});
}

get themeData$(): Observable<ThemeData | undefined> {
return this.#themeData.asObservable();
}

get themeData(): ThemeData | undefined {
return this.#themeData.value;
}
Expand Down Expand Up @@ -519,6 +525,14 @@ export class Editor {
);
}

private handleThemeChanged(themeData: ThemeData | undefined) {
const cssVariables = themeDataToCssVariables(themeData);

for (const [key, value] of Object.entries(cssVariables)) {
this.#container.style.setProperty(key, value);
}
}

render(option: RenderOption, done?: AfterFn) {
try {
const newDom = this.#renderer.render(option, this.#renderedDom);
Expand All @@ -531,28 +545,7 @@ export class Editor {

this.#themeData
.pipe(takeUntil(this.dispose$))
.subscribe((themeData) => {
if (isString(themeData?.primary?.color)) {
this.#container.style.setProperty(
"--blocky-primary-color",
themeData!.primary!.color
);
} else {
this.#container.style.setProperty("--blocky-primary-color", null);
}

if (isString(themeData?.font)) {
this.#container.style.setProperty(
"--blocky-font",
themeData!.font!
);
} else {
this.#container.style.setProperty(
"--blocky-font",
blockyDefaultFonts
);
}
});
.subscribe(this.handleThemeChanged.bind(this));

fromEvent<MouseEvent>(this.#container, "mousemove")
.pipe(
Expand Down
45 changes: 45 additions & 0 deletions packages/blocky-core/src/view/spannerDelegate.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it, vi } from "vitest";
import { SpannerDelegate, SpannerInstance } from "./spannerDelegate";
import { EditorController } from "./controller";
import { BlockDataElement } from "..";

describe("SpannerDelegate", () => {
it("focusedNode", () => {
const editorController = new EditorController("user");

const spannerInstance: SpannerInstance = {
onFocusedNodeChanged: () => {},
dispose() {},
};

const mount = document.createElement("div");

const delegate = new SpannerDelegate(editorController, () => {
return spannerInstance;
});
delegate.mount(mount);

const focusedNode1 = new BlockDataElement("Text", "id-1");
const focusedNode2 = new BlockDataElement("Text", "id-2");

const focusedNodeChangedSpy = vi.spyOn(
spannerInstance,
"onFocusedNodeChanged"
);
const disposeSpy = vi.spyOn(spannerInstance, "dispose");

delegate.focusedNode = focusedNode1;

expect(focusedNodeChangedSpy).toHaveBeenCalledTimes(1);

delegate.focusedNode = focusedNode2;

expect(focusedNodeChangedSpy).toHaveBeenCalledTimes(2);

delegate.focusedNode = focusedNode2;
expect(focusedNodeChangedSpy).toHaveBeenCalledTimes(2); // shoud not increase

delegate.dispose();
expect(disposeSpy).toHaveBeenCalledOnce();
});
});
11 changes: 11 additions & 0 deletions packages/blocky-core/src/view/spannerDelegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export class SpannerDelegate extends UIDelegate {
}

set focusedNode(v: BlockDataElement | undefined) {
if (this.#focusedNode === v) {
return;
}
this.#focusedNode = v;
this.#instance?.onFocusedNodeChanged?.(v);
}
Expand Down Expand Up @@ -62,8 +65,16 @@ export class SpannerDelegate extends UIDelegate {
}
}

#cachedX = 0;
#cachedY = 0;

setPosition(x: number, y: number) {
if (this.#cachedX === x && this.#cachedY === y) {
return;
}
this.container.style.top = y + "px";
this.container.style.left = x + "px";
this.#cachedX = x;
this.#cachedY = y;
}
}
4 changes: 3 additions & 1 deletion packages/blocky-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"homepage": "https://github.com/vincentdchan/blocky-editor",
"keywords": [
"editor",
"preact"
"react"
],
"author": "Vincent Chan <okcdz@diverse.space>",
"license": "MIT",
Expand All @@ -27,11 +27,13 @@
"blocky-core": "workspace:^3.6.0"
},
"dependencies": {
"@emotion/css": "^11.11.2",
"@emotion/react": "^11.11.1",
"blocky-common": "workspace:3.6.0",
"lodash-es": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"rxjs": "^7.8.1"
}
}
8 changes: 6 additions & 2 deletions packages/blocky-react/src/components/dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { RefObject, useEffect, useRef, useState } from "react";
import { RefObject, useContext, useEffect, useRef, useState } from "react";
import ReactDOM, { createPortal } from "react-dom";
import Mask from "@pkg/components/mask";
import { ReactTheme } from "@pkg/reactTheme";
import { themeDataToCssVariables } from "blocky-core";

export interface DropdownProps {
show?: boolean;
Expand All @@ -16,7 +18,7 @@ interface Coord {
}

const zero: Coord = { x: 0, y: 0 };
const margin = 16;
const margin = 24;

function fixMenuCoord(
coord: Coord,
Expand All @@ -40,6 +42,7 @@ function Dropdown(props: DropdownProps) {
const [menuCoord, setMenuCoord] = useState<Coord>(zero);
const [shown, setShown] = useState(false);
const contentRef = useRef<HTMLDivElement>(null);
const themeData = useContext(ReactTheme);

useEffect(() => {
if (show) {
Expand Down Expand Up @@ -85,6 +88,7 @@ function Dropdown(props: DropdownProps) {
position: "fixed",
left: `${menuCoord.x}px`,
top: `${menuCoord.y}px`,
...themeDataToCssVariables(themeData),
}}
>
{overlay()}
Expand Down
24 changes: 20 additions & 4 deletions packages/blocky-react/src/components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,46 @@ export function Menu(props: MenuProps) {
}

export interface MenuItemProps {
icon?: React.ReactNode;
style?: React.CSSProperties;
onClick?: () => void;
children?: any;
}

const menuItemStyle = css({
width: "240px",
display: "flex",
flexDirection: "row",
alignItems: "center",
width: 240,
padding: "8px 12px",
fontSize: "14px",
color: "rgb(72, 72, 72)",
fontSize: 12,
color: "var(--blocky-primary-color)",
"&:hover": {
backgroundColor: "rgba(0, 0, 0, 0.1)",
},
});

const menuIconStyle = css({
marginRight: 8,
display: "flex",
justifyContent: "center",
alignItems: "center",
svg: {
width: 16,
height: 16,
},
});

export function MenuItem(props: MenuItemProps) {
const { style, onClick, children } = props;
const { icon, style, onClick, children } = props;
return (
<div
css={menuItemStyle}
className="blocky-cm-noselect"
onClick={onClick}
style={style}
>
<div css={menuIconStyle}>{icon}</div>
{children}
</div>
);
Expand Down
Loading

1 comment on commit 26e21b6

@vercel
Copy link

@vercel vercel bot commented on 26e21b6 Dec 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.