react-dom/server#renderToString TypeScript Examples

The following examples show how to use react-dom/server#renderToString. 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: IconButton.tsx    From lucide with ISC License 6 votes vote down vote up
function IconButton({ name, component: IconComponent }: IconButtonProps) {
  const onIconClick = () => {
    const svg = renderToString(<IconComponent/>);

    parent.postMessage({ pluginMessage: {
      type: 'drawIcon',
      icon: { name, svg }
    }}, '*')
  }

  return (
    <button
      key={name}
      aria-label={name}
      onClick={onIconClick}
      className='icon-button'
    >
      <IconComponent />
    </button>
  )
}
Example #2
Source File: article.tsx    From fluent-reader with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
articleView = () => {
        const a = encodeURIComponent(
            this.state.loadFull
                ? this.state.fullContent
                : this.props.item.content
        )
        const h = encodeURIComponent(
            renderToString(
                <>
                    <p className="title">{this.props.item.title}</p>
                    <p className="date">
                        {this.props.item.date.toLocaleString(
                            this.props.locale,
                            { hour12: !this.props.locale.startsWith("zh") }
                        )}
                    </p>
                    <article></article>
                </>
            )
        )
        return `article/article.html?a=${a}&h=${h}&f=${encodeURIComponent(
            this.state.fontFamily
        )}&s=${this.state.fontSize}&d=${this.props.source.textDir}&u=${
            this.props.item.link
        }&m=${this.state.loadFull ? 1 : 0}`
    }
