history#createPath TypeScript Examples

The following examples show how to use history#createPath. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.ts    From react-resource-router with Apache License 2.0 6 votes vote down vote up
createLegacyHistory = (): BrowserHistory => {
  let currentLocation = getLocation();
  let currentAction: HistoryAction = 'PUSH';
  const updateExposedLocation: Listener = (v, a) => {
    currentLocation = v;
    currentAction = a;
  };

  return {
    get location() {
      return currentLocation;
    },
    get length() {
      return hasWindow() ? window.history.length : 1; // default length is 1
    },
    get action() {
      return currentAction;
    },
    ...(hasWindow()
      ? {
          push: (path: string) => window.location.assign(path),
          replace: (path: string) =>
            window.history.replaceState({}, document.title, path),
          goBack: () => window.history.back(),
          goForward: () => window.history.forward(),
          listen: createLegacyListener(updateExposedLocation),
          block: () => noop,
          createHref: (location: Location) => createPath(location),
        }
      : methodsPlaceholders),
  };
}
Example #2
Source File: index.tsx    From react-resource-router with Apache License 2.0 6 votes vote down vote up
componentDidMount() {
    const { to, location, push, params, query, actions } = this.props;
    const routeAttributes = {
      params,
      query,
      basePath: actions.getBasePath(),
    };
    const newPath =
      typeof to === 'object'
        ? 'path' in to
          ? createPath(generateLocationFromPath(to.path, routeAttributes))
          : createPath(to)
        : to;
    const currentPath = createPath(location);
    const action = push ? actions.push : actions.replace;

    if (currentPath === newPath) {
      if (
        process.env.NODE_ENV === 'test' ||
        process.env.NODE_ENV === 'development'
      ) {
        // eslint-disable-next-line no-console
        console.warn(
          `You tried to redirect to the same route you're currently on: "${currentPath}"`
        );
      }

      return;
    }

    action(newPath);
  }
