From 06e9f203db52919f11c4229d455ba0f0dc9c0a98 Mon Sep 17 00:00:00 2001 From: Chris Shepherd Date: Sun, 14 Jun 2020 21:08:19 +0100 Subject: [PATCH 1/2] Add Action component --- src/components/Action/RNAction.ts | 146 ++++++++++++++++++++++++++++++ src/components/Action/index.ts | 37 ++++++++ src/index.ts | 1 + 3 files changed, 184 insertions(+) create mode 100644 src/components/Action/RNAction.ts create mode 100644 src/components/Action/index.ts diff --git a/src/components/Action/RNAction.ts b/src/components/Action/RNAction.ts new file mode 100644 index 00000000..ba44cd5c --- /dev/null +++ b/src/components/Action/RNAction.ts @@ -0,0 +1,146 @@ +import { + QAction, + QIcon, + QActionSignals, + Component, + QFont, + QShortcut, + QKeySequence, + ShortcutContext, +} from "@nodegui/nodegui"; +import { RNComponent, RNProps } from "../config"; +import { throwUnsupported } from "../../utils/helpers"; + +export interface ActionProps extends RNProps { + /** + * Sets whether the action is a checkable action. [QAction: setCheckable](https://docs.nodegui.org/docs/api/generated/classes/qaction#setcheckable) + */ + checkable?: boolean; + + /** + * Sets whether the action is checked. [QAction: setChecked](https://docs.nodegui.org/docs/api/generated/classes/qaction#setchecked) + */ + checked?: boolean; + + /** + * Sets whether the action is enabled. [QAction: setEnabled](https://docs.nodegui.org/docs/api/generated/classes/qaction#setenabled) + */ + enabled?: boolean; + + /** + * Sets a font for the action. [QAction: setFont](https://docs.nodegui.org/docs/api/generated/classes/qaction#setfont) + */ + font?: QFont; + + /** + * Sets an icon for the action. [QSystemTrayIcon: setIcon](https://docs.nodegui.org/docs/api/generated/classes/qsystemtrayicon#seticon) + */ + icon?: QIcon; + + /** + * Sets the object name (id) of the widget in Qt. Object name can be analogous to id of an element in the web world. Using the objectName of the widget one can reference it in the Qt's stylesheet much like what we do with id in the web world. [QWidget: setObjectName](https://docs.nodegui.org/docs/api/NodeWidget#widgetsetobjectnameobjectname) + */ + id?: string; + + /** + * Prop to set the event listener map. See [Handlong Events](/docs/guides/handle-events) + */ + on?: Partial; + + /** + * Sets whether this action will be considered a separator. [QAction: setSeparator](https://docs.nodegui.org/docs/api/generated/classes/qaction#setseparator) + */ + separator?: boolean; + + /** + * Sets the action's primary shortcut key. [QAction: setShortcut](https://docs.nodegui.org/docs/api/generated/classes/qaction#setshortcut) + */ + shortcut?: QKeySequence; + + /** + * Sets the context for action's shortcut. [QAction: setShortcutContext](https://docs.nodegui.org/docs/api/generated/classes/qaction#setshortcutcontext) + */ + shortcutContext?: ShortcutContext; + + /** + * Sets descriptive text. [QAction: setText](https://docs.nodegui.org/docs/api/generated/classes/qaction#settext) + */ + text?: string; +} + +const setActionProps = ( + widget: RNAction, + newProps: ActionProps, + oldProps: ActionProps +) => { + const setter: ActionProps = { + set checkable(isCheckable: boolean) { + widget.setCheckable(isCheckable); + }, + set checked(isChecked: boolean) { + widget.setChecked(isChecked); + }, + set enabled(isEnabled: boolean) { + widget.setEnabled(isEnabled); + }, + set font(font: QFont) { + widget.setFont(font); + }, + set icon(icon: QIcon) { + widget.setIcon(icon); + }, + set id(id: string) { + widget.setObjectName(id); + }, + set on(listenerMap: Partial) { + const listenerMapLatest: any = Object.assign({}, listenerMap); + const oldListenerMap = Object.assign({}, oldProps.on); + Object.entries(oldListenerMap).forEach(([eventType, oldEvtListener]) => { + const newEvtListener = listenerMapLatest[eventType]; + if (oldEvtListener !== newEvtListener) { + widget.removeEventListener(eventType as any, oldEvtListener); + } else { + delete listenerMapLatest[eventType]; + } + }); + + Object.entries(listenerMapLatest).forEach( + ([eventType, newEvtListener]) => { + widget.addEventListener(eventType as any, newEvtListener); + } + ); + }, + set separator(isSeparator: boolean) { + widget.setSeparator(isSeparator); + }, + set shortcut(shortcut: QKeySequence) { + widget.setShortcut(shortcut); + }, + set shortcutContext(shortcutContext: ShortcutContext) { + widget.setShortcutContext(shortcutContext); + }, + set text(text: string) { + widget.setText(text); + }, + }; + Object.assign(setter, newProps); +}; + +export class RNAction extends QAction implements RNComponent { + setProps(newProps: ActionProps, oldProps: ActionProps): void { + setActionProps(this, newProps, oldProps); + } + appendInitialChild(child: Component) { + throwUnsupported(this); + } + appendChild(child: Component): void { + throwUnsupported(this); + } + insertBefore(child: Component, beforeChild: Component): void { + throwUnsupported(this); + } + removeChild(child: Component): void { + throwUnsupported(this); + } + static tagName = "action"; +} diff --git a/src/components/Action/index.ts b/src/components/Action/index.ts new file mode 100644 index 00000000..a4c86c9b --- /dev/null +++ b/src/components/Action/index.ts @@ -0,0 +1,37 @@ +import { Fiber } from "react-reconciler"; +import { registerComponent, ComponentConfig } from "../config"; +import { RNAction, ActionProps } from "./RNAction"; +import { AppContainer } from "../../reconciler"; + +class ActionConfig extends ComponentConfig { + tagName = RNAction.tagName; + shouldSetTextContent(nextProps: ActionProps): boolean { + return false; + } + createInstance( + newProps: ActionProps, + rootInstance: AppContainer, + context: any, + workInProgress: Fiber + ): RNAction { + const widget = new RNAction(); + widget.setProps(newProps, {}); + return widget; + } + commitMount( + instance: RNAction, + newProps: ActionProps, + internalInstanceHandle: any + ): void {} + commitUpdate( + instance: RNAction, + updatePayload: any, + oldProps: ActionProps, + newProps: ActionProps, + finishedWork: Fiber + ): void { + instance.setProps(newProps, oldProps); + } +} + +export const Action = registerComponent(new ActionConfig()); diff --git a/src/index.ts b/src/index.ts index 98679bb4..7ca7dec3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +export { Action } from "./components/Action"; export { BoxView } from "./components/BoxView"; export { GridView } from "./components/GridView"; export { Slider } from "./components/Slider"; From 1f612cccf6390d581d67305e6ebf4b5a815bd769 Mon Sep 17 00:00:00 2001 From: Chris Shepherd Date: Sun, 14 Jun 2020 21:08:50 +0100 Subject: [PATCH 2/2] Enable Menu to have Action as children --- src/components/Menu/RNMenu.ts | 34 +++++++++-------- src/demo.tsx | 69 ++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/components/Menu/RNMenu.ts b/src/components/Menu/RNMenu.ts index f74bbc46..68656942 100644 --- a/src/components/Menu/RNMenu.ts +++ b/src/components/Menu/RNMenu.ts @@ -1,11 +1,11 @@ -import { NodeWidget, QAction, QMenu, QMenuSignals } from "@nodegui/nodegui"; -import { ViewProps, setViewProps } from "../View/RNView"; +import { QMenu, QMenuSignals, Component, NodeWidget } from "@nodegui/nodegui"; import { RNWidget } from "../config"; import { throwUnsupported } from "../../utils/helpers"; +import { RNAction } from "../Action/RNAction"; +import { setViewProps, ViewProps } from "../View/RNView"; export interface MenuProps extends ViewProps { title?: string; - actions?: QAction[]; } const setMenuProps = ( @@ -17,11 +17,6 @@ const setMenuProps = ( set title(title: string) { widget.setTitle(title); }, - set actions(actions: QAction[]) { - actions.forEach(action => { - widget.addAction(action); - }); - } }; Object.assign(setter, newProps); setViewProps(widget, newProps, oldProps); @@ -31,17 +26,24 @@ export class RNMenu extends QMenu implements RNWidget { setProps(newProps: MenuProps, oldProps: MenuProps): void { setMenuProps(this, newProps, oldProps); } - appendInitialChild(child: NodeWidget): void { - throwUnsupported(this); + appendInitialChild(child: Component): void { + this.appendChild(child); } - appendChild(child: NodeWidget): void { - throwUnsupported(this); + appendChild(child: Component): void { + if (!(child instanceof RNAction)) { + console.warn("Menu only supports Action as its children"); + return; + } + + this.addAction(child); } - insertBefore(child: NodeWidget, beforeChild: NodeWidget): void { + insertBefore(child: Component, beforeChild: Component): void { throwUnsupported(this); } - removeChild(child: NodeWidget): void { - throwUnsupported(this); + removeChild(child: Component): void { + if (child instanceof RNAction) { + this.removeAction(child); + } } static tagName = "menu"; -}; +} diff --git a/src/demo.tsx b/src/demo.tsx index 95af9c21..436234cb 100644 --- a/src/demo.tsx +++ b/src/demo.tsx @@ -1,42 +1,59 @@ import React from "react"; -import { QIcon, QAction, QApplication } from "@nodegui/nodegui"; +import { QIcon, QApplication, QKeySequence } from "@nodegui/nodegui"; import path from "path"; -import { MenuBar, Menu, SystemTrayIcon, Renderer, Window } from "."; - -const quitAction = new QAction(); -quitAction.setText("Quit"); -quitAction.addEventListener("triggered", () => { - const app = QApplication.instance(); - app.exit(0); -}); - -const fileActions: QAction[] = [quitAction]; - -const sayHi = new QAction(); -sayHi.setText("Hello"); -sayHi.addEventListener("triggered", () => { - console.log("hello"); -}); - -const randActions: QAction[] = [sayHi]; +import { Action, MenuBar, Menu, SystemTrayIcon, Renderer, Window } from "."; + +const quitAction = ( + { + QApplication.instance().exit(0); + }, + }} + shortcut={new QKeySequence("Ctrl+Q")} + text="Quit" + /> +); +const sayHiAction = ( + { + console.log("hello"); + }, + }} + text="Hello" + /> +); const trayIcon = new QIcon( path.join(__dirname, "../extras/assets/nodegui.png") ); -const separatorAction = new QAction(); -separatorAction.setSeparator(true); - -const systemTrayMenuActions = [sayHi, separatorAction, quitAction]; const App = () => { return ( - + + { + console.log("print"); + }, + }} + text="Print" + shortcut={new QKeySequence("Ctrl+P")} + /> + + {quitAction} + - - + + {sayHiAction} + + {sayHiAction} + {quitAction} + );