@qwik.dev/router 2.0.0-beta.6 → 2.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -12,6 +12,8 @@ import { QRLEventHandlerMulti } from '@qwik.dev/core';
12
12
  import { QwikIntrinsicElements } from '@qwik.dev/core';
13
13
  import { QwikJSX } from '@qwik.dev/core';
14
14
  import type { ReadonlySignal } from '@qwik.dev/core';
15
+ import { Render } from '@qwik.dev/core/server';
16
+ import { RenderOptions } from '@qwik.dev/core/server';
15
17
  import { RequestEvent } from '@qwik.dev/router/middleware/request-handler';
16
18
  import { RequestEventAction } from '@qwik.dev/router/middleware/request-handler';
17
19
  import { RequestEventBase } from '@qwik.dev/router/middleware/request-handler';
@@ -189,6 +191,38 @@ export { CookieOptions }
189
191
 
190
192
  export { CookieValue }
191
193
 
194
+ /**
195
+ * Creates the `render()` function that is required by `createQwikRouter()`. It requires a function
196
+ * that returns the `jsx` and `options` for the renderer.
197
+ *
198
+ * @example
199
+ *
200
+ * ```tsx
201
+ * const renderer = createRenderer((opts) => {
202
+ * if (opts.requestHeaders['x-hello'] === 'world') {
203
+ * return { jsx: <Hello />, options: opts };
204
+ * }
205
+ * return { jsx: <Root />, options: {
206
+ * ...opts,
207
+ * serverData: {
208
+ * ...opts.serverData,
209
+ * documentHead: {
210
+ * meta: [
211
+ * { name: 'renderedAt', content: new Date().toISOString() },
212
+ * ],
213
+ * },
214
+ * },
215
+ * } };
216
+ * });
217
+ * ```
218
+ *
219
+ * @public
220
+ */
221
+ export declare const createRenderer: (getOptions: (options: RendererOptions) => {
222
+ jsx: JSXOutput_2;
223
+ options: RendererOutputOptions;
224
+ }) => Render;
225
+
192
226
  /** @public */
