@jsenv/navi 0.14.0 → 0.14.1
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/jsenv_navi.js +878 -429
- package/dist/jsenv_navi.js.map +63 -34
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -318,85 +318,95 @@ const getSignalType = (value) => {
|
|
|
318
318
|
*/
|
|
319
319
|
const SYMBOL_IDENTITY = Symbol.for("navi_object_identity");
|
|
320
320
|
|
|
321
|
-
const compareTwoJsValues = (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const aIsIsTruthy = Boolean(a);
|
|
326
|
-
const bIsTruthy = Boolean(b);
|
|
327
|
-
if (aIsIsTruthy && !bIsTruthy) {
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
|
-
if (!aIsIsTruthy && !bIsTruthy) {
|
|
331
|
-
// null, undefined, 0, false, NaN
|
|
332
|
-
if (isNaN(a) && isNaN(b)) {
|
|
321
|
+
const compareTwoJsValues = (rootA, rootB, { keyComparator } = {}) => {
|
|
322
|
+
const seenSet = new Set();
|
|
323
|
+
const compare = (a, b) => {
|
|
324
|
+
if (a === b) {
|
|
333
325
|
return true;
|
|
334
326
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return false;
|
|
364
|
-
}
|
|
365
|
-
if (aIsArray) {
|
|
366
|
-
// compare arrays
|
|
367
|
-
if (a.length !== b.length) {
|
|
327
|
+
const aIsIsTruthy = Boolean(a);
|
|
328
|
+
const bIsTruthy = Boolean(b);
|
|
329
|
+
if (aIsIsTruthy && !bIsTruthy) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
if (!aIsIsTruthy && !bIsTruthy) {
|
|
333
|
+
// null, undefined, 0, false, NaN
|
|
334
|
+
if (isNaN(a) && isNaN(b)) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
return a === b;
|
|
338
|
+
}
|
|
339
|
+
const aType = typeof a;
|
|
340
|
+
const bType = typeof b;
|
|
341
|
+
if (aType !== bType) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
const aIsPrimitive =
|
|
345
|
+
a === null || (aType !== "object" && aType !== "function");
|
|
346
|
+
const bIsPrimitive =
|
|
347
|
+
b === null || (bType !== "object" && bType !== "function");
|
|
348
|
+
if (aIsPrimitive !== bIsPrimitive) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
if (aIsPrimitive && bIsPrimitive) {
|
|
352
|
+
return a === b;
|
|
353
|
+
}
|
|
354
|
+
if (seenSet.has(a)) {
|
|
368
355
|
return false;
|
|
369
356
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
357
|
+
if (seenSet.has(b)) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
seenSet.add(a);
|
|
361
|
+
seenSet.add(b);
|
|
362
|
+
const aIsArray = Array.isArray(a);
|
|
363
|
+
const bIsArray = Array.isArray(b);
|
|
364
|
+
if (aIsArray !== bIsArray) {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
if (aIsArray) {
|
|
368
|
+
// compare arrays
|
|
369
|
+
if (a.length !== b.length) {
|
|
375
370
|
return false;
|
|
376
371
|
}
|
|
377
|
-
i
|
|
372
|
+
let i = 0;
|
|
373
|
+
while (i < a.length) {
|
|
374
|
+
const aValue = a[i];
|
|
375
|
+
const bValue = b[i];
|
|
376
|
+
const comparator = keyComparator || compare;
|
|
377
|
+
if (!comparator(aValue, bValue, i, compare)) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
i++;
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
378
383
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
for (const key of aKeys) {
|
|
393
|
-
const aValue = a[key];
|
|
394
|
-
const bValue = b[key];
|
|
395
|
-
if (!compareTwoJsValues(aValue, bValue, seenSet)) {
|
|
384
|
+
// compare objects
|
|
385
|
+
const aIdentity = a[SYMBOL_IDENTITY];
|
|
386
|
+
const bIdentity = b[SYMBOL_IDENTITY];
|
|
387
|
+
if (
|
|
388
|
+
aIdentity === bIdentity &&
|
|
389
|
+
SYMBOL_IDENTITY in a &&
|
|
390
|
+
SYMBOL_IDENTITY in b
|
|
391
|
+
) {
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
const aKeys = Object.keys(a);
|
|
395
|
+
const bKeys = Object.keys(b);
|
|
396
|
+
if (aKeys.length !== bKeys.length) {
|
|
396
397
|
return false;
|
|
397
398
|
}
|
|
398
|
-
|
|
399
|
-
|
|
399
|
+
for (const key of aKeys) {
|
|
400
|
+
const aValue = a[key];
|
|
401
|
+
const bValue = b[key];
|
|
402
|
+
const comparator = keyComparator || compare;
|
|
403
|
+
if (!comparator(aValue, bValue, key, compare)) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
};
|
|
409
|
+
return compare(rootA, rootB);
|
|
400
410
|
};
|
|
401
411
|
|
|
402
412
|
/**
|
|
@@ -1247,8 +1257,8 @@ ${lines.join("\n")}`);
|
|
|
1247
1257
|
};
|
|
1248
1258
|
};
|
|
1249
1259
|
|
|
1250
|
-
const NO_PARAMS
|
|
1251
|
-
const initialParamsDefault = NO_PARAMS
|
|
1260
|
+
const NO_PARAMS = {};
|
|
1261
|
+
const initialParamsDefault = NO_PARAMS;
|
|
1252
1262
|
|
|
1253
1263
|
const actionWeakMap = new WeakMap();
|
|
1254
1264
|
const createAction = (callback, rootOptions = {}) => {
|
|
@@ -1855,7 +1865,7 @@ const createActionProxyFromSignal = (
|
|
|
1855
1865
|
const _updateTarget = (params) => {
|
|
1856
1866
|
const previousActionTarget = actionTargetPreviousWeakRef?.deref();
|
|
1857
1867
|
|
|
1858
|
-
if (params === NO_PARAMS
|
|
1868
|
+
if (params === NO_PARAMS) {
|
|
1859
1869
|
actionTarget = null;
|
|
1860
1870
|
currentAction = action;
|
|
1861
1871
|
currentActionPrivateProperties = getActionPrivateProperties(action);
|
|
@@ -2060,7 +2070,7 @@ const createActionProxyFromSignal = (
|
|
|
2060
2070
|
};
|
|
2061
2071
|
|
|
2062
2072
|
const generateActionName = (name, params) => {
|
|
2063
|
-
if (params === NO_PARAMS
|
|
2073
|
+
if (params === NO_PARAMS) {
|
|
2064
2074
|
return `${name}({})`;
|
|
2065
2075
|
}
|
|
2066
2076
|
// Use stringifyForDisplay with asFunctionArgs option for the entire args array
|
|
@@ -4734,7 +4744,7 @@ const DIMENSION_PROPS = {
|
|
|
4734
4744
|
return null;
|
|
4735
4745
|
}
|
|
4736
4746
|
if (parentBoxFlow === "column" || parentBoxFlow === "inline-column") {
|
|
4737
|
-
return { flexGrow: 1 }; // Grow horizontally in row
|
|
4747
|
+
return { flexGrow: 1, flexBasis: "0%" }; // Grow horizontally in row
|
|
4738
4748
|
}
|
|
4739
4749
|
if (parentBoxFlow === "row") {
|
|
4740
4750
|
return { minWidth: "100%", width: "auto" }; // Take full width in column
|
|
@@ -4749,7 +4759,7 @@ const DIMENSION_PROPS = {
|
|
|
4749
4759
|
return { minHeight: "100%", height: "auto" }; // Make column full height
|
|
4750
4760
|
}
|
|
4751
4761
|
if (parentBoxFlow === "row" || parentBoxFlow === "inline-row") {
|
|
4752
|
-
return { flexGrow: 1 }; // Make row full height
|
|
4762
|
+
return { flexGrow: 1, flexBasis: "0%" }; // Make row full height
|
|
4753
4763
|
}
|
|
4754
4764
|
return { minHeight: "100%", height: "auto" }; // Take full height outside flex
|
|
4755
4765
|
},
|
|
@@ -4933,6 +4943,9 @@ const VISUAL_PROPS = {
|
|
|
4933
4943
|
filter: PASS_THROUGH,
|
|
4934
4944
|
cursor: PASS_THROUGH,
|
|
4935
4945
|
transition: PASS_THROUGH,
|
|
4946
|
+
overflow: PASS_THROUGH,
|
|
4947
|
+
overflowX: PASS_THROUGH,
|
|
4948
|
+
overflowY: PASS_THROUGH,
|
|
4936
4949
|
};
|
|
4937
4950
|
const CONTENT_PROPS = {
|
|
4938
4951
|
align: applyOnTwoProps("alignX", "alignY"),
|
|
@@ -7173,26 +7186,337 @@ const useUITransitionContentId = value => {
|
|
|
7173
7186
|
}, []);
|
|
7174
7187
|
};
|
|
7175
7188
|
|
|
7189
|
+
const rawUrlPartSymbol = Symbol("raw_url_part");
|
|
7190
|
+
const rawUrlPart = (value) => {
|
|
7191
|
+
return {
|
|
7192
|
+
[rawUrlPartSymbol]: true,
|
|
7193
|
+
value,
|
|
7194
|
+
};
|
|
7195
|
+
};
|
|
7196
|
+
|
|
7197
|
+
const removeOptionalParts = (url) => {
|
|
7198
|
+
// Only remove optional parts that still have ? (weren't replaced with actual values)
|
|
7199
|
+
// Find the first unused optional part and remove everything from there onwards
|
|
7200
|
+
let result = url;
|
|
7201
|
+
|
|
7202
|
+
// Find the first occurrence of an unused optional part (still has ?)
|
|
7203
|
+
const optionalPartMatch = result.match(/(\/?\*|\/:[^/?]*|\{[^}]*\})\?/);
|
|
7204
|
+
|
|
7205
|
+
if (optionalPartMatch) {
|
|
7206
|
+
// Remove everything from the start of the first unused optional part
|
|
7207
|
+
const optionalStartIndex = optionalPartMatch.index;
|
|
7208
|
+
result = result.substring(0, optionalStartIndex);
|
|
7209
|
+
|
|
7210
|
+
// Clean up trailing slashes
|
|
7211
|
+
result = result.replace(/\/$/, "");
|
|
7212
|
+
}
|
|
7213
|
+
|
|
7214
|
+
return result;
|
|
7215
|
+
};
|
|
7216
|
+
|
|
7217
|
+
const buildRouteRelativeUrl = (
|
|
7218
|
+
urlPatternInput,
|
|
7219
|
+
params,
|
|
7220
|
+
{ extraParamEffect = "inject_as_search_param" } = {},
|
|
7221
|
+
) => {
|
|
7222
|
+
let relativeUrl = urlPatternInput;
|
|
7223
|
+
let hasRawUrlPartWithInvalidChars = false;
|
|
7224
|
+
let stringQueryParams = "";
|
|
7225
|
+
|
|
7226
|
+
// Handle string params (query string) - store for later appending
|
|
7227
|
+
if (typeof params === "string") {
|
|
7228
|
+
stringQueryParams = params;
|
|
7229
|
+
// Remove leading ? if present for processing
|
|
7230
|
+
if (stringQueryParams.startsWith("?")) {
|
|
7231
|
+
stringQueryParams = stringQueryParams.slice(1);
|
|
7232
|
+
}
|
|
7233
|
+
// Set params to empty object so the rest of the function processes the URL pattern
|
|
7234
|
+
params = null;
|
|
7235
|
+
}
|
|
7236
|
+
|
|
7237
|
+
// Encode parameter values for URL usage, with special handling for raw URL parts.
|
|
7238
|
+
// When a parameter is wrapped with rawUrlPart(), it bypasses encoding and is
|
|
7239
|
+
// inserted as-is into the URL. This allows including pre-encoded values or
|
|
7240
|
+
// special characters that should not be percent-encoded.
|
|
7241
|
+
const encodeParamValue = (value) => {
|
|
7242
|
+
if (value && value[rawUrlPartSymbol]) {
|
|
7243
|
+
const rawValue = value.value;
|
|
7244
|
+
// Check if raw value contains invalid URL characters
|
|
7245
|
+
if (/[\s<>{}|\\^`]/.test(rawValue)) {
|
|
7246
|
+
hasRawUrlPartWithInvalidChars = true;
|
|
7247
|
+
}
|
|
7248
|
+
return rawValue;
|
|
7249
|
+
}
|
|
7250
|
+
return encodeURIComponent(value);
|
|
7251
|
+
};
|
|
7252
|
+
const extraParamMap = new Map();
|
|
7253
|
+
if (params) {
|
|
7254
|
+
const keys = Object.keys(params);
|
|
7255
|
+
// Replace named parameters (:param and {param}) and remove optional markers
|
|
7256
|
+
for (const key of keys) {
|
|
7257
|
+
const value = params[key];
|
|
7258
|
+
const encodedValue = encodeParamValue(value);
|
|
7259
|
+
const beforeReplace = relativeUrl;
|
|
7260
|
+
|
|
7261
|
+
// Replace parameter and remove optional marker if present
|
|
7262
|
+
relativeUrl = relativeUrl.replace(`:${key}?`, encodedValue);
|
|
7263
|
+
relativeUrl = relativeUrl.replace(`:${key}`, encodedValue);
|
|
7264
|
+
relativeUrl = relativeUrl.replace(`{${key}}?`, encodedValue);
|
|
7265
|
+
relativeUrl = relativeUrl.replace(`{${key}}`, encodedValue);
|
|
7266
|
+
|
|
7267
|
+
// If the URL did not change we'll maybe delete that param
|
|
7268
|
+
if (relativeUrl === beforeReplace) {
|
|
7269
|
+
extraParamMap.set(key, value);
|
|
7270
|
+
}
|
|
7271
|
+
}
|
|
7272
|
+
// Handle complex optional groups like {/time/:duration}?
|
|
7273
|
+
// Replace parameters inside optional groups and remove the optional marker
|
|
7274
|
+
relativeUrl = relativeUrl.replace(/\{([^}]*)\}\?/g, (match, group) => {
|
|
7275
|
+
let processedGroup = group;
|
|
7276
|
+
let hasReplacements = false;
|
|
7277
|
+
|
|
7278
|
+
// Check if any parameters in the group were provided
|
|
7279
|
+
for (const key of keys) {
|
|
7280
|
+
if (params[key] !== undefined) {
|
|
7281
|
+
const encodedValue = encodeParamValue(params[key]);
|
|
7282
|
+
const paramPattern = new RegExp(`:${key}\\b`);
|
|
7283
|
+
if (paramPattern.test(processedGroup)) {
|
|
7284
|
+
processedGroup = processedGroup.replace(paramPattern, encodedValue);
|
|
7285
|
+
hasReplacements = true;
|
|
7286
|
+
extraParamMap.delete(key);
|
|
7287
|
+
}
|
|
7288
|
+
}
|
|
7289
|
+
}
|
|
7290
|
+
|
|
7291
|
+
// Also check for literal parts that match parameter names (like /time where time is a param)
|
|
7292
|
+
for (const key of keys) {
|
|
7293
|
+
if (params[key] !== undefined) {
|
|
7294
|
+
const encodedValue = encodeParamValue(params[key]);
|
|
7295
|
+
// Check for literal parts like /time that match parameter names
|
|
7296
|
+
const literalPattern = new RegExp(`\\/${key}\\b`);
|
|
7297
|
+
if (literalPattern.test(processedGroup)) {
|
|
7298
|
+
processedGroup = processedGroup.replace(
|
|
7299
|
+
literalPattern,
|
|
7300
|
+
`/${encodedValue}`,
|
|
7301
|
+
);
|
|
7302
|
+
hasReplacements = true;
|
|
7303
|
+
extraParamMap.delete(key);
|
|
7304
|
+
}
|
|
7305
|
+
}
|
|
7306
|
+
}
|
|
7307
|
+
|
|
7308
|
+
// If we made replacements, include the group (without the optional marker)
|
|
7309
|
+
// If no replacements, return empty string (remove the optional group)
|
|
7310
|
+
return hasReplacements ? processedGroup : "";
|
|
7311
|
+
});
|
|
7312
|
+
}
|
|
7313
|
+
|
|
7314
|
+
// Clean up any double slashes or trailing slashes that might result
|
|
7315
|
+
relativeUrl = relativeUrl.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
7316
|
+
|
|
7317
|
+
// Handle remaining wildcards
|
|
7318
|
+
if (params) {
|
|
7319
|
+
let wildcardIndex = 0;
|
|
7320
|
+
relativeUrl = relativeUrl.replace(/\*/g, () => {
|
|
7321
|
+
const paramKey = wildcardIndex.toString();
|
|
7322
|
+
const paramValue = params[paramKey];
|
|
7323
|
+
if (paramValue) {
|
|
7324
|
+
extraParamMap.delete(paramKey);
|
|
7325
|
+
}
|
|
7326
|
+
const replacement = paramValue ? encodeParamValue(paramValue) : "*";
|
|
7327
|
+
wildcardIndex++;
|
|
7328
|
+
return replacement;
|
|
7329
|
+
});
|
|
7330
|
+
}
|
|
7331
|
+
|
|
7332
|
+
// Handle optional parts after parameter replacement
|
|
7333
|
+
// This includes patterns like /*?, {/time/*}?, :param?, etc.
|
|
7334
|
+
relativeUrl = removeOptionalParts(relativeUrl);
|
|
7335
|
+
// we did not replace anything, or not enough to remove the last "*"
|
|
7336
|
+
if (relativeUrl.endsWith("*")) {
|
|
7337
|
+
relativeUrl = relativeUrl.slice(0, -1);
|
|
7338
|
+
}
|
|
7339
|
+
|
|
7340
|
+
// Normalize trailing slash: always favor URLs without trailing slash
|
|
7341
|
+
// except for root path which should remain "/"
|
|
7342
|
+
if (relativeUrl.endsWith("/") && relativeUrl.length > 1) {
|
|
7343
|
+
relativeUrl = relativeUrl.slice(0, -1);
|
|
7344
|
+
}
|
|
7345
|
+
|
|
7346
|
+
// Add remaining parameters as search params
|
|
7347
|
+
if (extraParamMap.size > 0) {
|
|
7348
|
+
if (extraParamEffect === "inject_as_search_param") {
|
|
7349
|
+
const searchParamPairs = [];
|
|
7350
|
+
for (const [key, value] of extraParamMap) {
|
|
7351
|
+
if (value !== undefined && value !== null) {
|
|
7352
|
+
const encodedKey = encodeURIComponent(key);
|
|
7353
|
+
// Handle boolean values - if true, just add the key without value
|
|
7354
|
+
if (value === true) {
|
|
7355
|
+
searchParamPairs.push(encodedKey);
|
|
7356
|
+
} else {
|
|
7357
|
+
const encodedValue = encodeParamValue(value);
|
|
7358
|
+
searchParamPairs.push(`${encodedKey}=${encodedValue}`);
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
}
|
|
7362
|
+
if (searchParamPairs.length > 0) {
|
|
7363
|
+
const searchString = searchParamPairs.join("&");
|
|
7364
|
+
relativeUrl += (relativeUrl.includes("?") ? "&" : "?") + searchString;
|
|
7365
|
+
}
|
|
7366
|
+
} else if (extraParamEffect === "warn") {
|
|
7367
|
+
console.warn(
|
|
7368
|
+
`Unknown parameters given to "${urlPatternInput}":`,
|
|
7369
|
+
Array.from(extraParamMap.keys()),
|
|
7370
|
+
);
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
|
|
7374
|
+
// Append string query params if any
|
|
7375
|
+
if (stringQueryParams) {
|
|
7376
|
+
relativeUrl += (relativeUrl.includes("?") ? "&" : "?") + stringQueryParams;
|
|
7377
|
+
}
|
|
7378
|
+
|
|
7379
|
+
return {
|
|
7380
|
+
relativeUrl,
|
|
7381
|
+
hasRawUrlPartWithInvalidChars,
|
|
7382
|
+
};
|
|
7383
|
+
};
|
|
7384
|
+
|
|
7385
|
+
const createRoutePattern = (urlPatternInput, baseUrl) => {
|
|
7386
|
+
// Remove leading slash from urlPattern to make it relative to baseUrl
|
|
7387
|
+
const normalizedUrlPattern = urlPatternInput.startsWith("/")
|
|
7388
|
+
? urlPatternInput.slice(1)
|
|
7389
|
+
: urlPatternInput;
|
|
7390
|
+
const urlPattern = new URLPattern(normalizedUrlPattern, baseUrl, {
|
|
7391
|
+
ignoreCase: true,
|
|
7392
|
+
});
|
|
7393
|
+
|
|
7394
|
+
// Analyze pattern once to detect optional params (named and wildcard indices)
|
|
7395
|
+
// Note: Wildcard indices are stored as strings ("0", "1", ...) to match keys from extractParams
|
|
7396
|
+
const optionalParamKeySet = new Set();
|
|
7397
|
+
normalizedUrlPattern.replace(/:([A-Za-z0-9_]+)\?/g, (_m, name) => {
|
|
7398
|
+
optionalParamKeySet.add(name);
|
|
7399
|
+
return "";
|
|
7400
|
+
});
|
|
7401
|
+
let wildcardIndex = 0;
|
|
7402
|
+
normalizedUrlPattern.replace(/\*(\?)?/g, (_m, opt) => {
|
|
7403
|
+
if (opt === "?") {
|
|
7404
|
+
optionalParamKeySet.add(String(wildcardIndex));
|
|
7405
|
+
}
|
|
7406
|
+
wildcardIndex++;
|
|
7407
|
+
return "";
|
|
7408
|
+
});
|
|
7409
|
+
|
|
7410
|
+
const applyOn = (url) => {
|
|
7411
|
+
|
|
7412
|
+
// Check if the URL matches the route pattern
|
|
7413
|
+
const match = urlPattern.exec(url);
|
|
7414
|
+
if (match) {
|
|
7415
|
+
return extractParams(match, url);
|
|
7416
|
+
}
|
|
7417
|
+
|
|
7418
|
+
// If no match, try with normalized URLs (trailing slash handling)
|
|
7419
|
+
const urlObj = new URL(url, baseUrl);
|
|
7420
|
+
const pathname = urlObj.pathname;
|
|
7421
|
+
|
|
7422
|
+
// Try removing trailing slash from pathname
|
|
7423
|
+
if (pathname.endsWith("/") && pathname.length > 1) {
|
|
7424
|
+
const pathnameWithoutSlash = pathname.slice(0, -1);
|
|
7425
|
+
urlObj.pathname = pathnameWithoutSlash;
|
|
7426
|
+
const normalizedUrl = urlObj.href;
|
|
7427
|
+
const matchWithoutTrailingSlash = urlPattern.exec(normalizedUrl);
|
|
7428
|
+
if (matchWithoutTrailingSlash) {
|
|
7429
|
+
return extractParams(matchWithoutTrailingSlash, url);
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
// Try adding trailing slash to pathname
|
|
7433
|
+
else if (!pathname.endsWith("/")) {
|
|
7434
|
+
const pathnameWithSlash = `${pathname}/`;
|
|
7435
|
+
urlObj.pathname = pathnameWithSlash;
|
|
7436
|
+
const normalizedUrl = urlObj.href;
|
|
7437
|
+
const matchWithTrailingSlash = urlPattern.exec(normalizedUrl);
|
|
7438
|
+
if (matchWithTrailingSlash) {
|
|
7439
|
+
return extractParams(matchWithTrailingSlash, url);
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
return null;
|
|
7443
|
+
};
|
|
7444
|
+
|
|
7445
|
+
const extractParams = (match, originalUrl) => {
|
|
7446
|
+
const params = {};
|
|
7447
|
+
|
|
7448
|
+
// Extract search parameters from the original URL
|
|
7449
|
+
const urlObj = new URL(originalUrl, baseUrl);
|
|
7450
|
+
for (const [key, value] of urlObj.searchParams) {
|
|
7451
|
+
params[key] = value;
|
|
7452
|
+
}
|
|
7453
|
+
|
|
7454
|
+
// Collect all parameters from URLPattern groups, handling both named and numbered groups
|
|
7455
|
+
let wildcardOffset = 0;
|
|
7456
|
+
for (const property of URL_PATTERN_PROPERTIES_WITH_GROUP_SET) {
|
|
7457
|
+
const urlPartMatch = match[property];
|
|
7458
|
+
if (urlPartMatch && urlPartMatch.groups) {
|
|
7459
|
+
let localWildcardCount = 0;
|
|
7460
|
+
for (const key of Object.keys(urlPartMatch.groups)) {
|
|
7461
|
+
const value = urlPartMatch.groups[key];
|
|
7462
|
+
const keyAsNumber = parseInt(key, 10);
|
|
7463
|
+
if (!isNaN(keyAsNumber)) {
|
|
7464
|
+
// Skip group "0" from search params as it captures the entire search string
|
|
7465
|
+
if (property === "search" && key === "0") {
|
|
7466
|
+
continue;
|
|
7467
|
+
}
|
|
7468
|
+
if (value) {
|
|
7469
|
+
// Only include non-empty values and non-ignored wildcard indices
|
|
7470
|
+
const wildcardKey = String(wildcardOffset + keyAsNumber);
|
|
7471
|
+
if (!optionalParamKeySet.has(wildcardKey)) {
|
|
7472
|
+
params[wildcardKey] = decodeURIComponent(value);
|
|
7473
|
+
}
|
|
7474
|
+
localWildcardCount++;
|
|
7475
|
+
}
|
|
7476
|
+
} else if (!optionalParamKeySet.has(key)) {
|
|
7477
|
+
// Named group (:param or {param}) - only include if not ignored
|
|
7478
|
+
params[key] = decodeURIComponent(value);
|
|
7479
|
+
}
|
|
7480
|
+
}
|
|
7481
|
+
// Update wildcard offset for next URL part
|
|
7482
|
+
wildcardOffset += localWildcardCount;
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
return params;
|
|
7486
|
+
};
|
|
7487
|
+
|
|
7488
|
+
return {
|
|
7489
|
+
urlPattern,
|
|
7490
|
+
applyOn,
|
|
7491
|
+
};
|
|
7492
|
+
};
|
|
7493
|
+
|
|
7494
|
+
const URL_PATTERN_PROPERTIES_WITH_GROUP_SET = new Set([
|
|
7495
|
+
"protocol",
|
|
7496
|
+
"username",
|
|
7497
|
+
"password",
|
|
7498
|
+
"hostname",
|
|
7499
|
+
"pathname",
|
|
7500
|
+
"search",
|
|
7501
|
+
"hash",
|
|
7502
|
+
]);
|
|
7503
|
+
|
|
7176
7504
|
/**
|
|
7177
7505
|
*
|
|
7178
7506
|
*
|
|
7179
7507
|
*/
|
|
7180
7508
|
|
|
7181
7509
|
|
|
7182
|
-
let baseUrl
|
|
7510
|
+
let baseUrl;
|
|
7511
|
+
if (typeof window === "undefined") {
|
|
7512
|
+
baseUrl = "http://localhost/";
|
|
7513
|
+
} else {
|
|
7514
|
+
baseUrl = window.location.origin;
|
|
7515
|
+
}
|
|
7183
7516
|
|
|
7184
7517
|
const setBaseUrl = (value) => {
|
|
7185
7518
|
baseUrl = new URL(value, window.location).href;
|
|
7186
7519
|
};
|
|
7187
|
-
|
|
7188
|
-
const rawUrlPartSymbol = Symbol("raw_url_part");
|
|
7189
|
-
const rawUrlPart = (value) => {
|
|
7190
|
-
return {
|
|
7191
|
-
[rawUrlPartSymbol]: true,
|
|
7192
|
-
value,
|
|
7193
|
-
};
|
|
7194
|
-
};
|
|
7195
|
-
const NO_PARAMS = { [SYMBOL_IDENTITY]: Symbol("no_params") };
|
|
7196
7520
|
// Controls what happens to actions when their route becomes inactive:
|
|
7197
7521
|
// 'abort' - Cancel the action immediately when route deactivates
|
|
7198
7522
|
// 'keep-loading' - Allow action to continue running after route deactivation
|
|
@@ -7218,26 +7542,19 @@ const updateRoutes = (
|
|
|
7218
7542
|
const routeMatchInfoSet = new Set();
|
|
7219
7543
|
for (const route of routeSet) {
|
|
7220
7544
|
const routePrivateProperties = getRoutePrivateProperties(route);
|
|
7221
|
-
const {
|
|
7545
|
+
const { routePattern } = routePrivateProperties;
|
|
7222
7546
|
|
|
7223
7547
|
// Get previous state
|
|
7224
7548
|
const previousState = routePreviousStateMap.get(route) || {
|
|
7225
7549
|
active: false,
|
|
7226
|
-
params:
|
|
7550
|
+
params: null,
|
|
7227
7551
|
};
|
|
7228
7552
|
const oldActive = previousState.active;
|
|
7229
7553
|
const oldParams = previousState.params;
|
|
7230
|
-
|
|
7231
|
-
const
|
|
7232
|
-
const newActive = Boolean(match);
|
|
7554
|
+
const extractedParams = routePattern.applyOn(url);
|
|
7555
|
+
const newActive = Boolean(extractedParams);
|
|
7233
7556
|
let newParams;
|
|
7234
|
-
if (
|
|
7235
|
-
const { optionalParamKeySet } = routePrivateProperties;
|
|
7236
|
-
const extractedParams = extractParams(
|
|
7237
|
-
urlPattern,
|
|
7238
|
-
url,
|
|
7239
|
-
optionalParamKeySet,
|
|
7240
|
-
);
|
|
7557
|
+
if (extractedParams) {
|
|
7241
7558
|
if (compareTwoJsValues(oldParams, extractedParams)) {
|
|
7242
7559
|
// No change in parameters, keep the old params
|
|
7243
7560
|
newParams = oldParams;
|
|
@@ -7245,7 +7562,7 @@ const updateRoutes = (
|
|
|
7245
7562
|
newParams = extractedParams;
|
|
7246
7563
|
}
|
|
7247
7564
|
} else {
|
|
7248
|
-
newParams =
|
|
7565
|
+
newParams = null;
|
|
7249
7566
|
}
|
|
7250
7567
|
|
|
7251
7568
|
const routeMatchInfo = {
|
|
@@ -7374,51 +7691,6 @@ const updateRoutes = (
|
|
|
7374
7691
|
activeRouteSet,
|
|
7375
7692
|
};
|
|
7376
7693
|
};
|
|
7377
|
-
const extractParams = (urlPattern, url, ignoreSet = new Set()) => {
|
|
7378
|
-
const match = urlPattern.exec(url);
|
|
7379
|
-
if (!match) {
|
|
7380
|
-
return NO_PARAMS;
|
|
7381
|
-
}
|
|
7382
|
-
const params = {};
|
|
7383
|
-
|
|
7384
|
-
// Collect all parameters from URLPattern groups, handling both named and numbered groups
|
|
7385
|
-
let wildcardOffset = 0;
|
|
7386
|
-
for (const property of URL_PATTERN_PROPERTIES_WITH_GROUP_SET) {
|
|
7387
|
-
const urlPartMatch = match[property];
|
|
7388
|
-
if (urlPartMatch && urlPartMatch.groups) {
|
|
7389
|
-
let localWildcardCount = 0;
|
|
7390
|
-
for (const key of Object.keys(urlPartMatch.groups)) {
|
|
7391
|
-
const value = urlPartMatch.groups[key];
|
|
7392
|
-
const keyAsNumber = parseInt(key, 10);
|
|
7393
|
-
if (!isNaN(keyAsNumber)) {
|
|
7394
|
-
if (value) {
|
|
7395
|
-
// Only include non-empty values and non-ignored wildcard indices
|
|
7396
|
-
const wildcardKey = String(wildcardOffset + keyAsNumber);
|
|
7397
|
-
if (!ignoreSet.has(wildcardKey)) {
|
|
7398
|
-
params[wildcardKey] = decodeURIComponent(value);
|
|
7399
|
-
}
|
|
7400
|
-
localWildcardCount++;
|
|
7401
|
-
}
|
|
7402
|
-
} else if (!ignoreSet.has(key)) {
|
|
7403
|
-
// Named group (:param or {param}) - only include if not ignored
|
|
7404
|
-
params[key] = decodeURIComponent(value);
|
|
7405
|
-
}
|
|
7406
|
-
}
|
|
7407
|
-
// Update wildcard offset for next URL part
|
|
7408
|
-
wildcardOffset += localWildcardCount;
|
|
7409
|
-
}
|
|
7410
|
-
}
|
|
7411
|
-
return params;
|
|
7412
|
-
};
|
|
7413
|
-
const URL_PATTERN_PROPERTIES_WITH_GROUP_SET = new Set([
|
|
7414
|
-
"protocol",
|
|
7415
|
-
"username",
|
|
7416
|
-
"password",
|
|
7417
|
-
"hostname",
|
|
7418
|
-
"pathname",
|
|
7419
|
-
"search",
|
|
7420
|
-
"hash",
|
|
7421
|
-
]);
|
|
7422
7694
|
|
|
7423
7695
|
const routePrivatePropertiesMap = new Map();
|
|
7424
7696
|
const getRoutePrivateProperties = (route) => {
|
|
@@ -7439,7 +7711,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
7439
7711
|
urlPattern: urlPatternInput,
|
|
7440
7712
|
isRoute: true,
|
|
7441
7713
|
active: false,
|
|
7442
|
-
params:
|
|
7714
|
+
params: null,
|
|
7443
7715
|
buildUrl: null,
|
|
7444
7716
|
bindAction: null,
|
|
7445
7717
|
relativeUrl: null,
|
|
@@ -7455,13 +7727,12 @@ const createRoute = (urlPatternInput) => {
|
|
|
7455
7727
|
routeSet.add(route);
|
|
7456
7728
|
|
|
7457
7729
|
const routePrivateProperties = {
|
|
7458
|
-
|
|
7730
|
+
routePattern: null,
|
|
7459
7731
|
activeSignal: null,
|
|
7460
7732
|
paramsSignal: null,
|
|
7461
7733
|
visitedSignal: null,
|
|
7462
7734
|
relativeUrlSignal: null,
|
|
7463
7735
|
urlSignal: null,
|
|
7464
|
-
optionalParamKeySet: null,
|
|
7465
7736
|
updateStatus: ({ active, params, visited }) => {
|
|
7466
7737
|
let someChange = false;
|
|
7467
7738
|
activeSignal.value = active;
|
|
@@ -7486,101 +7757,32 @@ const createRoute = (urlPatternInput) => {
|
|
|
7486
7757
|
};
|
|
7487
7758
|
routePrivatePropertiesMap.set(route, routePrivateProperties);
|
|
7488
7759
|
|
|
7489
|
-
const buildRelativeUrl = (
|
|
7490
|
-
params
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
// Encode parameter values for URL usage, with special handling for raw URL parts.
|
|
7497
|
-
// When a parameter is wrapped with rawUrlPart(), it bypasses encoding and is
|
|
7498
|
-
// inserted as-is into the URL. This allows including pre-encoded values or
|
|
7499
|
-
// special characters that should not be percent-encoded.
|
|
7500
|
-
const encodeParamValue = (value) => {
|
|
7501
|
-
if (value && value[rawUrlPartSymbol]) {
|
|
7502
|
-
const rawValue = value.value;
|
|
7503
|
-
// Check if raw value contains invalid URL characters
|
|
7504
|
-
if (/[\s<>{}|\\^`]/.test(rawValue)) {
|
|
7505
|
-
hasRawUrlPartWithInvalidChars = true;
|
|
7506
|
-
}
|
|
7507
|
-
return rawValue;
|
|
7508
|
-
}
|
|
7509
|
-
return encodeURIComponent(value);
|
|
7510
|
-
};
|
|
7511
|
-
|
|
7512
|
-
const keys = Object.keys(params);
|
|
7513
|
-
const extraParamSet = new Set(keys);
|
|
7760
|
+
const buildRelativeUrl = (params, options) =>
|
|
7761
|
+
buildRouteRelativeUrl(urlPatternInput, params, options);
|
|
7762
|
+
route.buildRelativeUrl = (params, options) => {
|
|
7763
|
+
const { relativeUrl } = buildRelativeUrl(params, options);
|
|
7764
|
+
return relativeUrl;
|
|
7765
|
+
};
|
|
7514
7766
|
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
// If the URL changed, no need to inject this param
|
|
7523
|
-
if (relativeUrl !== beforeReplace) {
|
|
7524
|
-
extraParamSet.delete(key);
|
|
7525
|
-
}
|
|
7767
|
+
route.matchesParams = (otherParams) => {
|
|
7768
|
+
const params = route.params;
|
|
7769
|
+
const paramsIsFalsyOrEmpty = !params || Object.keys(params).length === 0;
|
|
7770
|
+
const otherParamsFalsyOrEmpty =
|
|
7771
|
+
!otherParams || Object.keys(otherParams).length === 0;
|
|
7772
|
+
if (paramsIsFalsyOrEmpty) {
|
|
7773
|
+
return otherParamsFalsyOrEmpty;
|
|
7526
7774
|
}
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
// always remove the wildcard part for URL building since it's optional
|
|
7530
|
-
if (relativeUrl.endsWith("/*?")) {
|
|
7531
|
-
// Always remove the optional wildcard part for URL building
|
|
7532
|
-
relativeUrl = relativeUrl.slice(0, -"/*?".length);
|
|
7533
|
-
} else if (relativeUrl.endsWith("{/}?*")) {
|
|
7534
|
-
relativeUrl = relativeUrl.slice(0, -"{/}?*".length);
|
|
7535
|
-
} else {
|
|
7536
|
-
// For required wildcards (/*) or other patterns, replace normally
|
|
7537
|
-
let wildcardIndex = 0;
|
|
7538
|
-
relativeUrl = relativeUrl.replace(/\*/g, () => {
|
|
7539
|
-
const paramKey = wildcardIndex.toString();
|
|
7540
|
-
const paramValue = params[paramKey];
|
|
7541
|
-
if (paramValue) {
|
|
7542
|
-
extraParamSet.delete(paramKey);
|
|
7543
|
-
}
|
|
7544
|
-
const replacement = paramValue ? encodeParamValue(paramValue) : "*";
|
|
7545
|
-
wildcardIndex++;
|
|
7546
|
-
return replacement;
|
|
7547
|
-
});
|
|
7548
|
-
// we did not replace anything, or not enough to remove the last "*"
|
|
7549
|
-
if (relativeUrl.endsWith("*")) {
|
|
7550
|
-
relativeUrl = relativeUrl.slice(0, -1);
|
|
7551
|
-
}
|
|
7775
|
+
if (otherParamsFalsyOrEmpty) {
|
|
7776
|
+
return false;
|
|
7552
7777
|
}
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
const searchParamPairs = [];
|
|
7558
|
-
for (const key of extraParamSet) {
|
|
7559
|
-
const value = params[key];
|
|
7560
|
-
if (value !== undefined && value !== null) {
|
|
7561
|
-
const encodedKey = encodeURIComponent(key);
|
|
7562
|
-
const encodedValue = encodeParamValue(value);
|
|
7563
|
-
searchParamPairs.push(`${encodedKey}=${encodedValue}`);
|
|
7564
|
-
}
|
|
7565
|
-
}
|
|
7566
|
-
if (searchParamPairs.length > 0) {
|
|
7567
|
-
const searchString = searchParamPairs.join("&");
|
|
7568
|
-
relativeUrl += (relativeUrl.includes("?") ? "&" : "?") + searchString;
|
|
7569
|
-
}
|
|
7570
|
-
} else if (extraParamEffect === "warn") {
|
|
7571
|
-
console.warn(
|
|
7572
|
-
`Unknown parameters given to "${urlPatternInput}":`,
|
|
7573
|
-
Array.from(extraParamSet),
|
|
7574
|
-
);
|
|
7778
|
+
const paramsWithoutWildcards = {};
|
|
7779
|
+
for (const key of Object.keys(params)) {
|
|
7780
|
+
if (!Number.isInteger(Number(key))) {
|
|
7781
|
+
paramsWithoutWildcards[key] = params[key];
|
|
7575
7782
|
}
|
|
7576
7783
|
}
|
|
7577
|
-
|
|
7578
|
-
return {
|
|
7579
|
-
relativeUrl,
|
|
7580
|
-
hasRawUrlPartWithInvalidChars,
|
|
7581
|
-
};
|
|
7784
|
+
return compareTwoJsValues(paramsWithoutWildcards, otherParams);
|
|
7582
7785
|
};
|
|
7583
|
-
route.buildRelativeUrl = buildRelativeUrl;
|
|
7584
7786
|
|
|
7585
7787
|
/**
|
|
7586
7788
|
* Builds a complete URL for this route with the given parameters.
|
|
@@ -7608,7 +7810,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
7608
7810
|
processedRelativeUrl = processedRelativeUrl.slice(1);
|
|
7609
7811
|
}
|
|
7610
7812
|
if (hasRawUrlPartWithInvalidChars) {
|
|
7611
|
-
return `${baseUrl}
|
|
7813
|
+
return `${baseUrl}${processedRelativeUrl}`;
|
|
7612
7814
|
}
|
|
7613
7815
|
const url = new URL(processedRelativeUrl, baseUrl).href;
|
|
7614
7816
|
return url;
|
|
@@ -7616,7 +7818,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
7616
7818
|
route.buildUrl = buildUrl;
|
|
7617
7819
|
|
|
7618
7820
|
const activeSignal = signal(false);
|
|
7619
|
-
const paramsSignal = signal(
|
|
7821
|
+
const paramsSignal = signal(null);
|
|
7620
7822
|
const visitedSignal = signal(false);
|
|
7621
7823
|
const relativeUrlSignal = computed(() => {
|
|
7622
7824
|
const params = paramsSignal.value;
|
|
@@ -7645,7 +7847,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
7645
7847
|
if (route.action) {
|
|
7646
7848
|
route.action.replaceParams(updatedParams);
|
|
7647
7849
|
}
|
|
7648
|
-
browserIntegration$1.
|
|
7850
|
+
browserIntegration$1.navTo(updatedUrl, { replace: true });
|
|
7649
7851
|
};
|
|
7650
7852
|
route.replaceParams = replaceParams;
|
|
7651
7853
|
|
|
@@ -7656,7 +7858,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
7656
7858
|
* and listen store changes to do this:
|
|
7657
7859
|
*
|
|
7658
7860
|
* When we detect changes we want to update the route params
|
|
7659
|
-
* so we'll need to use
|
|
7861
|
+
* so we'll need to use navTo(buildUrl(params), { replace: true })
|
|
7660
7862
|
*
|
|
7661
7863
|
* reinserted is useful because the item id might have changed
|
|
7662
7864
|
* but not the mutable key
|
|
@@ -7721,37 +7923,14 @@ const createRoute = (urlPatternInput) => {
|
|
|
7721
7923
|
route.bindAction = bindAction;
|
|
7722
7924
|
|
|
7723
7925
|
{
|
|
7724
|
-
// Remove leading slash from urlPattern to make it relative to baseUrl
|
|
7725
|
-
const normalizedUrlPattern = urlPatternInput.startsWith("/")
|
|
7726
|
-
? urlPatternInput.slice(1)
|
|
7727
|
-
: urlPatternInput;
|
|
7728
|
-
const urlPattern = new URLPattern(normalizedUrlPattern, baseUrl, {
|
|
7729
|
-
ignoreCase: true,
|
|
7730
|
-
});
|
|
7731
|
-
routePrivateProperties.urlPattern = urlPattern;
|
|
7732
7926
|
routePrivateProperties.activeSignal = activeSignal;
|
|
7733
7927
|
routePrivateProperties.paramsSignal = paramsSignal;
|
|
7734
7928
|
routePrivateProperties.visitedSignal = visitedSignal;
|
|
7735
7929
|
routePrivateProperties.relativeUrlSignal = relativeUrlSignal;
|
|
7736
7930
|
routePrivateProperties.urlSignal = urlSignal;
|
|
7737
7931
|
routePrivateProperties.cleanupCallbackSet = cleanupCallbackSet;
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
// Note: Wildcard indices are stored as strings ("0", "1", ...) to match keys from extractParams
|
|
7741
|
-
const optionalParamKeySet = new Set();
|
|
7742
|
-
normalizedUrlPattern.replace(/:([A-Za-z0-9_]+)\?/g, (_m, name) => {
|
|
7743
|
-
optionalParamKeySet.add(name);
|
|
7744
|
-
return "";
|
|
7745
|
-
});
|
|
7746
|
-
let wildcardIndex = 0;
|
|
7747
|
-
normalizedUrlPattern.replace(/\*(\?)?/g, (_m, opt) => {
|
|
7748
|
-
if (opt === "?") {
|
|
7749
|
-
optionalParamKeySet.add(String(wildcardIndex));
|
|
7750
|
-
}
|
|
7751
|
-
wildcardIndex++;
|
|
7752
|
-
return "";
|
|
7753
|
-
});
|
|
7754
|
-
routePrivateProperties.optionalParamKeySet = optionalParamKeySet;
|
|
7932
|
+
const routePattern = createRoutePattern(urlPatternInput, baseUrl);
|
|
7933
|
+
routePrivateProperties.routePattern = routePattern;
|
|
7755
7934
|
}
|
|
7756
7935
|
|
|
7757
7936
|
return route;
|
|
@@ -7944,14 +8123,6 @@ computed(() => {
|
|
|
7944
8123
|
return reasonArray;
|
|
7945
8124
|
});
|
|
7946
8125
|
|
|
7947
|
-
const documentStateSignal = signal(null);
|
|
7948
|
-
const useDocumentState = () => {
|
|
7949
|
-
return documentStateSignal.value;
|
|
7950
|
-
};
|
|
7951
|
-
const updateDocumentState = (value) => {
|
|
7952
|
-
documentStateSignal.value = value;
|
|
7953
|
-
};
|
|
7954
|
-
|
|
7955
8126
|
const documentUrlSignal = signal(window.location.href);
|
|
7956
8127
|
const useDocumentUrl = () => {
|
|
7957
8128
|
return documentUrlSignal.value;
|
|
@@ -7994,6 +8165,14 @@ const urlToScheme = (url) => {
|
|
|
7994
8165
|
return scheme;
|
|
7995
8166
|
};
|
|
7996
8167
|
|
|
8168
|
+
const documentStateSignal = signal(null);
|
|
8169
|
+
const useDocumentState = () => {
|
|
8170
|
+
return documentStateSignal.value;
|
|
8171
|
+
};
|
|
8172
|
+
const updateDocumentState = (value) => {
|
|
8173
|
+
documentStateSignal.value = value;
|
|
8174
|
+
};
|
|
8175
|
+
|
|
7997
8176
|
const getHrefTargetInfo = (href) => {
|
|
7998
8177
|
href = String(href);
|
|
7999
8178
|
|
|
@@ -8214,12 +8393,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
8214
8393
|
});
|
|
8215
8394
|
});
|
|
8216
8395
|
|
|
8217
|
-
const
|
|
8218
|
-
const url = new URL(target, window.location.href).href;
|
|
8219
|
-
const currentUrl = documentUrlSignal.peek();
|
|
8220
|
-
if (url === currentUrl) {
|
|
8221
|
-
return;
|
|
8222
|
-
}
|
|
8396
|
+
const navTo = async (url, { state = null, replace } = {}) => {
|
|
8223
8397
|
if (replace) {
|
|
8224
8398
|
window.history.replaceState(state, null, url);
|
|
8225
8399
|
} else {
|
|
@@ -8228,7 +8402,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
8228
8402
|
handleRoutingTask(url, {
|
|
8229
8403
|
state,
|
|
8230
8404
|
replace,
|
|
8231
|
-
reason: `
|
|
8405
|
+
reason: `navTo called with "${url}"`,
|
|
8232
8406
|
});
|
|
8233
8407
|
};
|
|
8234
8408
|
|
|
@@ -8244,11 +8418,11 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
8244
8418
|
});
|
|
8245
8419
|
};
|
|
8246
8420
|
|
|
8247
|
-
const
|
|
8421
|
+
const navBack = () => {
|
|
8248
8422
|
window.history.back();
|
|
8249
8423
|
};
|
|
8250
8424
|
|
|
8251
|
-
const
|
|
8425
|
+
const navForward = () => {
|
|
8252
8426
|
window.history.forward();
|
|
8253
8427
|
};
|
|
8254
8428
|
|
|
@@ -8266,11 +8440,11 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
8266
8440
|
return {
|
|
8267
8441
|
integration: "browser_history_api",
|
|
8268
8442
|
init,
|
|
8269
|
-
|
|
8443
|
+
navTo,
|
|
8270
8444
|
stop,
|
|
8271
8445
|
reload,
|
|
8272
|
-
|
|
8273
|
-
|
|
8446
|
+
navBack,
|
|
8447
|
+
navForward,
|
|
8274
8448
|
getDocumentState,
|
|
8275
8449
|
replaceDocumentState,
|
|
8276
8450
|
isVisited,
|
|
@@ -8348,7 +8522,17 @@ setOnRouteDefined(() => {
|
|
|
8348
8522
|
setBrowserIntegration(browserIntegration);
|
|
8349
8523
|
|
|
8350
8524
|
const actionIntegratedVia = browserIntegration.integration;
|
|
8351
|
-
const
|
|
8525
|
+
const navTo = (target, options) => {
|
|
8526
|
+
const url = new URL(target, window.location.href).href;
|
|
8527
|
+
const currentUrl = documentUrlSignal.peek();
|
|
8528
|
+
if (url === currentUrl) {
|
|
8529
|
+
return null;
|
|
8530
|
+
}
|
|
8531
|
+
return browserIntegration.navTo(url, options);
|
|
8532
|
+
};
|
|
8533
|
+
const replaceUrl = (target, options = {}) => {
|
|
8534
|
+
return navTo(target, { ...options, replace: true });
|
|
8535
|
+
};
|
|
8352
8536
|
const stopLoad = (reason = "stopLoad() called") => {
|
|
8353
8537
|
const windowIsLoading = windowIsLoadingSignal.value;
|
|
8354
8538
|
if (windowIsLoading) {
|
|
@@ -8360,8 +8544,8 @@ const stopLoad = (reason = "stopLoad() called") => {
|
|
|
8360
8544
|
}
|
|
8361
8545
|
};
|
|
8362
8546
|
const reload = browserIntegration.reload;
|
|
8363
|
-
const
|
|
8364
|
-
const
|
|
8547
|
+
const navBack = browserIntegration.navBack;
|
|
8548
|
+
const navForward = browserIntegration.navForward;
|
|
8365
8549
|
const isVisited = browserIntegration.isVisited;
|
|
8366
8550
|
const visitedUrlsSignal = browserIntegration.visitedUrlsSignal;
|
|
8367
8551
|
browserIntegration.handleActionTask;
|
|
@@ -8451,11 +8635,11 @@ const useUrlSearchParam = (paramName, defaultValue) => {
|
|
|
8451
8635
|
setValue(searchParam);
|
|
8452
8636
|
}
|
|
8453
8637
|
|
|
8454
|
-
const setSearchParamValue = (newValue, { replace =
|
|
8638
|
+
const setSearchParamValue = (newValue, { replace = false } = {}) => {
|
|
8455
8639
|
const newUrlObject = new URL(window.location.href);
|
|
8456
8640
|
newUrlObject.searchParams.set(paramName, newValue);
|
|
8457
8641
|
const newUrl = newUrlObject.href;
|
|
8458
|
-
|
|
8642
|
+
navTo(newUrl, { replace });
|
|
8459
8643
|
};
|
|
8460
8644
|
|
|
8461
8645
|
return [value, setSearchParamValue];
|
|
@@ -8492,6 +8676,26 @@ const useForceRender = () => {
|
|
|
8492
8676
|
const debug$1 = (...args) => {
|
|
8493
8677
|
return;
|
|
8494
8678
|
};
|
|
8679
|
+
|
|
8680
|
+
// Check if a route is a "parent" route (catches multiple routes) and if current URL matches exactly
|
|
8681
|
+
const isParentRouteExactMatch = route => {
|
|
8682
|
+
if (!route) {
|
|
8683
|
+
return false;
|
|
8684
|
+
}
|
|
8685
|
+
const currentUrl = window.location.href;
|
|
8686
|
+
const parentUrl = route.buildUrl();
|
|
8687
|
+
if (currentUrl === parentUrl) {
|
|
8688
|
+
return true;
|
|
8689
|
+
}
|
|
8690
|
+
const currentUrlObject = new URL(currentUrl);
|
|
8691
|
+
if (!currentUrlObject.pathname.endsWith("/")) {
|
|
8692
|
+
return false;
|
|
8693
|
+
}
|
|
8694
|
+
const pathnameWithoutSlash = currentUrlObject.pathname.slice(0, -1);
|
|
8695
|
+
currentUrlObject.pathname = pathnameWithoutSlash;
|
|
8696
|
+
const currentUrlWithoutTrailingSlash = currentUrlObject.href;
|
|
8697
|
+
return currentUrlWithoutTrailingSlash === parentUrl;
|
|
8698
|
+
};
|
|
8495
8699
|
const RootElement = () => {
|
|
8496
8700
|
return jsx(Route.Slot, {});
|
|
8497
8701
|
};
|
|
@@ -8501,7 +8705,10 @@ const Routes = ({
|
|
|
8501
8705
|
element = RootElement,
|
|
8502
8706
|
children
|
|
8503
8707
|
}) => {
|
|
8708
|
+
const routeInfo = useActiveRouteInfo();
|
|
8709
|
+
const route = routeInfo?.route;
|
|
8504
8710
|
return jsx(Route, {
|
|
8711
|
+
route: route,
|
|
8505
8712
|
element: element,
|
|
8506
8713
|
children: children
|
|
8507
8714
|
});
|
|
@@ -8510,6 +8717,7 @@ const useActiveRouteInfo = () => useContext(RouteInfoContext);
|
|
|
8510
8717
|
const Route = ({
|
|
8511
8718
|
element,
|
|
8512
8719
|
route,
|
|
8720
|
+
index,
|
|
8513
8721
|
fallback,
|
|
8514
8722
|
meta,
|
|
8515
8723
|
children
|
|
@@ -8521,6 +8729,7 @@ const Route = ({
|
|
|
8521
8729
|
return jsx(ActiveRouteManager, {
|
|
8522
8730
|
element: element,
|
|
8523
8731
|
route: route,
|
|
8732
|
+
index: index,
|
|
8524
8733
|
fallback: fallback,
|
|
8525
8734
|
meta: meta,
|
|
8526
8735
|
onActiveInfoChange: activeInfo => {
|
|
@@ -8548,6 +8757,7 @@ it's executed once for the entier app lifecycle */
|
|
|
8548
8757
|
const ActiveRouteManager = ({
|
|
8549
8758
|
element,
|
|
8550
8759
|
route,
|
|
8760
|
+
index,
|
|
8551
8761
|
fallback,
|
|
8552
8762
|
meta,
|
|
8553
8763
|
onActiveInfoChange,
|
|
@@ -8557,23 +8767,42 @@ const ActiveRouteManager = ({
|
|
|
8557
8767
|
throw new Error("Route cannot have both route and fallback props");
|
|
8558
8768
|
}
|
|
8559
8769
|
const registerChildRouteFromContext = useContext(RegisterChildRouteContext);
|
|
8560
|
-
getElementSignature(element);
|
|
8770
|
+
const elementId = getElementSignature(element);
|
|
8561
8771
|
const candidateSet = new Set();
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8772
|
+
let indexCandidate = null;
|
|
8773
|
+
let fallbackCandidate = null;
|
|
8774
|
+
const registerChildRoute = childRouteInfo => {
|
|
8775
|
+
const childElementId = getElementSignature(childRouteInfo.element);
|
|
8776
|
+
candidateSet.add(childRouteInfo);
|
|
8777
|
+
if (childRouteInfo.index) {
|
|
8778
|
+
if (indexCandidate) {
|
|
8779
|
+
throw new Error(`Multiple index routes registered under the same parent route (${elementId}):
|
|
8780
|
+
- ${getElementSignature(indexCandidate.element)}
|
|
8781
|
+
- ${childElementId}`);
|
|
8782
|
+
}
|
|
8783
|
+
indexCandidate = childRouteInfo;
|
|
8784
|
+
}
|
|
8785
|
+
if (childRouteInfo.fallback) {
|
|
8786
|
+
if (fallbackCandidate) {
|
|
8787
|
+
throw new Error(`Multiple fallback routes registered under the same parent route (${elementId}):
|
|
8788
|
+
- ${getElementSignature(fallbackCandidate.element)}
|
|
8789
|
+
- ${childElementId}`);
|
|
8790
|
+
}
|
|
8791
|
+
if (childRouteInfo.route.routeFromProps) {
|
|
8792
|
+
throw new Error(`Fallback route cannot have a route prop (${childElementId})`);
|
|
8793
|
+
}
|
|
8794
|
+
fallbackCandidate = childRouteInfo;
|
|
8795
|
+
}
|
|
8570
8796
|
};
|
|
8571
8797
|
useLayoutEffect(() => {
|
|
8572
8798
|
initRouteObserver({
|
|
8573
8799
|
element,
|
|
8574
8800
|
route,
|
|
8801
|
+
index,
|
|
8575
8802
|
fallback,
|
|
8576
8803
|
meta,
|
|
8804
|
+
indexCandidate,
|
|
8805
|
+
fallbackCandidate,
|
|
8577
8806
|
candidateSet,
|
|
8578
8807
|
onActiveInfoChange,
|
|
8579
8808
|
registerChildRouteFromContext
|
|
@@ -8587,15 +8816,24 @@ const ActiveRouteManager = ({
|
|
|
8587
8816
|
const initRouteObserver = ({
|
|
8588
8817
|
element,
|
|
8589
8818
|
route,
|
|
8819
|
+
index,
|
|
8590
8820
|
fallback,
|
|
8591
8821
|
meta,
|
|
8822
|
+
indexCandidate,
|
|
8823
|
+
fallbackCandidate,
|
|
8592
8824
|
candidateSet,
|
|
8593
8825
|
onActiveInfoChange,
|
|
8594
8826
|
registerChildRouteFromContext
|
|
8595
8827
|
}) => {
|
|
8828
|
+
if (!fallbackCandidate && indexCandidate && indexCandidate.fallback !== false) {
|
|
8829
|
+
// no fallback + an index -> index behaves as a fallback (handle urls under a parent when no sibling matches)
|
|
8830
|
+
// to disable this behavior set fallback={false} on the index route
|
|
8831
|
+
// (in that case no route will be rendered when no child matches meaning only parent route element will be shown)
|
|
8832
|
+
fallbackCandidate = indexCandidate;
|
|
8833
|
+
}
|
|
8596
8834
|
const [teardown, addTeardown] = createPubSub();
|
|
8597
8835
|
const elementId = getElementSignature(element);
|
|
8598
|
-
const candidateElementIds = Array.from(candidateSet, c => getElementSignature(c.
|
|
8836
|
+
const candidateElementIds = Array.from(candidateSet, c => getElementSignature(c.element));
|
|
8599
8837
|
if (candidateElementIds.length === 0) ; else {
|
|
8600
8838
|
debug$1(`initRouteObserver ${elementId}, child candidates:
|
|
8601
8839
|
- ${candidateElementIds.join("\n - ")}`);
|
|
@@ -8611,19 +8849,26 @@ const initRouteObserver = ({
|
|
|
8611
8849
|
elementFromProps: element
|
|
8612
8850
|
};
|
|
8613
8851
|
const findActiveChildInfo = () => {
|
|
8614
|
-
let fallbackInfo = null;
|
|
8615
8852
|
for (const candidate of candidateSet) {
|
|
8616
8853
|
if (candidate.route?.active) {
|
|
8617
8854
|
return candidate;
|
|
8618
8855
|
}
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8856
|
+
}
|
|
8857
|
+
if (indexCandidate) {
|
|
8858
|
+
if (indexCandidate === fallbackCandidate) {
|
|
8859
|
+
// the index is also used as fallback (catch all routes under a parent)
|
|
8860
|
+
return indexCandidate;
|
|
8861
|
+
}
|
|
8862
|
+
// Only return the index candidate if the current URL matches exactly the parent route
|
|
8863
|
+
// This allows fallback routes to handle non-defined URLs under this parent route
|
|
8864
|
+
if (route && isParentRouteExactMatch(route)) {
|
|
8865
|
+
return indexCandidate;
|
|
8624
8866
|
}
|
|
8625
8867
|
}
|
|
8626
|
-
|
|
8868
|
+
if (fallbackCandidate) {
|
|
8869
|
+
return fallbackCandidate;
|
|
8870
|
+
}
|
|
8871
|
+
return null;
|
|
8627
8872
|
};
|
|
8628
8873
|
const getActiveInfo = route ? () => {
|
|
8629
8874
|
if (!route.active) {
|
|
@@ -8637,8 +8882,8 @@ const initRouteObserver = ({
|
|
|
8637
8882
|
return activeChildInfo;
|
|
8638
8883
|
}
|
|
8639
8884
|
return {
|
|
8640
|
-
ActiveElement: null,
|
|
8641
8885
|
route,
|
|
8886
|
+
element: null,
|
|
8642
8887
|
meta
|
|
8643
8888
|
};
|
|
8644
8889
|
} : () => {
|
|
@@ -8659,6 +8904,13 @@ const initRouteObserver = ({
|
|
|
8659
8904
|
const Element = element;
|
|
8660
8905
|
element = jsx(Element, {});
|
|
8661
8906
|
}
|
|
8907
|
+
// ensure we re-render on document url change (useful when navigating from /users/list to /users)
|
|
8908
|
+
// so that we re-replace urls back to /users/list when /users/list is an index
|
|
8909
|
+
useDocumentUrl();
|
|
8910
|
+
if (activeRouteInfo && activeRouteInfo.index && !activeRouteInfo.route.active) {
|
|
8911
|
+
const routeUrl = activeRouteInfo.route.routeFromProps.buildUrl();
|
|
8912
|
+
replaceUrl(routeUrl);
|
|
8913
|
+
}
|
|
8662
8914
|
return jsx(RouteInfoContext.Provider, {
|
|
8663
8915
|
value: activeRouteInfo,
|
|
8664
8916
|
children: jsx(SlotContext.Provider, {
|
|
@@ -8673,11 +8925,13 @@ const initRouteObserver = ({
|
|
|
8673
8925
|
if (newActiveInfo) {
|
|
8674
8926
|
compositeRoute.active = true;
|
|
8675
8927
|
activeRouteInfoSignal.value = newActiveInfo;
|
|
8676
|
-
SlotActiveElementSignal.value = newActiveInfo.
|
|
8928
|
+
SlotActiveElementSignal.value = newActiveInfo.element;
|
|
8677
8929
|
onActiveInfoChange({
|
|
8678
|
-
ActiveElement,
|
|
8679
|
-
SlotActiveElement: newActiveInfo.ActiveElement,
|
|
8680
8930
|
route: newActiveInfo.route,
|
|
8931
|
+
ActiveElement,
|
|
8932
|
+
SlotActiveElement: newActiveInfo.element,
|
|
8933
|
+
index: newActiveInfo.index,
|
|
8934
|
+
fallback: newActiveInfo.fallback,
|
|
8681
8935
|
meta: newActiveInfo.meta
|
|
8682
8936
|
});
|
|
8683
8937
|
} else {
|
|
@@ -8698,7 +8952,13 @@ const initRouteObserver = ({
|
|
|
8698
8952
|
addTeardown(candidate.route.subscribeStatus(onChange));
|
|
8699
8953
|
}
|
|
8700
8954
|
if (registerChildRouteFromContext) {
|
|
8701
|
-
registerChildRouteFromContext(
|
|
8955
|
+
registerChildRouteFromContext({
|
|
8956
|
+
route: compositeRoute,
|
|
8957
|
+
element: ActiveElement,
|
|
8958
|
+
index,
|
|
8959
|
+
fallback,
|
|
8960
|
+
meta
|
|
8961
|
+
});
|
|
8702
8962
|
}
|
|
8703
8963
|
updateActiveInfo();
|
|
8704
8964
|
return () => {
|
|
@@ -13732,6 +13992,10 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
13732
13992
|
.navi_text {
|
|
13733
13993
|
position: relative;
|
|
13734
13994
|
color: inherit;
|
|
13995
|
+
|
|
13996
|
+
&[data-has-absolute-child] {
|
|
13997
|
+
display: inline-block;
|
|
13998
|
+
}
|
|
13735
13999
|
}
|
|
13736
14000
|
|
|
13737
14001
|
.navi_text_overflow {
|
|
@@ -13755,6 +14019,53 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
13755
14019
|
|
|
13756
14020
|
.navi_custom_space {
|
|
13757
14021
|
}
|
|
14022
|
+
|
|
14023
|
+
.navi_text_bold_wrapper {
|
|
14024
|
+
position: relative;
|
|
14025
|
+
display: inline-block;
|
|
14026
|
+
}
|
|
14027
|
+
.navi_text_bold_clone {
|
|
14028
|
+
font-weight: bold;
|
|
14029
|
+
opacity: 0;
|
|
14030
|
+
}
|
|
14031
|
+
.navi_text_bold_foreground {
|
|
14032
|
+
position: absolute;
|
|
14033
|
+
inset: 0;
|
|
14034
|
+
}
|
|
14035
|
+
|
|
14036
|
+
.navi_text_bold_background {
|
|
14037
|
+
position: absolute;
|
|
14038
|
+
top: 0;
|
|
14039
|
+
left: 0;
|
|
14040
|
+
color: currentColor;
|
|
14041
|
+
font-weight: normal;
|
|
14042
|
+
background: currentColor;
|
|
14043
|
+
background-clip: text;
|
|
14044
|
+
-webkit-background-clip: text;
|
|
14045
|
+
transform-origin: center;
|
|
14046
|
+
-webkit-text-fill-color: transparent;
|
|
14047
|
+
opacity: 0;
|
|
14048
|
+
}
|
|
14049
|
+
|
|
14050
|
+
.navi_text[data-bold] {
|
|
14051
|
+
.navi_text_bold_background {
|
|
14052
|
+
opacity: 1;
|
|
14053
|
+
}
|
|
14054
|
+
}
|
|
14055
|
+
|
|
14056
|
+
.navi_text[data-bold-transition] {
|
|
14057
|
+
.navi_text_bold_foreground {
|
|
14058
|
+
transition-property: font-weight;
|
|
14059
|
+
transition-duration: 0.3s;
|
|
14060
|
+
transition-timing-function: ease;
|
|
14061
|
+
}
|
|
14062
|
+
|
|
14063
|
+
.navi_text_bold_background {
|
|
14064
|
+
transition-property: opacity;
|
|
14065
|
+
transition-duration: 0.3s;
|
|
14066
|
+
transition-timing-function: ease;
|
|
14067
|
+
}
|
|
14068
|
+
}
|
|
13758
14069
|
`;
|
|
13759
14070
|
const REGULAR_SPACE = jsx("span", {
|
|
13760
14071
|
"data-navi-space": "",
|
|
@@ -13924,14 +14235,65 @@ const TextWithSelectRange = ({
|
|
|
13924
14235
|
};
|
|
13925
14236
|
const TextBasic = ({
|
|
13926
14237
|
spacing = " ",
|
|
14238
|
+
boldTransition,
|
|
14239
|
+
boldStable,
|
|
14240
|
+
preventBoldLayoutShift = boldTransition,
|
|
13927
14241
|
children,
|
|
13928
14242
|
...rest
|
|
13929
14243
|
}) => {
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
14244
|
+
const shouldPreserveSpacing = rest.as === "pre" || rest.box || rest.column || rest.row;
|
|
14245
|
+
if (!shouldPreserveSpacing) {
|
|
14246
|
+
children = applySpacingOnTextChildren(children, spacing);
|
|
14247
|
+
}
|
|
14248
|
+
const boxProps = {
|
|
14249
|
+
"as": "span",
|
|
14250
|
+
"data-bold-transition": boldTransition ? "" : undefined,
|
|
13933
14251
|
...rest,
|
|
13934
|
-
|
|
14252
|
+
"baseClassName": withPropsClassName("navi_text", rest.baseClassName)
|
|
14253
|
+
};
|
|
14254
|
+
if (boldStable) {
|
|
14255
|
+
const {
|
|
14256
|
+
bold
|
|
14257
|
+
} = boxProps;
|
|
14258
|
+
return jsxs(Box, {
|
|
14259
|
+
...boxProps,
|
|
14260
|
+
bold: undefined,
|
|
14261
|
+
"data-bold": bold ? "" : undefined,
|
|
14262
|
+
"data-has-absolute-child": "",
|
|
14263
|
+
children: [jsx("span", {
|
|
14264
|
+
className: "navi_text_bold_background",
|
|
14265
|
+
"aria-hidden": "true",
|
|
14266
|
+
children: children
|
|
14267
|
+
}), children]
|
|
14268
|
+
});
|
|
14269
|
+
}
|
|
14270
|
+
if (preventBoldLayoutShift) {
|
|
14271
|
+
const alignX = rest.alignX || rest.align || "start";
|
|
14272
|
+
|
|
14273
|
+
// La technique consiste a avoid un double gras qui force une taille
|
|
14274
|
+
// et la version light par dessus en position absolute
|
|
14275
|
+
// on la centre aussi pour donner l'impression que le gras s'applique depuis le centre
|
|
14276
|
+
// ne fonctionne que sur une seul ligne de texte (donc lorsque noWrap est actif)
|
|
14277
|
+
// on pourrait auto-active cela sur une prop genre boldCanChange
|
|
14278
|
+
return jsx(Box, {
|
|
14279
|
+
...boxProps,
|
|
14280
|
+
children: jsxs("span", {
|
|
14281
|
+
className: "navi_text_bold_wrapper",
|
|
14282
|
+
children: [jsx("span", {
|
|
14283
|
+
className: "navi_text_bold_clone",
|
|
14284
|
+
"aria-hidden": "true",
|
|
14285
|
+
children: children
|
|
14286
|
+
}), jsx("span", {
|
|
14287
|
+
className: "navi_text_bold_foreground",
|
|
14288
|
+
"data-align": alignX,
|
|
14289
|
+
children: children
|
|
14290
|
+
})]
|
|
14291
|
+
})
|
|
14292
|
+
});
|
|
14293
|
+
}
|
|
14294
|
+
return jsx(Box, {
|
|
14295
|
+
...boxProps,
|
|
14296
|
+
children: children
|
|
13935
14297
|
});
|
|
13936
14298
|
};
|
|
13937
14299
|
|
|
@@ -16400,14 +16762,15 @@ const RouteLink = ({
|
|
|
16400
16762
|
}
|
|
16401
16763
|
const routeStatus = useRouteStatus(route);
|
|
16402
16764
|
const url = route.buildUrl(routeParams);
|
|
16403
|
-
const
|
|
16765
|
+
const active = routeStatus.active;
|
|
16766
|
+
const paramsAreMatching = route.matchesParams(routeParams);
|
|
16404
16767
|
return jsx(Link, {
|
|
16405
16768
|
...rest,
|
|
16406
16769
|
href: url,
|
|
16407
16770
|
pseudoState: {
|
|
16408
|
-
":-navi-href-current":
|
|
16771
|
+
":-navi-href-current": active && paramsAreMatching
|
|
16409
16772
|
},
|
|
16410
|
-
children: children
|
|
16773
|
+
children: children || route.buildRelativeUrl(routeParams)
|
|
16411
16774
|
});
|
|
16412
16775
|
};
|
|
16413
16776
|
|
|
@@ -16429,8 +16792,9 @@ import.meta.css = /* css */`
|
|
|
16429
16792
|
--tab-color: inherit;
|
|
16430
16793
|
--tab-color-hover: #010409;
|
|
16431
16794
|
--tab-color-selected: inherit;
|
|
16432
|
-
--tab-
|
|
16433
|
-
--tab-
|
|
16795
|
+
--tab-indicator-size: 2px;
|
|
16796
|
+
--tab-indicator-spacing: 5px;
|
|
16797
|
+
--tab-indicator-color: rgb(205, 52, 37);
|
|
16434
16798
|
}
|
|
16435
16799
|
}
|
|
16436
16800
|
|
|
@@ -16439,100 +16803,175 @@ import.meta.css = /* css */`
|
|
|
16439
16803
|
line-height: 2em;
|
|
16440
16804
|
overflow-x: auto;
|
|
16441
16805
|
overflow-y: hidden;
|
|
16442
|
-
}
|
|
16443
|
-
.navi_tablist > ul {
|
|
16444
|
-
display: flex;
|
|
16445
|
-
width: 100%;
|
|
16446
|
-
margin: 0;
|
|
16447
|
-
padding: 0;
|
|
16448
|
-
align-items: center;
|
|
16449
|
-
gap: 0.5rem;
|
|
16450
|
-
list-style: none;
|
|
16451
|
-
background: var(--tablist-background);
|
|
16452
|
-
border-radius: var(--tablist-border-radius);
|
|
16453
|
-
}
|
|
16454
|
-
.navi_tablist > ul > li {
|
|
16455
|
-
position: relative;
|
|
16456
|
-
display: inline-flex;
|
|
16457
|
-
}
|
|
16458
|
-
|
|
16459
|
-
.navi_tab {
|
|
16460
|
-
--x-tab-background: var(--tab-background);
|
|
16461
|
-
--x-tab-color: var(--tab-color);
|
|
16462
16806
|
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
border-radius: var(--tab-border-radius);
|
|
16467
|
-
|
|
16468
|
-
.navi_tab_content {
|
|
16469
|
-
display: flex;
|
|
16470
|
-
color: var(--x-tab-color);
|
|
16471
|
-
background: var(--x-tab-background);
|
|
16472
|
-
border-radius: inherit;
|
|
16473
|
-
transition: background 0.12s ease-out;
|
|
16474
|
-
|
|
16475
|
-
.navi_link {
|
|
16476
|
-
flex-grow: 1;
|
|
16477
|
-
text-align: center;
|
|
16478
|
-
border-radius: inherit;
|
|
16807
|
+
&[data-tab-indicator-position="start"] {
|
|
16808
|
+
.navi_tab {
|
|
16809
|
+
margin-top: var(--tab-indicator-spacing);
|
|
16479
16810
|
}
|
|
16480
16811
|
}
|
|
16481
|
-
|
|
16482
|
-
|
|
16483
|
-
|
|
16484
|
-
|
|
16485
|
-
font-weight: 600; /* force bold to compute max width */
|
|
16486
|
-
visibility: hidden; /* not visible */
|
|
16487
|
-
pointer-events: none; /* inert */
|
|
16488
|
-
overflow: hidden; /* avoid any accidental height */
|
|
16812
|
+
&[data-tab-indicator-position="end"] {
|
|
16813
|
+
.navi_tab {
|
|
16814
|
+
margin-bottom: var(--tab-indicator-spacing);
|
|
16815
|
+
}
|
|
16489
16816
|
}
|
|
16490
|
-
|
|
16491
|
-
|
|
16817
|
+
|
|
16818
|
+
> ul {
|
|
16492
16819
|
display: flex;
|
|
16493
16820
|
width: 100%;
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16821
|
+
margin: 0;
|
|
16822
|
+
padding: 2px; /* space for border radius and outline */
|
|
16823
|
+
align-items: center;
|
|
16824
|
+
gap: 0.5rem;
|
|
16825
|
+
list-style: none;
|
|
16826
|
+
background: var(--tablist-background);
|
|
16827
|
+
border-radius: var(--tablist-border-radius);
|
|
16499
16828
|
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
|
|
16507
|
-
|
|
16829
|
+
> li {
|
|
16830
|
+
position: relative;
|
|
16831
|
+
display: inline-flex;
|
|
16832
|
+
|
|
16833
|
+
.navi_tab {
|
|
16834
|
+
--x-tab-background: var(--tab-background);
|
|
16835
|
+
--x-tab-color: var(--tab-color);
|
|
16836
|
+
|
|
16837
|
+
display: flex;
|
|
16838
|
+
flex-direction: column;
|
|
16839
|
+
color: var(--x-tab-color);
|
|
16840
|
+
white-space: nowrap;
|
|
16841
|
+
background: var(--x-tab-background);
|
|
16842
|
+
border-radius: var(--tab-border-radius);
|
|
16843
|
+
transition: background 0.12s ease-out;
|
|
16844
|
+
user-select: none;
|
|
16845
|
+
|
|
16846
|
+
span,
|
|
16847
|
+
a {
|
|
16848
|
+
display: inline-flex;
|
|
16849
|
+
flex-grow: 1;
|
|
16850
|
+
justify-content: center;
|
|
16851
|
+
text-align: center;
|
|
16852
|
+
border-radius: inherit;
|
|
16853
|
+
}
|
|
16854
|
+
|
|
16855
|
+
.navi_tab_indicator {
|
|
16856
|
+
position: absolute;
|
|
16857
|
+
z-index: 1;
|
|
16858
|
+
display: flex;
|
|
16859
|
+
width: 100%;
|
|
16860
|
+
height: var(--tab-indicator-size);
|
|
16861
|
+
background: transparent;
|
|
16862
|
+
border-radius: 0.1px;
|
|
16863
|
+
|
|
16864
|
+
&[data-position="start"] {
|
|
16865
|
+
top: 0;
|
|
16866
|
+
left: 0;
|
|
16867
|
+
}
|
|
16868
|
+
|
|
16869
|
+
&[data-position="end"] {
|
|
16870
|
+
bottom: 0;
|
|
16871
|
+
left: 0;
|
|
16872
|
+
}
|
|
16873
|
+
}
|
|
16874
|
+
|
|
16875
|
+
/* Interactive */
|
|
16876
|
+
&[data-interactive] {
|
|
16877
|
+
cursor: pointer;
|
|
16878
|
+
}
|
|
16879
|
+
/* Hover */
|
|
16880
|
+
&:hover {
|
|
16881
|
+
--x-tab-background: var(--tab-background-hover);
|
|
16882
|
+
--x-tab-color: var(--tab-color-hover);
|
|
16883
|
+
}
|
|
16884
|
+
/* Selected */
|
|
16885
|
+
&[data-selected] {
|
|
16886
|
+
--x-tab-background: var(--tab-background-selected);
|
|
16887
|
+
--x-tab-color: var(--tab-color-selected);
|
|
16888
|
+
font-weight: bold;
|
|
16889
|
+
|
|
16890
|
+
.navi_tab_indicator {
|
|
16891
|
+
background: var(--tab-indicator-color);
|
|
16892
|
+
}
|
|
16893
|
+
}
|
|
16894
|
+
}
|
|
16895
|
+
}
|
|
16508
16896
|
}
|
|
16509
|
-
/* Selected */
|
|
16510
|
-
&[data-selected] {
|
|
16511
|
-
--x-tab-background: var(--tab-background-selected);
|
|
16512
|
-
--x-tab-color: var(--tab-color-selected);
|
|
16513
16897
|
|
|
16514
|
-
|
|
16515
|
-
|
|
16898
|
+
/* Vertical layout */
|
|
16899
|
+
&[data-vertical] {
|
|
16900
|
+
overflow-x: hidden;
|
|
16901
|
+
overflow-y: auto;
|
|
16902
|
+
|
|
16903
|
+
.navi_tab {
|
|
16904
|
+
span,
|
|
16905
|
+
a {
|
|
16906
|
+
justify-content: start;
|
|
16907
|
+
}
|
|
16908
|
+
|
|
16909
|
+
&[data-align-x="end"] {
|
|
16910
|
+
span,
|
|
16911
|
+
a {
|
|
16912
|
+
justify-content: end;
|
|
16913
|
+
}
|
|
16914
|
+
}
|
|
16915
|
+
}
|
|
16916
|
+
|
|
16917
|
+
&[data-tab-indicator-position="start"] {
|
|
16918
|
+
.navi_tab {
|
|
16919
|
+
margin-top: 0;
|
|
16920
|
+
margin-left: var(--tab-indicator-spacing);
|
|
16921
|
+
|
|
16922
|
+
.navi_tab_indicator {
|
|
16923
|
+
top: 0;
|
|
16924
|
+
left: 0;
|
|
16925
|
+
}
|
|
16926
|
+
}
|
|
16516
16927
|
}
|
|
16517
|
-
|
|
16518
|
-
|
|
16928
|
+
&[data-tab-indicator-position="end"] {
|
|
16929
|
+
.navi_tab {
|
|
16930
|
+
margin-right: var(--tab-indicator-spacing);
|
|
16931
|
+
margin-bottom: 0;
|
|
16932
|
+
|
|
16933
|
+
.navi_tab_indicator {
|
|
16934
|
+
top: 0;
|
|
16935
|
+
right: 0;
|
|
16936
|
+
left: auto;
|
|
16937
|
+
}
|
|
16938
|
+
}
|
|
16519
16939
|
}
|
|
16520
|
-
}
|
|
16521
|
-
}
|
|
16522
16940
|
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16941
|
+
> ul {
|
|
16942
|
+
flex-direction: column;
|
|
16943
|
+
align-items: start;
|
|
16944
|
+
|
|
16945
|
+
> li {
|
|
16946
|
+
width: 100%;
|
|
16947
|
+
|
|
16948
|
+
.navi_tab {
|
|
16949
|
+
flex-direction: row;
|
|
16950
|
+
text-align: left;
|
|
16951
|
+
|
|
16952
|
+
.navi_tab_indicator {
|
|
16953
|
+
width: var(--tab-indicator-size);
|
|
16954
|
+
height: 100%;
|
|
16955
|
+
}
|
|
16956
|
+
}
|
|
16957
|
+
}
|
|
16958
|
+
}
|
|
16527
16959
|
}
|
|
16528
16960
|
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16961
|
+
&[data-expand] {
|
|
16962
|
+
> ul {
|
|
16963
|
+
.navi_tab {
|
|
16964
|
+
width: 100%;
|
|
16965
|
+
flex: 1;
|
|
16966
|
+
align-items: stretch;
|
|
16967
|
+
justify-content: center;
|
|
16968
|
+
}
|
|
16969
|
+
}
|
|
16532
16970
|
}
|
|
16533
16971
|
}
|
|
16534
16972
|
`;
|
|
16535
|
-
const
|
|
16973
|
+
const TabListIndicatorContext = createContext();
|
|
16974
|
+
const TabListAlignXContext = createContext();
|
|
16536
16975
|
const TabListStyleCSSVars = {
|
|
16537
16976
|
borderRadius: "--tablist-border-radius",
|
|
16538
16977
|
background: "--tablist-background"
|
|
@@ -16540,7 +16979,9 @@ const TabListStyleCSSVars = {
|
|
|
16540
16979
|
const TabList = ({
|
|
16541
16980
|
children,
|
|
16542
16981
|
spacing,
|
|
16543
|
-
|
|
16982
|
+
vertical,
|
|
16983
|
+
indicator = vertical ? "start" : "end",
|
|
16984
|
+
alignX,
|
|
16544
16985
|
expand,
|
|
16545
16986
|
expandX,
|
|
16546
16987
|
paddingX,
|
|
@@ -16548,11 +16989,14 @@ const TabList = ({
|
|
|
16548
16989
|
padding,
|
|
16549
16990
|
...props
|
|
16550
16991
|
}) => {
|
|
16992
|
+
children = toChildArray(children);
|
|
16551
16993
|
return jsx(Box, {
|
|
16552
16994
|
as: "nav",
|
|
16553
16995
|
baseClassName: "navi_tablist",
|
|
16554
16996
|
role: "tablist",
|
|
16997
|
+
"data-tab-indicator-position": indicator === "start" || indicator === "end" ? indicator : undefined,
|
|
16555
16998
|
"data-expand": expand || expandX ? "" : undefined,
|
|
16999
|
+
"data-vertical": vertical ? "" : undefined,
|
|
16556
17000
|
expand: expand,
|
|
16557
17001
|
expandX: expandX,
|
|
16558
17002
|
...props,
|
|
@@ -16565,16 +17009,19 @@ const TabList = ({
|
|
|
16565
17009
|
paddingY: paddingY,
|
|
16566
17010
|
padding: padding,
|
|
16567
17011
|
spacing: spacing,
|
|
16568
|
-
children: jsx(
|
|
16569
|
-
value:
|
|
16570
|
-
children:
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
17012
|
+
children: jsx(TabListIndicatorContext.Provider, {
|
|
17013
|
+
value: indicator,
|
|
17014
|
+
children: jsx(TabListAlignXContext.Provider, {
|
|
17015
|
+
value: alignX,
|
|
17016
|
+
children: children.map(child => {
|
|
17017
|
+
return jsx(Box, {
|
|
17018
|
+
as: "li",
|
|
17019
|
+
column: true,
|
|
17020
|
+
expandX: expandX,
|
|
17021
|
+
expand: expand,
|
|
17022
|
+
children: child
|
|
17023
|
+
}, child.props.key);
|
|
17024
|
+
})
|
|
16578
17025
|
})
|
|
16579
17026
|
})
|
|
16580
17027
|
})
|
|
@@ -16593,7 +17040,7 @@ const TAB_STYLE_CSS_VARS = {
|
|
|
16593
17040
|
}
|
|
16594
17041
|
};
|
|
16595
17042
|
const TAB_PSEUDO_CLASSES = [":hover", ":-navi-selected"];
|
|
16596
|
-
const TAB_PSEUDO_ELEMENTS = ["::-navi-
|
|
17043
|
+
const TAB_PSEUDO_ELEMENTS = ["::-navi-indicator"];
|
|
16597
17044
|
const Tab = props => {
|
|
16598
17045
|
if (props.route) {
|
|
16599
17046
|
return jsx(TabRoute, {
|
|
@@ -16604,8 +17051,10 @@ const Tab = props => {
|
|
|
16604
17051
|
...props
|
|
16605
17052
|
});
|
|
16606
17053
|
};
|
|
17054
|
+
TabList.Tab = Tab;
|
|
16607
17055
|
const TabRoute = ({
|
|
16608
17056
|
route,
|
|
17057
|
+
routeParams,
|
|
16609
17058
|
children,
|
|
16610
17059
|
paddingX,
|
|
16611
17060
|
padding,
|
|
@@ -16615,15 +17064,17 @@ const TabRoute = ({
|
|
|
16615
17064
|
const {
|
|
16616
17065
|
active
|
|
16617
17066
|
} = useRouteStatus(route);
|
|
17067
|
+
const paramsAreMatching = route.matchesParams(routeParams);
|
|
17068
|
+
const selected = active && paramsAreMatching;
|
|
16618
17069
|
return jsx(TabBasic, {
|
|
16619
|
-
selected:
|
|
17070
|
+
selected: selected,
|
|
16620
17071
|
paddingX: "0",
|
|
16621
17072
|
...props,
|
|
16622
17073
|
children: jsx(RouteLink, {
|
|
16623
17074
|
route: route,
|
|
17075
|
+
routeParams: routeParams,
|
|
16624
17076
|
expand: true,
|
|
16625
17077
|
discrete: true,
|
|
16626
|
-
align: "center",
|
|
16627
17078
|
paddingX: paddingX,
|
|
16628
17079
|
padding: padding,
|
|
16629
17080
|
paddingY: paddingY,
|
|
@@ -16634,18 +17085,17 @@ const TabRoute = ({
|
|
|
16634
17085
|
const TabBasic = ({
|
|
16635
17086
|
children,
|
|
16636
17087
|
selected,
|
|
16637
|
-
padding,
|
|
16638
|
-
paddingX = "s",
|
|
16639
|
-
paddingY,
|
|
16640
17088
|
onClick,
|
|
16641
17089
|
...props
|
|
16642
17090
|
}) => {
|
|
16643
|
-
const
|
|
17091
|
+
const tabListIndicator = useContext(TabListIndicatorContext);
|
|
17092
|
+
const tabListAlignX = useContext(TabListAlignXContext);
|
|
16644
17093
|
return jsxs(Box, {
|
|
16645
17094
|
role: "tab",
|
|
16646
17095
|
"aria-selected": selected ? "true" : "false",
|
|
16647
17096
|
"data-interactive": onClick ? "" : undefined,
|
|
16648
|
-
onClick: onClick
|
|
17097
|
+
onClick: onClick,
|
|
17098
|
+
paddingX: "s"
|
|
16649
17099
|
// Style system
|
|
16650
17100
|
,
|
|
16651
17101
|
baseClassName: "navi_tab",
|
|
@@ -16655,19 +17105,18 @@ const TabBasic = ({
|
|
|
16655
17105
|
basePseudoState: {
|
|
16656
17106
|
":-navi-selected": selected
|
|
16657
17107
|
},
|
|
17108
|
+
selfAlignX: tabListAlignX,
|
|
17109
|
+
"data-align-x": tabListAlignX,
|
|
16658
17110
|
...props,
|
|
16659
|
-
children: [jsx(
|
|
16660
|
-
className: "
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
"aria-hidden": "true",
|
|
17111
|
+
children: [(tabListIndicator === "start" || tabListIndicator === "end") && jsx("span", {
|
|
17112
|
+
className: "navi_tab_indicator",
|
|
17113
|
+
"data-position": tabListIndicator
|
|
17114
|
+
}), jsx(Text, {
|
|
17115
|
+
noWrap: true,
|
|
17116
|
+
preventBoldLayoutShift: true
|
|
17117
|
+
// boldTransition
|
|
17118
|
+
,
|
|
16668
17119
|
children: children
|
|
16669
|
-
}), tabListUnderline && jsx("span", {
|
|
16670
|
-
className: "navi_tab_selected_marker"
|
|
16671
17120
|
})]
|
|
16672
17121
|
});
|
|
16673
17122
|
};
|
|
@@ -23788,5 +24237,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
23788
24237
|
})
|
|
23789
24238
|
});
|
|
23790
24239
|
|
|
23791
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, BadgeCount, Box, Button, Caption, CheckSvg, Checkbox, CheckboxList, Code, Col, Colgroup, Details, DialogLayout, Editable, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, MessageBox, Paragraph, Radio, RadioList, Route, RouteLink, Routes, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, SearchSvg, Select, SelectionContext, SettingsSvg, StarSvg, SummaryMarker, Svg, Tab, TabList, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, addCustomMessage, compareTwoJsValues, createAction, createRequestCanceller, createSelectionKeyboardShortcuts, createUniqueValueConstraint, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested,
|
|
24240
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, BadgeCount, Box, Button, Caption, CheckSvg, Checkbox, CheckboxList, Code, Col, Colgroup, Details, DialogLayout, Editable, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, MessageBox, Paragraph, Radio, RadioList, Route, RouteLink, Routes, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, SearchSvg, Select, SelectionContext, SettingsSvg, StarSvg, SummaryMarker, Svg, Tab, TabList, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, addCustomMessage, compareTwoJsValues, createAction, createRequestCanceller, createSelectionKeyboardShortcuts, createUniqueValueConstraint, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useActiveRouteInfo, useCellsAndColumns, useConstraintValidityState, useDependenciesDiff, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState$1 as useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, useUrlSearchParam, valueInLocalStorage };
|
|
23792
24241
|
//# sourceMappingURL=jsenv_navi.js.map
|