1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  */
    
  7. 
    
  8. import * as React from 'react';
    
  9. import ReactVersion from 'shared/ReactVersion';
    
  10. import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
    
  11. import {
    
  12.   createContainer,
    
  13.   updateContainer,
    
  14.   injectIntoDevTools,
    
  15. } from 'react-reconciler/src/ReactFiberReconciler';
    
  16. import Transform from 'art/core/transform';
    
  17. import Mode from 'art/modes/current';
    
  18. import FastNoSideEffects from 'art/modes/fast-noSideEffects';
    
  19. 
    
  20. import {TYPES, childrenAsString} from './ReactARTInternals';
    
  21. 
    
  22. Mode.setCurrent(
    
  23.   // Change to 'art/modes/dom' for easier debugging via SVG
    
  24.   FastNoSideEffects,
    
  25. );
    
  26. 
    
  27. /** Declarative fill-type objects; API design not finalized */
    
  28. 
    
  29. const slice = Array.prototype.slice;
    
  30. 
    
  31. class LinearGradient {
    
  32.   constructor(stops, x1, y1, x2, y2) {
    
  33.     this._args = slice.call(arguments);
    
  34.   }
    
  35. 
    
  36.   applyFill(node) {
    
  37.     node.fillLinear.apply(node, this._args);
    
  38.   }
    
  39. }
    
  40. 
    
  41. class RadialGradient {
    
  42.   constructor(stops, fx, fy, rx, ry, cx, cy) {
    
  43.     this._args = slice.call(arguments);
    
  44.   }
    
  45. 
    
  46.   applyFill(node) {
    
  47.     node.fillRadial.apply(node, this._args);
    
  48.   }
    
  49. }
    
  50. 
    
  51. class Pattern {
    
  52.   constructor(url, width, height, left, top) {
    
  53.     this._args = slice.call(arguments);
    
  54.   }
    
  55. 
    
  56.   applyFill(node) {
    
  57.     node.fillImage.apply(node, this._args);
    
  58.   }
    
  59. }
    
  60. 
    
  61. /** React Components */
    
  62. 
    
  63. class Surface extends React.Component {
    
  64.   componentDidMount() {
    
  65.     const {height, width} = this.props;
    
  66. 
    
  67.     this._surface = Mode.Surface(+width, +height, this._tagRef);
    
  68. 
    
  69.     this._mountNode = createContainer(
    
  70.       this._surface,
    
  71.       LegacyRoot,
    
  72.       null,
    
  73.       false,
    
  74.       false,
    
  75.       '',
    
  76.     );
    
  77.     updateContainer(this.props.children, this._mountNode, this);
    
  78.   }
    
  79. 
    
  80.   componentDidUpdate(prevProps, prevState) {
    
  81.     const props = this.props;
    
  82. 
    
  83.     if (props.height !== prevProps.height || props.width !== prevProps.width) {
    
  84.       this._surface.resize(+props.width, +props.height);
    
  85.     }
    
  86. 
    
  87.     updateContainer(this.props.children, this._mountNode, this);
    
  88. 
    
  89.     if (this._surface.render) {
    
  90.       this._surface.render();
    
  91.     }
    
  92.   }
    
  93. 
    
  94.   componentWillUnmount() {
    
  95.     updateContainer(null, this._mountNode, this);
    
  96.   }
    
  97. 
    
  98.   render() {
    
  99.     // This is going to be a placeholder because we don't know what it will
    
  100.     // actually resolve to because ART may render canvas, vml or svg tags here.
    
  101.     // We only allow a subset of properties since others might conflict with
    
  102.     // ART's properties.
    
  103.     const props = this.props;
    
  104. 
    
  105.     // TODO: ART's Canvas Mode overrides surface title and cursor
    
  106.     const Tag = Mode.Surface.tagName;
    
  107. 
    
  108.     return (
    
  109.       <Tag
    
  110.         ref={ref => (this._tagRef = ref)}
    
  111.         accessKey={props.accessKey}
    
  112.         className={props.className}
    
  113.         draggable={props.draggable}
    
  114.         role={props.role}
    
  115.         style={props.style}
    
  116.         tabIndex={props.tabIndex}
    
  117.         title={props.title}
    
  118.       />
    
  119.     );
    
  120.   }
    
  121. }
    
  122. 
    
  123. class Text extends React.Component {
    
  124.   constructor(props) {
    
  125.     super(props);
    
  126.     // We allow reading these props. Ideally we could expose the Text node as
    
  127.     // ref directly.
    
  128.     ['height', 'width', 'x', 'y'].forEach(key => {
    
  129.       Object.defineProperty(this, key, {
    
  130.         get: function () {
    
  131.           return this._text ? this._text[key] : undefined;
    
  132.         },
    
  133.       });
    
  134.     });
    
  135.   }
    
  136.   render() {
    
  137.     // This means you can't have children that render into strings...
    
  138.     const T = TYPES.TEXT;
    
  139.     return (
    
  140.       <T {...this.props} ref={t => (this._text = t)}>
    
  141.         {childrenAsString(this.props.children)}
    
  142.       </T>
    
  143.     );
    
  144.   }
    
  145. }
    
  146. 
    
  147. injectIntoDevTools({
    
  148.   findFiberByHostInstance: () => null,
    
  149.   bundleType: __DEV__ ? 1 : 0,
    
  150.   version: ReactVersion,
    
  151.   rendererPackageName: 'react-art',
    
  152. });
    
  153. 
    
  154. /** API */
    
  155. 
    
  156. export const ClippingRectangle = TYPES.CLIPPING_RECTANGLE;
    
  157. export const Group = TYPES.GROUP;
    
  158. export const Shape = TYPES.SHAPE;
    
  159. export const Path = Mode.Path;
    
  160. export {LinearGradient, Pattern, RadialGradient, Surface, Text, Transform};