Example #3
Source File: render.tsx    From cra-serverless with MIT License 6 votes vote down vote up
render = (Tree: React.ElementType, path: string) => {
  const context = { helmet: {} as HelmetData }
  const sheets = new ServerStyleSheet()

  const markup = renderToString(
    sheets.collectStyles(
      <HelmetProvider context={context}>
        <StaticRouter location={path}>
          <Tree />
        </StaticRouter>
      </HelmetProvider>,
    ),
  )

  return html
    .replace('<div id="root"></div>', `<div id="root">${markup}</div>`)
    .replace('<title>React App</title>', context.helmet.title.toString())
    .replace('</head>', `${context.helmet.meta.toString()}</head>`)
    .replace('</head>', `${context.helmet.link.toString()}</head>`)
    .replace('</head>', `${sheets.getStyleTags()}</head>`)
    .replace('<body>', `<body ${context.helmet.bodyAttributes.toString()}>`)
}
Example #4
Source File: expectToBeDefault404Page.tsx    From next-page-tester with MIT License 6 votes vote down vote up
export function expectToBeDefault404Page(actual: Element): void {
  const expectedHtml = renderToString(
    <div id={NEXT_ROOT_ELEMENT_ID}>
      <ErrorPage statusCode={404} />
    </div>
  );

  const expectedDocument = parseHTML(expectedHtml);
  const expected = expectedDocument.getElementById(NEXT_ROOT_ELEMENT_ID);
  if (!expected) {
    throw new InternalError(`Missing ${NEXT_ROOT_ELEMENT_ID} div`);
  }

  expectDOMElementsToMatch(actual, expected);
}
Example #5
Source File: top-tracks.ts    From natemoo-re with MIT License 6 votes vote down vote up
export default async function (req: NowRequest, res: NowResponse) {
  let { i, open } = req.query;
  i = Array.isArray(i) ? i[0] : i;
  const item = await topTrack({ index: Number.parseInt(i) });
  
  if (!item) {
      return res.status(404).end();
  }

  if (typeof open !== "undefined") {
    if (item && item.external_urls) {
      res.writeHead(302, {
        Location: item.external_urls.spotify,
      });
      return res.end();
    }
    return res.status(200).end();
  }

  res.setHeader("Content-Type", "image/svg+xml");
  res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");

  const { name: track } = item;
  const { images = [] } = item.album || {};

  const cover = images[images.length - 1]?.url;
  let coverImg = null;
  if (cover) {
    const buff = await (await fetch(cover)).arrayBuffer();
    coverImg = `data:image/jpeg;base64,${Buffer.from(buff).toString("base64")}`;
  }

  const artist = (item.artists || []).map(({ name }) => name).join(", ");
  const text = renderToString(
    Track({ index: Number.parseInt(i), cover: coverImg, artist, track })
  );
  return res.status(200).send(text);
}
Example #6
Source File: now-playing.ts    From natemoo-re with MIT License 6 votes vote down vote up
export default async function (req: NowRequest, res: NowResponse) {
  const {
    item = ({} as any),
    is_playing: isPlaying = false,
    progress_ms: progress = 0,
  } = await nowPlaying();

  const params = decode(req.url.split("?")[1]) as any;

  if (params && typeof params.open !== "undefined") {
    if (item && item.external_urls) {
      res.writeHead(302, {
        Location: item.external_urls.spotify,
      });
      return res.end();
    }
    return res.status(200).end();
  }

  res.setHeader("Content-Type", "image/svg+xml");
  res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");

  const { duration_ms: duration, name: track } = item;
  const { images = [] } = item.album || {};

  const cover = images[images.length - 1]?.url;
  let coverImg = null;
  if (cover) {
    const buff = await (await fetch(cover)).arrayBuffer();
    coverImg = `data:image/jpeg;base64,${Buffer.from(buff).toString("base64")}`;
  }

  const artist = (item.artists || []).map(({ name }) => name).join(", ");
  const text = renderToString(
    Player({ cover: coverImg, artist, track, isPlaying, progress, duration })
  );
  return res.status(200).send(text);
}
Example #7
Source File: [num].ts    From natemoo-re with MIT License 6 votes vote down vote up
export default async function (req: NowRequest, res: NowResponse) {
  const { query: { num }, headers } = req;
  const index = Number.parseInt(num as string) - 1;
  const dest = headers["sec-fetch-dest"] || headers["Sec-Fetch-Dest"];
  const accept = headers['accept'];
  const image = dest ? dest === 'image' : !/text\/html/.test(accept);
  
  const color = await getBlockColor(index);
  if (image) {
    const svg = renderToString(Block({ color }));
    const etag = createHash("md5").update(svg).digest("hex");
    res.setHeader("Content-Type", "image/svg+xml");
    res.setHeader("Cache-Control", "no-cache, max-age=0");
    res.setHeader("Etag", etag);
    return res.status(200).send(svg);
  }
  
  const newColor: string = getNextColor(color);
  await setBlockColor(index, newColor);
  return res.status(204).end();
}
Example #8
Source File: worker.ts    From lucide with ISC License 6 votes vote down vote up
getSvg = async ({ cachedIcons, iconName, size = 24 }: { cachedIcons: LucideIcons, iconName: string, size: number }) => {
  if (!cachedIcons) {
    return;
  }

  console.log( iconName, size)

  const iconNode = cachedIcons.iconNodes[iconName];

  if (iconNode) {
    const IconComponent = createReactComponent(iconName, iconNode)
    const svg = renderToString(createElement(IconComponent, { size }));

    parent.postMessage({ pluginMessage: {
      type: 'drawIcon',
      icon: {
        name: iconName,
        svg,
        size
      }
    }}, '*')

    parent.postMessage({ pluginMessage: {
      type: 'close',
    }}, '*')
  }
}
Example #9
Source File: MapClusterMarker.tsx    From Teyvat.moe with GNU General Public License v3.0 6 votes vote down vote up
createClusterIcon = (cluster: leaflet.MarkerCluster): L.DivIcon => {
  const childMarkers = cluster.getAllChildMarkers() as LExtendedMarker[];
  const childCount = childMarkers.length;
  // Filter by the 'completed' property of each marker.
  const childMarkersCompleted = _.filter(childMarkers, 'completed');
  const childCompletedCount = childMarkersCompleted.length;
  const iconUrl = childMarkers?.[0]?.clusterIconUrl ?? '';

  // Since createClusterIcon is called by Leaflet, we can't use makeStyles.
  // We have to use hard-coded classnames, then define the styles in index.css.
  const iconHTML = renderToString(
    <>
      <img
        className="map-marker-cluster-marker"
        src="/images/icons/marker/marker_blue_bg.svg"
        alt=""
      />
      <b className="map-marker-cluster-label">
        {childCompletedCount}/{childCount}
      </b>
      <img className="map-marker-cluster-img" src={iconUrl} alt="" />
    </>
  );

  const iconSize = 36 + childCount / 3;

  return leaflet.divIcon({
    html: iconHTML,
    className: 'map-marker-cluster',
    iconSize: [iconSize, iconSize], // size of the icon
    shadowSize: [iconSize, iconSize], // size of the shadow
    iconAnchor: [iconSize / 2, iconSize * 0.95],
  });
}
Example #10
Source File: entry.server.tsx    From geist-ui with MIT License 6 votes vote down vote up
export default function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
) {
  let markup = renderToString(<RemixServer context={remixContext} url={request.url} />)
  markup = markup.replace('__STYLES__', CssBaseline.flushToHTML())

  responseHeaders.set('Content-Type', 'text/html')

  return new Response('<!DOCTYPE html>' + markup, {
    status: responseStatusCode,
    headers: responseHeaders,
  })
}
Example #11
Source File: ssr.test.tsx    From frontend-frameworks with MIT License 6 votes vote down vote up
describe('ssr', () => {
  it('should render accessibility transformation with accessibility', function (done) {
    const ElementImageHtml = renderToString(<AdvancedImage cldImg={cloudinaryImage} plugins={[accessibility()]} />);
    setTimeout(() => {
      expect(ElementImageHtml).toContain('https://res.cloudinary.com/demo/image/upload/co_black,e_colorize:70/sample');
      done();
    }, 0);// one tick
  });

  it('should render the placeholder image in SSR', function (done) {
    const ElementImageHtml = renderToString(<AdvancedImage cldImg={cloudinaryImage} plugins={[placeholder()]} />);
    setTimeout(() => {
      expect(ElementImageHtml).toContain('https://res.cloudinary.com/demo/image/upload/e_vectorize/q_auto/f_svg/sample');
      done();
    }, 0);// one tick
  });

  it('should render original image when responsive', function (done) {
    const ElementImageHtml = renderToString(<AdvancedImage cldImg={cloudinaryImage} plugins={[responsive()]} />);
    setTimeout(() => {
      expect(ElementImageHtml).toContain('https://res.cloudinary.com/demo/image/upload/sample');
      done();
    }, 0);// one tick
  });

  it('should render original image when lazy loaded', function (done) {
    const ElementImageHtml = renderToString(<AdvancedImage cldImg={cloudinaryImage} plugins={[lazyload()]} />);
    setTimeout(() => {
      expect(ElementImageHtml).toContain('https://res.cloudinary.com/demo/image/upload/sample');
      done();
    }, 0);// one tick
  });
});
Example #12
Source File: entry.server.tsx    From tweet2image with MIT License 6 votes vote down vote up
export default function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext
) {
  const markup = renderToString(
    <RemixServer context={remixContext} url={request.url} />
  )

  responseHeaders.set("Content-Type", "text/html")

  return new Response("<!DOCTYPE html>" + markup, {
    status: responseStatusCode,
    headers: responseHeaders,
  })
}
Example #13
Source File: RegionLabelLayer.tsx    From Teyvat.moe with GNU General Public License v3.0 6 votes vote down vote up
_RegionLabelLayer: FunctionComponent<RegionLabelLayerProps> = ({ displayed, zoomLevel }) => {
  const classes = useStyles();

  const map = useMap();
  const layerReference = useRef<GeoJSONLeaflet | null>(null);

  useEffect(() => {
    if (layerReference.current != null) {
      if (displayed) {
        layerReference.current.addTo(map);
      } else {
        layerReference.current.removeFrom(map);
      }
    }
  }, [map, displayed]);

  const pointToLayer = (featureData: Feature<Point, any>, latLng: LatLng) => {
    const html = renderToString(<RegionLabel featureData={featureData} zoomLevel={zoomLevel} />);

    return LeafletMarker([latLng.lng, latLng.lat], {
      interactive: false, // Allow clicks to pass through.
      icon: LeafletDivIcon({
        html,
        className: classes.regionLabelMarker,
      }),
      zIndexOffset: -900,
    });
  };

  return (
    <GeoJSON
      ref={layerReference}
      key={zoomLevel}
      pointToLayer={pointToLayer}
      data={RegionLabelData as GeoJsonObject}
    />
  );
}
Example #14
Source File: entry.server.tsx    From remix-hexagonal-architecture with MIT License 6 votes vote down vote up
export default function handleRequest(
    request: Request,
    responseStatusCode: number,
    responseHeaders: Headers,
    remixContext: EntryContext
) {
  let markup = renderToString(
      <RemixServer context={remixContext} url={request.url} />
  );

  responseHeaders.set("Content-Type", "text/html");

  return new Response("<!DOCTYPE html>" + markup, {
    status: responseStatusCode,
    headers: responseHeaders,
  });
}
Example #15
Source File: index.tsx    From react-loosely-lazy with Apache License 2.0 6 votes vote down vote up
renderApp = (v: string) => {
  const appContainer = document.querySelector('#app');
  const mode = isRender() ? MODE.RENDER : MODE.HYDRATE;

  if (v === 'SSR' && appContainer && !isFailSsr()) {
    const components = buildServerComponents(mode);
    const ssr = renderToString(<App initialStep={v} components={components} />);
    appContainer.innerHTML = isRender() ? `<div>${ssr}</div>` : ssr;
  }
  if (v === 'PAINT LOADING') {
    const components = buildClientComponents(mode);
    const renderer = isRender() ? render : hydrate;

    renderer(<App initialStep={v} components={components} />, appContainer);
  }
}
Example #16
Source File: index-ssr.tsx    From clearflask with Apache License 2.0 6 votes vote down vote up
renderIndexSsr = (props: {
  i18n: typeof i18n;
  url: string;
  staticRouterContext: StaticRouterContext;
  storesState: StoresState;
  awaitPromises: Array<Promise<any>>;
  renderResult: RenderResult;
  requestedUrl: string;
}) => renderToString(props.renderResult.muiSheets.collect(
  <ChunkExtractorManager extractor={props.renderResult.extractor}>
    <WindowIsoSsrProvider
      fetch={fetch}
      apiBasePath={connectConfig.apiBasePath}
      url={props.requestedUrl}
      setTitle={newTitle => props.renderResult.title = newTitle}
      setFaviconUrl={newFaviconUrl => props.renderResult.faviconUrl = newFaviconUrl}
      setMaxAge={maxAge => props.renderResult.maxAge = maxAge}
      storesState={props.storesState}
      awaitPromises={props.awaitPromises}
      staticRouterContext={props.staticRouterContext}
      parentDomain={connectConfig.parentDomain}
    >
      <Main
        i18n={props.i18n}
        ssrLocation={props.url}
        ssrStaticRouterContext={props.staticRouterContext}
      />
    </WindowIsoSsrProvider>
  </ChunkExtractorManager>
))
Example #17
Source File: iconNodeToSvg.ts    From lucide with ISC License 5 votes vote down vote up
iconNodeToSvg = (iconName: string, iconNode : IconNode) => {
  const IconComponent = createReactComponent(iconName, iconNode)
  return  renderToString(createElement(IconComponent));
}
Example #18
Source File: entry-server.tsx    From vite-tsconfig-paths with MIT License 5 votes vote down vote up
export function renderPage() {
  return renderToString(<Root />)
}
Example #19
Source File: pageBuilder.tsx    From react-app-architecture with Apache License 2.0 5 votes vote down vote up
export default function pageBuilder(
  req: PublicRequest,
  pageinfo: PageInfo = {
    title: 'AfterAcademy | React Project',
    description: 'This is the sample project to learn and implement React app.',
  },
  currentState: Partial<RootState> = {},
): string {
  // create mui server style
  const sheets = new ServerStyleSheets();

  const authData = req.universalCookies.get(KEY_AUTH_DATA);
  if (authData?.tokens?.accessToken) {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const { tokens, ...data } = authData;
    currentState.authState = {
      data: data, // security
      isLoggingIn: false,
      isLoggingOut: false,
      isLoggedIn: true,
      isForcedLogout: false,
      isRedirectHome: false,
      message: null,
    };
  }

  const store = isDev
    ? configureStore(currentState)
    : createStore(rootReducer, currentState, applyMiddleware(thunk));

  // Render the component to a string
  const html = renderToString(
    sheets.collect(
      <Provider store={store}>
        <CookiesProvider cookies={req.universalCookies}>
          <StaticRouter location={req.url} context={{}}>
            <ThemeProvider theme={theme}>
              <App />
            </ThemeProvider>
          </StaticRouter>
        </CookiesProvider>
      </Provider>,
    ),
  );

  // Grab the CSS from our sheets.
  const css = sheets.toString();

  const baseUrl = `${getProtocol(req)}://${req.get('host')}`;
  const siteUrl = baseUrl + req.originalUrl;

  const { coverImg, title, description } = pageinfo;

  let htmlPage = render({
    html: html,
    css: css,
    preloadedState: store.getState(),
    siteUrl: siteUrl,
    title: title,
    coverImg: coverImg ? coverImg : `${baseUrl}/assets/og-cover-image.jpg`,
    description: description,
  });

  try {
    htmlPage = minifyHtml(htmlPage, {
      minifyCSS: true,
      minifyJS: true,
    });
  } catch (e) {
    console.log(e);
  }

  return htmlPage;
}
Example #20
Source File: server.tsx    From elephize with MIT License 5 votes vote down vote up
server.get('/', (req, res) => {
  const body = renderToString(<App />);
  res.send(html.replace('{{placeholder}}', body));
});
Example #21
Source File: gatsby-ssr.ts    From plasmic with MIT License 5 votes vote down vote up
replaceRenderer = async (
  { bodyComponent, replaceBodyHTMLString }: any,
  opts: GatsbyPluginOptions
) => {
  await fetchServerFiles(opts);
  replaceBodyHTMLString(renderToString(bodyComponent));
}
Example #22
Source File: render.tsx    From elephize with MIT License 5 votes vote down vote up
body = renderToString(<App />)
Example #23
Source File: render.tsx    From vanilla-extract with MIT License 5 votes vote down vote up
render = (route: string, headTags: HeadTags) =>
  renderToString(
    <StaticRouter location={route}>
      <HeadProvider headTags={headTags}>
        <App />
      </HeadProvider>
    </StaticRouter>,
  )
