From 0222fda811f66c617fa8415d56f5bf5fc5f47962 Mon Sep 17 00:00:00 2001
From: macintoshhelper
Date: Thu, 2 Apr 2020 18:30:29 +0100
Subject: [PATCH 1/5] create vx-primitives package with initial setup
---
packages/vx-primitives/.npmrc | 1 +
packages/vx-primitives/README.md | 9 ++
packages/vx-primitives/package.json | 49 ++++++++++
packages/vx-primitives/src/VxPrimitives.ts | 92 +++++++++++++++++++
packages/vx-primitives/src/core.android.ts | 10 ++
packages/vx-primitives/src/core.ios.ts | 10 ++
packages/vx-primitives/src/core.native.ts | 55 +++++++++++
packages/vx-primitives/src/core.sketch.ts | 56 +++++++++++
packages/vx-primitives/src/core.ts | 4 +
packages/vx-primitives/src/core.web.ts | 31 +++++++
packages/vx-primitives/src/index.ts | 1 +
.../vx-primitives/src/modules/Platform.ts | 25 +++++
12 files changed, 343 insertions(+)
create mode 100644 packages/vx-primitives/.npmrc
create mode 100644 packages/vx-primitives/README.md
create mode 100644 packages/vx-primitives/package.json
create mode 100644 packages/vx-primitives/src/VxPrimitives.ts
create mode 100644 packages/vx-primitives/src/core.android.ts
create mode 100644 packages/vx-primitives/src/core.ios.ts
create mode 100644 packages/vx-primitives/src/core.native.ts
create mode 100644 packages/vx-primitives/src/core.sketch.ts
create mode 100644 packages/vx-primitives/src/core.ts
create mode 100644 packages/vx-primitives/src/core.web.ts
create mode 100644 packages/vx-primitives/src/index.ts
create mode 100644 packages/vx-primitives/src/modules/Platform.ts
diff --git a/packages/vx-primitives/.npmrc b/packages/vx-primitives/.npmrc
new file mode 100644
index 000000000..43c97e719
--- /dev/null
+++ b/packages/vx-primitives/.npmrc
@@ -0,0 +1 @@
+package-lock=false
diff --git a/packages/vx-primitives/README.md b/packages/vx-primitives/README.md
new file mode 100644
index 000000000..35b7b816a
--- /dev/null
+++ b/packages/vx-primitives/README.md
@@ -0,0 +1,9 @@
+# @vx/primitives
+
+
+
+
+
+The `@vx/primitives` package is here to help you make cross-platform apps.
+
+Inspired by https://github.com/lelandrichardson/react-primitives and https://github.com/chengyin/react-primitives-svg.
diff --git a/packages/vx-primitives/package.json b/packages/vx-primitives/package.json
new file mode 100644
index 000000000..4c449e26f
--- /dev/null
+++ b/packages/vx-primitives/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "@vx/primitives",
+ "version": "0.0.195",
+ "description": "vx primitives",
+ "sideEffects": false,
+ "main": "lib/index.js",
+ "module": "esm/index.js",
+ "types": "lib/index.d.ts",
+ "files": [
+ "lib",
+ "esm"
+ ],
+ "scripts": {
+ "docs": "cd ./docs && ../../../node_modules/.bin/react-docgen ../src/components | ../../../scripts/buildDocs.sh"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/hshoff/vx.git"
+ },
+ "keywords": [
+ "vx",
+ "react",
+ "d3",
+ "visualizations",
+ "charts"
+ ],
+ "author": "@macintoshhelper",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/hshoff/vx/issues"
+ },
+ "homepage": "https://github.com/hshoff/vx#readme",
+ "dependencies": {
+ "@types/lodash": "^4.14.146",
+ "@types/react": "*",
+ "lodash": "^4.17.10",
+ "prop-types": "^15.6.1"
+ },
+ "peerDependencies": {
+ "react": "^15.0.0-0 || ^16.0.0-0"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "react-native-svg": "^12.0.3",
+ "react-sketchapp": "^3.1.1"
+ }
+}
diff --git a/packages/vx-primitives/src/VxPrimitives.ts b/packages/vx-primitives/src/VxPrimitives.ts
new file mode 100644
index 000000000..59d275add
--- /dev/null
+++ b/packages/vx-primitives/src/VxPrimitives.ts
@@ -0,0 +1,92 @@
+import { ReactNode } from 'react';
+
+import Platform from './modules/Platform';
+
+type Primitives = {
+ Svg?: ReactNode | string;
+
+ Circle?: ReactNode | string;
+ ClipPath?: ReactNode | string;
+ Defs?: ReactNode | string;
+ Ellipse?: ReactNode | string;
+ G?: ReactNode | string;
+ Image?: ReactNode | string;
+ Line?: ReactNode | string;
+ LinearGradient?: ReactNode | string;
+ Path?: ReactNode | string;
+ Pattern?: ReactNode | string;
+ Polygon?: ReactNode | string;
+ Polyline?: ReactNode | string;
+ RadialGradient?: ReactNode | string;
+ Rect?: ReactNode | string;
+ Stop?: ReactNode | string;
+ Symbol?: ReactNode | string;
+ Text?: ReactNode | string;
+ TextPath?: ReactNode | string;
+ TSpan?: ReactNode | string;
+ Use?: ReactNode | string;
+ Platform: typeof Platform;
+};
+
+const VxPrimitives: Primitives & { inject: (elements: Primitives) => void } = {
+ /* Svg primitives: */
+ Svg: null,
+
+ Circle: null,
+ ClipPath: null,
+ Defs: null,
+ Ellipse: null,
+ G: null,
+ Image: null,
+ Line: null,
+ LinearGradient: null,
+ Path: null,
+ Pattern: null,
+ Polygon: null,
+ Polyline: null,
+ RadialGradient: null,
+ Rect: null,
+ Stop: null,
+ Symbol: null,
+ Text: null,
+ TextPath: null,
+ TSpan: null,
+ Use: null,
+
+ // Touchable: null,
+ // View: null,
+ // Text: null,
+ // Dimensions: null,
+ // PixelRatio: require('./modules/PixelRatio'),
+ Platform,
+ inject: api => {
+ [
+ 'Svg',
+ 'Circle',
+ 'Ellipse',
+ 'G',
+ 'LinearGradient',
+ 'RadialGradient',
+ 'Line',
+ 'Path',
+ 'Polygon',
+ 'Polyline',
+ 'Rect',
+ 'Symbol',
+ 'Text',
+ 'Use',
+ 'Defs',
+ 'Stop',
+ ].forEach(k => {
+ if (api[k]) {
+ VxPrimitives[k] = api[k];
+ }
+ });
+
+ if (api.Platform) {
+ VxPrimitives['Platform'].inject(api.Platform);
+ }
+ },
+};
+
+export default VxPrimitives;
diff --git a/packages/vx-primitives/src/core.android.ts b/packages/vx-primitives/src/core.android.ts
new file mode 100644
index 000000000..556930b76
--- /dev/null
+++ b/packages/vx-primitives/src/core.android.ts
@@ -0,0 +1,10 @@
+import './core.native';
+
+import VxPrimitives from './VxPrimitives';
+
+VxPrimitives.inject({
+ Platform: {
+ OS: 'android',
+ Version: 1,
+ },
+});
diff --git a/packages/vx-primitives/src/core.ios.ts b/packages/vx-primitives/src/core.ios.ts
new file mode 100644
index 000000000..5a32a1751
--- /dev/null
+++ b/packages/vx-primitives/src/core.ios.ts
@@ -0,0 +1,10 @@
+import './core.native';
+
+import VxPrimitives from './VxPrimitives';
+
+VxPrimitives.inject({
+ Platform: {
+ OS: 'ios',
+ Version: 1,
+ },
+});
diff --git a/packages/vx-primitives/src/core.native.ts b/packages/vx-primitives/src/core.native.ts
new file mode 100644
index 000000000..f6075eb9f
--- /dev/null
+++ b/packages/vx-primitives/src/core.native.ts
@@ -0,0 +1,55 @@
+import {
+ Svg,
+ Circle,
+ ClipPath,
+ Defs,
+ Ellipse,
+ G,
+ Image,
+ Line,
+ LinearGradient,
+ Path,
+ Pattern,
+ Polygon,
+ Polyline,
+ RadialGradient,
+ Rect,
+ Stop,
+ Symbol,
+ Text,
+ TextPath,
+ TSpan,
+ Use,
+} from 'react-native-svg';
+
+import VxPrimitives from './VxPrimitives';
+
+VxPrimitives.inject({
+ Svg,
+ Circle,
+ ClipPath,
+ Ellipse,
+ G,
+ Image,
+ LinearGradient,
+ RadialGradient,
+ Line,
+ Path,
+ Pattern,
+ Polygon,
+ Polyline,
+ Rect,
+ Symbol,
+ Text,
+ TextPath,
+ TSpan,
+ Use,
+ Defs,
+ Stop,
+ Platform: {
+ OS: 'native',
+ Version: 1,
+ },
+});
+
+module.exports = VxPrimitives;
diff --git a/packages/vx-primitives/src/core.sketch.ts b/packages/vx-primitives/src/core.sketch.ts
new file mode 100644
index 000000000..402f63a0d
--- /dev/null
+++ b/packages/vx-primitives/src/core.sketch.ts
@@ -0,0 +1,56 @@
+import { Svg } from 'react-sketchapp';
+
+const {
+ Circle,
+ ClipPath,
+ Defs,
+ Ellipse,
+ G,
+ Image,
+ Line,
+ LinearGradient,
+ Path,
+ Pattern,
+ Polygon,
+ Polyline,
+ RadialGradient,
+ Rect,
+ Stop,
+ Symbol,
+ Text,
+ TextPath,
+ TSpan,
+ Use,
+} = Svg;
+
+import VxPrimitives from './VxPrimitives';
+
+VxPrimitives.inject({
+ Svg,
+ Circle,
+ ClipPath,
+ Ellipse,
+ G,
+ Image,
+ LinearGradient,
+ RadialGradient,
+ Line,
+ Path,
+ Pattern,
+ Polygon,
+ Polyline,
+ Rect,
+ Symbol,
+ Text,
+ TextPath,
+ TSpan,
+ Use,
+ Defs,
+ Stop,
+ Platform: {
+ OS: 'sketch',
+ Version: 1,
+ },
+});
+
+module.exports = VxPrimitives;
diff --git a/packages/vx-primitives/src/core.ts b/packages/vx-primitives/src/core.ts
new file mode 100644
index 000000000..2511f7a96
--- /dev/null
+++ b/packages/vx-primitives/src/core.ts
@@ -0,0 +1,4 @@
+// Default to web implementation if there is no platform extension resolver
+if (typeof window !== 'undefined') {
+ require('./core.web');
+}
diff --git a/packages/vx-primitives/src/core.web.ts b/packages/vx-primitives/src/core.web.ts
new file mode 100644
index 000000000..dab193a36
--- /dev/null
+++ b/packages/vx-primitives/src/core.web.ts
@@ -0,0 +1,31 @@
+import 'react-dom';
+
+import VxPrimitives from './VxPrimitives';
+
+VxPrimitives.inject({
+ Svg: 'svg',
+ Circle: 'circle',
+ ClipPath: 'clipPath',
+ Ellipse: 'ellipse',
+ G: 'g',
+ Image: 'image',
+ LinearGradient: 'linearGradient',
+ RadialGradient: 'radialGradient',
+ Line: 'line',
+ Path: 'path',
+ Pattern: 'pattern',
+ Polygon: 'polygon',
+ Polyline: 'polyline',
+ Rect: 'rect',
+ Symbol: 'symbol',
+ Text: 'text',
+ TextPath: 'textPath',
+ TSpan: 'tspan',
+ Use: 'use',
+ Defs: 'defs',
+ Stop: 'stop',
+ Platform: {
+ OS: 'web',
+ Version: 1,
+ },
+});
diff --git a/packages/vx-primitives/src/index.ts b/packages/vx-primitives/src/index.ts
new file mode 100644
index 000000000..0b879cb24
--- /dev/null
+++ b/packages/vx-primitives/src/index.ts
@@ -0,0 +1 @@
+module.exports = require('./core');
diff --git a/packages/vx-primitives/src/modules/Platform.ts b/packages/vx-primitives/src/modules/Platform.ts
new file mode 100644
index 000000000..4cba12db7
--- /dev/null
+++ b/packages/vx-primitives/src/modules/Platform.ts
@@ -0,0 +1,25 @@
+const { hasOwnProperty } = Object.prototype;
+
+type PlatformType = {
+ OS: string;
+ Version: number;
+};
+
+const Platform: PlatformType & { select?: (Object) => void; inject?: (PlatformType) => void } = {
+ OS: 'unknown',
+ Version: 0,
+ select: obj => {
+ if (hasOwnProperty.call(obj, Platform.OS)) {
+ return obj[Platform.OS];
+ }
+ return obj.default;
+ },
+ inject: platform => {
+ // Use bracket accessor notation as workaround for
+ // https://github.com/facebook/metro-bundler/issues/27
+ Platform['OS'] = platform.OS; // eslint-disable-line dot-notation
+ Platform['Version'] = platform.Version; // eslint-disable-line dot-notation
+ },
+};
+
+export default Platform;
From 8eb3412356e053153bf9a136b4a86a356716b3f9 Mon Sep 17 00:00:00 2001
From: macintoshhelper
Date: Fri, 3 Apr 2020 01:21:19 +0100
Subject: [PATCH 2/5] port initial components (shapes/gradients) to
@vx/primitives
---
packages/vx-geo/src/graticule/Graticule.tsx | 16 +++++++++++-----
packages/vx-geo/src/projections/Projection.tsx | 13 +++++++------
.../vx-gradient/src/gradients/LinearGradient.tsx | 15 ++++++++-------
packages/vx-group/src/Group.tsx | 15 ++++++++-------
packages/vx-shape/package.json | 1 +
packages/vx-shape/src/shapes/Bar.tsx | 9 ++++++++-
packages/vx-shape/src/shapes/Pie.tsx | 11 ++++++++---
7 files changed, 51 insertions(+), 29 deletions(-)
diff --git a/packages/vx-geo/src/graticule/Graticule.tsx b/packages/vx-geo/src/graticule/Graticule.tsx
index 24fe746c7..0d1512c24 100644
--- a/packages/vx-geo/src/graticule/Graticule.tsx
+++ b/packages/vx-geo/src/graticule/Graticule.tsx
@@ -3,6 +3,7 @@ import { Group } from '@vx/group';
import { geoGraticule, GeoGraticuleGenerator } from 'd3-geo';
// eslint-disable-next-line import/no-unresolved
import { LineString, MultiLineString, Polygon } from 'geojson';
+import { G, Path } from '@vx/primitives';
export type GraticuleProps = {
/**
@@ -67,16 +68,21 @@ export default function Graticule({
return (
{graticule && (
-
+
)}
{lines &&
currGraticule.lines().map((line, i) => (
-
-
-
+
+
+
))}
{outline && (
-
+
)}
);
diff --git a/packages/vx-geo/src/projections/Projection.tsx b/packages/vx-geo/src/projections/Projection.tsx
index f0daa9155..ab171de32 100644
--- a/packages/vx-geo/src/projections/Projection.tsx
+++ b/packages/vx-geo/src/projections/Projection.tsx
@@ -14,6 +14,7 @@ import {
} from 'd3-geo';
// eslint-disable-next-line import/no-unresolved
import { LineString, Polygon, MultiLineString } from 'geojson';
+import { Platform, G, Path } from '@vx/primitives';
import Graticule, { GraticuleProps } from '../graticule/Graticule';
import { GeoPermissibleObjects, ProjectionPreset, Projection as ProjectionShape } from '../types';
@@ -172,15 +173,15 @@ export default function Projection({
)}
{features.map((feature, i) => (
-
-
+
{centroid && centroid(feature.centroid, feature)}
-
+
))}
{/* TODO: Maybe find a different way to pass projection function to use for example invert */}
diff --git a/packages/vx-gradient/src/gradients/LinearGradient.tsx b/packages/vx-gradient/src/gradients/LinearGradient.tsx
index e8caa5977..c83e9d0e8 100644
--- a/packages/vx-gradient/src/gradients/LinearGradient.tsx
+++ b/packages/vx-gradient/src/gradients/LinearGradient.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { Stop, Defs, LinearGradient as SvgLinearGradient } from '@vx/primitives';
type LinearGradientOwnProps = {
/** Unique id for the gradient. Should be unique across all page elements. */
@@ -65,20 +66,20 @@ export default function LinearGradient({
y2 = '1';
}
return (
-
-
+
{!!children && children}
- {!children && }
- {!children && }
-
-
+ {!children && }
+ {!children && }
+
+
);
}
diff --git a/packages/vx-group/src/Group.tsx b/packages/vx-group/src/Group.tsx
index e62a73ba4..92f1537c1 100644
--- a/packages/vx-group/src/Group.tsx
+++ b/packages/vx-group/src/Group.tsx
@@ -1,12 +1,13 @@
-import React from 'react';
+import React, { ReactNode } from 'react';
import cx from 'classnames';
+import { Platform, G } from '@vx/primitives';
type GroupProps = {
top?: number;
left?: number;
transform?: string;
className?: string;
- children?: React.ReactNode;
+ children?: ReactNode;
innerRef?: React.Ref;
};
@@ -20,13 +21,13 @@ export default function Group({
...restProps
}: GroupProps & Omit, keyof GroupProps>) {
return (
- }
+ className={Platform.OS === 'web' ? cx('vx-group', className) : undefined}
transform={transform || `translate(${left}, ${top})`}
- {...restProps}
+ {...(restProps as any)}
>
{children}
-
+
);
}
diff --git a/packages/vx-shape/package.json b/packages/vx-shape/package.json
index c3c6c9d4b..44c7b7f21 100644
--- a/packages/vx-shape/package.json
+++ b/packages/vx-shape/package.json
@@ -30,6 +30,7 @@
"@types/react": "*",
"@vx/curve": "0.0.195",
"@vx/group": "0.0.195",
+ "@vx/primitives": "0.0.195",
"classnames": "^2.2.5",
"d3-path": "^1.0.5",
"d3-shape": "^1.2.0",
diff --git a/packages/vx-shape/src/shapes/Bar.tsx b/packages/vx-shape/src/shapes/Bar.tsx
index e29b1388d..e449d8bfd 100644
--- a/packages/vx-shape/src/shapes/Bar.tsx
+++ b/packages/vx-shape/src/shapes/Bar.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import cx from 'classnames';
+import { Platform, Rect } from '@vx/primitives';
export type BarProps = {
/** className to apply to rect element. */
@@ -13,5 +14,11 @@ export default function Bar({
innerRef,
...restProps
}: BarProps & Omit, keyof BarProps>) {
- return ;
+ return (
+
+ );
}
diff --git a/packages/vx-shape/src/shapes/Pie.tsx b/packages/vx-shape/src/shapes/Pie.tsx
index 74f282e93..204ebc797 100644
--- a/packages/vx-shape/src/shapes/Pie.tsx
+++ b/packages/vx-shape/src/shapes/Pie.tsx
@@ -2,6 +2,7 @@
import React from 'react';
import cx from 'classnames';
import { Group } from '@vx/group';
+import { Platform, G, Path } from '@vx/primitives';
import {
arc as d3Arc,
Arc as ArcType,
@@ -99,10 +100,14 @@ export default function Pie({
return (
{arcs.map((arc, i) => (
-
-
+
+
{centroid && centroid(path.centroid(arc), arc)}
-
+
))}
);
From 947b92a6191c7a88c1eda9fac8eed6500ccd0846 Mon Sep 17 00:00:00 2001
From: macintoshhelper
Date: Fri, 3 Apr 2020 01:24:46 +0100
Subject: [PATCH 3/5] fix injection in @vx/primitives
---
.../src/@types/react-native/index.d.ts | 315 ++++++++++++++++++
packages/vx-primitives/src/VxPrimitives.ts | 88 +++--
packages/vx-primitives/src/core.ts | 4 +-
packages/vx-primitives/src/core.web.ts | 2 +
packages/vx-primitives/src/index.ts | 72 +++-
.../vx-primitives/src/modules/Platform.ts | 2 +-
6 files changed, 451 insertions(+), 32 deletions(-)
create mode 100644 packages/vx-primitives/src/@types/react-native/index.d.ts
diff --git a/packages/vx-primitives/src/@types/react-native/index.d.ts b/packages/vx-primitives/src/@types/react-native/index.d.ts
new file mode 100644
index 000000000..716e1d6f9
--- /dev/null
+++ b/packages/vx-primitives/src/@types/react-native/index.d.ts
@@ -0,0 +1,315 @@
+
+declare module 'react-native' {
+ const a: any;
+
+ export default a;
+ export const GestureResponderHandlers: any;
+ export const ImageProps: any;
+ export interface ViewProperties { [key: string]: any }
+
+ type NodeHandle = number;
+
+
+ type Falsy = undefined | null | false;
+ interface RecursiveArray extends Array | RecursiveArray> { }
+ /** Keep a brand of 'T' so that calls to `StyleSheet.flatten` can take `RegisteredStyle` and return `T`. */
+ type RegisteredStyle = number & { __registeredStyleBrand: T };
+ export type StyleProp = T | RegisteredStyle | RecursiveArray | Falsy> | Falsy;
+
+ /**
+ * @see https://facebook.github.io/react-native/docs/image.html
+ */
+ export interface ImagePropsBase {
+ /**
+ * onLayout function
+ *
+ * Invoked on mount and layout changes with
+ *
+ * {nativeEvent: { layout: {x, y, width, height} }}.
+ */
+ onLayout?: (event: any) => void;
+
+ /**
+ * Invoked on load error with {nativeEvent: {error}}
+ */
+ onError?: (error: NativeSyntheticEvent) => void;
+
+ /**
+ * Invoked when load completes successfully
+ * { source: { url, height, width } }.
+ */
+ onLoad?: (event: NativeSyntheticEvent) => void;
+
+ /**
+ * Invoked when load either succeeds or fails
+ */
+ onLoadEnd?: () => void;
+
+ /**
+ * Invoked on load start
+ */
+ onLoadStart?: () => void;
+
+ progressiveRenderingEnabled?: boolean;
+
+ borderRadius?: number;
+
+ borderTopLeftRadius?: number;
+
+ borderTopRightRadius?: number;
+
+ borderBottomLeftRadius?: number;
+
+ borderBottomRightRadius?: number;
+
+ /**
+ * Determines how to resize the image when the frame doesn't match the raw
+ * image dimensions.
+ *
+ * 'cover': Scale the image uniformly (maintain the image's aspect ratio)
+ * so that both dimensions (width and height) of the image will be equal
+ * to or larger than the corresponding dimension of the view (minus padding).
+ *
+ * 'contain': Scale the image uniformly (maintain the image's aspect ratio)
+ * so that both dimensions (width and height) of the image will be equal to
+ * or less than the corresponding dimension of the view (minus padding).
+ *
+ * 'stretch': Scale width and height independently, This may change the
+ * aspect ratio of the src.
+ *
+ * 'repeat': Repeat the image to cover the frame of the view.
+ * The image will keep it's size and aspect ratio. (iOS only)
+ *
+ * 'center': Scale the image down so that it is completely visible,
+ * if bigger than the area of the view.
+ * The image will not be scaled up.
+ */
+ resizeMode?: any;
+
+ /**
+ * The mechanism that should be used to resize the image when the image's dimensions
+ * differ from the image view's dimensions. Defaults to `auto`.
+ *
+ * - `auto`: Use heuristics to pick between `resize` and `scale`.
+ *
+ * - `resize`: A software operation which changes the encoded image in memory before it
+ * gets decoded. This should be used instead of `scale` when the image is much larger
+ * than the view.
+ *
+ * - `scale`: The image gets drawn downscaled or upscaled. Compared to `resize`, `scale` is
+ * faster (usually hardware accelerated) and produces higher quality images. This
+ * should be used if the image is smaller than the view. It should also be used if the
+ * image is slightly bigger than the view.
+ *
+ * More details about `resize` and `scale` can be found at http://frescolib.org/docs/resizing-rotating.html.
+ *
+ * @platform android
+ */
+ resizeMethod?: 'auto' | 'resize' | 'scale';
+
+ /**
+ * The image source (either a remote URL or a local file resource).
+ *
+ * This prop can also contain several remote URLs, specified together with their width and height and potentially with scale/other URI arguments.
+ * The native side will then choose the best uri to display based on the measured size of the image container.
+ * A cache property can be added to control how networked request interacts with the local cache.
+ *
+ * The currently supported formats are png, jpg, jpeg, bmp, gif, webp (Android only), psd (iOS only).
+ */
+ source: any;
+
+ /**
+ * similarly to `source`, this property represents the resource used to render
+ * the loading indicator for the image, displayed until image is ready to be
+ * displayed, typically after when it got downloaded from network.
+ */
+ loadingIndicatorSource?: any;
+
+ /**
+ * A unique identifier for this element to be used in UI Automation testing scripts.
+ */
+ testID?: string;
+
+ /**
+ * A static image to display while downloading the final image off the network.
+ */
+ defaultSource?: any | number;
+ }
+
+ /**
+ * Image style
+ * @see https://facebook.github.io/react-native/docs/image.html#style
+ * @see https://github.com/facebook/react-native/blob/master/Libraries/Image/ImageStylePropTypes.js
+ */
+ export interface ImageStyle {
+ resizeMode?: any;
+ backfaceVisibility?: 'visible' | 'hidden';
+ borderBottomLeftRadius?: number;
+ borderBottomRightRadius?: number;
+ backgroundColor?: string;
+ borderColor?: string;
+ borderWidth?: number;
+ borderRadius?: number;
+ borderTopLeftRadius?: number;
+ borderTopRightRadius?: number;
+ overflow?: 'visible' | 'hidden';
+ overlayColor?: string;
+ tintColor?: string;
+ opacity?: number;
+ }
+
+ export interface ImageProps extends ImagePropsBase {
+ /**
+ *
+ * Style
+ */
+ style?: StyleProp;
+ }
+
+
+ export interface NativeSyntheticEvent extends React.BaseSyntheticEvent { }
+
+
+ export interface NativeTouchEvent {
+ /**
+ * Array of all touch events that have changed since the last event
+ */
+ changedTouches: NativeTouchEvent[];
+
+ /**
+ * The ID of the touch
+ */
+ identifier: string;
+
+ /**
+ * The X position of the touch, relative to the element
+ */
+ locationX: number;
+
+ /**
+ * The Y position of the touch, relative to the element
+ */
+ locationY: number;
+
+ /**
+ * The X position of the touch, relative to the screen
+ */
+ pageX: number;
+
+ /**
+ * The Y position of the touch, relative to the screen
+ */
+ pageY: number;
+
+ /**
+ * The node id of the element receiving the touch event
+ */
+ target: string;
+
+ /**
+ * A time identifier for the touch, useful for velocity calculation
+ */
+ timestamp: number;
+
+ /**
+ * Array of all current touches on the screen
+ */
+ touches: NativeTouchEvent[];
+ }
+
+ export interface GestureResponderEvent extends NativeSyntheticEvent { }
+
+
+ export interface GestureResponderHandlers {
+ /**
+ * A view can become the touch responder by implementing the correct negotiation methods.
+ * There are two methods to ask the view if it wants to become responder:
+ */
+
+ /**
+ * Does this view want to become responder on the start of a touch?
+ */
+ onStartShouldSetResponder?: (event: GestureResponderEvent) => boolean;
+
+ /**
+ * Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness?
+ */
+ onMoveShouldSetResponder?: (event: GestureResponderEvent) => boolean;
+
+ /**
+ * If the View returns true and attempts to become the responder, one of the following will happen:
+ */
+
+ onResponderEnd?: (event: GestureResponderEvent) => void;
+
+ /**
+ * The View is now responding for touch events.
+ * This is the time to highlight and show the user what is happening
+ */
+ onResponderGrant?: (event: GestureResponderEvent) => void;
+
+ /**
+ * Something else is the responder right now and will not release it
+ */
+ onResponderReject?: (event: GestureResponderEvent) => void;
+
+ /**
+ * If the view is responding, the following handlers can be called:
+ */
+
+ /**
+ * The user is moving their finger
+ */
+ onResponderMove?: (event: GestureResponderEvent) => void;
+
+ /**
+ * Fired at the end of the touch, ie "touchUp"
+ */
+ onResponderRelease?: (event: GestureResponderEvent) => void;
+
+ onResponderStart?: (event: GestureResponderEvent) => void;
+
+ /**
+ * Something else wants to become responder.
+ * Should this view release the responder? Returning true allows release
+ */
+ onResponderTerminationRequest?: (event: GestureResponderEvent) => boolean;
+
+ /**
+ * The responder has been taken from the View.
+ * Might be taken by other views after a call to onResponderTerminationRequest,
+ * or might be taken by the OS without asking (happens with control center/ notification center on iOS)
+ */
+ onResponderTerminate?: (event: GestureResponderEvent) => void;
+
+ /**
+ * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern,
+ * where the deepest node is called first.
+ * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers.
+ * This is desirable in most cases, because it makes sure all controls and buttons are usable.
+ *
+ * However, sometimes a parent will want to make sure that it becomes responder.
+ * This can be handled by using the capture phase.
+ * Before the responder system bubbles up from the deepest component,
+ * it will do a capture phase, firing on*ShouldSetResponderCapture.
+ * So if a parent View wants to prevent the child from becoming responder on a touch start,
+ * it should have a onStartShouldSetResponderCapture handler which returns true.
+ */
+ onStartShouldSetResponderCapture?: (event: GestureResponderEvent) => boolean;
+
+ /**
+ * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern,
+ * where the deepest node is called first.
+ * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers.
+ * This is desirable in most cases, because it makes sure all controls and buttons are usable.
+ *
+ * However, sometimes a parent will want to make sure that it becomes responder.
+ * This can be handled by using the capture phase.
+ * Before the responder system bubbles up from the deepest component,
+ * it will do a capture phase, firing on*ShouldSetResponderCapture.
+ * So if a parent View wants to prevent the child from becoming responder on a touch start,
+ * it should have a onStartShouldSetResponderCapture handler which returns true.
+ */
+ onMoveShouldSetResponderCapture?: (event: GestureResponderEvent) => boolean;
+ }
+}
diff --git a/packages/vx-primitives/src/VxPrimitives.ts b/packages/vx-primitives/src/VxPrimitives.ts
index 59d275add..ee7149b30 100644
--- a/packages/vx-primitives/src/VxPrimitives.ts
+++ b/packages/vx-primitives/src/VxPrimitives.ts
@@ -3,32 +3,65 @@ import { ReactNode } from 'react';
import Platform from './modules/Platform';
type Primitives = {
- Svg?: ReactNode | string;
-
- Circle?: ReactNode | string;
- ClipPath?: ReactNode | string;
- Defs?: ReactNode | string;
- Ellipse?: ReactNode | string;
- G?: ReactNode | string;
- Image?: ReactNode | string;
- Line?: ReactNode | string;
- LinearGradient?: ReactNode | string;
- Path?: ReactNode | string;
- Pattern?: ReactNode | string;
- Polygon?: ReactNode | string;
- Polyline?: ReactNode | string;
- RadialGradient?: ReactNode | string;
- Rect?: ReactNode | string;
- Stop?: ReactNode | string;
- Symbol?: ReactNode | string;
- Text?: ReactNode | string;
- TextPath?: ReactNode | string;
- TSpan?: ReactNode | string;
- Use?: ReactNode | string;
- Platform: typeof Platform;
+ Svg: null | ReactNode | string;
+ Circle: null | ReactNode | string;
+ ClipPath: null | ReactNode | string;
+ Defs: null | ReactNode | string;
+ Ellipse: null | ReactNode | string;
+ G: null | ReactNode | string;
+ Image: null | ReactNode | string;
+ Line: null | ReactNode | string;
+ LinearGradient: null | ReactNode | string;
+ Path: null | ReactNode | string;
+ Pattern: null | ReactNode | string;
+ Polygon: null | ReactNode | string;
+ Polyline: null | ReactNode | string;
+ RadialGradient: null | ReactNode | string;
+ Rect: null | ReactNode | string;
+ Stop: null | ReactNode | string;
+ Symbol: null | ReactNode | string;
+ Text: null | ReactNode | string;
+ TextPath: null | ReactNode | string;
+ TSpan: null | ReactNode | string;
+ Use: null | ReactNode | string;
+ Platform: {
+ OS: string;
+ Version: number;
+ } & {
+ select?: ((_: any) => void) | undefined;
+ inject?: ((_: { OS: string; Version: number }) => void) | undefined;
+ };
+ inject: (
+ api: {
+ [key: string]: any;
+ } & {
+ Platform: {
+ OS: string;
+ Version: number;
+ };
+ },
+ ) => void;
};
-const VxPrimitives: Primitives & { inject: (elements: Primitives) => void } = {
+type SvgElement =
+ | 'Svg'
+ | 'Circle'
+ | 'Ellipse'
+ | 'G'
+ | 'LinearGradient'
+ | 'RadialGradient'
+ | 'Line'
+ | 'Path'
+ | 'Polygon'
+ | 'Polyline'
+ | 'Rect'
+ | 'Symbol'
+ | 'Text'
+ | 'Use'
+ | 'Defs'
+ | 'Stop';
+
+const VxPrimitives: Primitives = {
/* Svg primitives: */
Svg: null,
@@ -59,7 +92,7 @@ const VxPrimitives: Primitives & { inject: (elements: Primitives) => void } = {
// Dimensions: null,
// PixelRatio: require('./modules/PixelRatio'),
Platform,
- inject: api => {
+ inject: (api: { [key: string]: any } & { Platform: { OS: string; Version: number } }) => {
[
'Svg',
'Circle',
@@ -77,13 +110,14 @@ const VxPrimitives: Primitives & { inject: (elements: Primitives) => void } = {
'Use',
'Defs',
'Stop',
- ].forEach(k => {
+ // @ts-ignore
+ ].forEach((k: SvgElement) => {
if (api[k]) {
VxPrimitives[k] = api[k];
}
});
-
if (api.Platform) {
+ // @ts-ignore
VxPrimitives['Platform'].inject(api.Platform);
}
},
diff --git a/packages/vx-primitives/src/core.ts b/packages/vx-primitives/src/core.ts
index 2511f7a96..e9b7cb114 100644
--- a/packages/vx-primitives/src/core.ts
+++ b/packages/vx-primitives/src/core.ts
@@ -1,4 +1,2 @@
// Default to web implementation if there is no platform extension resolver
-if (typeof window !== 'undefined') {
- require('./core.web');
-}
+module.exports = require('./core.web');
diff --git a/packages/vx-primitives/src/core.web.ts b/packages/vx-primitives/src/core.web.ts
index dab193a36..127434551 100644
--- a/packages/vx-primitives/src/core.web.ts
+++ b/packages/vx-primitives/src/core.web.ts
@@ -29,3 +29,5 @@ VxPrimitives.inject({
Version: 1,
},
});
+
+module.exports = VxPrimitives;
diff --git a/packages/vx-primitives/src/index.ts b/packages/vx-primitives/src/index.ts
index 0b879cb24..08253e9ef 100644
--- a/packages/vx-primitives/src/index.ts
+++ b/packages/vx-primitives/src/index.ts
@@ -1 +1,71 @@
-module.exports = require('./core');
+// @ts-ignore
+declare module '@vx/primitives' {
+ import { FunctionComponent, ReactNode, ComponentClass } from 'react';
+ import {
+ CommonPathProps,
+ ImageProps,
+ LineProps,
+ LinearGradientProps,
+ PathProps,
+ PatternProps,
+ EllipseProps,
+ DefinitionProps,
+ SvgProps,
+ PolygonProps,
+ PolylineProps,
+ RadialGradientProps,
+ RectProps,
+ StopProps,
+ SymbolProps,
+ TextProps,
+ TextPathProps,
+ TSpanProps,
+ UseProps,
+ GProps,
+ } from 'react-native-svg';
+
+ // type BaseSvgElement = FunctionComponent<{ className?: string | undefined, children?: ReactNode }>
+ type BaseProps = { className?: string; ref?: any };
+
+ export const Defs: ComponentClass;
+ export const Ellipse: ComponentClass;
+ export const G: ComponentClass;
+ export const Image: ComponentClass;
+ export const Line: ComponentClass;
+ export const LinearGradient: ComponentClass;
+ export const Path: ComponentClass;
+ export const Pattern: ComponentClass;
+ export const Polygon: ComponentClass;
+ export const Polyline: ComponentClass;
+ export const RadialGradient: ComponentClass;
+ export const Rect: ComponentClass;
+ export const Stop: ComponentClass;
+ export const Symbol: ComponentClass;
+ export const Text: ComponentClass;
+ export const TextPath: ComponentClass;
+ export const TSpan: ComponentClass;
+ export const Use: ComponentClass;
+
+ export const Platform: {
+ OS: string;
+ Version: number;
+ } & {
+ select?: ((_: any) => void) | undefined;
+ inject?: ((_: { OS: string; Version: number }) => void) | undefined;
+ };
+
+ export const inject: (
+ api: {
+ [key: string]: any;
+ } & {
+ Platform: {
+ OS: string;
+ Version: number;
+ };
+ },
+ ) => void;
+}
+
+const _core = require('./core');
+
+module.exports = _core;
diff --git a/packages/vx-primitives/src/modules/Platform.ts b/packages/vx-primitives/src/modules/Platform.ts
index 4cba12db7..5f490a57a 100644
--- a/packages/vx-primitives/src/modules/Platform.ts
+++ b/packages/vx-primitives/src/modules/Platform.ts
@@ -5,7 +5,7 @@ type PlatformType = {
Version: number;
};
-const Platform: PlatformType & { select?: (Object) => void; inject?: (PlatformType) => void } = {
+const Platform: PlatformType & { select?: (_: any) => void; inject?: (_: PlatformType) => void } = {
OS: 'unknown',
Version: 0,
select: obj => {
From 0ffdc6215b0b49625ce80c48990891b17c7da412 Mon Sep 17 00:00:00 2001
From: macintoshhelper
Date: Fri, 3 Apr 2020 01:30:00 +0100
Subject: [PATCH 4/5] create vx-demo sketch example
---
packages/vx-demo/src/sketch/README.md | 28 +++++++++
packages/vx-demo/src/sketch/package.json | 44 ++++++++++++++
packages/vx-demo/src/sketch/src/index.js | 56 +++++++++++++++++
packages/vx-demo/src/sketch/src/manifest.json | 17 ++++++
.../vx-demo/src/sketch/src/pages/Bars.jsx | 60 +++++++++++++++++++
5 files changed, 205 insertions(+)
create mode 100644 packages/vx-demo/src/sketch/README.md
create mode 100644 packages/vx-demo/src/sketch/package.json
create mode 100644 packages/vx-demo/src/sketch/src/index.js
create mode 100644 packages/vx-demo/src/sketch/src/manifest.json
create mode 100644 packages/vx-demo/src/sketch/src/pages/Bars.jsx
diff --git a/packages/vx-demo/src/sketch/README.md b/packages/vx-demo/src/sketch/README.md
new file mode 100644
index 000000000..36ce867be
--- /dev/null
+++ b/packages/vx-demo/src/sketch/README.md
@@ -0,0 +1,28 @@
+# react-sketchapp vx demo
+
+Cross platform VX primitives used to render to `react-sketchapp`
+
+## How to use
+
+Download the example or [clone the repo](https://github.com/hshoff/vx):
+
+```bash
+curl https://codeload.github.com/hshoff/vx/tar.gz/master | tar -xz --strip=2 vx-master/packages/vx-demo/src/sketch
+cd sketch
+```
+
+Install the dependencies
+
+```bash
+npm install
+```
+
+Then, open Sketch and navigate to `Plugins → vx-demo: Sketch`
+
+### Run it in Sketch
+
+Run with live reloading in Sketch
+
+```bash
+npm run render
+```
diff --git a/packages/vx-demo/src/sketch/package.json b/packages/vx-demo/src/sketch/package.json
new file mode 100644
index 000000000..b7d2489c2
--- /dev/null
+++ b/packages/vx-demo/src/sketch/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@vx/demo-sketch",
+ "private": true,
+ "version": "1.0.0",
+ "description": "",
+ "skpm": {
+ "main": "vx-demo.sketchplugin",
+ "manifest": "src/manifest.json"
+ },
+ "scripts": {
+ "build": "skpm-build",
+ "watch": "skpm-build --watch",
+ "render": "skpm-build --watch --run",
+ "render:once": "skpm-build --run",
+ "postinstall": "npm run build && skpm-link"
+ },
+ "author": "macintoshhelper",
+ "license": "MIT",
+ "devDependencies": {
+ "@babel/cli": "^7.5.5",
+ "@babel/core": "^7.5.5",
+ "@babel/plugin-proposal-class-properties": "^7.5.5",
+ "@babel/preset-env": "^7.5.5",
+ "@babel/preset-flow": "^7.0.0",
+ "@babel/preset-react": "^7.0.0",
+ "@skpm/builder": "^0.5.16"
+ },
+ "dependencies": {
+ "chroma-js": "^1.2.2",
+ "d3-hierarchy": "^1.1.8",
+ "d3-scale": "^1.0.6",
+ "d3-shape": "^1.3.5",
+ "elemental-react": "^0.1.1",
+ "prop-types": "^15.5.8",
+ "react": "^16.9.0",
+ "react-primitives": "^0.6.0",
+ "react-primitives-svg": "0.0.3",
+ "react-sketchapp": "^3.1.1",
+ "react-test-renderer": "^16.9.0",
+ "styled-components": "^4.3.2",
+ "styled-system": "^5.1.1",
+ "topojson-client": "^3.0.0"
+ }
+}
diff --git a/packages/vx-demo/src/sketch/src/index.js b/packages/vx-demo/src/sketch/src/index.js
new file mode 100644
index 000000000..c5d86425b
--- /dev/null
+++ b/packages/vx-demo/src/sketch/src/index.js
@@ -0,0 +1,56 @@
+import React from 'react';
+import * as PropTypes from 'prop-types';
+import styled from 'styled-components/primitives';
+import { render, Document, Artboard, Page, Text, RedBox } from 'react-sketchapp';
+import {
+ width as styledWidth,
+ position,
+ space,
+ height as styledHeight,
+ color,
+} from 'styled-system';
+import chroma from 'chroma-js';
+import { Svg, Platform } from '@vx/primitives';
+
+import Bars from './pages/Bars';
+
+const Screen = styled(Artboard)`
+ ${styledWidth}
+ ${position}
+ ${space}
+ ${styledHeight}
+ ${color}
+`;
+
+Screen.defaultProps = {
+ width: 360,
+ position: 'relative',
+ ml: 0,
+};
+
+const DocumentContainer = ({ a }) => (
+
+
+
+
+
+
+
+);
+
+DocumentContainer.propTypes = {
+ colors: PropTypes.objectOf(PropTypes.string).isRequired,
+};
+
+export default () => {
+ const data = context.document.documentData();
+ const pages = context.document.pages();
+
+ data.setCurrentPage(pages.firstObject());
+
+ try {
+ render();
+ } catch (err) {
+ render();
+ }
+};
diff --git a/packages/vx-demo/src/sketch/src/manifest.json b/packages/vx-demo/src/sketch/src/manifest.json
new file mode 100644
index 000000000..a89b81e42
--- /dev/null
+++ b/packages/vx-demo/src/sketch/src/manifest.json
@@ -0,0 +1,17 @@
+{
+ "compatibleVersion": 3,
+ "bundleVersion": 1,
+ "commands": [
+ {
+ "name": "vx-demo: Sketch",
+ "identifier": "main",
+ "script": "./index.js"
+ }
+ ],
+ "menu": {
+ "isRoot": true,
+ "items": [
+ "main"
+ ]
+ }
+}
diff --git a/packages/vx-demo/src/sketch/src/pages/Bars.jsx b/packages/vx-demo/src/sketch/src/pages/Bars.jsx
new file mode 100644
index 000000000..cc556ad32
--- /dev/null
+++ b/packages/vx-demo/src/sketch/src/pages/Bars.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { Bar } from '@vx/shape';
+import { Group } from '@vx/group';
+import { GradientTealBlue } from '@vx/gradient';
+import { letterFrequency } from '@vx/mock-data';
+import { scaleBand, scaleLinear } from '@vx/scale';
+
+import { Svg, Rect } from '@vx/primitives';
+
+const data = letterFrequency.slice(5);
+
+// accessors
+const x = d => d.letter;
+const y = d => +d.frequency * 100;
+
+export default ({ width, height }) => {
+ // bounds
+ const xMax = width;
+ const yMax = height - 120;
+
+ // scales
+ const xScale = scaleBand({
+ rangeRound: [0, xMax],
+ domain: data.map(x),
+ padding: 0.4,
+ });
+ const yScale = scaleLinear({
+ rangeRound: [yMax, 0],
+ domain: [0, Math.max(...data.map(y))],
+ });
+
+ return (
+
+ );
+};
From e8ab9d0b8a3a319709eb31195e0df0b2fe2c1ce2 Mon Sep 17 00:00:00 2001
From: macintoshhelper
Date: Sat, 9 May 2020 04:04:22 +0100
Subject: [PATCH 5/5] Update README.md
---
README.md | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index ca216e53a..02b27d96d 100644
--- a/README.md
+++ b/README.md
@@ -25,11 +25,22 @@
-### vx
+### vx-primitives
-vx is a collection of reusable low-level visualization components. vx combines the power of d3 to
+vx-primitives is a collection of reusable cross-platform low-level visualization components. vx combines the power of d3 to
generate your visualization with the benefits of react for updating the DOM.
+This repository is a working fork of [hshoff/vx](https://github.com/hshoff/vx) that adds support for react-primitives platforms.
+
+You can find the working development branch at: https://github.com/elemental-design/vx-primitives/tree/develop
+
+Supported platforms:
+
+- [x] [React Web](https://github.com/facebook/react/tree/master/packages/react-dom)
+- [x] [React Sketch.app](https://github.com/airbnb/react-sketchapp/)
+- [ ] [React Native](https://github.com/facebook/react-native)
+- [ ] [React Native Windows](https://github.com/Microsoft/react-native-windows)
+