Skip to content

Commit f062346

Browse files
fix lexical plugins + add notebook2 store + rm vscode (#410)
* bump: lexical version * bump: lexical version * temp: disable plugins * rm: vscode * fix: restore toolbar * Automatic application of license header * lint * export * notebook2: store * fix: build --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 8456d41 commit f062346

File tree

104 files changed

+3201
-19640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+3201
-19640
lines changed

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
* MIT License
55
*/
66

7+
import { fileURLToPath } from 'node:url'
8+
import { dirname } from 'node:path'
9+
10+
const __filename = fileURLToPath(import.meta.url)
11+
const __dirname = dirname(__filename)
12+
713
module.exports = {
814
root: true,
915
parser: '@typescript-eslint/parser',

eslint.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@ const reactPlugin = require('eslint-plugin-react');
1010
const reactHooksPlugin = require('eslint-plugin-react-hooks');
1111
const prettierPlugin = require('eslint-plugin-prettier');
1212
const prettierConfig = require('eslint-config-prettier');
13+
const path = require('path');
1314

1415
module.exports = tseslint.config(
16+
{
17+
languageOptions: {
18+
parserOptions: {
19+
tsconfigRootDir: path.resolve(__dirname),
20+
projectService: true,
21+
},
22+
},
23+
},
1524
js.configs.recommended,
1625
...tseslint.configs.recommended,
1726
{

packages/lexical/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@datalayer/jupyter-lexical",
3-
"version": "1.0.5",
3+
"version": "1.0.6",
44
"description": "Jupyter UI for Lexical",
55
"license": "MIT",
66
"main": "lib/index.js",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2021-2023 Datalayer, Inc.
3+
*
4+
* MIT License
5+
*/
6+
7+
/**
8+
* Copyright (c) Meta Platforms, Inc. and affiliates.
9+
*
10+
* This source code is licensed under the MIT license found in the
11+
* LICENSE file in the root directory of this source tree.
12+
*
13+
*/
14+
15+
const hostName = window.location.hostname;
16+
export const isDevPlayground: boolean =
17+
hostName !== 'playground.lexical.dev' &&
18+
hostName !== 'lexical-playground.vercel.app';
19+
20+
export const DEFAULT_SETTINGS = {
21+
disableBeforeInput: false,
22+
emptyEditor: isDevPlayground,
23+
hasLinkAttributes: false,
24+
isAutocomplete: false,
25+
isCharLimit: false,
26+
isCharLimitUtf8: false,
27+
isCodeHighlighted: true,
28+
isCodeShiki: false,
29+
isCollab: false,
30+
isMaxLength: false,
31+
isRichText: true,
32+
listStrictIndent: false,
33+
measureTypingPerf: false,
34+
selectionAlwaysOnDisplay: false,
35+
shouldAllowHighlightingWithBrackets: false,
36+
shouldPreserveNewLinesInMarkdown: false,
37+
shouldUseLexicalContextMenu: false,
38+
showNestedEditorTreeView: false,
39+
showTableOfContents: false,
40+
showTreeView: true,
41+
tableCellBackgroundColor: true,
42+
tableCellMerge: true,
43+
tableHorizontalScroll: true,
44+
} as const;
45+
46+
// These are mutated in setupEnv
47+
export const INITIAL_SETTINGS: Record<SettingName, boolean> = {
48+
...DEFAULT_SETTINGS,
49+
};
50+
51+
export type SettingName = keyof typeof DEFAULT_SETTINGS;
52+
53+
export type Settings = typeof INITIAL_SETTINGS;

packages/lexical/src/components/DropDown.tsx

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44
* MIT License
55
*/
66

7+
/**
8+
* Copyright (c) Meta Platforms, Inc. and affiliates.
9+
*
10+
* This source code is licensed under the MIT license found in the
11+
* LICENSE file in the root directory of this source tree.
12+
*
13+
*/
14+
15+
import type { JSX } from 'react';
16+
17+
import { isDOMNode } from 'lexical';
18+
import * as React from 'react';
719
import {
820
ReactNode,
921
useCallback,
@@ -12,15 +24,16 @@ import {
1224
useRef,
1325
useState,
1426
} from 'react';
15-
import * as React from 'react';
1627
import { createPortal } from 'react-dom';
1728

1829
type DropDownContextType = {
19-
registerItem: (ref: React.RefObject<HTMLButtonElement>) => void;
30+
registerItem: (ref: React.RefObject<null | HTMLButtonElement>) => void;
2031
};
2132

2233
const DropDownContext = React.createContext<DropDownContextType | null>(null);
2334

35+
const dropDownPadding = 4;
36+
2437
export function DropDownItem({
2538
children,
2639
className,
@@ -32,7 +45,7 @@ export function DropDownItem({
3245
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
3346
title?: string;
3447
}) {
35-
const ref = useRef<HTMLButtonElement>(null);
48+
const ref = useRef<null | HTMLButtonElement>(null);
3649

3750
const dropDownContext = React.useContext(DropDownContext);
3851

@@ -49,13 +62,18 @@ export function DropDownItem({
4962
}, [ref, registerItem]);
5063

5164
return (
52-
<button className={className} onClick={onClick} ref={ref} title={title}>
65+
<button
66+
className={className}
67+
onClick={onClick}
68+
ref={ref}
69+
title={title}
70+
type="button">
5371
{children}
5472
</button>
5573
);
5674
}
5775

58-
function DropDownItems({
76+
export function DropDownItems({
5977
children,
6078
dropDownRef,
6179
onClose,
@@ -64,51 +82,66 @@ function DropDownItems({
6482
dropDownRef: React.Ref<HTMLDivElement>;
6583
onClose: () => void;
6684
}) {
67-
const [items, setItems] = useState<React.RefObject<HTMLButtonElement>[]>();
85+
const [items, setItems] =
86+
useState<React.RefObject<null | HTMLButtonElement>[]>();
6887
const [highlightedItem, setHighlightedItem] =
69-
useState<React.RefObject<HTMLButtonElement>>();
88+
useState<React.RefObject<null | HTMLButtonElement>>();
89+
7090
const registerItem = useCallback(
71-
(itemRef: React.RefObject<HTMLButtonElement>) => {
72-
setItems(prev => (prev ? [...prev, itemRef] : [itemRef]));
91+
(itemRef: React.RefObject<null | HTMLButtonElement>) => {
92+
setItems((prev) => (prev ? [...prev, itemRef] : [itemRef]));
7393
},
7494
[setItems],
7595
);
96+
7697
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
77-
if (!items) return;
98+
if (!items) {
99+
return;
100+
}
101+
78102
const key = event.key;
103+
79104
if (['Escape', 'ArrowUp', 'ArrowDown', 'Tab'].includes(key)) {
80105
event.preventDefault();
81106
}
82107

83108
if (key === 'Escape' || key === 'Tab') {
84109
onClose();
85110
} else if (key === 'ArrowUp') {
86-
setHighlightedItem(prev => {
87-
if (!prev) return items[0];
111+
setHighlightedItem((prev) => {
112+
if (!prev) {
113+
return items[0];
114+
}
88115
const index = items.indexOf(prev) - 1;
89116
return items[index === -1 ? items.length - 1 : index];
90117
});
91118
} else if (key === 'ArrowDown') {
92-
setHighlightedItem(prev => {
93-
if (!prev) return items[0];
119+
setHighlightedItem((prev) => {
120+
if (!prev) {
121+
return items[0];
122+
}
94123
return items[items.indexOf(prev) + 1];
95124
});
96125
}
97126
};
127+
98128
const contextValue = useMemo(
99129
() => ({
100130
registerItem,
101131
}),
102132
[registerItem],
103133
);
134+
104135
useEffect(() => {
105136
if (items && !highlightedItem) {
106137
setHighlightedItem(items[0]);
107138
}
139+
108140
if (highlightedItem && highlightedItem.current) {
109141
highlightedItem.current.focus();
110142
}
111143
}, [items, highlightedItem]);
144+
112145
return (
113146
<DropDownContext.Provider value={contextValue}>
114147
<div className="dropdown" ref={dropDownRef} onKeyDown={handleKeyDown}>
@@ -118,21 +151,23 @@ function DropDownItems({
118151
);
119152
}
120153

121-
export const DropDown = ({
154+
export function DropDown({
155+
disabled = false,
122156
buttonLabel,
123157
buttonAriaLabel,
124158
buttonClassName,
125159
buttonIconClassName,
126160
children,
127161
stopCloseOnClickSelf,
128162
}: {
163+
disabled?: boolean;
129164
buttonAriaLabel?: string;
130165
buttonClassName: string;
131166
buttonIconClassName?: string;
132167
buttonLabel?: string;
133168
children: ReactNode;
134169
stopCloseOnClickSelf?: boolean;
135-
}): JSX.Element => {
170+
}): JSX.Element {
136171
const dropDownRef = useRef<HTMLDivElement>(null);
137172
const buttonRef = useRef<HTMLButtonElement>(null);
138173
const [showDropDown, setShowDropDown] = useState(false);
@@ -149,8 +184,8 @@ export const DropDown = ({
149184
const dropDown = dropDownRef.current;
150185

151186
if (showDropDown && button !== null && dropDown !== null) {
152-
const { top, left } = button.getBoundingClientRect();
153-
dropDown.style.top = `${top + 40}px`;
187+
const {top, left} = button.getBoundingClientRect();
188+
dropDown.style.top = `${top + button.offsetHeight + dropDownPadding}px`;
154189
dropDown.style.left = `${Math.min(
155190
left,
156191
window.innerWidth - dropDown.offsetWidth - 20,
@@ -164,14 +199,15 @@ export const DropDown = ({
164199
if (button !== null && showDropDown) {
165200
const handle = (event: MouseEvent) => {
166201
const target = event.target;
202+
if (!isDOMNode(target)) {
203+
return;
204+
}
167205
if (stopCloseOnClickSelf) {
168-
if (
169-
dropDownRef.current &&
170-
dropDownRef.current.contains(target as Node)
171-
)
206+
if (dropDownRef.current && dropDownRef.current.contains(target)) {
172207
return;
208+
}
173209
}
174-
if (!button.contains(target as Node)) {
210+
if (!button.contains(target)) {
175211
setShowDropDown(false);
176212
}
177213
};
@@ -183,14 +219,37 @@ export const DropDown = ({
183219
}
184220
}, [dropDownRef, buttonRef, showDropDown, stopCloseOnClickSelf]);
185221

222+
useEffect(() => {
223+
const handleButtonPositionUpdate = () => {
224+
if (showDropDown) {
225+
const button = buttonRef.current;
226+
const dropDown = dropDownRef.current;
227+
if (button !== null && dropDown !== null) {
228+
const {top} = button.getBoundingClientRect();
229+
const newPosition = top + button.offsetHeight + dropDownPadding;
230+
if (newPosition !== dropDown.getBoundingClientRect().top) {
231+
dropDown.style.top = `${newPosition}px`;
232+
}
233+
}
234+
}
235+
};
236+
237+
document.addEventListener('scroll', handleButtonPositionUpdate);
238+
239+
return () => {
240+
document.removeEventListener('scroll', handleButtonPositionUpdate);
241+
};
242+
}, [buttonRef, dropDownRef, showDropDown]);
243+
186244
return (
187245
<>
188246
<button
247+
type="button"
248+
disabled={disabled}
189249
aria-label={buttonAriaLabel || buttonLabel}
190250
className={buttonClassName}
191251
onClick={() => setShowDropDown(!showDropDown)}
192-
ref={buttonRef}
193-
>
252+
ref={buttonRef}>
194253
{buttonIconClassName && <span className={buttonIconClassName} />}
195254
{buttonLabel && (
196255
<span className="text dropdown-button-text">{buttonLabel}</span>
@@ -207,6 +266,6 @@ export const DropDown = ({
207266
)}
208267
</>
209268
);
210-
};
269+
}
211270

212271
export default DropDown;

0 commit comments

Comments
 (0)