react-native-navigation的迁移库

LayoutTreeCrawler.ts 2.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import merge from 'lodash/merge'
  2. import isFunction from 'lodash/isFunction'
  3. import { LayoutType } from './LayoutType';
  4. import { OptionsProcessor } from './OptionsProcessor';
  5. import { Store } from '../components/Store';
  6. import { Options } from '../interfaces/Options';
  7. export interface Data {
  8. name?: string;
  9. options?: any;
  10. passProps?: any;
  11. }
  12. export interface LayoutNode {
  13. id: string;
  14. type: LayoutType;
  15. data: Data;
  16. children: LayoutNode[];
  17. }
  18. type ComponentWithOptions = React.ComponentType<any> & { options(passProps: any): Options };
  19. export class LayoutTreeCrawler {
  20. constructor(public readonly store: Store, private readonly optionsProcessor: OptionsProcessor) {
  21. this.crawl = this.crawl.bind(this);
  22. }
  23. crawl(node: LayoutNode): void {
  24. if (node.type === LayoutType.Component) {
  25. this.handleComponent(node);
  26. }
  27. this.optionsProcessor.processOptions(node.data.options);
  28. node.children.forEach(this.crawl);
  29. }
  30. private handleComponent(node: LayoutNode) {
  31. this.assertComponentDataName(node);
  32. this.savePropsToStore(node);
  33. this.applyStaticOptions(node);
  34. node.data.passProps = undefined;
  35. }
  36. private savePropsToStore(node: LayoutNode) {
  37. this.store.updateProps(node.id, node.data.passProps);
  38. }
  39. private isComponentWithOptions(component: any): component is ComponentWithOptions {
  40. return (component as ComponentWithOptions).options !== undefined;
  41. }
  42. private applyStaticOptions(node: LayoutNode) {
  43. node.data.options = merge({}, this.staticOptionsIfPossible(node), node.data.options);
  44. }
  45. private staticOptionsIfPossible(node: LayoutNode) {
  46. const foundReactGenerator = this.store.getComponentClassForName(node.data.name!);
  47. const reactComponent = foundReactGenerator ? foundReactGenerator() : undefined;
  48. if (reactComponent && this.isComponentWithOptions(reactComponent)) {
  49. return isFunction(reactComponent.options) ? reactComponent.options(node.data.passProps || {}) : reactComponent.options;
  50. }
  51. return {};
  52. }
  53. private assertComponentDataName(component: LayoutNode) {
  54. if (!component.data.name) {
  55. throw new Error('Missing component data.name');
  56. }
  57. }
  58. }