├── .babelrc ├── .editorconfig ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-issue.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── .vscode └── launch.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __mocks__ └── node-qt.js ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── SVG │ ├── Artboard 1.svg │ └── proton native.ai ├── _coverpage.md ├── _sidebar.md ├── about.md ├── calculator.png ├── catapi_v2.png ├── components.md ├── components │ ├── View.md │ └── Window.md ├── debugging.md ├── external_functionality.md ├── hot_reloading.md ├── images │ ├── CatApi.gif │ ├── app_icon.svg │ ├── favicon.png │ ├── icon_black.svg │ ├── icon_white.svg │ ├── logo_black.svg │ ├── logo_white.svg │ ├── windows_example.png │ └── windows_packaging.png ├── index.html ├── js_example.js ├── main.js ├── packaging.md ├── python_example.py ├── quickstart.md ├── v2_changes.md └── wx_backend.md ├── examples ├── Calculator │ ├── .babelrc │ ├── app.js │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── webpack.config.js ├── CatApi │ ├── .babelrc │ ├── app.js │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── actions │ │ │ └── index.js │ │ ├── components │ │ │ └── main.js │ │ ├── consts │ │ │ └── index.js │ │ └── reducers │ │ │ └── index.js │ └── webpack.config.js └── Notepad │ ├── .babelrc │ ├── index.js │ ├── package-lock.json │ └── package.json ├── package-lock.json ├── package.json ├── src ├── backends │ ├── index.ts │ ├── qt.ts │ └── wx.ts ├── components │ ├── App.ts │ ├── Base.ts │ ├── Button.ts │ ├── Container.ts │ ├── Image.ts │ ├── PickerInternal.ts │ ├── Root.ts │ ├── RootText.ts │ ├── TextFuncs.ts │ ├── TextInput.ts │ ├── View.ts │ ├── VirtualText.ts │ ├── Window.ts │ ├── YogaComponent.ts │ └── index.ts ├── devtools.ts ├── index.ts ├── misc │ ├── hot.ts │ ├── index.ts │ ├── node-qt-napi.d.ts │ ├── node-wx-napi.ts │ ├── react-proxy.d.ts │ ├── styleSheet.ts │ └── yoga-layout-prebuilt.d.ts ├── react-components │ ├── Picker.tsx │ ├── Text.tsx │ ├── TouchableHighlight.tsx │ ├── TouchableOpacity.tsx │ ├── TouchableWithoutFeedback.tsx │ └── index.ts ├── reconciler │ └── index.ts ├── render │ └── index.ts └── utils │ ├── convertStyleSheet.ts │ ├── createElement.ts │ ├── propChecker.ts │ ├── propsUpdater.ts │ ├── requireImpl.ts │ └── yogaHelper.ts ├── test ├── components │ ├── Window.test.js │ └── __image_snapshots__ │ │ ├── window-test-js-window-basic-window-1-snap.png │ │ ├── window-test-js-window-multiple-windows-1-snap.png │ │ ├── window-test-js-window-window-add-state-1-snap.png │ │ ├── window-test-js-window-window-add-state-2-snap.png │ │ ├── window-test-js-window-window-insert-state-1-snap.png │ │ ├── window-test-js-window-window-insert-state-2-snap.png │ │ ├── window-test-js-window-window-removal-state-1-snap.png │ │ ├── window-test-js-window-window-removal-state-2-snap.png │ │ ├── window-test-js-window-window-size-1-snap.png │ │ ├── window-test-js-window-window-size-percent-1-snap.png │ │ ├── window-test-js-window-window-styling-1-snap.png │ │ ├── window-test-js-window-window-update-state-1-snap.png │ │ └── window-test-js-window-window-update-state-2-snap.png └── index.js ├── testprog.js ├── testyoga.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style = space 4 | indent_size = 2 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: kusti8 # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Include a minimal example of code that causes this bug. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Versions:** 23 | - OS: [e.g. Windows, Mac, Linux] 24 | - Version [e.g. 2.0.0] 25 | - Node version [eg. 12.0.1] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation Issue 3 | about: Found an error or something missing in the documentation? 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Link to the page** 11 | 12 | **Quote of Error** 13 | Preferably a quote of the error, if there is one. 14 | 15 | **Proposed Changes** 16 | Include what changes should be made [ex. add section on X, remove sentence about Y] 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # console.logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | bin 61 | dist/ 62 | 63 | # ide 64 | .idea/ 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: xenial 3 | cache: false 4 | node_js: 5 | - "9.3" 6 | - "10" 7 | - "11" 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - xvfb 14 | - qtbase5-dev 15 | - build-essential 16 | - qt5-default 17 | - g++-6 18 | - x11-apps 19 | - imagemagick 20 | before_install: 21 | - export CXX="g++-6" 22 | install: 23 | - npm install 24 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/testprog.js", 12 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/babel-node" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | ## Getting Started 4 | 5 | Clone the repository, and install dependencies with `npm i`. To test changes, make changes to `testprog.js` and run `npm run testprog`. Just don't commit any changes to this file. 6 | 7 | ### Docs 8 | 9 | All documentation is housed in `docs/`, and is written in Markdown. Follow the format for all other pages. If you're making a page that doesn't follow previous formats, ask me. Changes made to `index.html` will not be made lightly and 99% of cases don't need to change that. The format is set for documentation, so don't try and change it. 10 | 11 | ## Important Points 12 | 13 | Proton Native welcomes contributions to constantly improve. Contributions are accepted in the form of a PR, which has a few important points that should be followed. 14 | 15 | 1. Styling is done with prettier. A git-hook has been added for convience, but any PR that isn't styled won't be accepted. 16 | 17 | 2. Follow common sense. If there already exists a file similar, use it as a template. Don't make up your own style. 18 | 19 | 3. Minimize hacks. If there's a clean way to do it, do it. 20 | 21 | 4. **Document everything**! Every additional feature should be well documented. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gustav Hansen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Logo by @elisiri
6 |
(
5 | props: P,
6 | propTypes: T,
7 | defaultProps: D,
8 | name: string
9 | ): any {
10 | // for (let prop in defaultProps) {
11 | // if (!(prop in props) || typeof props[prop] === 'undefined') {
12 | // props[prop] = defaultProps[prop];
13 | // }
14 | // }
15 | props = _.merge(defaultProps, props);
16 | PropTypes.checkPropTypes(propTypes, props, "prop", name);
17 | return props;
18 | }
19 |
20 | export default propChecker;
21 |
--------------------------------------------------------------------------------
/src/utils/propsUpdater.ts:
--------------------------------------------------------------------------------
1 | const propsUpdater = (...updateMaps: any[]) => (changes: object) =>
2 | updateMaps.forEach(updateMap => {
3 | /** updateMap can be any of:
4 | * A) { [prop]: (newValue) => void }
5 | * B) [ mutableObject, ...prop | { [prop]: [string objectKey] }]
6 | **/
7 |
8 | if (!Array.isArray(updateMap)) {
9 | // A
10 | return Object.entries(updateMap).forEach(([prop, updateFn]: any) => {
11 | if (prop in changes) {
12 | updateFn((changes as any)[prop]);
13 | }
14 | });
15 | }
16 |
17 | // B
18 | const mutableObject = updateMap[0];
19 | updateMap.slice(1).forEach(p => {
20 | if (typeof p === "object") {
21 | Object.entries(p).forEach(([prop, objectKey]: any) => {
22 | if (prop in changes) {
23 | mutableObject[objectKey] = (changes as any)[prop];
24 | }
25 | });
26 | } else {
27 | if (p in changes) {
28 | mutableObject[p] = (changes as any)[p];
29 | }
30 | }
31 | });
32 | });
33 |
34 | export default propsUpdater;
35 |
--------------------------------------------------------------------------------
/src/utils/requireImpl.ts:
--------------------------------------------------------------------------------
1 | //@ts-ignore
2 | import * as Module from "module";
3 | import * as fileType from "file-type";
4 | import readChunk from "read-chunk";
5 | //@ts-ignore
6 | import sizeOf from "image-size";
7 |
8 | //@ts-ignore
9 | const originalLoader = Module._load;
10 |
11 | //@ts-ignore
12 | Module._load = function (request, parent) {
13 | let buffer;
14 | try {
15 | buffer = readChunk.sync(request, 0, fileType.minimumBytes);
16 | } catch {
17 | return originalLoader.apply(this, arguments);
18 | }
19 | const fullType = fileType(buffer)
20 | if (!fullType) return originalLoader.apply(this, arguments);
21 | const type = fullType.mime
22 | if (type.split("/")[0] != "image")
23 | return originalLoader.apply(this, arguments);
24 |
25 | const size = sizeOf(request);
26 | return { uri: request, width: size.width, height: size.height };
27 | };
28 |
--------------------------------------------------------------------------------
/src/utils/yogaHelper.ts:
--------------------------------------------------------------------------------
1 | import * as yoga from "yoga-layout-prebuilt";
2 |
3 | const mixedYogaValueTransformers = {
4 | display(value: "flex" | "none") {
5 | switch (value) {
6 | case "flex":
7 | return yoga.DISPLAY_FLEX;
8 | case "none":
9 | return yoga.DISPLAY_NONE;
10 | }
11 | },
12 |
13 | top: {
14 | functionName: "setPosition",
15 | transform: (value: any) => [yoga.EDGE_TOP, value]
16 | },
17 | right: {
18 | functionName: "setPosition",
19 | transform: (value: any) => [yoga.EDGE_RIGHT, value]
20 | },
21 | bottom: {
22 | functionName: "setPosition",
23 | transform: (value: any) => [yoga.EDGE_BOTTOM, value]
24 | },
25 | left: {
26 | functionName: "setPosition",
27 | transform: (value: any) => [yoga.EDGE_LEFT, value]
28 | },
29 |
30 | border: {
31 | functionName: "",
32 | transform: (value: any) => [yoga.EDGE_ALL, value]
33 | },
34 | borderTop: {
35 | functionName: "",
36 | transform: (value: any) => [yoga.EDGE_TOP, value]
37 | },
38 | borderRight: {
39 | functionName: "",
40 | transform: (value: any) => [yoga.EDGE_RIGHT, value]
41 | },
42 | borderBottom: {
43 | functionName: "",
44 | transform: (value: any) => [yoga.EDGE_BOTTOM, value]
45 | },
46 | borderLeft: {
47 | functionName: "",
48 | transform: (value: any) => [yoga.EDGE_LEFT, value]
49 | },
50 |
51 | margin: {
52 | functionName: "setMargin",
53 | transform: (value: any) => [yoga.EDGE_ALL, value]
54 | },
55 | marginTop: {
56 | functionName: "setMargin",
57 | transform: (value: any) => [yoga.EDGE_TOP, value]
58 | },
59 | marginRight: {
60 | functionName: "setMargin",
61 | transform: (value: any) => [yoga.EDGE_RIGHT, value]
62 | },
63 | marginBottom: {
64 | functionName: "setMargin",
65 | transform: (value: any) => [yoga.EDGE_BOTTOM, value]
66 | },
67 | marginLeft: {
68 | functionName: "setMargin",
69 | transform: (value: any) => [yoga.EDGE_LEFT, value]
70 | },
71 |
72 | padding: {
73 | functionName: "setPadding",
74 | transform: (value: any) => [yoga.EDGE_ALL, value]
75 | },
76 | paddingTop: {
77 | functionName: "setPadding",
78 | transform: (value: any) => [yoga.EDGE_TOP, value]
79 | },
80 | paddingRight: {
81 | functionName: "setPadding",
82 | transform: (value: any) => [yoga.EDGE_RIGHT, value]
83 | },
84 | paddingBottom: {
85 | functionName: "setPadding",
86 | transform: (value: any) => [yoga.EDGE_BOTTOM, value]
87 | },
88 | paddingLeft: {
89 | functionName: "setPadding",
90 | transform: (value: any) => [yoga.EDGE_LEFT, value]
91 | },
92 |
93 | position: {
94 | functionName: "setPositionType",
95 | transform(value: "relative" | "absolute") {
96 | switch (value) {
97 | case "relative":
98 | return [yoga.POSITION_TYPE_RELATIVE];
99 | case "absolute":
100 | return [yoga.POSITION_TYPE_ABSOLUTE];
101 | }
102 | throw new Error("Position not supported: " + value);
103 | }
104 | },
105 |
106 | overflow(value: "visible" | "hidden" | "scroll") {
107 | switch (value) {
108 | case "visible":
109 | return yoga.OVERFLOW_VISIBLE;
110 | case "hidden":
111 | return yoga.OVERFLOW_HIDDEN;
112 | case "scroll":
113 | return yoga.OVERFLOW_SCROLL;
114 | }
115 | },
116 |
117 | alignItems(
118 | value:
119 | | "auto"
120 | | "flex-start"
121 | | "center"
122 | | "flex-end"
123 | | "stretch"
124 | | "baseline"
125 | | "space-between"
126 | | "space-around"
127 | ) {
128 | switch (value) {
129 | case "auto":
130 | return yoga.ALIGN_AUTO;
131 | case "flex-start":
132 | return yoga.ALIGN_FLEX_START;
133 | case "center":
134 | return yoga.ALIGN_CENTER;
135 | case "flex-end":
136 | return yoga.ALIGN_FLEX_END;
137 | case "stretch":
138 | return yoga.ALIGN_STRETCH;
139 | case "baseline":
140 | return yoga.ALIGN_BASELINE;
141 | case "space-between":
142 | return yoga.ALIGN_SPACE_BETWEEN;
143 | case "space-around":
144 | return yoga.ALIGN_SPACE_AROUND;
145 | }
146 | },
147 |
148 | alignSelf(
149 | value:
150 | | "auto"
151 | | "flex-start"
152 | | "center"
153 | | "flex-end"
154 | | "stretch"
155 | | "baseline"
156 | | "space-between"
157 | | "space-around"
158 | ) {
159 | switch (value) {
160 | case "auto":
161 | return yoga.ALIGN_AUTO;
162 | case "flex-start":
163 | return yoga.ALIGN_FLEX_START;
164 | case "center":
165 | return yoga.ALIGN_CENTER;
166 | case "flex-end":
167 | return yoga.ALIGN_FLEX_END;
168 | case "stretch":
169 | return yoga.ALIGN_STRETCH;
170 | case "baseline":
171 | return yoga.ALIGN_BASELINE;
172 | case "space-between":
173 | return yoga.ALIGN_SPACE_BETWEEN;
174 | case "space-around":
175 | return yoga.ALIGN_SPACE_AROUND;
176 | }
177 | },
178 |
179 | alignContent(
180 | value:
181 | | "auto"
182 | | "flex-start"
183 | | "center"
184 | | "flex-end"
185 | | "stretch"
186 | | "baseline"
187 | | "space-between"
188 | | "space-around"
189 | ) {
190 | switch (value) {
191 | case "auto":
192 | return yoga.ALIGN_AUTO;
193 | case "flex-start":
194 | return yoga.ALIGN_FLEX_START;
195 | case "center":
196 | return yoga.ALIGN_CENTER;
197 | case "flex-end":
198 | return yoga.ALIGN_FLEX_END;
199 | case "stretch":
200 | return yoga.ALIGN_STRETCH;
201 | case "baseline":
202 | return yoga.ALIGN_BASELINE;
203 | case "space-between":
204 | return yoga.ALIGN_SPACE_BETWEEN;
205 | case "space-around":
206 | return yoga.ALIGN_SPACE_AROUND;
207 | }
208 | },
209 |
210 | justifyContent(
211 | value:
212 | | "flex-start"
213 | | "center"
214 | | "flex-end"
215 | | "space-between"
216 | | "space-around"
217 | | "space-evenly"
218 | ) {
219 | switch (value) {
220 | case "flex-start":
221 | return yoga.JUSTIFY_FLEX_START;
222 | case "center":
223 | return yoga.JUSTIFY_CENTER;
224 | case "flex-end":
225 | return yoga.JUSTIFY_FLEX_END;
226 | case "space-between":
227 | return yoga.JUSTIFY_SPACE_BETWEEN;
228 | case "space-around":
229 | return yoga.JUSTIFY_SPACE_AROUND;
230 | case "space-evenly":
231 | return yoga.JUSTIFY_SPACE_EVENLY;
232 | }
233 | },
234 |
235 | flexDirection(value: "column" | "row") {
236 | switch (value) {
237 | case "column":
238 | return yoga.FLEX_DIRECTION_COLUMN;
239 | case "row":
240 | return yoga.FLEX_DIRECTION_ROW;
241 | }
242 | },
243 |
244 | flexWrap(value: "wrap" | "nowrap" | "wrap-reverse") {
245 | switch (value) {
246 | case "wrap":
247 | return yoga.WRAP_WRAP;
248 | case "nowrap":
249 | return yoga.WRAP_NO_WRAP;
250 | case "wrap-reverse":
251 | return yoga.WRAP_WRAP_REVERSE;
252 | }
253 | }
254 | };
255 |
256 | export function getYogaValueTransformer(propertyName: string) {
257 | const transformer = (mixedYogaValueTransformers as any)[propertyName];
258 | if (!transformer) {
259 | return {
260 | transform: (value: any) => [value],
261 | functionName: getYogaNodeSetFunctionName(propertyName)
262 | };
263 | }
264 |
265 | if (typeof transformer === "function") {
266 | return {
267 | transform: (value: any) => [transformer(value)],
268 | functionName: getYogaNodeSetFunctionName(propertyName)
269 | };
270 | }
271 |
272 | return transformer;
273 | }
274 |
275 | export function getYogaNodeSetFunctionName(propertyName: string) {
276 | return "set" + propertyName[0].toUpperCase() + propertyName.substr(1);
277 | }
278 |
--------------------------------------------------------------------------------
/test/components/Window.test.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { App, Window, AppRegistry } from '../../src';
3 | import qt from 'node-qt-napi';
4 | jest.unmock('node-qt-napi');
5 | const { toMatchImageSnapshot } = require('jest-image-snapshot');
6 | import { compareSnapshot, clearShown } from '../index';
7 | import { updateExpression } from '@babel/types';
8 |
9 | describe('Window', () => {
10 | beforeAll(() => {
11 | expect.extend({ toMatchImageSnapshot });
12 | });
13 | beforeEach(() => {
14 | jest.useFakeTimers();
15 | });
16 | afterEach(() => {
17 | clearShown();
18 | });
19 | test('Basic window', () => {
20 | class Test extends Component {
21 | render() {
22 | return (
23 |