Skip to content

Commit

Permalink
fix(@lexical/devtools): Misc fixes before first public release (faceb…
Browse files Browse the repository at this point in the history
…ook#5942)

- feat(@lexical/devtools): Correct handling of the restricted tabs
- fix(@lexical/devtools): Now we refresh editors before starting interactive selection
- fix(@lexical/devtools): Fixed work of the $isElementNode wrapper in websites that rely on "babelHelpers.inheritsLoose"
  • Loading branch information
StyleT authored Apr 23, 2024
1 parent 25b3579 commit 0b02af5
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 55 deletions.
1 change: 1 addition & 0 deletions packages/lexical-devtools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $ npm run dev
- Extension activity log: [chrome://extensions/?activity=eddfjidloofnnmloonifcjkpmfmlblab](chrome://extensions/?activity=eddfjidloofnnmloonifcjkpmfmlblab)
- Status of ServiceWorkers: [chrome://serviceworker-internals/?devtools](chrome://serviceworker-internals/?devtools)
- WXT Framework debugging: `DEBUG_WXT=1 npm run dev`
- If you detach the Dev Tools in a separate window, and press `Cmd+Option+I` while Dev Tools window is focused, you will invoke the Dev Tools for the Dev Tools window.

## Design

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function EditorsRefreshCTA({tabID, setErrorMessage}: Props) {
);

injectedPegasusService
.refreshLexicalEditorsForTabID()
.refreshLexicalEditors()
.catch((err) => {
setErrorMessage(err.message);
console.error(err);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {Tabs} from 'wxt/browser';
import type {StoreApi} from 'zustand';

import {IS_FIREFOX} from 'shared/environment';

import {ExtensionState} from '../../store';

export default class ActionIconWatchdog {
private constructor(
private readonly extensionStore: StoreApi<ExtensionState>,
) {}

static async start(store: StoreApi<ExtensionState>) {
return new ActionIconWatchdog(store).init();
}

async init() {
const tabs = await browser.tabs.query({});
await Promise.all(
tabs.map(this.checkAndHandleRestrictedPageIfSo.bind(this)),
);

browser.tabs.onCreated.addListener((tab) => {
this.checkAndHandleRestrictedPageIfSo(tab);
});

// Listen to URL changes on the active tab and update the DevTools icon.
browser.tabs.onUpdated.addListener(this.handleTabsUpdatedEvent.bind(this));
}

private async setIcon(
lexicalBuildType: 'restricted' | 'enabled',
tabId: number,
) {
const action = IS_FIREFOX ? browser.browserAction : browser.action;

await action.setIcon({
path: {
'128': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/128.png'
: '/icon/128-restricted.png',
),
'16': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/16.png'
: '/icon/16-restricted.png',
),
'32': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/32.png'
: '/icon/32-restricted.png',
),
'48': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/48.png'
: '/icon/48-restricted.png',
),
},
tabId: tabId,
});

if (lexicalBuildType === 'restricted') {
this.extensionStore.getState().markTabAsRestricted(tabId);
}
}

private handleTabsUpdatedEvent(
tabId: number,
_changeInfo: unknown,
tab: Tabs.Tab,
): void {
this.checkAndHandleRestrictedPageIfSo(tab);
}

private isRestrictedBrowserPage(url: string | undefined) {
return (
!url || ['chrome:', 'about:', 'file:'].includes(new URL(url).protocol)
);
}

private async checkAndHandleRestrictedPageIfSo(tab: Tabs.Tab) {
if (tab.id == null) {
return;
}

if (tab.id == null || this.isRestrictedBrowserPage(tab.url)) {
return this.setIcon('restricted', tab.id);
}

return this.setIcon('enabled', tab.id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
import {registerRPCService} from '@webext-pegasus/rpc';
import {initPegasusTransport} from '@webext-pegasus/transport/background';

import {initExtensionStoreBackend} from '../../store.ts';
import {
initExtensionStoreBackend,
useExtensionStore as extensionStore,
} from '../../store.ts';
import ActionIconWatchdog from './ActionIconWatchdog.ts';
import {getTabIDService} from './getTabIDService';

export default defineBackground(() => {
Expand All @@ -20,4 +24,6 @@ export default defineBackground(() => {
// Store initialization so other extension surfaces can use it
// as all changes go through background SW
initExtensionStoreBackend();

ActionIconWatchdog.start(extensionStore).catch(console.error);
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ export function EditorInspectorButton({tabID, setErrorMessage}: Props) {
{context: 'window', tabId: tabID},
);

injectedPegasusService.toggleEditorPicker().catch((err) => {
setErrorMessage(err.message);
console.error(err);
});
injectedPegasusService
.refreshLexicalEditors()
.then(() => injectedPegasusService.toggleEditorPicker())
.catch((err) => {
setErrorMessage(err.message);
console.error(err);
});
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class InjectedPegasusService
private readonly commandLog: WeakMap<LexicalEditor, LexicalCommandLog>,
) {}

refreshLexicalEditorsForTabID() {
refreshLexicalEditors() {
scanAndListenForEditors(this.tabID, this.extensionStore, this.commandLog);
}

Expand Down
14 changes: 0 additions & 14 deletions packages/lexical-devtools/src/entrypoints/popup/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,3 @@ body {
margin: 0 auto;
padding: 1rem;
}

.logo {
height: 2em;
/* padding: 1.5em; */
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

.card {
padding-top: 2em;
}
65 changes: 36 additions & 29 deletions packages/lexical-devtools/src/entrypoints/popup/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
*/
import './App.css';

import {Box, Flex} from '@chakra-ui/react';
import * as React from 'react';
import {useState} from 'react';

import lexicalLogo from '@/public/lexical.svg';

import EditorsRefreshCTA from '../../components/EditorsRefreshCTA';
import {useExtensionStore} from '../../store';

Expand All @@ -27,38 +26,46 @@ function App({tabID}: Props) {
const lexicalCount = Object.keys(states ?? {}).length;

return (
<>
<div>
<a href="https://lexical.dev" target="_blank">
<img src={lexicalLogo} className="logo" alt="Lexical logo" />
</a>
</div>
<Flex direction="column">
{errorMessage !== '' ? (
<div className="card error">{errorMessage}</div>
<Box className="error" mb={2} color="red">
{errorMessage}
</Box>
) : null}
<div className="card">
{states === undefined ? (
<span>Loading...</span>
) : (
<Box>
{states === null ? (
<span>
Found <b>{lexicalCount}</b> editor{lexicalCount > 1 ? 's' : ''} on
the page
{lexicalCount > 0 ? (
<>
{' '}
&#x2705;
<br />
Open the developer tools, and "Lexical" tab will appear to the
right.
</>
) : null}
This is a restricted browser page. Lexical DevTools cannot access
this page.
</span>
) : states === undefined ? (
<span>Loading...</span>
) : (
<>
<Box>
Found <b>{lexicalCount}</b> editor
{lexicalCount > 1 || lexicalCount === 0 ? 's' : ''} on the page
{lexicalCount > 0 ? (
<>
{' '}
&#x2705;
<br />
Open the developer tools, and "Lexical" tab will appear to the
right.
</>
) : null}
</Box>

<Box mt={1}>
<EditorsRefreshCTA
tabID={tabID}
setErrorMessage={setErrorMessage}
/>
</Box>
</>
)}
<p>
<EditorsRefreshCTA tabID={tabID} setErrorMessage={setErrorMessage} />
</p>
</div>
</>
</Box>
</Flex>
);
}

Expand Down
16 changes: 12 additions & 4 deletions packages/lexical-devtools/src/lexicalForExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,25 @@ export function $getSelection(): null | lexical.BaseSelection {
export function $isElementNode(
node: lexical.LexicalNode | null | undefined,
): node is lexical.ElementNode {
if (node == null) {
return false;
}

const editor = getActiveEditor();
const ElementNode = Object.getPrototypeOf(
editor._nodes.get('paragraph')!.klass,
);
const ParagraphNode = editor._nodes.get('paragraph')!.klass;
const ElementNode = Object.getPrototypeOf(ParagraphNode.prototype);

return node instanceof ElementNode;
// eslint-disable-next-line no-prototype-builtins
return ElementNode.isPrototypeOf(node);
}

export function $isTextNode(
node: lexical.LexicalNode | null | undefined,
): node is lexical.TextNode {
if (node == null) {
return false;
}

const editor = getActiveEditor();
const TextNode = editor._nodes.get('text')!.klass;

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion packages/lexical-devtools/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import {SerializedRawEditorState} from './types';

export interface ExtensionState {
lexicalState: {
[tabID: number]: {[editorKey: string]: SerializedRawEditorState};
[tabID: number]: {[editorKey: string]: SerializedRawEditorState} | null;
};
selectedEditorKey: {
[tabID: number]: string | null;
};
markTabAsRestricted: (tabID: number) => void;
setStatesForTab: (
id: number,
states: {[editorKey: string]: SerializedRawEditorState},
Expand All @@ -32,6 +33,13 @@ export interface ExtensionState {
export const useExtensionStore = create<ExtensionState>()(
subscribeWithSelector((set) => ({
lexicalState: {},
markTabAsRestricted: (tabID: number) =>
set((state) => ({
lexicalState: {
...state.lexicalState,
[tabID]: null,
},
})),
selectedEditorKey: {},
setSelectedEditorKey: (tabID: number, editorKey: string | null) =>
set((state) => ({
Expand Down

0 comments on commit 0b02af5

Please sign in to comment.