193
227
  export declare type DataValidator<T extends Record<string, any> = {}> = {
194
228
  validate(ev: RequestEvent, data: unknown): Promise<ValidatorReturn<T>>;
@@ -214,14 +248,35 @@ export declare interface DocumentHeadProps extends RouteLocation {
214
248
  readonly resolveValue: ResolveSyncValue;
215
249
  }
216
250
 
251
+ /**
252
+ * This renders all the tags collected from `head`.
253
+ *
254
+ * You can partially override the head, for example if you want to change the title:
255
+ *
256
+ * ```tsx
257
+ * import { DocumentHeadTags, useDocumentHead } from '@qwik.dev/router';
258
+ *
259
+ * export default component$(() => {
260
+ * const head = useDocumentHead();
261
+ * return <DocumentHeadTags title={`${head.title} - My App`} />;
262
+ * });
263
+ * ```
264
+ *
265
+ * You don't have to use this component, you can also do it yourself for full control. Just copy the
266
+ * code from this component and modify it to your needs.
267
+ *
268
+ * Note that this component normally only runs once, during SSR. You can use Signals in your
269
+ * `src/root.tsx` to make runtime changes to `<head>` if needed.
270
+ *
271
+ * @public
272
+ */
273
+ export declare const DocumentHeadTags: Component<DocumentHeadValue<Record<string, unknown>>>;
274
+
217
275
  /** @public */
218
276
  export declare interface DocumentHeadValue<FrontMatter extends Record<string, any> = Record<string, unknown>> {
219
277
  /** Sets `document.title`. */
220
278
  readonly title?: string;
221
- /**
222
- * Used to manually set meta tags in the head. Additionally, the `data` property could be used to
223
- * set arbitrary data which the `<head>` component could later use to generate `<meta>` tags.
224
- */
279
+ /** Used to manually set meta tags in the head. */
225
280
  readonly meta?: readonly DocumentMeta[];
226
281
  /** Used to manually append `<link>` elements to the `<head>`. */
227
282
  readonly links?: readonly DocumentLink[];
@@ -238,53 +293,59 @@ export declare interface DocumentHeadValue<FrontMatter extends Record<string, an
238
293
  }
239
294
 
240
295
  /** @public */
241
- export declare interface DocumentLink {
242
- as?: string;
243
- crossorigin?: string;
244
- disabled?: boolean;
245
- href?: string;
246
- hreflang?: string;
247
- id?: string;
248
- imagesizes?: string;
249
- imagesrcset?: string;
250
- integrity?: string;
251
- media?: string;
252
- prefetch?: string;
253
- referrerpolicy?: string;
254
- rel?: string;
255
- sizes?: string;
256
- title?: string;
257
- type?: string;
258
- key?: string;
259
- }
296
+ export declare type DocumentLink = QwikIntrinsicElements['link'];
260
297
 
261
298
  /** @public */
262
- export declare interface DocumentMeta {
263
- readonly content?: string;
264
- readonly httpEquiv?: string;
265
- readonly name?: string;
266
- readonly property?: string;
267
- readonly key?: string;
268
- readonly itemprop?: string;
269
- readonly media?: string;
270
- }
271
-
272
- /** @beta */
273
- export declare interface DocumentScript {
274
- readonly script?: string;
275
- readonly props?: Readonly<QwikIntrinsicElements['script']>;
276
- readonly key?: string;
277
- }
299
+ export declare type DocumentMeta = QwikIntrinsicElements['meta'];
278
300
 
279
301
  /** @public */
280
- export declare interface DocumentStyle {
281
- readonly style: string;
282
- readonly props?: Readonly<QwikIntrinsicElements['style']>;
283
- readonly key?: string;
284
- }
302
+ export declare type DocumentScript = ((Omit<QwikIntrinsicElements['script'], 'dangerouslySetInnerHTML'> & {
303
+ props?: never;
304
+ }) | {
305
+ key?: string;
306
+ /**
307
+ * The props of the script element. @deprecated Prefer setting the properties directly instead
308
+ * of using this property.
309
+ */
310
+ props: Readonly<QwikIntrinsicElements['script']>;
311
+ }) & ({
312
+ /** The inline script content. */
313
+ script?: string;
314
+ dangerouslySetInnerHTML?: never;
315
+ } | {
316
+ dangerouslySetInnerHTML?: string;
317
+ script?: never;
318
+ });
319
+
320
+ /** @public */
321
+ export declare type DocumentStyle = Readonly<((Omit<QwikIntrinsicElements['style'], 'dangerouslySetInnerHTML'> & {
322
+ props?: never;
323
+ }) | {
324
+ key?: string;
325
+ /**
326
+ * The props of the style element. @deprecated Prefer setting the properties directly
327
+ * instead of using this property.
328
+ */
329
+ props: Readonly<QwikIntrinsicElements['style']>;
330
+ }) & ({
331
+ /** The inline style content. */
332
+ style?: string;
333
+ dangerouslySetInnerHTML?: never;
334
+ } | {
335
+ dangerouslySetInnerHTML?: string;
336
+ style?: never;
337
+ })>;
285
338
 
286
339
  declare type EndpointModuleLoader = () => Promise<RouteModule>;
287
340
 
341
+ declare interface EndpointResponse {
342
+ status: number;
343
+ loaders: Record<string, unknown>;
344
+ loadersSerializationStrategy: Map<string, SerializationStrategy>;
345
+ formData?: FormData;
346
+ action?: string;
347
+ }
348
+
288
349
  /** @public */
289
350
  export declare const ErrorBoundary: Component<ErrorBoundaryProps>;
290
351
 
@@ -427,6 +488,14 @@ export declare interface LinkProps extends AnchorAttributes {
427
488
  scroll?: boolean;
428
489
  }
429
490
 
491
+ declare type LoadedRoute = [
492
+ routeName: string,
493
+ params: PathParams,
494
+ mods: (RouteModule | ContentModule)[],
495
+ menu: ContentMenu | undefined,
496
+ routeBundleNames: string[] | undefined
497
+ ];
498
+
430
499
  /** @public */
431
500
  declare type Loader_2<RETURN> = {
432
501
  /**
@@ -510,6 +579,9 @@ declare type Prettify<T> = {} & {
510
579
  */
511
580
  export declare type PreventNavigateCallback = (url?: number | URL) => ValueOrPromise<boolean>;
512
581
 
582
+ /** @public */
583
+ export declare const Q_ROUTE = "q:route";
584
+
513
585
  /**
514
586
  * @deprecated Use `QWIK_ROUTER_SCROLLER` instead (will be removed in V3)
515
587
  * @public
@@ -526,7 +598,7 @@ export declare const QWIK_ROUTER_SCROLLER = "_qRouterScroller";
526
598
  export declare type QwikCityMockProps = QwikRouterMockProps;
527
599
 
528
600
  /**
529
- * @deprecated Use `QwikRouterMockProvider` instead. Will be removed in V3
601
+ * @deprecated Use `useQwikMockRouter()` instead. Will be removed in V3
530
602
  * @public
531
603
  */
532
604
  export declare const QwikCityMockProvider: Component<QwikRouterMockProps>;
@@ -538,13 +610,13 @@ export declare const QwikCityMockProvider: Component<QwikRouterMockProps>;
538
610
  export declare type QwikCityPlan = QwikRouterConfig;
539
611
 
540
612
  /**
541
- * @deprecated Use `QwikRouterProps` instead. will be removed in V3
613
+ * @deprecated Use `QwikRouterProps` instead. Will be removed in v3.
542
614
  * @public
543
615
  */
544
616
  export declare type QwikCityProps = QwikRouterProps;
545
617
 
546
618
  /**
547
- * @deprecated Use `QwikRouterProvider` instead. will be removed in V3
619
+ * @deprecated Use `useQwikRouter()` instead. Will be removed in v3.
548
620
  * @public
549
621
  */
550
622
  export declare const QwikCityProvider: Component<QwikRouterProps>;
@@ -559,6 +631,15 @@ export declare interface QwikRouterConfig {
559
631
  readonly cacheModules?: boolean;
560
632
  }
561
633
 
634
+ /** @public */
635
+ export declare interface QwikRouterEnvData {
636
+ routeName: string;
637
+ ev: RequestEvent;
638
+ params: PathParams;
639
+ response: EndpointResponse;
640
+ loadedRoute: LoadedRoute | null;
641
+ }
642
+
562
643
  /** @public */
563
644
  export declare interface QwikRouterMockProps {
564
645
  url?: string;
@@ -583,7 +664,7 @@ export declare interface QwikRouterProps {
583
664
  viewTransition?: boolean;
584
665
  }
585
666
 
586
- /** @public */
667
+ /** @public This is a wrapper around the `useQwikRouter()` hook. We recommend using the hook instead of this component. */
587
668
  export declare const QwikRouterProvider: Component<QwikRouterProps>;
588
669
 
589
670
  /** @public */
@@ -591,6 +672,18 @@ declare interface ReadonlySignal_2<T = unknown> {
591
672
  readonly value: T;
592
673
  }
593
674
 
675
+ /** @public */
676
+ export declare type RendererOptions = Omit<RenderOptions, 'serverData'> & {
677
+ serverData: ServerData;
678
+ };
679
+
680
+ /** @public */
681
+ export declare type RendererOutputOptions = Omit<RenderOptions, 'serverData'> & {
682
+ serverData: ServerData & {
683
+ documentHead?: DocumentHeadValue;
684
+ } & Record<string, unknown>;
685
+ };
686
+
594
687
  export { RequestEvent }
595
688
 
596
689
  export { RequestEventAction }
@@ -665,6 +758,18 @@ declare interface ServerConfig {
665
758
  fetchOptions?: any;
666
759
  }
667
760
 
761
+ /** @public The server data that is provided by Qwik Router during SSR rendering. It can be retrieved with `useServerData(key)` in the server, but it is not available in the client. */
762
+ export declare type ServerData = {
763
+ url: string;
764
+ requestHeaders: Record<string, string>;
765
+ locale: string | undefined;
766
+ nonce: string | undefined;
767
+ containerAttributes: Record<string, string> & {
768
+ [Q_ROUTE]: string;
769
+ };
770
+ qwikrouter: QwikRouterEnvData;
771
+ };
772
+
668
773
  /** @public */
669
774
  export declare type ServerFunction = {
670
775
  (this: RequestEventBase, ...args: any[]): any;
@@ -788,6 +893,14 @@ export declare const usePreventNavigate$: (qrl: PreventNavigateCallback) => void
788
893
 
789
894
  /* Excluded from this release type: usePreventNavigateQrl */
790
895
 
896
+ /**
897
+ * @public
898
+ * This hook initializes Qwik Router, providing the necessary context for it to work.
899
+ *
900
+ * This hook should be used once, at the root of your application.
901
+ */
902
+ export declare const useQwikRouter: (props?: QwikRouterProps) => void;
903
+
791
904
  /** @beta */
792
905
  export declare const valibot$: ValibotConstructor;
793
906
 
@@ -7,6 +7,7 @@ const internal = require("@qwik.dev/core/internal");
7
7
  const qwikRouterConfig = require("@qwik-router-config");
8
8
  const zod = require("zod");
9
9
  const swRegister = require("@qwik-router-sw-register");
10
+ const server = require("@qwik.dev/core/server");
10
11
  function _interopNamespaceDefault(e) {
11
12
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
12
13
  if (e) {
@@ -366,8 +367,8 @@ const Link = core.component$((props) => {
366
367
  children: /* @__PURE__ */ jsxRuntime.jsx(core.Slot, {})
367
368
  });
368
369
  });
369
- const resolveHead = (endpoint, routeLocation, contentModules, locale) => {
370
- const head = createDocumentHead();
370
+ const resolveHead = (endpoint, routeLocation, contentModules, locale, defaults) => {
371
+ const head = createDocumentHead(defaults);
371
372
  const getData = (loaderOrAction) => {
372
373
  const id = loaderOrAction.__id;
373
374
  if (loaderOrAction.__brand === "server_loader") {
@@ -423,13 +424,23 @@ const mergeArray = (existingArr, newArr) => {
423
424
  }
424
425
  }
425
426
  };
426
- const createDocumentHead = () => ({
427
- title: "",
428
- meta: [],
429
- links: [],
430
- styles: [],
431
- scripts: [],
432
- frontmatter: {}
427
+ const createDocumentHead = (defaults) => ({
428
+ title: defaults?.title || "",
429
+ meta: [
430
+ ...defaults?.meta || []
431
+ ],
432
+ links: [
433
+ ...defaults?.links || []
434
+ ],
435
+ styles: [
436
+ ...defaults?.styles || []
437
+ ],
438
+ scripts: [
439
+ ...defaults?.scripts || []
440
+ ],
441
+ frontmatter: {
442
+ ...defaults?.frontmatter
443
+ }
433
444
  });
434
445
  function matchRoute(route, path) {
435
446
  const routeIdx = startIdxSkipSlash(route);
@@ -841,7 +852,7 @@ const preventNav = {};
841
852
  const internalState = {
842
853
  navCount: 0
843
854
  };
844
- const QwikRouterProvider = core.component$((props) => {
855
+ const useQwikRouter = (props) => {
845
856
  core.useStyles$(`
846
857
  @layer qwik {
847
858
  @supports selector(html:active-view-transition-type(type)) {
@@ -862,6 +873,7 @@ const QwikRouterProvider = core.component$((props) => {
862
873
  if (!urlEnv) {
863
874
  throw new Error(`Missing Qwik URL Env Data`);
864
875
  }
876
+ const serverHead = core.useServerData("documentHead");
865
877
  if (core.isServer) {
866
878
  if (env.ev.originalUrl.pathname !== env.ev.url.pathname && !__EXPERIMENTAL__.enableRequestRewrite) {
867
879
  throw new Error(`enableRequestRewrite is an experimental feature and is not enabled. Please enable the feature flag by adding \`experimental: ["enableRequestRewrite"]\` to your qwikVite plugin options.`);
@@ -901,7 +913,7 @@ const QwikRouterProvider = core.component$((props) => {
901
913
  replaceState: false,
902
914
  scroll: true
903
915
  });
904
- const documentHead = core.useStore(createDocumentHead);
916
+ const documentHead = core.useStore(() => createDocumentHead(serverHead));
905
917
  const content = core.useStore({
906
918
  headings: void 0,
907
919
  menu: void 0
@@ -1106,7 +1118,7 @@ const QwikRouterProvider = core.component$((props) => {
1106
1118
  type: navType,
1107
1119
  dest: trackUrl
1108
1120
  };
1109
- const resolvedHead = resolveHead(clientPageData, routeLocation, contentModules, locale);
1121
+ const resolvedHead = resolveHead(clientPageData, routeLocation, contentModules, locale, serverHead);
1110
1122
  content.headings = pageModule.headings;
1111
1123
  content.menu = menu;
1112
1124
  contentInternal.value = core.noSerialize(contentModules);
@@ -1254,7 +1266,7 @@ const QwikRouterProvider = core.component$((props) => {
1254
1266
  return internal._waitUntilRendered(elm);
1255
1267
  };
1256
1268
  const _waitNextPage = () => {
1257
- if (core.isServer || props.viewTransition === false) {
1269
+ if (core.isServer || props?.viewTransition === false) {
1258
1270
  return navigate();
1259
1271
  } else {
1260
1272
  const viewTransition = startViewTransition({
@@ -1290,10 +1302,13 @@ const QwikRouterProvider = core.component$((props) => {
1290
1302
  run();
1291
1303
  }
1292
1304
  });
1305
+ };
1306
+ const QwikRouterProvider = core.component$((props) => {
1307
+ useQwikRouter(props);
1293
1308
  return /* @__PURE__ */ jsxRuntime.jsx(core.Slot, {});
1294
1309
  });
1295
1310
  const QwikCityProvider = QwikRouterProvider;
1296
- const QwikRouterMockProvider = core.component$((props) => {
1311
+ const useQwikMockRouter = (props) => {
1297
1312
  const urlEnv = props.url ?? "http://localhost/";
1298
1313
  const url = new URL(urlEnv);
1299
1314
  const routeLocation = core.useStore({
@@ -1331,6 +1346,9 @@ const QwikRouterMockProvider = core.component$((props) => {
1331
1346
  core.useContextProvider(RouteStateContext, loaderState);
1332
1347
  core.useContextProvider(RouteActionContext, actionState);
1333
1348
  core.useContextProvider(RouteInternalContext, routeInternal);
1349
+ };
1350
+ const QwikRouterMockProvider = core.component$((props) => {
1351
+ useQwikMockRouter(props);
1334
1352
  return /* @__PURE__ */ jsxRuntime.jsx(core.Slot, {});
1335
1353
  });
1336
1354
  const QwikCityMockProvider = QwikRouterMockProvider;
@@ -1981,10 +1999,55 @@ function omitProps(obj, keys) {
1981
1999
  }
1982
2000
  return omittedObj;
1983
2001
  }
2002
+ const createRenderer = (getOptions) => {
2003
+ return (opts) => {
2004
+ const { jsx, options } = getOptions(opts);
2005
+ return server.renderToStream(jsx, options);
2006
+ };
2007
+ };
2008
+ const DocumentHeadTags = core.component$((props) => {
2009
+ let head = useDocumentHead();
2010
+ if (props) {
2011
+ head = {
2012
+ ...head,
2013
+ ...props
2014
+ };
2015
+ }
2016
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
2017
+ children: [
2018
+ head.title && /* @__PURE__ */ jsxRuntime.jsx("title", {
2019
+ children: head.title
2020
+ }),
2021
+ head.meta.map((m) => /* @__PURE__ */ jsxRuntime.jsx("meta", {
2022
+ ...m
2023
+ })),
2024
+ head.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx("link", {
2025
+ ...l
2026
+ })),
2027
+ head.styles.map((s) => {
2028
+ const props2 = s.props || s;
2029
+ return /* @__PURE__ */ core.createElement("style", {
2030
+ ...props2,
2031
+ dangerouslySetInnerHTML: s.style || props2.dangerouslySetInnerHTML,
2032
+ key: s.key
2033
+ });
2034
+ }),
2035
+ head.scripts.map((s) => {
2036
+ const props2 = s.props || s;
2037
+ return /* @__PURE__ */ core.createElement("script", {
2038
+ ...props2,
2039
+ dangerouslySetInnerHTML: s.script || props2.dangerouslySetInnerHTML,
2040
+ key: s.key
2041
+ });
2042
+ })
2043
+ ]
2044
+ });
2045
+ });
1984
2046
  Object.defineProperty(exports, "z", {
1985
2047
  enumerable: true,
1986
2048
  get: () => zod.z
1987
2049
  });
2050
+ exports.DocumentHeadTags = DocumentHeadTags;
1988
2051
  exports.ErrorBoundary = ErrorBoundary;
1989
2052
  exports.Form = Form;
1990
2053
  exports.Link = Link;
@@ -1996,6 +2059,7 @@ exports.QwikRouterMockProvider = QwikRouterMockProvider;
1996
2059
  exports.QwikRouterProvider = QwikRouterProvider;
1997
2060
  exports.RouterOutlet = RouterOutlet;
1998
2061
  exports.ServiceWorkerRegister = ServiceWorkerRegister;
2062
+ exports.createRenderer = createRenderer;
1999
2063
  exports.globalAction$ = globalAction$;
2000
2064
  exports.globalActionQrl = globalActionQrl;
2001
2065
  exports.omitProps = omitProps;
@@ -2012,6 +2076,7 @@ exports.useLocation = useLocation;
2012
2076
  exports.useNavigate = useNavigate;
2013
2077
  exports.usePreventNavigate$ = usePreventNavigate$;
2014
2078
  exports.usePreventNavigateQrl = usePreventNavigateQrl;
2079
+ exports.useQwikRouter = useQwikRouter;
2015
2080
  exports.valibot$ = valibot$;
2016
2081
  exports.valibotQrl = valibotQrl;
2017
2082
  exports.validator$ = validator$;
@@ -1,11 +1,12 @@
1
1
  import { jsx, Fragment, jsxs } from "@qwik.dev/core/jsx-runtime";
2
- import { component$, useErrorBoundary, useOnWindow, $, Slot, createAsyncComputed$, isBrowser, createContextId, implicit$FirstArg, useContext, useVisibleTask$, noSerialize, useServerData, useSignal, untrack, sync$, isDev, withLocale, event$, useStyles$, isServer, useStore, useContextProvider, useTask$, getLocale, jsx as jsx$1, SkipRender } from "@qwik.dev/core";
2
+ import { component$, useErrorBoundary, useOnWindow, $, Slot, createAsyncComputed$, isBrowser, createContextId, implicit$FirstArg, useContext, useVisibleTask$, noSerialize, useServerData, useSignal, untrack, sync$, isDev, withLocale, event$, useStyles$, isServer, useStore, useContextProvider, useTask$, getLocale, jsx as jsx$1, SkipRender, createElement } from "@qwik.dev/core";
3
3
  import { p } from "@qwik.dev/core/preloader";
4
4
  import { _deserialize, _UNINITIALIZED, _getContextContainer, SerializerSymbol, _getContextElement, _getQContainerElement, _waitUntilRendered, _resolveContextWithoutSequentialScope, _getContextEvent, _serialize } from "@qwik.dev/core/internal";
5
5
  import * as qwikRouterConfig from "@qwik-router-config";
6
6
  import { z } from "zod";
7
7
  import { z as z2 } from "zod";
8
8
  import swRegister from "@qwik-router-sw-register";
9
+ import { renderToStream } from "@qwik.dev/core/server";
9
10
  const ErrorBoundary = component$((props) => {
10
11
  const store2 = useErrorBoundary();
11
12
  useOnWindow("qerror", $((e) => {
@@ -348,8 +349,8 @@ const Link = component$((props) => {
348
349
  children: /* @__PURE__ */ jsx(Slot, {})
349
350
  });
350
351
  });
351
- const resolveHead = (endpoint, routeLocation, contentModules, locale) => {
352
- const head = createDocumentHead();
352
+ const resolveHead = (endpoint, routeLocation, contentModules, locale, defaults) => {
353
+ const head = createDocumentHead(defaults);
353
354
  const getData = (loaderOrAction) => {
354
355
  const id = loaderOrAction.__id;
355
356
  if (loaderOrAction.__brand === "server_loader") {
@@ -405,13 +406,23 @@ const mergeArray = (existingArr, newArr) => {
405
406
  }
406
407
  }
407
408
  };
408
- const createDocumentHead = () => ({
409
- title: "",
410
- meta: [],
411
- links: [],
412
- styles: [],
413
- scripts: [],
414
- frontmatter: {}
409
+ const createDocumentHead = (defaults) => ({
410
+ title: defaults?.title || "",
411
+ meta: [
412
+ ...defaults?.meta || []
413
+ ],
414
+ links: [
415
+ ...defaults?.links || []
416
+ ],
417
+ styles: [
418
+ ...defaults?.styles || []
419
+ ],
420
+ scripts: [
421
+ ...defaults?.scripts || []
422
+ ],
423
+ frontmatter: {
424
+ ...defaults?.frontmatter
425
+ }
415
426
  });
416
427
  function matchRoute(route, path) {
417
428
  const routeIdx = startIdxSkipSlash(route);
@@ -823,7 +834,7 @@ const preventNav = {};
823
834
  const internalState = {
824
835
  navCount: 0
825
836
  };
826
- const QwikRouterProvider = component$((props) => {
837
+ const useQwikRouter = (props) => {
827
838
  useStyles$(`
828
839
  @layer qwik {
829
840
  @supports selector(html:active-view-transition-type(type)) {
@@ -844,6 +855,7 @@ const QwikRouterProvider = component$((props) => {
844
855
  if (!urlEnv) {
845
856
  throw new Error(`Missing Qwik URL Env Data`);
846
857
  }
858
+ const serverHead = useServerData("documentHead");
847
859
  if (isServer) {
848
860
  if (env.ev.originalUrl.pathname !== env.ev.url.pathname && !__EXPERIMENTAL__.enableRequestRewrite) {
849
861
  throw new Error(`enableRequestRewrite is an experimental feature and is not enabled. Please enable the feature flag by adding \`experimental: ["enableRequestRewrite"]\` to your qwikVite plugin options.`);
@@ -883,7 +895,7 @@ const QwikRouterProvider = component$((props) => {
883
895
  replaceState: false,
884
896
  scroll: true
885
897
  });
886
- const documentHead = useStore(createDocumentHead);
898
+ const documentHead = useStore(() => createDocumentHead(serverHead));
887
899
  const content = useStore({
888
900
  headings: void 0,
889
901
  menu: void 0
@@ -1088,7 +1100,7 @@ const QwikRouterProvider = component$((props) => {
1088
1100
  type: navType,
1089
1101
  dest: trackUrl
1090
1102
  };
1091
- const resolvedHead = resolveHead(clientPageData, routeLocation, contentModules, locale);
1103
+ const resolvedHead = resolveHead(clientPageData, routeLocation, contentModules, locale, serverHead);
1092
1104
  content.headings = pageModule.headings;
1093
1105
  content.menu = menu;
1094
1106
  contentInternal.value = noSerialize(contentModules);
@@ -1236,7 +1248,7 @@ const QwikRouterProvider = component$((props) => {
1236
1248
  return _waitUntilRendered(elm);
1237
1249
  };
1238
1250
  const _waitNextPage = () => {
1239
- if (isServer || props.viewTransition === false) {
1251
+ if (isServer || props?.viewTransition === false) {
1240
1252
  return navigate();
1241
1253
  } else {
1242
1254
  const viewTransition = startViewTransition({
@@ -1272,10 +1284,13 @@ const QwikRouterProvider = component$((props) => {
1272
1284
  run();
1273
1285
  }
1274
1286
  });
1287
+ };
1288
+ const QwikRouterProvider = component$((props) => {
1289
+ useQwikRouter(props);
1275
1290
  return /* @__PURE__ */ jsx(Slot, {});
1276
1291
  });
1277
1292
  const QwikCityProvider = QwikRouterProvider;
1278
- const QwikRouterMockProvider = component$((props) => {
1293
+ const useQwikMockRouter = (props) => {
1279
1294
  const urlEnv = props.url ?? "http://localhost/";
1280
1295
  const url = new URL(urlEnv);
1281
1296
  const routeLocation = useStore({
@@ -1313,6 +1328,9 @@ const QwikRouterMockProvider = component$((props) => {
1313
1328
  useContextProvider(RouteStateContext, loaderState);
1314
1329
  useContextProvider(RouteActionContext, actionState);
1315
1330
  useContextProvider(RouteInternalContext, routeInternal);
1331
+ };
1332
+ const QwikRouterMockProvider = component$((props) => {
1333
+ useQwikMockRouter(props);
1316
1334
  return /* @__PURE__ */ jsx(Slot, {});
1317
1335
  });
1318
1336
  const QwikCityMockProvider = QwikRouterMockProvider;
@@ -1963,7 +1981,52 @@ function omitProps(obj, keys) {
1963
1981
  }
1964
1982
  return omittedObj;
1965
1983
  }
1984
+ const createRenderer = (getOptions) => {
1985
+ return (opts) => {
1986
+ const { jsx: jsx2, options } = getOptions(opts);
1987
+ return renderToStream(jsx2, options);
1988
+ };
1989
+ };
1990
+ const DocumentHeadTags = component$((props) => {
1991
+ let head = useDocumentHead();
1992
+ if (props) {
1993
+ head = {
1994
+ ...head,
1995
+ ...props
1996
+ };
1997
+ }
1998
+ return /* @__PURE__ */ jsxs(Fragment, {
1999
+ children: [
2000
+ head.title && /* @__PURE__ */ jsx("title", {
2001
+ children: head.title
2002
+ }),
2003
+ head.meta.map((m) => /* @__PURE__ */ jsx("meta", {
2004
+ ...m
2005
+ })),
2006
+ head.links.map((l) => /* @__PURE__ */ jsx("link", {
2007
+ ...l
2008
+ })),
2009
+ head.styles.map((s) => {
2010
+ const props2 = s.props || s;
2011
+ return /* @__PURE__ */ createElement("style", {
2012
+ ...props2,
2013
+ dangerouslySetInnerHTML: s.style || props2.dangerouslySetInnerHTML,
2014
+ key: s.key
2015
+ });
2016
+ }),
2017
+ head.scripts.map((s) => {
2018
+ const props2 = s.props || s;
2019
+ return /* @__PURE__ */ createElement("script", {
2020
+ ...props2,
2021
+ dangerouslySetInnerHTML: s.script || props2.dangerouslySetInnerHTML,
2022
+ key: s.key
2023
+ });
2024
+ })
2025
+ ]
2026
+ });
2027
+ });
1966
2028
  export {
2029
+ DocumentHeadTags,
1967
2030
  ErrorBoundary,
1968
2031
  Form,
1969
2032
  Link,
@@ -1975,6 +2038,7 @@ export {
1975
2038
  QwikRouterProvider,
1976
2039
  RouterOutlet,
1977
2040
  ServiceWorkerRegister,
2041
+ createRenderer,
1978
2042
  globalAction$,
1979
2043
  globalActionQrl,
1980
2044
  omitProps,
@@ -1991,6 +2055,7 @@ export {
1991
2055
  useNavigate,
1992
2056
  usePreventNavigate$,
1993
2057
  usePreventNavigateQrl,
2058
+ useQwikRouter,
1994
2059
  valibot$,
1995
2060
  valibotQrl,
1996
2061
  validator$,
@@ -215,10 +215,7 @@ declare interface DocumentHeadProps extends RouteLocation {
215
215
  declare interface DocumentHeadValue<FrontMatter extends Record<string, any> = Record<string, unknown>> {
216
216
  /** Sets `document.title`. */
217
217
  readonly title?: string;
218
- /**
219
- * Used to manually set meta tags in the head. Additionally, the `data` property could be used to
220
- * set arbitrary data which the `<head>` component could later use to generate `<meta>` tags.
221
- */
218
+ /** Used to manually set meta tags in the head. */
222
219
  readonly meta?: readonly DocumentMeta[];
223
220
  /** Used to manually append `<link>` elements to the `<head>`. */
224
221
  readonly links?: readonly DocumentLink[];
@@ -235,50 +232,48 @@ declare interface DocumentHeadValue<FrontMatter extends Record<string, any> = Re
235
232
  }
236
233
 
237
234
  /** @public */
238
- declare interface DocumentLink {
239
- as?: string;
240
- crossorigin?: string;
241
- disabled?: boolean;
242
- href?: string;
243
- hreflang?: string;
244
- id?: string;
245
- imagesizes?: string;
246
- imagesrcset?: string;
247
- integrity?: string;
248
- media?: string;
249
- prefetch?: string;
250
- referrerpolicy?: string;
251
- rel?: string;
252
- sizes?: string;
253
- title?: string;
254
- type?: string;
255
- key?: string;
256
- }
235
+ declare type DocumentLink = QwikIntrinsicElements['link'];
257
236
 
258
237
  /** @public */
259
- declare interface DocumentMeta {
260
- readonly content?: string;
261
- readonly httpEquiv?: string;
262
- readonly name?: string;
263
- readonly property?: string;
264
- readonly key?: string;
265
- readonly itemprop?: string;
266
- readonly media?: string;
267
- }
238
+ declare type DocumentMeta = QwikIntrinsicElements['meta'];
268
239
 
269
- /** @beta */
270
- declare interface DocumentScript {
271
- readonly script?: string;
272
- readonly props?: Readonly<QwikIntrinsicElements['script']>;
273
- readonly key?: string;
274
- }
240
+ /** @public */
241
+ declare type DocumentScript = ((Omit<QwikIntrinsicElements['script'], 'dangerouslySetInnerHTML'> & {
242
+ props?: never;
243
+ }) | {
244
+ key?: string;
245
+ /**
246
+ * The props of the script element. @deprecated Prefer setting the properties directly instead
247
+ * of using this property.
248
+ */
249
+ props: Readonly<QwikIntrinsicElements['script']>;
250
+ }) & ({
251
+ /** The inline script content. */
252
+ script?: string;
253
+ dangerouslySetInnerHTML?: never;
254
+ } | {
255
+ dangerouslySetInnerHTML?: string;
256
+ script?: never;
257
+ });
275
258
 
276
259
  /** @public */
277
- declare interface DocumentStyle {
278
- readonly style: string;
279
- readonly props?: Readonly<QwikIntrinsicElements['style']>;
280
- readonly key?: string;
281
- }
260
+ declare type DocumentStyle = Readonly<((Omit<QwikIntrinsicElements['style'], 'dangerouslySetInnerHTML'> & {
261
+ props?: never;
262
+ }) | {
263
+ key?: string;
264
+ /**
265
+ * The props of the style element. @deprecated Prefer setting the properties directly
266
+ * instead of using this property.
267
+ */
268
+ props: Readonly<QwikIntrinsicElements['style']>;
269
+ }) & ({
270
+ /** The inline style content. */
271
+ style?: string;
272
+ dangerouslySetInnerHTML?: never;
273
+ } | {
274
+ dangerouslySetInnerHTML?: string;
275
+ style?: never;
276
+ })>;
282
277
 
283
278
  /** @public */
284
279
  export declare interface EnvGetter {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qwik.dev/router",
3
3
  "description": "The router for Qwik.",
4
- "version": "2.0.0-beta.6",
4
+ "version": "2.0.0-beta.7",
5
5
  "bugs": "https://github.com/QwikDev/qwik/issues",
6
6
  "dependencies": {
7
7
  "@mdx-js/mdx": "^3",
@@ -40,7 +40,7 @@
40
40
  "unist-util-visit": "5.0.0",
41
41
  "uvu": "0.5.6",
42
42
  "yaml": "2.4.5",
43
- "@qwik.dev/core": "2.0.0-beta.6"
43
+ "@qwik.dev/core": "2.0.0-beta.7"
44
44
  },
45
45
  "engines": {
46
46
  "node": "^18.17.0 || ^20.3.0 || >=21.0.0"