Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/devtools_discord_notify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: (DevTools) Discord Notify

on:
pull_request_target:
types: [opened, ready_for_review]
paths:
- packages/react-devtools**
- .github/workflows/devtools_**.yml

permissions: {}

jobs:
check_access:
if: ${{ github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
outputs:
is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
steps:
- run: echo ${{ github.event.pull_request.author_association }}
- name: Check is member or collaborator
id: check_is_member_or_collaborator
if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"

check_maintainer:
if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
needs: [check_access]
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
permissions:
# Used by check_maintainer
contents: read
with:
actor: ${{ github.event.pull_request.user.login }}

notify:
if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
needs: check_maintainer
runs-on: ubuntu-latest
steps:
- name: Discord Webhook Action
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
with:
webhook-url: ${{ secrets.DEVTOOLS_DISCORD_WEBHOOK_URL }}
embed-author-name: ${{ github.event.pull_request.user.login }}
embed-author-url: ${{ github.event.pull_request.user.html_url }}
embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}'
embed-description: ${{ github.event.pull_request.body }}
embed-url: ${{ github.event.pull_request.html_url }}
2 changes: 2 additions & 0 deletions .github/workflows/runtime_discord_notify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ on:
pull_request_target:
types: [opened, ready_for_review]
paths-ignore:
- packages/react-devtools**
- compiler/**
- .github/workflows/compiler_**.yml
- .github/workflows/devtools**.yml

permissions: {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { c as _c } from "react/compiler-runtime"; // 
@compilationMode:"all"
import { c as _c } from "react/compiler-runtime"; // @compilationMode:"all"
function nonReactFn() {
  const $ = _c(1);
  let t0;
Expand Down
106 changes: 106 additions & 0 deletions compiler/apps/playground/components/AccordionWindow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* 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 {Resizable} from 're-resizable';
import React, {useCallback} from 'react';

type TabsRecord = Map<string, React.ReactNode>;

export default function AccordionWindow(props: {
defaultTab: string | null;
tabs: TabsRecord;
tabsOpen: Set<string>;
setTabsOpen: (newTab: Set<string>) => void;
changedPasses: Set<string>;
}): React.ReactElement {
if (props.tabs.size === 0) {
return (
<div
className="flex items-center justify-center"
style={{width: 'calc(100vw - 650px)'}}>
No compiler output detected, see errors below
</div>
);
}
return (
<div className="flex flex-row h-full">
{Array.from(props.tabs.keys()).map(name => {
return (
<AccordionWindowItem
name={name}
key={name}
tabs={props.tabs}
tabsOpen={props.tabsOpen}
setTabsOpen={props.setTabsOpen}
hasChanged={props.changedPasses.has(name)}
/>
);
})}
</div>
);
}

function AccordionWindowItem({
name,
tabs,
tabsOpen,
setTabsOpen,
hasChanged,
}: {
name: string;
tabs: TabsRecord;
tabsOpen: Set<string>;
setTabsOpen: (newTab: Set<string>) => void;
hasChanged: boolean;
}): React.ReactElement {
const isShow = tabsOpen.has(name);

const toggleTabs = useCallback(() => {
const nextState = new Set(tabsOpen);
if (nextState.has(name)) {
nextState.delete(name);
} else {
nextState.add(name);
}
setTabsOpen(nextState);
}, [tabsOpen, name, setTabsOpen]);

// Replace spaces with non-breaking spaces
const displayName = name.replace(/ /g, '\u00A0');

return (
<div key={name} className="flex flex-row">
{isShow ? (
<Resizable className="border-r" minWidth={550} enable={{right: true}}>
<h2
title="Minimize tab"
aria-label="Minimize tab"
onClick={toggleTabs}
className={`p-4 duration-150 ease-in border-b cursor-pointer border-grey-200 ${
hasChanged ? 'font-bold' : 'font-light'
} text-secondary hover:text-link`}>
- {displayName}
</h2>
{tabs.get(name) ?? <div>No output for {name}</div>}
</Resizable>
) : (
<div className="relative items-center h-full px-1 py-6 align-middle border-r border-grey-200">
<button
title={`Expand compiler tab: ${name}`}
aria-label={`Expand compiler tab: ${name}`}
style={{transform: 'rotate(90deg) translate(-50%)'}}
onClick={toggleTabs}
className={`flex-grow-0 w-5 transition-colors duration-150 ease-in ${
hasChanged ? 'font-bold' : 'font-light'
} text-secondary hover:text-link`}>
{displayName}
</button>
</div>
)}
</div>
);
}
145 changes: 92 additions & 53 deletions compiler/apps/playground/components/Editor/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
import type {editor} from 'monaco-editor';
import * as monaco from 'monaco-editor';
import React, {useState, useCallback} from 'react';
import React, {useState} from 'react';
import {Resizable} from 're-resizable';
import {useStore, useStoreDispatch} from '../StoreContext';
import {monacoOptions} from './monacoOptions';
import {IconChevron} from '../Icons/IconChevron';

// @ts-expect-error - webpack asset/source loader handles .d.ts files as strings
import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts';
Expand All @@ -20,13 +21,26 @@ loader.config({monaco});

export default function ConfigEditor(): React.ReactElement {
const [isExpanded, setIsExpanded] = useState(false);

return (
<div className="flex flex-row relative">
{isExpanded ? (
<ExpandedEditor onToggle={setIsExpanded} />
) : (
<CollapsedEditor onToggle={setIsExpanded} />
)}
</div>
);
}

function ExpandedEditor({
onToggle,
}: {
onToggle: (expanded: boolean) => void;
}): React.ReactElement {
const store = useStore();
const dispatchStore = useStoreDispatch();

const toggleExpanded = useCallback(() => {
setIsExpanded(prev => !prev);
}, []);

const handleChange: (value: string | undefined) => void = value => {
if (value === undefined) return;

Expand Down Expand Up @@ -68,57 +82,82 @@ export default function ConfigEditor(): React.ReactElement {
};

return (
<div className="flex flex-row relative">
{isExpanded ? (
<Resizable
className="border-r"
minWidth={300}
maxWidth={600}
defaultSize={{width: 350, height: 'auto'}}
enable={{right: true}}>
<h2
title="Minimize config editor"
aria-label="Minimize config editor"
onClick={toggleExpanded}
className="p-4 duration-150 ease-in border-b cursor-pointer border-grey-200 font-light text-secondary hover:text-link">
- Config Overrides
<Resizable
className="border-r"
minWidth={300}
maxWidth={600}
defaultSize={{width: 350, height: 'auto'}}
enable={{right: true, bottom: false}}
style={{position: 'relative', height: 'calc(100vh - 3.5rem)'}}>
<div className="bg-gray-700 p-2">
<div className="pb-2">
<h2 className="inline-block text-secondary-dark text-center outline-none py-1.5 px-1.5 xs:px-3 sm:px-4 rounded-full capitalize whitespace-nowrap text-sm">
Config Overrides
</h2>
<div className="h-[calc(100vh_-_3.5rem_-_4rem)]">
<MonacoEditor
path={'config.ts'}
language={'typescript'}
value={store.config}
onMount={handleMount}
onChange={handleChange}
options={{
...monacoOptions,
lineNumbers: 'off',
folding: false,
renderLineHighlight: 'none',
scrollBeyondLastLine: false,
hideCursorInOverviewRuler: true,
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
}}
/>
</div>
</Resizable>
) : (
<div className="relative items-center h-full px-1 py-6 align-middle border-r border-grey-200">
<button
title="Expand config editor"
aria-label="Expand config editor"
style={{
transform: 'rotate(90deg) translate(-50%)',
whiteSpace: 'nowrap',
</div>
<div
className="absolute w-10 h-16 bg-gray-700 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[5] cursor-pointer"
title="Minimize config editor"
onClick={() => onToggle(false)}
style={{
top: '50%',
marginTop: '-32px',
right: '-32px',
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
}}>
<IconChevron
displayDirection="left"
className="text-secondary-dark"
/>
</div>
<div className="h-[calc(100vh_-_3.5rem_-_3.5rem)] rounded-lg overflow-hidden">
<MonacoEditor
path={'config.ts'}
language={'typescript'}
value={store.config}
onMount={handleMount}
onChange={handleChange}
options={{
...monacoOptions,
lineNumbers: 'off',
folding: false,
renderLineHighlight: 'none',
hideCursorInOverviewRuler: true,
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
scrollBeyondLastLine: false,
}}
onClick={toggleExpanded}
className="flex-grow-0 w-5 transition-colors duration-150 ease-in font-light text-secondary hover:text-link">
Config Overrides
</button>
/>
</div>
)}
</div>
</Resizable>
);
}

function CollapsedEditor({
onToggle,
}: {
onToggle: (expanded: boolean) => void;
}): React.ReactElement {
return (
<div
className="w-4"
style={{height: 'calc(100vh - 3.5rem)', position: 'relative'}}>
<div
className="absolute w-10 h-16 bg-gray-700 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[5] cursor-pointer"
title="Expand config editor"
onClick={() => onToggle(true)}
style={{
top: '50%',
marginTop: '-32px',
left: '-8px',
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
}}>
<IconChevron displayDirection="right" className="text-secondary-dark" />
</div>
</div>
);
}
Loading
Loading