Example #24
Source File: jsx-runtime.test.tsx    From swc-node with MIT License 5 votes vote down vote up
test('should read jsx runtime options from tsconfig', () => {
  expect(renderToString(<Component />)).toMatchInlineSnapshot(`"<div>Hello</div>"`)
})
Example #25
Source File: createServerRender.tsx    From use-platform with MIT License 5 votes vote down vote up
function serverRender(element: ReactElement) {
  const html = renderToString(element)

  return { html }
}
Example #26
Source File: integration.test.tsx    From react-loosely-lazy with Apache License 2.0 4 votes vote down vote up
describe('hydrates', () => {
  const hydrate = true;

  describe('a lazyForPaint component', () => {
    describe('when ssr is true', () => {
      const ssr = true;

      it('by rendering and persisting the server content, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render content
        expect(document.body).toContainHTML('<p class="p">Content</p>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          server: false,
          ssr,
        });

        const { container } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // expect client to use placeholder and persist ssr content
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).toBeInTheDocument();

        await act(resolveImport);

        // expect component to be live after being resolved
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });

    describe('when ssr is false', () => {
      const ssr = false;

      it('by rendering  and persisting the server fallback, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render fallback
        expect(document.body).toContainHTML('<i>Fallback</i>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          server: false,
          ssr,
        });

        const { container } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // expect client to use placeholder and persist ssr fallback
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<i>Fallback</i>');
        expect(container.querySelector('input')).toBeInTheDocument();

        await act(resolveImport);

        // expect component to be live after being resolved
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });
  });

  describe('a lazyAfterPaint component', () => {
    const lazyMethod = lazyAfterPaint;

    describe('when ssr is true', () => {
      const ssr = true;

      it('by rendering and persisting the server content, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          lazyMethod,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render content
        expect(document.body).toContainHTML('<p class="p">Content</p>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          lazyMethod,
          server: false,
          ssr,
        });

        const { container, rerender } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // simulate component being ready on next tick
        await act(resolveImport);

        // expect client to use placeholder and persist ssr content regardless
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).toBeInTheDocument();

        rerender(<ClientApp phase={PHASE.AFTER_PAINT} />);

        await nextTick();

        // expect component to be live after phase changed
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });

    describe('when ssr is false', () => {
      const ssr = false;

      it('by rendering and persisting the server content, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          lazyMethod,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render fallback
        expect(document.body).toContainHTML('<i>Fallback</i>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          lazyMethod,
          server: false,
          ssr,
        });

        const { container, rerender } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // simulate component being ready on next tick
        await act(resolveImport);

        // expect client to use placeholder and persist ssr content
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<i>Fallback</i>');
        expect(container.querySelector('input')).toBeInTheDocument();

        rerender(<ClientApp phase={PHASE.AFTER_PAINT} />);

        await nextTick();

        // expect component to be live after phase changed
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });
  });
});
Example #27
Source File: integration.test.tsx    From react-loosely-lazy with Apache License 2.0 4 votes vote down vote up
describe('renders', () => {
  const hydrate = false;

  describe('a lazyForPaint component', () => {
    describe('when ssr is true', () => {
      const ssr = true;

      it('by rendering and persisting the server content, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render content
        expect(document.body).toContainHTML('<p class="p">Content</p>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          server: false,
          ssr,
        });

        const { container } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // expect client to use placeholder and persist ssr content
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).toBeInTheDocument();

        await act(resolveImport);

        // expect component to be live after being resolved
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });

    describe('when ssr is false', () => {
      const ssr = false;

      it('by rendering and persisting the server fallback, before replacing', async () => {
        const { App: ServerApp } = createApp({
          hydrate,
          server: true,
          ssr,
        });

        document.body.innerHTML = `
          <div id="root">${renderToString(<ServerApp />)}</div>
        `;

        // expect ssr to render fallback
        expect(document.body).toContainHTML('<i>Fallback</i>');
        expect(document.body.querySelector('input')).toBeInTheDocument();

        const {
          App: ClientApp,
          Child,
          resolveImport,
        } = createApp({
          hydrate,
          server: false,
          ssr,
        });

        const { container } = render(<ClientApp />, {
          container: document.getElementById('root') as HTMLElement,
          hydrate,
        });

        // expect client to use placeholder and persist ssr fallback
        expect(Child).not.toHaveBeenCalled();
        expect(container).toContainHTML('<i>Fallback</i>');
        expect(container.querySelector('input')).toBeInTheDocument();

        await act(resolveImport);

        // expect component to be live after being resolved
        expect(Child).toHaveBeenCalled();
        expect(container).toContainHTML('<p class="p">Content</p>');
        expect(container.querySelector('input')).not.toBeInTheDocument();
      });
    });
  });
});
Example #28
Source File: render.tsx    From next-page-tester with MIT License 4 votes vote down vote up
export default async function serverRenderDocument({
  options,
  appProps,
  pageProps,
  pageObject,
  wrapWithRouter,
}: {
  options: ExtendedOptions;
  appProps: PageProps | undefined;
  pageProps: PageProps | undefined;
  pageObject: PageObject;
  wrapWithRouter: (children: JSX.Element) => JSX.Element;
}): Promise<JSX.Element> {
  return executeAsIfOnServer(async () => {
    const { useDocument } = options;
    const {
      documentFile: { default: DocumentComponent },
      appFile: { default: AppComponent },
      pageFile: { default: PageComponent },
      wrappersFile,
    } = pageObject.files.server;

    const wrappers = {
      appWrapper: wrappersFile?.App,
      pageWrapper: wrappersFile?.Page,
    };

    const render = (App: NextApp, Page: NextPage) => {
      return renderEnhancedApp({
        App,
        Page,
        appProps,
        pageProps,
        wrappers,
      });
    };

    // Return an empty dummy document if useDocument is not enabled
    if (!useDocument) {
      return (
        <html>
          <head></head>
          <body>
            <div id={NEXT_ROOT_ELEMENT_ID}>
              {wrapWithRouter(render(AppComponent, PageComponent))}
            </div>
          </body>
        </html>
      );
    }

    const renderPage: RenderPage = (options = {}) => {
      const {
        App: EnhancedApp,
        Component: EnhancedComponent,
      } = enhanceComponents(options, AppComponent, PageComponent);

      let head: JSX.Element[] = [];
      const html = renderToString(
        // @NOTE: implemented from:
        // https://github.com/vercel/next.js/blob/v10.0.3/packages/next/next-server/server/render.tsx#L561
        // Now in: https://github.com/vercel/next.js/blob/v11.1.0/packages/next/server/render.tsx#L639
        <HeadManagerContext.Provider
          value={{
            updateHead: (state) => {
              head = state;
            },
            mountedInstances: new Set(),
          }}
        >
          {wrapWithRouter(render(EnhancedApp, EnhancedComponent))}
        </HeadManagerContext.Provider>
      );
      return { html, head };
    };

    const initialProps = await fetchDocumentData({
      Document: DocumentComponent,
      renderPage,
      pageObject,
    });

    const documentProps: DocumentProps = {
      ...initialProps,
      buildManifest: {
        ampDevFiles: [],
        ampFirstPages: [],
        devFiles: [],
        lowPriorityFiles: [],
        polyfillFiles: [],
        pages: {
          [APP_PATH]: [],
          [pageObject.pagePath]: [],
        },
      },
      __NEXT_DATA__: {
        page: pageObject.pagePath,
        query: pageObject.query,
        buildId: 'next-page-tester',
        props: { pageProps },
      },
      scriptLoader: {},
      docComponentsRendered: {},
      dangerousAsPath: '',
      ampPath: '',
      inAmpMode: false,
      dynamicImports: [],
      isDevelopment: false,
      hybridAmp: false,
      canonicalBase: '',
      headTags: [],
      devOnlyCacheBusterQueryString: '',
      // @ts-expect-error We don't expect to use this method
      useMaybeDeferContent: () => {},
    };

    // @ts-expect-error this method doesn't exist since Next.js v11.1.2 and useDocument option is currently disabled
    return DocumentComponent.renderDocument(DocumentComponent, documentProps);
  });
}
Example #29
Source File: SelectedIcon.tsx    From iconsax-react with MIT License 4 votes vote down vote up
SelectedIcon = () => {
  const { state } = useIconContext()
  const hideIcon = selectedStore((state) => state.hideIcon)
  const selected = selectedStore((state) => state.selected)
  const [isOpen, setIsOpen] = useState<boolean>(!!selected || false)
  const ref = useRef(null)
  const iconRef = useRef<SVGSVGElement>(null)

  const Icon = selected?.Icon

  useEffect(() => {
    if (isOpen) {
      gsap.to(ref.current, {
        y: '0',
        ease: 'expo.inOUt',
        duration: duration / 1000,
      })
    }
  }, [isOpen])
  useEffect(() => {
    setIsOpen(!!selected)
  }, [selected])

  useOnClickOutside(ref, (e) => {
    const path = e.composedPath() as HTMLElement[]
    let isAnIcon = false

    for (let p = 0; p < path.length; p++) {
      if (path[p].classList && path[p].classList.contains('icon')) {
        return (isAnIcon = true)
      }
    }
    if (!isAnIcon) handleClose()
  })

  const handleClose = () => {
    if (!hideIcon) return
    gsap.to(ref.current, {
      y: '500',
      ease: 'expo.inOUt',
      duration: duration / 1000,
    })
    setTimeout(() => {
      hideIcon()
    }, duration)
  }
  const iconSaveName = `${selected?.name}-${state.variant}-${state.size}px`

  const iconString =
    Icon &&
    renderToString(
      <Icon size={state.size} color={state.color} variant={state.variant} />
    )

  const handleCopySvg = () => {
    if (!iconString) return

    copy(iconString)
  }
  const handleDownloadSvg = () => {
    if (!iconString) return
    const blob = new Blob([iconString])
    saveAs(blob, `${iconSaveName}.svg`)
  }
  const handleDownloadPng = async () => {
    if (!iconString) return

    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const v = canvg.fromString(ctx, iconString)
    v.render()
    const img = canvas.toDataURL('image/png')
    console.log(img)
    saveAs(img, `${iconSaveName}.png`)
  }
  return (
    <>
      {isOpen && (
        <div
          ref={ref}
          className="fixed bg-bg p-3 h-72 md:w-96 mx-4 left-0 md:left-auto right-0 bottom-0 rounded-t-3xl border-2 translate-y-[500px] border-border"
        >
          <div className="flex justify-between items-center">
            <span className="font-bold text-md">{selected?.name}</span>
            <span className="cursor-pointer" onClick={handleClose}>
              <CloseCircle color="white" />
            </span>
          </div>
          <div className="flex gap-1 mt-3">
            <div className="flex-1 border-dashed border-2 p-4 border-border rounded-lg">
              {Icon && (
                <Icon size={64} color={state.color} variant={state.variant} />
              )}
            </div>
            <div className="flex-[7] flex flex-col gap-1 text-xs">
              <Button handleClick={handleCopySvg} name="copy#svg" />
              <div className="flex-1 grid grid-cols-2 gap-1">
                <Button handleClick={handleDownloadSvg} name="download#svg" />
                <Button handleClick={handleDownloadPng} name="download#png" />
              </div>
            </div>
          </div>
          <Code name={selected?.name!} />
        </div>
      )}
    </>
  )
}