Permalink
Please sign in to comment.
Showing
with
23,288 additions
and 0 deletions.
- +3 −0 .babelrc
- +30 −0 .eslintrc
- +34 −0 .flowconfig
- +6 −0 .gitignore
- +147 −0 README.md
- 0 __tests__/.gitkeep
- +86 −0 example-plugin/Layer From Props.js
- +85 −0 example-plugin/Test React.js
- +106 −0 example-plugin/Test Run.js
- +22 −0 flow-typed/fbjs.js
- +18 −0 flow-typed/sketch.js
- +120 −0 lib/ReactSketchComponent.js
- +51 −0 lib/ReactSketchDefaultInjection.js
- +79 −0 lib/ReactSketchMount.js
- +54 −0 lib/ReactSketchReconcileTransaction.js
- +75 −0 lib/SketchCache.js
- +53 −0 lib/SketchElements.js
- +37 −0 lib/SketchSharedStylesManager.js
- +35 −0 lib/SketchSharedStylesManger.js
- +75 −0 lib/SketchWrapper.js
- +4 −0 lib/components/index.js
- +27 −0 lib/createComponent.js
- +44 −0 lib/index.js
- +281 −0 lib/shared.js
- +1 −0 lib/types.js
- +45 −0 package.json
- +414 −0 react-example.sketchplugin/Contents/Sketch/Layer From Props.js
- +20,067 −0 react-example.sketchplugin/Contents/Sketch/Test React.js
- +442 −0 react-example.sketchplugin/Contents/Sketch/Test Run.js
- +39 −0 react-example.sketchplugin/Contents/Sketch/manifest.json
- +100 −0 src/ReactSketchComponent.js
- +31 −0 src/ReactSketchDefaultInjection.js
- +63 −0 src/ReactSketchMount.js
- +45 −0 src/ReactSketchReconcileTransaction.js
- +65 −0 src/SketchCache.js
- +54 −0 src/SketchElements.js
- +23 −0 src/SketchSharedStylesManager.js
- +3 −0 src/components/index.js
- +20 −0 src/createComponent.js
- +16 −0 src/index.js
- +335 −0 src/shared.js
- +19 −0 src/types.js
- +1 −0 symlink-plugin.sh
- +33 −0 webpack.config.js
3
.babelrc
| @@ -0,0 +1,3 @@ | ||
| +{ | ||
| + "presets": ["es2015", "react", "stage-0"] | ||
| +} |
30
.eslintrc
| @@ -0,0 +1,30 @@ | ||
| +{ | ||
| + "parser": "babel-eslint", | ||
| + "extends": "airbnb", | ||
| + "globals": { | ||
| + "ReactComponent": true, | ||
| + "React$Component": true, | ||
| + "ReactClass": true, | ||
| + "log": true, | ||
| + "React$Element": true, | ||
| + "COSAlertWindow": true, | ||
| + "NSTextField": true, | ||
| + "NSString": true, | ||
| + "NSFont": true, | ||
| + "NSTextView": true, | ||
| + "NSView": true, | ||
| + "MSRect": true, | ||
| + "NSMakeRect": true, | ||
| + "MSColor": true, | ||
| + "MSShapeGroup": true, | ||
| + "MSArtboardGroup": true, | ||
| + "MSOvalShape": true, | ||
| + "MSTextLayer": true, | ||
| + "MSLayerGroup": true, | ||
| + "MSRectangleShape": true | ||
| + }, | ||
| + "rules": { | ||
| + "no-underscore-dangle": 0, | ||
| + "new-cap": 0 | ||
| + } | ||
| +} |
34
.flowconfig
| @@ -0,0 +1,34 @@ | ||
| +[ignore] | ||
| +# Ignore react and fbjs where there are overlaps, but don't ignore | ||
| +# anything that react-native relies on | ||
| +.*/node_modules/fbjs.* | ||
| +.*/node_modules/babel.* | ||
| +.*/node_modules/babylon.* | ||
| + | ||
| +# npm3 and other tooling interop is so fun | ||
| +.*/examples/.*/node_modules | ||
| +.*/node_modules/binary-extensions.* | ||
| +.*/node_modules/builtin-modules.* | ||
| +.*/node_modules/jasmine-es6.* | ||
| +.*/node_modules/json5.* | ||
| +.*/node_modules/resolve.* | ||
| +.*/node_modules/spdx-exceptions.* | ||
| +.*/node_modules/spdx-license-ids.* | ||
| +.*/node_modules/ua-parser-js.* | ||
| +.*/node_modules/y18n.* | ||
| +.*/node_modules/iconv-lite.* | ||
| +.*/node_modules/is-my-json-valid.* | ||
| + | ||
| +.*/_backup | ||
| +.*/docs | ||
| + | ||
| +[include] | ||
| + | ||
| +[libs] | ||
| +types/fbjs.js | ||
| +types/sketch.js | ||
| + | ||
| +[options] | ||
| +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\) | ||
| + | ||
| +esproposal.class_static_fields=enable |
| @@ -0,0 +1,6 @@ | ||
| +# dependencies | ||
| +node_modules/ | ||
| + | ||
| +# log | ||
| +npm-debug.log | ||
| +.DS_Store |
147
README.md
| @@ -0,0 +1,147 @@ | ||
| +# react-sketch | ||
| + | ||
| +Declarative bridge to Sketch.app. | ||
| + | ||
| +WIP; not ready for public consumption yet! | ||
| + | ||
| +## Running example scripts | ||
| +Make sure Sketch automatically reloads plugins: | ||
| +``` | ||
| +defaults write ~/Library/Preferences/com.bohemiancoding.sketch3.plist AlwaysReloadScript -bool YES | ||
| +``` | ||
| + | ||
| +Clone the repo and symlink the examples: | ||
| +``` | ||
| +git clone git@github.com:jongold/react-sketchapp.git | ||
| +cd react-sketchapp | ||
| +./symlink-plugin.sh | ||
| +``` | ||
| + | ||
| +## Using react-sketchapp | ||
| +Check out: | ||
| +``` | ||
| +webpack.config.js | ||
| +example-plugin/ | ||
| + *.js (raw sources) | ||
| +react-example.sketchplugin | ||
| + Contents/ | ||
| + Sketch/ | ||
| + manifest.json | ||
| + *.js (compiled code) | ||
| +``` | ||
| + | ||
| +You'll want to create a new repo, create a similar build process to ^^^, and implement your handler ~= this: | ||
| + | ||
| +``` | ||
| +import { render } from 'react-sketchapp'; | ||
| + | ||
| +const document = () => ( | ||
| + <artboard> | ||
| + <group> | ||
| + <rect x={10} y={10} height={10} width={10} /> | ||
| + <oval x={10} y={10} height={10} width={10} /> | ||
| + <text value='yoooo' /> | ||
| + </group> | ||
| + </artboard> | ||
| +); | ||
| + | ||
| +const onRun = (context) => { | ||
| + render(document, context, (element) => { | ||
| + console.log(element) | ||
| + }); | ||
| +}; | ||
| +``` | ||
| + | ||
| +## Documentation | ||
| +WIP! | ||
| +``` | ||
| +<artboard /> | ||
| +type Artboard = { | ||
| + name?: string, | ||
| + children?: any, | ||
| + paddingTop?: number, | ||
| + paddingRight?: number, | ||
| + paddingBottom?: number, | ||
| + paddingLeft?: number, | ||
| + backgroundColor?: string, | ||
| +}; | ||
| + | ||
| +<rect /> | ||
| +export type Rect = { | ||
| + name?: string, | ||
| + x: number, | ||
| + y: number, | ||
| + width: number, | ||
| + height: number, | ||
| + radius?: number, | ||
| + locked?: boolean, | ||
| + backgroundColor?: string, | ||
| +} | ||
| + | ||
| +<oval /> | ||
| +export type Oval = { | ||
| + name?: string, | ||
| + x: number, | ||
| + y: number, | ||
| + width: number, | ||
| + height: number, | ||
| + locked?: boolean, | ||
| + backgroundColor?: string, | ||
| +} | ||
| + | ||
| +<group /> | ||
| +export type Group = { | ||
| + name?: string, | ||
| + x?: number, | ||
| + y?: number, | ||
| + locked?: boolean, | ||
| + clickThrough?: boolean, | ||
| + children: any[], | ||
| +} | ||
| + | ||
| +<text> | ||
| +export type Text = { | ||
| + name?: string, | ||
| + value: string, | ||
| + uppercase?: boolean, | ||
| + fontFamily: string, | ||
| + fontSize: number, | ||
| + color?: string, | ||
| + lineHeight?: number, | ||
| + opacity?: number, | ||
| + x?: number, | ||
| + y?: number, | ||
| + letterSpacing?: number, | ||
| + align?: 'left' | 'right' | 'center' | 'full', | ||
| + locked?: boolean, | ||
| +} | ||
| +``` | ||
| + | ||
| +## Further Reading & inspiration | ||
| +### React Renderers | ||
| +- [Dustan Hufar - tiny-react-renderer](https://github.com/iamdustan/tiny-react-renderer) | ||
| + | ||
| +- [Dustan Hufar - react-hardware](https://github.com/iamdustan/react-hardware) | ||
| + | ||
| +- [Dustan Hufar - React renderer directory](http://iamdustan.com/react-renderers/) | ||
| + | ||
| +- [Gosha Arinich - Making custom renderers for React](http://goshakkk.name/react-custom-renderers/) | ||
| + | ||
| +- [Flipboard - react-canvas](https://github.com/Flipboard/react-canvas) | ||
| + | ||
| +- 🎥 [Jafar Husain — Beyond The DOM](https://www.youtube.com/watch?v=eNC0mRYGWgc) | ||
| + | ||
| +### Sketch Plugins | ||
| +- Creating custom UIs https://github.com/romannurik/sketch-nibuitemplateplugin | ||
| + | ||
| +- Interacting with binaries https://github.com/abynim/Sketch-PluginHelper | ||
| + | ||
| +- CocoaScript reference https://sketchplugindev.james.ooo/interacting-with-objective-c-classes-in-cocoascript-68be7f39616f#.e2fndxvpp | ||
| + | ||
| +- Fluid for Sketch - provides a means to create constraint-based designs. Shows custom UI and interacts with a framework https://github.com/matt-curtis/Fluid-for-Sketch https://github.com/matt-curtis/Sketch-Plugin-Framework | ||
| + | ||
| +- Create shapes from props https://github.com/elliotekj/specify | ||
| + | ||
| +### Development | ||
| +``` | ||
| +``` |
No changes.
| @@ -0,0 +1,86 @@ | ||
| +const { drawRectangle, drawOval, initialize, utils } = require('../src/shared'); | ||
| + | ||
| +// CocoaScript doesn't like strict equality checks. | ||
| +const cocoaEqual = (a, b) => a == b; // eslint-disable-line | ||
| + | ||
| +const onRun = (context) => { | ||
| + const { artboard, page } = initialize(context); | ||
| + | ||
| + const alert = COSAlertWindow.new(); | ||
| + alert.setMessageText('Create a shape from props'); | ||
| + alert.addButtonWithTitle('Ok'); | ||
| + alert.addButtonWithTitle('Cancel'); | ||
| + | ||
| + const viewWidth = 300; | ||
| + const viewHeight = 250; | ||
| + // const viewSpacer = 10; | ||
| + const view = NSView.alloc().initWithFrame( | ||
| + NSMakeRect(0, 0, viewWidth, viewHeight) | ||
| + ); | ||
| + alert.addAccessoryView(view); | ||
| + | ||
| + const typeLabel = utils.createLabel( | ||
| + NSMakeRect(0, viewHeight - 20, viewWidth, 20), | ||
| + 'Type' | ||
| + ); | ||
| + view.addSubview(typeLabel); | ||
| + | ||
| + const typeTextField = NSTextField.alloc().initWithFrame( | ||
| + NSMakeRect(0, viewHeight - 40, viewWidth, 20) | ||
| + ); | ||
| + typeTextField.setStringValue('Rect'); | ||
| + view.addSubview(typeTextField); | ||
| + | ||
| + const propsLabel = utils.createLabel( | ||
| + NSMakeRect(0, viewHeight - 80, viewWidth, 20), | ||
| + 'Props' | ||
| + ); | ||
| + view.addSubview(propsLabel); | ||
| + | ||
| + const propsTextView = NSTextView.alloc().initWithFrame( | ||
| + NSMakeRect(0, viewHeight - 120, viewWidth, 40) | ||
| + ); | ||
| + propsTextView.setAutomaticQuoteSubstitutionEnabled(false); | ||
| + propsTextView.setString(`{ | ||
| + "name": "Test Layer", | ||
| + "x": 20, | ||
| + "y": 20, | ||
| + "width": 100, | ||
| + "height": 100, | ||
| + "radius": 2, | ||
| + "backgroundColor": "#01b0f0" | ||
| + }`); | ||
| + propsTextView.textStorage().setFont(NSFont.fontWithName_size('Menlo', 11)); | ||
| + | ||
| + view.addSubview(propsTextView); | ||
| + | ||
| + const response = alert.runModal(); | ||
| + | ||
| + if (cocoaEqual(response, 1000)) { | ||
| + const rawProps = propsTextView.string(); | ||
| + const props = JSON.parse(rawProps); | ||
| + const type = typeTextField.stringValue(); | ||
| + | ||
| + let layer; | ||
| + | ||
| + if (cocoaEqual(type, 'Rect')) { | ||
| + layer = drawRectangle(props); | ||
| + } | ||
| + | ||
| + if (cocoaEqual(type, 'Oval')) { | ||
| + layer = drawOval(props); | ||
| + } | ||
| + | ||
| + if (layer) { | ||
| + if (artboard) { | ||
| + artboard.addLayers([layer]); | ||
| + } else { | ||
| + page.addLayers([layer]); | ||
| + } | ||
| + | ||
| + layer.setIsSelected(true); | ||
| + } | ||
| + } | ||
| +}; | ||
| + | ||
| +module.exports = onRun; |
| @@ -0,0 +1,85 @@ | ||
| +import React from 'react'; | ||
| +import { render } from '../src'; | ||
| + | ||
| +const colors = { | ||
| + gray: '#F3F4F4', | ||
| + sur: '#96DBE4', | ||
| + peach: '#EFADA0', | ||
| + pear: '#93DAAB', | ||
| +}; | ||
| + | ||
| +const document = ( | ||
| + <group> | ||
| + <group name="✌️ My group"> | ||
| + <oval | ||
| + name="👏 Creative Cloud" | ||
| + x={20} | ||
| + y={20} | ||
| + width={100} | ||
| + height={100} | ||
| + backgroundColor={colors.sur} | ||
| + /> | ||
| + <rect | ||
| + name="👏 Shout it out loud" | ||
| + x={140} | ||
| + y={20} | ||
| + width={150} | ||
| + height={100} | ||
| + radius={100} | ||
| + backgroundColor={colors.peach} | ||
| + /> | ||
| + <rect | ||
| + name="👏 Gather the crowd" | ||
| + x={70} | ||
| + y={140} | ||
| + width={100} | ||
| + height={100} | ||
| + radius={2} | ||
| + backgroundColor={colors.pear} | ||
| + /> | ||
| + </group> | ||
| + | ||
| + <group name="✌️ Text tho" x={300}> | ||
| + <text | ||
| + name="👏 Gather the crowd" | ||
| + value="Gather the crowd" | ||
| + x={20} | ||
| + y={20} | ||
| + makeTextStyle | ||
| + color={colors.peach} | ||
| + fontFamily="GTAmericaTrial-Bold" | ||
| + fontSize={24} | ||
| + lineHeight={36} | ||
| + /> | ||
| + | ||
| + <text | ||
| + name="👏 Shout it aloud" | ||
| + value="Shout it aloud" | ||
| + x={20} | ||
| + y={60} | ||
| + makeTextStyle | ||
| + color={colors.peach} | ||
| + fontFamily="GTAmericaTrialExpanded-Bold" | ||
| + fontSize={24} | ||
| + lineHeight={36} | ||
| + /> | ||
| + | ||
| + <text | ||
| + value="Creative Cloud" | ||
| + makeTextStyle={false} | ||
| + x={20} | ||
| + y={100} | ||
| + color={colors.peach} | ||
| + fontFamily="GTAmericaTrialCondensed-Bold" | ||
| + fontSize={24} | ||
| + lineHeight={36} | ||
| + /> | ||
| + </group> | ||
| + </group> | ||
| +); | ||
| + | ||
| +const onRun = (context) => { | ||
| + render(document, context); | ||
| +}; | ||
| + | ||
| +module.exports = onRun; |
Oops, something went wrong.
0 comments on commit
66b6988