@jsenv/navi 0.13.2 → 0.13.4
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 +395 -205
- package/dist/jsenv_navi.js.map +12 -8
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -2103,6 +2103,340 @@ const localStorageSignal = (key) => {
|
|
|
2103
2103
|
return valueSignal;
|
|
2104
2104
|
};
|
|
2105
2105
|
|
|
2106
|
+
const valueInLocalStorage = (
|
|
2107
|
+
key,
|
|
2108
|
+
{ type = "string", fallback } = {},
|
|
2109
|
+
) => {
|
|
2110
|
+
const converter = typeConverters[type];
|
|
2111
|
+
if (converter === undefined) {
|
|
2112
|
+
console.warn(
|
|
2113
|
+
`Invalid type "${type}" for "${key}" in local storage, expected one of ${Object.keys(
|
|
2114
|
+
typeConverters,
|
|
2115
|
+
).join(", ")}`,
|
|
2116
|
+
);
|
|
2117
|
+
}
|
|
2118
|
+
const getValidityMessage = (
|
|
2119
|
+
valueToCheck,
|
|
2120
|
+
valueInLocalStorage = valueToCheck,
|
|
2121
|
+
) => {
|
|
2122
|
+
if (!converter) {
|
|
2123
|
+
return "";
|
|
2124
|
+
}
|
|
2125
|
+
if (!converter.checkValidity) {
|
|
2126
|
+
return "";
|
|
2127
|
+
}
|
|
2128
|
+
const checkValidityResult = converter.checkValidity(valueToCheck);
|
|
2129
|
+
if (checkValidityResult === false) {
|
|
2130
|
+
return `${valueInLocalStorage}`;
|
|
2131
|
+
}
|
|
2132
|
+
if (!checkValidityResult) {
|
|
2133
|
+
return "";
|
|
2134
|
+
}
|
|
2135
|
+
return `${checkValidityResult}, got "${valueInLocalStorage}"`;
|
|
2136
|
+
};
|
|
2137
|
+
|
|
2138
|
+
const get = () => {
|
|
2139
|
+
let valueInLocalStorage = window.localStorage.getItem(key);
|
|
2140
|
+
if (valueInLocalStorage === null) {
|
|
2141
|
+
return fallback;
|
|
2142
|
+
}
|
|
2143
|
+
if (converter && converter.decode) {
|
|
2144
|
+
const valueDecoded = converter.decode(valueInLocalStorage);
|
|
2145
|
+
const validityMessage = getValidityMessage(
|
|
2146
|
+
valueDecoded,
|
|
2147
|
+
valueInLocalStorage,
|
|
2148
|
+
);
|
|
2149
|
+
if (validityMessage) {
|
|
2150
|
+
console.warn(
|
|
2151
|
+
`The value found in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
2152
|
+
);
|
|
2153
|
+
return undefined;
|
|
2154
|
+
}
|
|
2155
|
+
return valueDecoded;
|
|
2156
|
+
}
|
|
2157
|
+
const validityMessage = getValidityMessage(valueInLocalStorage);
|
|
2158
|
+
if (validityMessage) {
|
|
2159
|
+
console.warn(
|
|
2160
|
+
`The value found in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
2161
|
+
);
|
|
2162
|
+
return undefined;
|
|
2163
|
+
}
|
|
2164
|
+
return valueInLocalStorage;
|
|
2165
|
+
};
|
|
2166
|
+
const set = (value) => {
|
|
2167
|
+
if (value === undefined) {
|
|
2168
|
+
window.localStorage.removeItem(key);
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
const validityMessage = getValidityMessage(value);
|
|
2172
|
+
if (validityMessage) {
|
|
2173
|
+
console.warn(
|
|
2174
|
+
`The value to set in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
if (converter && converter.encode) {
|
|
2178
|
+
const valueEncoded = converter.encode(value);
|
|
2179
|
+
window.localStorage.setItem(key, valueEncoded);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
window.localStorage.setItem(key, value);
|
|
2183
|
+
};
|
|
2184
|
+
const remove = () => {
|
|
2185
|
+
window.localStorage.removeItem(key);
|
|
2186
|
+
};
|
|
2187
|
+
|
|
2188
|
+
return [get, set, remove];
|
|
2189
|
+
};
|
|
2190
|
+
|
|
2191
|
+
const createNumberValidator = ({ min, max, step } = {}) => {
|
|
2192
|
+
return {
|
|
2193
|
+
decode: (value) => {
|
|
2194
|
+
const valueParsed = parseFloat(value);
|
|
2195
|
+
return valueParsed;
|
|
2196
|
+
},
|
|
2197
|
+
checkValidity: (value) => {
|
|
2198
|
+
if (typeof value !== "number") {
|
|
2199
|
+
return `must be a number`;
|
|
2200
|
+
}
|
|
2201
|
+
if (!Number.isFinite(value)) {
|
|
2202
|
+
return `must be finite`;
|
|
2203
|
+
}
|
|
2204
|
+
if (min !== undefined && value < min) {
|
|
2205
|
+
return min === 0 ? `must be positive` : `must be >= ${min}`;
|
|
2206
|
+
}
|
|
2207
|
+
if (max !== undefined && value > max) {
|
|
2208
|
+
return max === 0 ? `must be negative` : `must be <= ${max}`;
|
|
2209
|
+
}
|
|
2210
|
+
if (step !== undefined) {
|
|
2211
|
+
const remainder = (value - (min || 0)) % step;
|
|
2212
|
+
const epsilon = 0.0000001;
|
|
2213
|
+
if (remainder > epsilon && step - remainder > epsilon) {
|
|
2214
|
+
if (step === 1) {
|
|
2215
|
+
return `must be an integer`;
|
|
2216
|
+
}
|
|
2217
|
+
return `must be a multiple of ${step}`;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
return "";
|
|
2221
|
+
},
|
|
2222
|
+
};
|
|
2223
|
+
};
|
|
2224
|
+
const typeConverters = {
|
|
2225
|
+
boolean: {
|
|
2226
|
+
checkValidity: (value) => {
|
|
2227
|
+
if (typeof value !== "boolean") {
|
|
2228
|
+
return `must be a boolean`;
|
|
2229
|
+
}
|
|
2230
|
+
return "";
|
|
2231
|
+
},
|
|
2232
|
+
decode: (value) => {
|
|
2233
|
+
return value === "true";
|
|
2234
|
+
},
|
|
2235
|
+
encode: (value) => {
|
|
2236
|
+
return value ? "true" : "false";
|
|
2237
|
+
},
|
|
2238
|
+
},
|
|
2239
|
+
string: {
|
|
2240
|
+
checkValidity: (value) => {
|
|
2241
|
+
if (typeof value !== "string") {
|
|
2242
|
+
return `must be a string`;
|
|
2243
|
+
}
|
|
2244
|
+
return "";
|
|
2245
|
+
},
|
|
2246
|
+
},
|
|
2247
|
+
number: createNumberValidator(),
|
|
2248
|
+
float: createNumberValidator(),
|
|
2249
|
+
positive_number: createNumberValidator({ min: 0 }),
|
|
2250
|
+
integer: createNumberValidator({ step: 1 }),
|
|
2251
|
+
positive_integer: createNumberValidator({ min: 0, step: 1 }),
|
|
2252
|
+
percentage: {
|
|
2253
|
+
checkValidity: (value) => {
|
|
2254
|
+
if (typeof value !== "string") {
|
|
2255
|
+
return `must be a percentage`;
|
|
2256
|
+
}
|
|
2257
|
+
if (!value.endsWith("%")) {
|
|
2258
|
+
return `must end with %`;
|
|
2259
|
+
}
|
|
2260
|
+
const percentageString = value.slice(0, -1);
|
|
2261
|
+
const percentageFloat = parseFloat(percentageString);
|
|
2262
|
+
if (typeof percentageFloat !== "number") {
|
|
2263
|
+
return `must be a percentage`;
|
|
2264
|
+
}
|
|
2265
|
+
if (percentageFloat < 0 || percentageFloat > 100) {
|
|
2266
|
+
return `must be between 0 and 100`;
|
|
2267
|
+
}
|
|
2268
|
+
return "";
|
|
2269
|
+
},
|
|
2270
|
+
},
|
|
2271
|
+
object: {
|
|
2272
|
+
decode: (value) => {
|
|
2273
|
+
const valueParsed = JSON.parse(value);
|
|
2274
|
+
return valueParsed;
|
|
2275
|
+
},
|
|
2276
|
+
encode: (value) => {
|
|
2277
|
+
const valueStringified = JSON.stringify(value);
|
|
2278
|
+
return valueStringified;
|
|
2279
|
+
},
|
|
2280
|
+
checkValidity: (value) => {
|
|
2281
|
+
if (value === null || typeof value !== "object") {
|
|
2282
|
+
return `must be an object`;
|
|
2283
|
+
}
|
|
2284
|
+
return "";
|
|
2285
|
+
},
|
|
2286
|
+
},
|
|
2287
|
+
};
|
|
2288
|
+
|
|
2289
|
+
/**
|
|
2290
|
+
* Creates an advanced signal with optional source signal synchronization and local storage persistence.
|
|
2291
|
+
*
|
|
2292
|
+
* The sourceSignal option creates a fallback mechanism where:
|
|
2293
|
+
* 1. The signal initially takes the value from sourceSignal (if defined) or falls back to defaultValue
|
|
2294
|
+
* 2. The signal can be manually overridden with any value
|
|
2295
|
+
* 3. When sourceSignal changes, it will override the current value again
|
|
2296
|
+
*
|
|
2297
|
+
* This is useful for scenarios like UI state management where you want to:
|
|
2298
|
+
* - Start with a value from an external source (e.g., backend data)
|
|
2299
|
+
* - Allow temporary local overrides (e.g., user interactions)
|
|
2300
|
+
* - Reset to the external source when context changes (e.g., navigation, data refresh)
|
|
2301
|
+
*
|
|
2302
|
+
* @param {any} defaultValue - The default value to use when no other value is available
|
|
2303
|
+
* @param {Object} [options={}] - Configuration options
|
|
2304
|
+
* @param {import("@preact/signals").Signal} [options.sourceSignal] - Source signal to synchronize with. When the source signal changes, this signal will be updated
|
|
2305
|
+
* @param {string} [options.localStorageKey] - Key for local storage persistence. When provided, the signal value will be saved to and restored from localStorage
|
|
2306
|
+
* @param {"string" | "number" | "boolean" | "object"} [options.type="string"] - Type for localStorage serialization/deserialization
|
|
2307
|
+
* @returns {import("@preact/signals").Signal} A signal that can be synchronized with a source signal and/or persisted in localStorage
|
|
2308
|
+
*
|
|
2309
|
+
* @example
|
|
2310
|
+
* // Basic signal with default value
|
|
2311
|
+
* const count = stateSignal(0);
|
|
2312
|
+
*
|
|
2313
|
+
* @example
|
|
2314
|
+
* // Position that follows backend data but allows temporary overrides
|
|
2315
|
+
* const backendPosition = signal({ x: 100, y: 50 });
|
|
2316
|
+
* const currentPosition = stateSignal({ x: 0, y: 0 }, { sourceSignal: backendPosition });
|
|
2317
|
+
*
|
|
2318
|
+
* // Initially: currentPosition.value = { x: 100, y: 50 } (from backend)
|
|
2319
|
+
* // User drags: currentPosition.value = { x: 150, y: 80 } (manual override)
|
|
2320
|
+
* // Backend updates: backendPosition.value = { x: 200, y: 60 }
|
|
2321
|
+
* // Result: currentPosition.value = { x: 200, y: 60 } (reset to new backend value)
|
|
2322
|
+
*
|
|
2323
|
+
* @example
|
|
2324
|
+
* // Signal with localStorage persistence
|
|
2325
|
+
* const userPreference = stateSignal("light", {
|
|
2326
|
+
* localStorageKey: "theme",
|
|
2327
|
+
* type: "string"
|
|
2328
|
+
* });
|
|
2329
|
+
*
|
|
2330
|
+
* @example
|
|
2331
|
+
* // Combined: follows source with localStorage backup
|
|
2332
|
+
* const serverConfig = signal({ timeout: 5000 });
|
|
2333
|
+
* const appConfig = stateSignal({ timeout: 3000 }, {
|
|
2334
|
+
* sourceSignal: serverConfig,
|
|
2335
|
+
* localStorageKey: "app-config",
|
|
2336
|
+
* type: "object"
|
|
2337
|
+
* });
|
|
2338
|
+
*/
|
|
2339
|
+
const stateSignal = (
|
|
2340
|
+
defaultValue,
|
|
2341
|
+
{ sourceSignal, localStorageKey, type } = {},
|
|
2342
|
+
) => {
|
|
2343
|
+
const advancedSignal = signal();
|
|
2344
|
+
if (sourceSignal) {
|
|
2345
|
+
connectSignalToSource(advancedSignal, sourceSignal, defaultValue);
|
|
2346
|
+
} else {
|
|
2347
|
+
advancedSignal.value = defaultValue;
|
|
2348
|
+
}
|
|
2349
|
+
if (localStorageKey) {
|
|
2350
|
+
connectSignalWithLocalStorage(advancedSignal, localStorageKey, { type });
|
|
2351
|
+
}
|
|
2352
|
+
return advancedSignal;
|
|
2353
|
+
};
|
|
2354
|
+
|
|
2355
|
+
const connectSignalToSource = (signal, sourceSignal, defaultValue) => {
|
|
2356
|
+
connectSignalFallbacks(signal, [sourceSignal], defaultValue);
|
|
2357
|
+
updateSignalOnChange(sourceSignal, signal);
|
|
2358
|
+
};
|
|
2359
|
+
const connectSignalFallbacks = (signal, fallbackSignals, defaultValue) => {
|
|
2360
|
+
if (fallbackSignals.length === 0) {
|
|
2361
|
+
signal.value = defaultValue;
|
|
2362
|
+
return () => {};
|
|
2363
|
+
}
|
|
2364
|
+
if (fallbackSignals.length === 1) {
|
|
2365
|
+
const [fallbackSignal] = fallbackSignals;
|
|
2366
|
+
const applyFallback = () => {
|
|
2367
|
+
const value = signal.value;
|
|
2368
|
+
const fallbackValue = fallbackSignal.value;
|
|
2369
|
+
if (value !== undefined) {
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
if (fallbackValue !== undefined) {
|
|
2373
|
+
signal.value = fallbackValue;
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
signal.value = defaultValue;
|
|
2377
|
+
};
|
|
2378
|
+
applyFallback();
|
|
2379
|
+
return effect(() => {
|
|
2380
|
+
applyFallback();
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
const applyFallback = () => {
|
|
2384
|
+
const fallbackValues = fallbackSignals.map((s) => s.value);
|
|
2385
|
+
const value = signal.value;
|
|
2386
|
+
if (value !== undefined) {
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2389
|
+
for (const fallbackValue of fallbackValues) {
|
|
2390
|
+
if (fallbackValue === undefined) {
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
signal.value = fallbackValue;
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
signal.value = defaultValue;
|
|
2397
|
+
};
|
|
2398
|
+
applyFallback();
|
|
2399
|
+
return effect(() => {
|
|
2400
|
+
applyFallback();
|
|
2401
|
+
});
|
|
2402
|
+
};
|
|
2403
|
+
const updateSignalOnChange = (sourceSignal, targetSignal) => {
|
|
2404
|
+
let sourcePreviousValue = sourceSignal.value;
|
|
2405
|
+
return effect(() => {
|
|
2406
|
+
const sourceValue = sourceSignal.value;
|
|
2407
|
+
if (sourcePreviousValue !== undefined && sourceValue !== undefined) {
|
|
2408
|
+
// console.log(
|
|
2409
|
+
// "value modified from",
|
|
2410
|
+
// sourcePreviousValue,
|
|
2411
|
+
// "to",
|
|
2412
|
+
// sourceValue,
|
|
2413
|
+
// );
|
|
2414
|
+
targetSignal.value = sourceValue;
|
|
2415
|
+
}
|
|
2416
|
+
sourcePreviousValue = sourceValue;
|
|
2417
|
+
});
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
const connectSignalWithLocalStorage = (
|
|
2421
|
+
signal,
|
|
2422
|
+
key,
|
|
2423
|
+
{ type = "string" } = {},
|
|
2424
|
+
) => {
|
|
2425
|
+
const [get, set, remove] = valueInLocalStorage(key, { type });
|
|
2426
|
+
const valueFromLocalStorage = get();
|
|
2427
|
+
if (valueFromLocalStorage !== undefined) {
|
|
2428
|
+
signal.value = valueFromLocalStorage;
|
|
2429
|
+
}
|
|
2430
|
+
effect(() => {
|
|
2431
|
+
const value = signal.value;
|
|
2432
|
+
if (value === undefined || value === null) {
|
|
2433
|
+
remove();
|
|
2434
|
+
} else {
|
|
2435
|
+
set(value);
|
|
2436
|
+
}
|
|
2437
|
+
});
|
|
2438
|
+
};
|
|
2439
|
+
|
|
2106
2440
|
const getCallerInfo = (targetFunction = null, additionalOffset = 0) => {
|
|
2107
2441
|
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
2108
2442
|
try {
|
|
@@ -4208,193 +4542,51 @@ const useStateArray = (
|
|
|
4208
4542
|
return [array, add, remove, reset];
|
|
4209
4543
|
};
|
|
4210
4544
|
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
if (converter && converter.decode) {
|
|
4247
|
-
const valueDecoded = converter.decode(valueInLocalStorage);
|
|
4248
|
-
const validityMessage = getValidityMessage(
|
|
4249
|
-
valueDecoded,
|
|
4250
|
-
valueInLocalStorage,
|
|
4251
|
-
);
|
|
4252
|
-
if (validityMessage) {
|
|
4253
|
-
console.warn(
|
|
4254
|
-
`The value found in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
4255
|
-
);
|
|
4256
|
-
return undefined;
|
|
4257
|
-
}
|
|
4258
|
-
return valueDecoded;
|
|
4259
|
-
}
|
|
4260
|
-
const validityMessage = getValidityMessage(valueInLocalStorage);
|
|
4261
|
-
if (validityMessage) {
|
|
4262
|
-
console.warn(
|
|
4263
|
-
`The value found in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
4264
|
-
);
|
|
4265
|
-
return undefined;
|
|
4266
|
-
}
|
|
4267
|
-
return valueInLocalStorage;
|
|
4268
|
-
};
|
|
4269
|
-
const set = (value) => {
|
|
4270
|
-
if (value === undefined) {
|
|
4271
|
-
window.localStorage.removeItem(key);
|
|
4272
|
-
return;
|
|
4273
|
-
}
|
|
4274
|
-
const validityMessage = getValidityMessage(value);
|
|
4275
|
-
if (validityMessage) {
|
|
4276
|
-
console.warn(
|
|
4277
|
-
`The value to set in localStorage "${key}" is invalid: ${validityMessage}`,
|
|
4278
|
-
);
|
|
4279
|
-
}
|
|
4280
|
-
if (converter && converter.encode) {
|
|
4281
|
-
const valueEncoded = converter.encode(value);
|
|
4282
|
-
window.localStorage.setItem(key, valueEncoded);
|
|
4283
|
-
return;
|
|
4284
|
-
}
|
|
4285
|
-
window.localStorage.setItem(key, value);
|
|
4286
|
-
};
|
|
4287
|
-
const remove = () => {
|
|
4288
|
-
window.localStorage.removeItem(key);
|
|
4545
|
+
/**
|
|
4546
|
+
* Creates a function that generates abort signals, automatically cancelling previous requests.
|
|
4547
|
+
*
|
|
4548
|
+
* This prevents race conditions when multiple fetch requests are triggered rapidly,
|
|
4549
|
+
* ensuring only the most recent request completes while canceling outdated ones.
|
|
4550
|
+
*
|
|
4551
|
+
* @param {string} [reason="Request superseded"] - Custom reason for the abort signal
|
|
4552
|
+
* @returns {() => AbortSignal} A function that returns a fresh AbortSignal and cancels the previous one
|
|
4553
|
+
*
|
|
4554
|
+
* @example
|
|
4555
|
+
* // Setup the request canceller
|
|
4556
|
+
* const cancelPrevious = createRequestCanceller();
|
|
4557
|
+
*
|
|
4558
|
+
* // Use it in sequential fetch operations
|
|
4559
|
+
* const searchUsers = async (query) => {
|
|
4560
|
+
* const signal = cancelPrevious(); // Cancels previous search
|
|
4561
|
+
* const response = await fetch(`/api/users?q=${query}`, { signal });
|
|
4562
|
+
* return response.json();
|
|
4563
|
+
* };
|
|
4564
|
+
*
|
|
4565
|
+
* // Rapid successive calls - only the last one will complete
|
|
4566
|
+
* searchUsers("john"); // Will be aborted
|
|
4567
|
+
* searchUsers("jane"); // Will be aborted
|
|
4568
|
+
* searchUsers("jack"); // Will complete
|
|
4569
|
+
*
|
|
4570
|
+
* @example
|
|
4571
|
+
* // With custom reason
|
|
4572
|
+
* const cancelPrevious = createRequestCanceller("Search cancelled");
|
|
4573
|
+
*/
|
|
4574
|
+
const createRequestCanceller = (reason = "Request superseded") => {
|
|
4575
|
+
let previousAbortController;
|
|
4576
|
+
return () => {
|
|
4577
|
+
previousAbortController?.abort(reason);
|
|
4578
|
+
previousAbortController = new AbortController();
|
|
4579
|
+
return previousAbortController.signal;
|
|
4289
4580
|
};
|
|
4290
|
-
|
|
4291
|
-
return [get, set, remove];
|
|
4292
|
-
};
|
|
4293
|
-
|
|
4294
|
-
const typeConverters = {
|
|
4295
|
-
boolean: {
|
|
4296
|
-
checkValidity: (value) => {
|
|
4297
|
-
if (typeof value !== "boolean") {
|
|
4298
|
-
return `must be a boolean`;
|
|
4299
|
-
}
|
|
4300
|
-
return "";
|
|
4301
|
-
},
|
|
4302
|
-
decode: (value) => {
|
|
4303
|
-
return value === "true";
|
|
4304
|
-
},
|
|
4305
|
-
},
|
|
4306
|
-
string: {
|
|
4307
|
-
checkValidity: (value) => {
|
|
4308
|
-
if (typeof value !== "string") {
|
|
4309
|
-
return `must be a string`;
|
|
4310
|
-
}
|
|
4311
|
-
return "";
|
|
4312
|
-
},
|
|
4313
|
-
},
|
|
4314
|
-
number: {
|
|
4315
|
-
decode: (value) => {
|
|
4316
|
-
const valueParsed = parseFloat(value);
|
|
4317
|
-
return valueParsed;
|
|
4318
|
-
},
|
|
4319
|
-
checkValidity: (value) => {
|
|
4320
|
-
if (typeof value !== "number") {
|
|
4321
|
-
return `must be a number`;
|
|
4322
|
-
}
|
|
4323
|
-
if (!Number.isFinite(value)) {
|
|
4324
|
-
return `must be finite`;
|
|
4325
|
-
}
|
|
4326
|
-
return "";
|
|
4327
|
-
},
|
|
4328
|
-
},
|
|
4329
|
-
positive_number: {
|
|
4330
|
-
decode: (value) => {
|
|
4331
|
-
const valueParsed = parseFloat(value);
|
|
4332
|
-
return valueParsed;
|
|
4333
|
-
},
|
|
4334
|
-
checkValidity: (value) => {
|
|
4335
|
-
if (typeof value !== "number") {
|
|
4336
|
-
return `must be a number`;
|
|
4337
|
-
}
|
|
4338
|
-
if (value < 0) {
|
|
4339
|
-
return `must be positive`;
|
|
4340
|
-
}
|
|
4341
|
-
return "";
|
|
4342
|
-
},
|
|
4343
|
-
},
|
|
4344
|
-
positive_integer: {
|
|
4345
|
-
decode: (value) => {
|
|
4346
|
-
const valueParsed = parseInt(value, 10);
|
|
4347
|
-
return valueParsed;
|
|
4348
|
-
},
|
|
4349
|
-
checkValidity: (value) => {
|
|
4350
|
-
if (typeof value !== "number") {
|
|
4351
|
-
return `must be a number`;
|
|
4352
|
-
}
|
|
4353
|
-
if (!Number.isInteger(value)) {
|
|
4354
|
-
return `must be an integer`;
|
|
4355
|
-
}
|
|
4356
|
-
if (value < 0) {
|
|
4357
|
-
return `must be positive`;
|
|
4358
|
-
}
|
|
4359
|
-
return "";
|
|
4360
|
-
},
|
|
4361
|
-
},
|
|
4362
|
-
percentage: {
|
|
4363
|
-
checkValidity: (value) => {
|
|
4364
|
-
if (typeof value !== "string") {
|
|
4365
|
-
return `must be a percentage`;
|
|
4366
|
-
}
|
|
4367
|
-
if (!value.endsWith("%")) {
|
|
4368
|
-
return `must end with %`;
|
|
4369
|
-
}
|
|
4370
|
-
const percentageString = value.slice(0, -1);
|
|
4371
|
-
const percentageFloat = parseFloat(percentageString);
|
|
4372
|
-
if (typeof percentageFloat !== "number") {
|
|
4373
|
-
return `must be a percentage`;
|
|
4374
|
-
}
|
|
4375
|
-
if (percentageFloat < 0 || percentageFloat > 100) {
|
|
4376
|
-
return `must be between 0 and 100`;
|
|
4377
|
-
}
|
|
4378
|
-
return "";
|
|
4379
|
-
},
|
|
4380
|
-
},
|
|
4381
|
-
object: {
|
|
4382
|
-
decode: (value) => {
|
|
4383
|
-
const valueParsed = JSON.parse(value);
|
|
4384
|
-
return valueParsed;
|
|
4385
|
-
},
|
|
4386
|
-
encode: (value) => {
|
|
4387
|
-
const valueStringified = JSON.stringify(value);
|
|
4388
|
-
return valueStringified;
|
|
4389
|
-
},
|
|
4390
|
-
checkValidity: (value) => {
|
|
4391
|
-
if (value === null || typeof value !== "object") {
|
|
4392
|
-
return `must be an object`;
|
|
4393
|
-
}
|
|
4394
|
-
return "";
|
|
4395
|
-
},
|
|
4396
|
-
},
|
|
4397
4581
|
};
|
|
4582
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
4583
|
+
if (
|
|
4584
|
+
event.reason?.name === "AbortError" &&
|
|
4585
|
+
event.reason?.message === "Request superseded"
|
|
4586
|
+
) {
|
|
4587
|
+
event.preventDefault(); // 💥 empêche les "uncaught rejection" devtools pour nos cancellations
|
|
4588
|
+
}
|
|
4589
|
+
});
|
|
4398
4590
|
|
|
4399
4591
|
/**
|
|
4400
4592
|
* Merges a component's base className with className received from props.
|
|
@@ -4561,19 +4753,19 @@ const DIMENSION_PROPS = {
|
|
|
4561
4753
|
return { minHeight: "100%", height: "auto" }; // Take full height outside flex
|
|
4562
4754
|
},
|
|
4563
4755
|
shrinkX: (value, { parentBoxFlow }) => {
|
|
4564
|
-
if (!value) {
|
|
4565
|
-
return null;
|
|
4566
|
-
}
|
|
4567
4756
|
if (parentBoxFlow === "row" || parentBoxFlow === "inline-row") {
|
|
4757
|
+
if (!value || value === "0") {
|
|
4758
|
+
return { flexShrink: 0 };
|
|
4759
|
+
}
|
|
4568
4760
|
return { flexShrink: 1 };
|
|
4569
4761
|
}
|
|
4570
4762
|
return { maxWidth: "100%" };
|
|
4571
4763
|
},
|
|
4572
4764
|
shrinkY: (value, { parentBoxFlow }) => {
|
|
4573
|
-
if (!value) {
|
|
4574
|
-
return null;
|
|
4575
|
-
}
|
|
4576
4765
|
if (parentBoxFlow === "column" || parentBoxFlow === "inline-column") {
|
|
4766
|
+
if (!value || value === "0") {
|
|
4767
|
+
return { flexShrink: 0 };
|
|
4768
|
+
}
|
|
4577
4769
|
return { flexShrink: 1 };
|
|
4578
4770
|
}
|
|
4579
4771
|
return { maxHeight: "100%" };
|
|
@@ -10726,6 +10918,7 @@ import.meta.css = /* css */ `
|
|
|
10726
10918
|
--callout-background-color: white;
|
|
10727
10919
|
--callout-icon-color: black;
|
|
10728
10920
|
--callout-padding: 8px;
|
|
10921
|
+
--callout-z-index: 1000;
|
|
10729
10922
|
}
|
|
10730
10923
|
}
|
|
10731
10924
|
|
|
@@ -10737,7 +10930,7 @@ import.meta.css = /* css */ `
|
|
|
10737
10930
|
position: absolute;
|
|
10738
10931
|
top: 0;
|
|
10739
10932
|
left: 0;
|
|
10740
|
-
z-index:
|
|
10933
|
+
z-index: var(--callout-z-index);
|
|
10741
10934
|
display: block;
|
|
10742
10935
|
height: auto;
|
|
10743
10936
|
opacity: 0;
|
|
@@ -11940,31 +12133,28 @@ const READONLY_CONSTRAINT = {
|
|
|
11940
12133
|
if (field.type === "hidden") {
|
|
11941
12134
|
return null;
|
|
11942
12135
|
}
|
|
12136
|
+
const isButton = field.tagName === "BUTTON";
|
|
12137
|
+
const isBusy = field.getAttribute("aria-busy") === "true";
|
|
11943
12138
|
const readonlySilent = field.hasAttribute("data-readonly-silent");
|
|
12139
|
+
const messageAttribute = field.getAttribute("data-readonly-message");
|
|
11944
12140
|
if (readonlySilent) {
|
|
11945
12141
|
return { silent: true };
|
|
11946
12142
|
}
|
|
11947
|
-
const messageAttribute = field.getAttribute("data-readonly-message");
|
|
11948
|
-
if (messageAttribute) {
|
|
11949
|
-
return {
|
|
11950
|
-
message: messageAttribute,
|
|
11951
|
-
status: "info",
|
|
11952
|
-
};
|
|
11953
|
-
}
|
|
11954
|
-
const isBusy = field.getAttribute("aria-busy") === "true";
|
|
11955
12143
|
if (isBusy) {
|
|
11956
12144
|
return {
|
|
11957
12145
|
target: field,
|
|
11958
|
-
message:
|
|
12146
|
+
message:
|
|
12147
|
+
messageAttribute || `Cette action est en cours. Veuillez patienter.`,
|
|
11959
12148
|
status: "info",
|
|
11960
12149
|
};
|
|
11961
12150
|
}
|
|
11962
12151
|
return {
|
|
11963
12152
|
target: field,
|
|
11964
12153
|
message:
|
|
11965
|
-
|
|
12154
|
+
messageAttribute ||
|
|
12155
|
+
(isButton
|
|
11966
12156
|
? `Cet action n'est pas disponible pour l'instant.`
|
|
11967
|
-
: `Cet élément est en lecture seule et ne peut pas être modifi
|
|
12157
|
+
: `Cet élément est en lecture seule et ne peut pas être modifié.`),
|
|
11968
12158
|
status: "info",
|
|
11969
12159
|
};
|
|
11970
12160
|
},
|
|
@@ -15389,12 +15579,12 @@ const ButtonBasic = props => {
|
|
|
15389
15579
|
};
|
|
15390
15580
|
const renderButtonContentMemoized = useCallback(renderButtonContent, [children]);
|
|
15391
15581
|
return jsxs(Box, {
|
|
15582
|
+
"data-readonly-silent": innerLoading ? "" : undefined,
|
|
15392
15583
|
...rest,
|
|
15393
15584
|
as: "button",
|
|
15394
15585
|
ref: ref,
|
|
15395
15586
|
"data-icon": icon ? "" : undefined,
|
|
15396
15587
|
"data-discrete": discrete ? "" : undefined,
|
|
15397
|
-
"data-readonly-silent": innerLoading ? "" : undefined,
|
|
15398
15588
|
"data-callout-arrow-x": "center",
|
|
15399
15589
|
"aria-busy": innerLoading
|
|
15400
15590
|
// style management
|
|
@@ -23597,5 +23787,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
23597
23787
|
})
|
|
23598
23788
|
});
|
|
23599
23789
|
|
|
23600
|
-
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, createSelectionKeyboardShortcuts, createUniqueValueConstraint, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested, goBack, goForward, goTo, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, setupRoutes, 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 };
|
|
23790
|
+
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, goBack, goForward, goTo, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, 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 };
|
|
23601
23791
|
//# sourceMappingURL=jsenv_navi.js.map
|