@sveltejs/kit 1.16.1 → 1.16.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.16.1",
3
+ "version": "1.16.3",
4
4
  "description": "The fastest way to build Svelte apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1125,7 +1125,7 @@ export function create_client(app, target) {
1125
1125
  document.activeElement !== document.body;
1126
1126
 
1127
1127
  if (!keepfocus && !changed_focus) {
1128
- await reset_focus();
1128
+ reset_focus();
1129
1129
  }
1130
1130
 
1131
1131
  autoscroll = true;
@@ -1135,6 +1135,11 @@ export function create_client(app, target) {
1135
1135
  }
1136
1136
 
1137
1137
  navigating = false;
1138
+
1139
+ if (type === 'popstate') {
1140
+ restore_snapshot(current_history_index);
1141
+ }
1142
+
1138
1143
  callbacks.after_navigate.forEach((fn) =>
1139
1144
  fn(/** @type {import('types').AfterNavigate} */ (navigation))
1140
1145
  );
@@ -1638,7 +1643,6 @@ export function create_client(app, target) {
1638
1643
  }
1639
1644
 
1640
1645
  const delta = event.state[INDEX_KEY] - current_history_index;
1641
- let blocked = false;
1642
1646
 
1643
1647
  await navigate({
1644
1648
  url: new URL(location.href),
@@ -1651,15 +1655,10 @@ export function create_client(app, target) {
1651
1655
  },
1652
1656
  blocked: () => {
1653
1657
  history.go(-delta);
1654
- blocked = true;
1655
1658
  },
1656
1659
  type: 'popstate',
1657
1660
  delta
1658
1661
  });
1659
-
1660
- if (!blocked) {
1661
- restore_snapshot(current_history_index);
1662
- }
1663
1662
  }
1664
1663
  });
1665
1664
 
@@ -1909,7 +1908,8 @@ function reset_focus() {
1909
1908
  const tabindex = root.getAttribute('tabindex');
1910
1909
 
1911
1910
  root.tabIndex = -1;
1912
- root.focus({ preventScroll: true });
1911
+ // @ts-expect-error
1912
+ root.focus({ preventScroll: true, focusVisible: false });
1913
1913
 
1914
1914
  // restore `tabindex` as to prevent `root` from stealing input from elements
1915
1915
  if (tabindex !== null) {
@@ -1918,12 +1918,44 @@ function reset_focus() {
1918
1918
  root.removeAttribute('tabindex');
1919
1919
  }
1920
1920
 
1921
- return new Promise((resolve) => {
1921
+ // capture current selection, so we can compare the state after
1922
+ // snapshot restoration and afterNavigate callbacks have run
1923
+ const selection = getSelection();
1924
+
1925
+ if (selection && selection.type !== 'None') {
1926
+ /** @type {Range[]} */
1927
+ const ranges = [];
1928
+
1929
+ for (let i = 0; i < selection.rangeCount; i += 1) {
1930
+ ranges.push(selection.getRangeAt(i));
1931
+ }
1932
+
1922
1933
  setTimeout(() => {
1934
+ if (selection.rangeCount !== ranges.length) return;
1935
+
1936
+ for (let i = 0; i < selection.rangeCount; i += 1) {
1937
+ const a = ranges[i];
1938
+ const b = selection.getRangeAt(i);
1939
+
1940
+ // we need to do a deep comparison rather than just `a !== b` because
1941
+ // Safari behaves differently to other browsers
1942
+ if (
1943
+ a.commonAncestorContainer !== b.commonAncestorContainer ||
1944
+ a.startContainer !== b.startContainer ||
1945
+ a.endContainer !== b.endContainer ||
1946
+ a.startOffset !== b.startOffset ||
1947
+ a.endOffset !== b.endOffset
1948
+ ) {
1949
+ return;
1950
+ }
1951
+ }
1952
+
1953
+ // if the selection hasn't changed (as a result of an element being (auto)focused,
1954
+ // or a programmatic selection, we reset everything as part of the navigation)
1923
1955
  // fixes https://github.com/sveltejs/kit/issues/8439
1924
- resolve(getSelection()?.removeAllRanges());
1956
+ selection.removeAllRanges();
1925
1957
  });
1926
- });
1958
+ }
1927
1959
  }
1928
1960
  }
1929
1961
 
@@ -96,7 +96,7 @@ export function parse_route_id(id) {
96
96
  return { pattern, params };
97
97
  }
98
98
 
99
- const basic_param_pattern = /\[(\[)?(?:\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/;
99
+ const basic_param_pattern = /\[(\[)?(?:\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
100
100
 
101
101
  /**
102
102
  * Parses a route ID, then resolves it to a path by replacing parameters with actual values from `entry`.
@@ -112,29 +112,23 @@ export function resolve_entry(id, entry) {
112
112
  return (
113
113
  '/' +
114
114
  segments
115
- .map((segment) => {
116
- const match = basic_param_pattern.exec(segment);
117
-
118
- // static content -- i.e. not a param
119
- if (!match) return segment;
120
-
121
- const optional = !!match[1];
122
- const name = match[2];
123
- const param_value = entry[name];
124
-
125
- // This is nested so TS correctly narrows the type
126
- if (!param_value) {
127
- if (optional) return '';
128
- throw new Error(`Missing parameter '${name}' in route ${id}`);
129
- }
130
-
131
- if (param_value.startsWith('/') || param_value.endsWith('/'))
132
- throw new Error(
133
- `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
134
- );
135
-
136
- return param_value;
137
- })
115
+ .map((segment) =>
116
+ segment.replace(basic_param_pattern, (_, optional, name) => {
117
+ const param_value = entry[name];
118
+
119
+ // This is nested so TS correctly narrows the type
120
+ if (!param_value) {
121
+ if (optional) return '';
122
+ throw new Error(`Missing parameter '${name}' in route ${id}`);
123
+ }
124
+
125
+ if (param_value.startsWith('/') || param_value.endsWith('/'))
126
+ throw new Error(
127
+ `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
128
+ );
129
+ return param_value;
130
+ })
131
+ )
138
132
  .filter(Boolean)
139
133
  .join('/')
140
134
  );
package/src/utils/url.js CHANGED
@@ -93,9 +93,15 @@ export function decode_uri(uri) {
93
93
  /**
94
94
  * URL properties that could change during the lifetime of the page,
95
95
  * which excludes things like `origin`
96
- * @type {Array<keyof URL>}
97
96
  */
98
- const tracked_url_properties = ['href', 'pathname', 'search', 'searchParams', 'toString', 'toJSON'];
97
+ const tracked_url_properties = /** @type {const} */ ([
98
+ 'href',
99
+ 'pathname',
100
+ 'search',
101
+ 'searchParams',
102
+ 'toString',
103
+ 'toJSON'
104
+ ]);
99
105
 
100
106
  /**
101
107
  * @param {URL} url
@@ -105,12 +111,10 @@ export function make_trackable(url, callback) {
105
111
  const tracked = new URL(url);
106
112
 
107
113
  for (const property of tracked_url_properties) {
108
- let value = tracked[property];
109
-
110
114
  Object.defineProperty(tracked, property, {
111
115
  get() {
112
116
  callback();
113
- return value;
117
+ return url[property];
114
118
  },
115
119
 
116
120
  enumerable: true,