@inflector/keeno-router 0.2.0 → 0.3.0

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/dist/index.d.ts CHANGED
@@ -65,6 +65,11 @@ export interface NavigateOptions {
65
65
  state?: unknown;
66
66
  /** Scroll to the top after navigating (default true, unless the URL has a hash). */
67
67
  scroll?: boolean;
68
+ /**
69
+ * Animate the change with the View Transitions API, where the browser supports it (default:
70
+ * the `viewTransition` prop of `<Router>`). The new page renders inside the transition.
71
+ */
72
+ transition?: boolean;
68
73
  }
69
74
  /** Go to an app path (`/users/1`, prefixed with `base`) or a relative URL (`?tab=2`). */
70
75
  export declare function navigate(to: string, options?: NavigateOptions): void;
@@ -85,6 +90,11 @@ export interface RouterProps {
85
90
  url?: string;
86
91
  /** Rendered when no route matches. */
87
92
  fallback?: () => unknown;
93
+ /**
94
+ * Animate navigations (links, `navigate()`, back and forward) with the View Transitions API,
95
+ * where the browser supports it. A navigation can opt out with `transition: false`.
96
+ */
97
+ viewTransition?: boolean;
88
98
  }
89
99
  /**
90
100
  * Render the component of the first route matching the URL. The component is kept when only
@@ -98,6 +108,8 @@ export interface LinkProps {
98
108
  href: string;
99
109
  /** Replace the current history entry. */
100
110
  replace?: boolean;
111
+ /** Animate the navigation with the View Transitions API (default: `<Router viewTransition>`). */
112
+ transition?: boolean;
101
113
  /** Class added while the link's path is active (default `active`). */
102
114
  activeClass?: string;
103
115
  /** Only active on exactly this path, not below it. */
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // ../../../../../../../tmp/keeno-build/_inflector_keeno-router/src/index.ts
2
- import { ErrorBoundary, State, createContext, derived, inject, lazy, provide, untrack } from "@inflector/keeno";
2
+ import { ErrorBoundary, State, createContext, derived, flush, inject, lazy, provide, untrack } from "@inflector/keeno";
3
3
  import { attr, callerScope, createComponent, insert, on, template } from "@inflector/keeno/internal";
4
4
 
5
5
  class HttpError extends Error {
@@ -58,6 +58,21 @@ function restoreScroll(l) {
58
58
  else
59
59
  setTimeout(run, 0);
60
60
  }
61
+ var transitionsDefault = false;
62
+ function withTransition(enabled, update) {
63
+ const start = enabled && hasWindow ? document.startViewTransition : undefined;
64
+ if (typeof start !== "function")
65
+ return update();
66
+ start.call(document, () => {
67
+ update();
68
+ flush();
69
+ });
70
+ }
71
+ function scrollTo(x, y) {
72
+ try {
73
+ window.scrollTo(x, y);
74
+ } catch {}
75
+ }
61
76
  function sync() {
62
77
  if (!hasWindow)
63
78
  return;
@@ -68,6 +83,18 @@ function sync() {
68
83
  window.addEventListener("popstate", () => {
69
84
  saveScroll(current.peek());
70
85
  const next = readLocation();
86
+ if (transitionsDefault && typeof document.startViewTransition === "function") {
87
+ withTransition(true, () => {
88
+ current.set(next);
89
+ flush();
90
+ const saved = scrollPositions.get(locKey(next));
91
+ if (!saved && next.hash)
92
+ scrollToHash(next.hash);
93
+ else
94
+ scrollTo(saved?.[0] ?? 0, saved?.[1] ?? 0);
95
+ });
96
+ return;
97
+ }
71
98
  current.set(next);
72
99
  restoreScroll(next);
73
100
  });
@@ -122,16 +149,15 @@ function navigate(to, options = {}) {
122
149
  else
123
150
  history.pushState(options.state ?? null, "", url);
124
151
  window.dispatchEvent(new CustomEvent("keeno:navigate", { detail: { url: url.href, state: options.state ?? null } }));
125
- current.set(readLocation());
126
- if (options.scroll === false)
127
- return;
128
- if (url.hash)
129
- scrollToHash(url.hash);
130
- else if (typeof window.scrollTo === "function") {
131
- try {
132
- window.scrollTo(0, 0);
133
- } catch {}
134
- }
152
+ withTransition(options.transition ?? transitionsDefault, () => {
153
+ current.set(readLocation());
154
+ if (options.scroll === false)
155
+ return;
156
+ if (url.hash)
157
+ scrollToHash(url.hash);
158
+ else if (typeof window.scrollTo === "function")
159
+ scrollTo(0, 0);
160
+ });
135
161
  }
136
162
  function isExternalClick(e, a) {
137
163
  if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
@@ -149,7 +175,10 @@ function link(e) {
149
175
  if (!underBase(url.pathname, base.peek()))
150
176
  return;
151
177
  e.preventDefault();
152
- navigate(stripBase(url.pathname, base.peek()) + url.search + url.hash, { replace: a.hasAttribute("data-replace") });
178
+ navigate(stripBase(url.pathname, base.peek()) + url.search + url.hash, {
179
+ replace: a.hasAttribute("data-replace"),
180
+ transition: a.hasAttribute("data-transition") ? a.getAttribute("data-transition") !== "false" : undefined
181
+ });
153
182
  }
154
183
  var compiled = new WeakMap;
155
184
  function compile(route) {
@@ -208,6 +237,7 @@ function Router(props) {
208
237
  const loc = url != null ? new State(parseUrl(url)) : current;
209
238
  if (url == null) {
210
239
  base.set(routerBase);
240
+ transitionsDefault = !!untrack(() => props.viewTransition);
211
241
  sync();
212
242
  }
213
243
  const outside = (l) => !underBase(l.pathname, routerBase);
@@ -323,7 +353,7 @@ function Link(props) {
323
353
  if (isExternalClick(e, a))
324
354
  return;
325
355
  e.preventDefault();
326
- navigate(props.href, { replace: props.replace });
356
+ navigate(props.href, { replace: props.replace, transition: props.transition });
327
357
  });
328
358
  insert(a, () => props.children?.());
329
359
  return a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inflector/keeno-router",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Client-side router for Keeno (.kn) apps",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -39,10 +39,10 @@
39
39
  "prepack": "bun run build"
40
40
  },
41
41
  "peerDependencies": {
42
- "@inflector/keeno": ">=0.4.0 <1.0.0"
42
+ "@inflector/keeno": ">=0.5.0 <1.0.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@inflector/keeno": "0.4.0"
45
+ "@inflector/keeno": "0.5.0"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"