react-native-wishlist
Version: 
The fastest List component for React Native.
183 lines (177 loc) • 7.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createTemplateComponent = createTemplateComponent;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _EventHandler = require("./EventHandler");
var _ForEachBase = require("./Components/ForEachBase");
var _InflatorRepository = _interopRequireDefault(require("./InflatorRepository"));
var _Switch = require("./Components/Switch");
var _TemplateContext = require("./TemplateContext");
var _TemplateValue = require("./TemplateValue");
var _Utils = require("./Utils");
var _WishlistContext = require("./WishlistContext");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function setInObject(obj, path, value) {
  'worklet';
  let current = obj;
  for (let i = 0; i < path.length - 1; i++) {
    current[path[i]] = current[path[i]] ?? {};
    current = current[path[i]];
  }
  current[path[path.length - 1]] = value;
}
function traverseObject(obj, callback) {
  const stack = [{
    path: [],
    value: obj
  }];
  while (stack.length > 0) {
    const {
      path,
      value
    } = stack.pop();
    if (value && typeof value === 'object' && !(0, _TemplateValue.isTemplateValue)(value) && !(value instanceof _EventHandler.TemplateCallback) && (path.length === 0 || path[path.length - 1] !== 'children')) {
      Object.keys(value).forEach(key => {
        stack.push({
          path: [...path, key],
          value: value[key]
        });
      });
    } else {
      callback(path, value);
    }
  }
}
function convertToTemplateValue(value, path) {
  let curTemplateType = value;
  return {
    // TODO(janic): Need to call remove for template values created here.
    templateValue: (0, _TemplateValue.createTemplateValue)(() => {
      'worklet';
      return curTemplateType;
    }),
    targetPath: path
  };
}
function createTemplateComponent(Component, addProps) {
  const WishListComponent = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
    let {
      style,
      ...props
    } = _ref;
    const {
      inflatorId
    } = (0, _WishlistContext.useWishlistContext)();
    const {
      templateType
    } = (0, _TemplateContext.useTemplateContext)();
    const nativeId = (0, _react.useMemo)(_Utils.generateId, []);
    const otherPropsMemoized = (0, _react.useMemo)(() => {
      const resolvedStyle = _reactNative.StyleSheet.flatten(style);
      const templateValues = [];
      const templateCallbacks = [];
      const otherProps = {};
      traverseObject({
        ...props,
        style: resolvedStyle
      }, (path, value) => {
        const applyHacks = () => {
          // Text component needs to receive a string child to work properly.
          // @ts-expect-error TODO: fix this.
          if (path[0] === 'children' && Component === _reactNative.Text) {
            setInObject(otherProps, path, ' ');
          }
        };
        if ((0, _TemplateValue.isTemplateValue)(value)) {
          templateValues.push({
            templateValue: value,
            targetPath: path
          });
          applyHacks();
        } else if (value instanceof _EventHandler.TemplateCallback) {
          templateCallbacks.push({
            worklet: value.worklet,
            // Callbacks should never be in objects.
            eventName: value.eventName ?? path[0].replace(/^on/, 'top')
          });
          // Events have a boolean prop associated to know whether the
          // function is set or not, so we still want to pass the prop.
          setInObject(otherProps, path, () => {});
        } else {
          // @ts-expect-error TODO: fix this.
          if (Component === _ForEachBase.ForEachBase && path[0] === 'template') {
            templateValues.push(convertToTemplateValue(value, path));
          }
          if (
          // @ts-expect-error TODO: fix this.
          Component === _Switch.CaseBase && path[0] === 'value' && !(0, _TemplateValue.isTemplateValue)(value)) {
            templateValues.push(convertToTemplateValue(value, path));
          }
          if (
          // @ts-expect-error TODO: fix this.
          Component === _reactNative.Text && path[0] === 'children' && !(0, _TemplateValue.isTemplateValue)(value)) {
            templateValues.push(convertToTemplateValue(value, path));
          }
          setInObject(otherProps, path, value);
        }
      });
      _InflatorRepository.default.registerMapping(inflatorId, nativeId, templateType, (value, templateItem, pool, rootValue) => {
        'worklet';
        templateValues.forEach(_ref2 => {
          let {
            templateValue
          } = _ref2;
          templateValue.__setDirty();
        });
        const propsToSet = {};
        templateValues.forEach(_ref3 => {
          let {
            templateValue,
            targetPath
          } = _ref3;
          setInObject(propsToSet, targetPath, templateValue.value());
        });
        templateCallbacks.forEach(_ref4 => {
          let {
            eventName,
            worklet
          } = _ref4;
          templateItem.setCallback(eventName, ev => {
            worklet(ev, value, rootValue);
          });
        });
        // Styles need to be passed as props.
        const {
          style: styleForProps,
          ...otherPropsToSet
        } = propsToSet;
        const finalPropsToSet = {
          ...otherPropsToSet,
          ...styleForProps
        };
        if (addProps) {
          addProps(templateItem, finalPropsToSet, inflatorId, pool, rootValue);
        } else {
          templateItem.addProps(finalPropsToSet);
        }
      });
      return otherProps;
      // TODO: This will change on every render, if we want this memo to work properly we need
      // to shallow compare the props object.
    }, [inflatorId, nativeId, props, style, templateType]);
    // @ts-expect-error: this is ok.
    return /*#__PURE__*/_react.default.createElement(Component, _extends({}, otherPropsMemoized, {
      ref: ref,
      nativeID: nativeId
    }));
  });
  WishListComponent.displayName = `WishList(${Component.displayName})`;
  return WishListComponent;
}
//# sourceMappingURL=createTemplateComponent.js.map