Example #3
Source File: index.tsx    From react-resource-router with Apache License 2.0 4 votes vote down vote up
Link = forwardRef<HTMLButtonElement | HTMLAnchorElement, LinkProps>(
  (
    {
      children,
      target = '_self',
      replace = false,
      href = undefined,
      to = undefined,
      onClick = undefined,
      onMouseEnter = undefined,
      onMouseLeave = undefined,
      type: linkType = 'a',
      params,
      query,
      prefetch = false,
      ...rest
    },
    ref
  ) => {
    const routerActions = useRouterStoreStatic()[1];
    const prefetchRef = useRef<NodeJS.Timeout>();

    const validLinkType = getValidLinkType(linkType);
    const [route, setRoute] = useState<Route | void>(() => {
      if (to && typeof to !== 'string') {
        if ('then' in to)
          to.then(r => setRoute('default' in r ? r.default : r));
        else return to;
      }
    });

    const routeAttributes = {
      params,
      query,
      basePath: routerActions.getBasePath(),
    };
    const linkDestination =
      href != null
        ? href
        : typeof to !== 'string'
        ? (route &&
            createPath(
              generateLocationFromPath(route.path, routeAttributes)
            )) ||
          ''
        : to;

    const triggerPrefetch = useCallback(() => {
      prefetchRef.current = undefined;

      // ignore if async route not ready yet
      if (typeof to !== 'string' && !route) return;

      const context =
        typeof to !== 'string' && route
          ? createRouterContext(route, { params, query })
          : null;
      routerActions.prefetchNextRouteResources(linkDestination, context);
      // omit params & query as already in linkDestination
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [route, linkDestination, routerActions]);

    useEffect(() => {
      let timeout: NodeJS.Timeout;
      if (prefetch === 'mount')
        timeout = setTimeout(triggerPrefetch, PREFETCH_DELAY);

      return () => clearTimeout(timeout);
    }, [prefetch, triggerPrefetch]);

    const handleLinkPress = (e: MouseEvent | KeyboardEvent) =>
      handleNavigation(e, {
        onClick,
        target,
        replace,
        routerActions,
        href: linkDestination,
        to: route && [route, { params, query }],
      });

    const handleMouseEnter = (e: MouseEvent) => {
      if (prefetch === 'hover') {
        prefetchRef.current = setTimeout(triggerPrefetch, PREFETCH_DELAY);
      }
      onMouseEnter && onMouseEnter(e);
    };

    const handleMouseLeave = (e: MouseEvent) => {
      if (prefetch === 'hover' && prefetchRef.current) {
        clearTimeout(prefetchRef.current);
        prefetchRef.current = undefined;
      }
      onMouseLeave && onMouseLeave(e);
    };

    return createElement(
      validLinkType,
      {
        ...rest,
        href: linkDestination,
        target,
        onClick: handleLinkPress,
        onKeyDown: handleLinkPress,
        onMouseEnter: handleMouseEnter,
        onMouseLeave: handleMouseLeave,
        ref,
      },
      children
    );
  }
)
Example #4
Source File: Router.ts    From next-core with GNU General Public License v3.0 4 votes vote down vote up
private async render(location: PluginLocation): Promise<void> {
    this.state = "initial";
    this.renderId = uniqueId("render-id-");

    resetAllInjected();
    clearPollTimeout();

    if (this.locationContext) {
      this.locationContext.resolver.resetRefreshQueue();
    }

    const history = getHistory();
    history.unblock();

    // Create the page tracker before page load.
    // And the API Analyzer maybe disabled.
    const pageTracker = apiAnalyzer.getInstance()?.pageTracker();

    const locationContext = (this.locationContext = new LocationContext(
      this.kernel,
      location
    ));

    const storyboard = locationContext.matchStoryboard(
      this.kernel.bootstrapData.storyboards
    );

    if (storyboard) {
      await this.kernel.fulfilStoryboard(storyboard);

      // 将动态解析后的模板还原,以便重新动态解析。
      restoreDynamicTemplates(storyboard);

      // 预加载权限信息
      if (isLoggedIn() && !getAuth().isAdmin) {
        await preCheckPermissions(storyboard);
      }

      // 如果找到匹配的 storyboard,那么根据路由匹配得到的 sub-storyboard 加载它的依赖库。
      const subStoryboard =
        this.locationContext.getSubStoryboardByRoute(storyboard);
      await this.kernel.loadDepsOfStoryboard(subStoryboard);

      // 注册 Storyboard 中定义的自定义模板和函数。
      this.kernel.registerCustomTemplatesInStoryboard(storyboard);
      registerStoryboardFunctions(storyboard.meta?.functions, storyboard.app);

      registerMock(storyboard.meta?.mocks);

      collectContract(storyboard.meta?.contracts);
    }

    const { mountPoints, currentApp: previousApp } = this.kernel;
    const currentApp = storyboard ? storyboard.app : undefined;
    // Storyboard maybe re-assigned, e.g. when open launchpad.
    const appChanged =
      previousApp && currentApp
        ? previousApp.id !== currentApp.id
        : previousApp !== currentApp;
    const legacy = currentApp ? currentApp.legacy : undefined;
    this.kernel.nextApp = currentApp;
    const layoutType: LayoutType = currentApp?.layoutType || "console";

    setTheme(
      getLocalAppsTheme()?.[currentApp?.id] || currentApp?.theme || "light"
    );
    setMode("default");

    devtoolsHookEmit("rendering");

    unmountTree(mountPoints.bg as MountableElement);

    const redirectToLogin = (): void => {
      history.replace(
        this.featureFlags["sso-enabled"] ? "/sso-auth/login" : "/auth/login",
        {
          from: location,
        }
      );
    };

    if (storyboard) {
      if (appChanged && currentApp.id && isLoggedIn()) {
        const usedCustomApis: CustomApiInfo[] = mapCustomApisToNameAndNamespace(
          scanCustomApisInStoryboard(storyboard)
        );
        if (usedCustomApis?.length) {
          await this.kernel.loadMicroAppApiOrchestrationAsync(usedCustomApis);
        }
      }

      const mountRoutesResult: MountRoutesResult = {
        main: [],
        menuInBg: [],
        menuBar: {},
        portal: [],
        appBar: {
          breadcrumb: [],
          documentId: null,
          noCurrentApp: currentApp.breadcrumb?.noCurrentApp ?? false,
        },
        flags: {
          redirect: undefined,
          hybrid: false,
          failed: false,
        },
      };
      try {
        const specificTemplatePreviewIndex = findLastIndex(
          storyboard.routes,
          (route) =>
            route.path.startsWith(
              "${APP.homepage}/_dev_only_/template-preview/"
            )
        );

        const specificSnippetPreviewIndex = findLastIndex(
          storyboard.routes,
          (route) =>
            route.path.startsWith("${APP.homepage}/_dev_only_/snippet-preview/")
        );
        const mergedRoutes = [
          ...storyboard.routes.slice(0, specificTemplatePreviewIndex + 1),
          ...storyboard.routes.slice(0, specificSnippetPreviewIndex + 1),
          {
            path: "${APP.homepage}/_dev_only_/template-preview/:templateId",
            bricks: [{ brick: "span" }],
            menu: false,
            exact: true,
          } as RouteConf,
          {
            path: "${APP.homepage}/_dev_only_/snippet-preview/:snippetId",
            bricks: [{ brick: "span" }],
            menu: false,
            exact: true,
          } as RouteConf,
          ...storyboard.routes.slice(specificTemplatePreviewIndex + 1),
        ];
        await locationContext.mountRoutes(
          mergedRoutes,
          undefined,
          mountRoutesResult
        );
      } catch (error) {
        // eslint-disable-next-line no-console
        console.error(error);

        // Redirect to login page if not logged in.
        if (isUnauthenticatedError(error) && !window.NO_AUTH_GUARD) {
          mountRoutesResult.flags.unauthenticated = true;
        } else {
          await this.kernel.layoutBootstrap(layoutType);
          const brickPageError = this.kernel.presetBricks.pageError;
          await this.kernel.loadDynamicBricks([brickPageError]);

          mountRoutesResult.flags.failed = true;
          mountRoutesResult.main = [
            {
              type: brickPageError,
              properties: {
                error: httpErrorToString(error),
                code:
                  error instanceof HttpResponseError
                    ? error.response.status
                    : null,
              },
              events: {},
            },
          ];
          mountRoutesResult.portal = [];
        }
      }

      const {
        main,
        menuInBg,
        menuBar,
        appBar,
        flags,
        portal,
        route,
        analyticsData,
      } = mountRoutesResult;

      const { unauthenticated, redirect, barsHidden, hybrid, failed } = flags;

      if (unauthenticated) {
        redirectToLogin();
        return;
      }

      if (redirect) {
        history.replace(redirect.path, redirect.state);
        return;
      }

      if (appChanged) {
        this.kernel.currentApp = currentApp;
        this.kernel.previousApp = previousApp;
      }
      this.kernel.currentUrl = createPath(location);
      this.kernel.currentRoute = route;
      await Promise.all([
        ...(window.STANDALONE_MICRO_APPS
          ? []
          : [this.kernel.updateWorkspaceStack()]),
        this.kernel.layoutBootstrap(layoutType),
      ]);

      this.state = "ready-to-mount";

      // Unmount main tree to avoid app change fired before new routes mounted.
      unmountTree(mountPoints.main as MountableElement);
      unmountTree(mountPoints.portal as MountableElement);

      const actualLegacy =
        (legacy === "iframe" && !hybrid) || (legacy !== "iframe" && hybrid)
          ? "iframe"
          : undefined;
      this.kernel.unsetBars({ appChanged, legacy: actualLegacy });

      if (this.mediaEventTargetHandler) {
        mediaEventTarget.removeEventListener(
          "change",
          this.mediaEventTargetHandler as EventListener
        );
        this.mediaEventTargetHandler = undefined;
      }

      // There is a window to set theme and mode by `lifeCycle.onBeforePageLoad`.
      this.locationContext.handleBeforePageLoad();
      applyTheme();
      applyMode();

      if (appChanged) {
        window.dispatchEvent(
          new CustomEvent<RecentApps>("app.change", {
            detail: this.kernel.getRecentApps(),
          })
        );
      }

      let misc: RuntimeMisc;
      if (
        barsHidden ||
        ((misc = getRuntimeMisc()),
        misc.isInIframeOfSameSite && !misc.isInIframeOfVisualBuilder)
      ) {
        this.kernel.toggleBars(false);
      } else {
        await constructMenu(
          menuBar,
          this.locationContext.getCurrentContext(),
          this.kernel
        );
        if (this.kernel.currentLayout === "console") {
          if (
            shouldBeDefaultCollapsed(
              menuBar.menu?.defaultCollapsed,
              menuBar.menu?.defaultCollapsedBreakpoint
            )
          ) {
            this.kernel.menuBar.collapse(true);
            this.defaultCollapsed = true;
          } else {
            if (this.defaultCollapsed) {
              this.kernel.menuBar.collapse(false);
            }
            this.defaultCollapsed = false;
          }
          if (actualLegacy === "iframe") {
            // Do not modify breadcrumb in iframe mode,
            // it will be *popped* from iframe automatically.
            delete appBar.breadcrumb;
          }
          mountStaticNode(this.kernel.menuBar.element, menuBar);
          mountStaticNode(this.kernel.appBar.element, appBar);
        }
      }

      this.setNavConfig(mountRoutesResult);

      this.kernel.toggleLegacyIframe(actualLegacy === "iframe");

      menuInBg.forEach((brick) => {
        appendBrick(brick, mountPoints.portal as MountableElement);
      });

      if (main.length > 0 || portal.length > 0) {
        main.length > 0 &&
          mountTree(main, mountPoints.main as MountableElement);
        portal.length > 0 &&
          mountTree(portal, mountPoints.portal as MountableElement);

        afterMountTree(mountPoints.main as MountableElement);
        afterMountTree(mountPoints.portal as MountableElement);
        afterMountTree(mountPoints.bg as MountableElement);

        // Scroll to top after each rendering.
        // See https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/guides/scroll-restoration.md
        window.scrollTo(0, 0);

        if (!failed) {
          this.locationContext.handleBrickBindObserver();
          this.locationContext.handlePageLoad();
          this.locationContext.handleAnchorLoad();
          this.locationContext.resolver.scheduleRefreshing();
          this.locationContext.handleMessage();
        }

        this.mediaEventTargetHandler = (event) =>
          this.locationContext.handleMediaChange(event.detail);
        mediaEventTarget.addEventListener(
          "change",
          this.mediaEventTargetHandler as EventListener
        );

        pageTracker?.(locationContext.getCurrentMatch().path);

        // analytics page_view event
        userAnalytics.event("page_view", {
          micro_app_id: this.kernel.currentApp.id,
          route_alias: route?.alias,
          ...analyticsData,
        });

        this.state = "mounted";

        devtoolsHookEmit("rendered");

        // Try to prefetch during a browser's idle periods.
        // https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
        if (typeof window.requestIdleCallback === "function") {
          window.requestIdleCallback(() => {
            this.kernel.prefetchDepsOfStoryboard(storyboard);
          });
        } else {
          Promise.resolve().then(() => {
            this.kernel.prefetchDepsOfStoryboard(storyboard);
          });
        }
        return;
      }
    } else if (!window.NO_AUTH_GUARD && !isLoggedIn()) {
      // Todo(steve): refine after api-gateway supports fetching storyboards before logged in.
      // Redirect to login if no storyboard is matched.
      redirectToLogin();
      return;
    }

    await this.kernel.layoutBootstrap(layoutType);
    const brickPageNotFound = this.kernel.presetBricks.pageNotFound;
    await this.kernel.loadDynamicBricks([brickPageNotFound]);

    this.state = "ready-to-mount";

    mountTree(
      [
        {
          type: brickPageNotFound,
          properties: {
            url: history.createHref(location),
          },
          events: {},
        },
      ],
      mountPoints.main as MountableElement
    );
    unmountTree(mountPoints.portal as MountableElement);

    // Scroll to top after each rendering.
    window.scrollTo(0, 0);

    this.state = "mounted";
    devtoolsHookEmit("rendered");
  }