@omerdlw/base-framework 1.0.1 → 1.0.2
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/atoms/index.d.ts +0 -1
- package/dist/atoms/index.d.ts.map +1 -1
- package/dist/atoms/index.js +1 -64
- package/dist/atoms/index.js.map +1 -1
- package/dist/error/index.js +22 -25
- package/dist/error/index.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +97 -4
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/types.d.ts +11 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/hooks/use-controllable-state.d.ts +1 -1
- package/dist/hooks/use-controllable-state.d.ts.map +1 -1
- package/dist/hooks/use-hotkey.d.ts +1 -1
- package/dist/hooks/use-hotkey.d.ts.map +1 -1
- package/dist/index.js +10811 -10696
- package/dist/index.js.map +1 -1
- package/dist/kernel/adapters.d.ts.map +1 -1
- package/dist/kernel/index.d.ts +1 -0
- package/dist/kernel/index.d.ts.map +1 -1
- package/dist/kernel/index.js +13 -84
- package/dist/kernel/index.js.map +1 -1
- package/dist/kernel/installed.d.ts.map +1 -1
- package/dist/kernel/page-controller.d.ts.map +1 -1
- package/dist/kernel/provider.d.ts.map +1 -1
- package/dist/modules/ambient/constants.d.ts +1 -1
- package/dist/modules/ambient/constants.d.ts.map +1 -1
- package/dist/modules/ambient/index.js +180 -326
- package/dist/modules/ambient/index.js.map +1 -1
- package/dist/modules/ambient/module.d.ts.map +1 -1
- package/dist/modules/background/constants.d.ts +4 -2
- package/dist/modules/background/constants.d.ts.map +1 -1
- package/dist/modules/background/context.d.ts +3 -0
- package/dist/modules/background/context.d.ts.map +1 -1
- package/dist/modules/background/hooks.d.ts +1 -1
- package/dist/modules/background/index.d.ts +2 -2
- package/dist/modules/background/index.d.ts.map +1 -1
- package/dist/modules/background/index.js +1172 -1270
- package/dist/modules/background/index.js.map +1 -1
- package/dist/modules/background/overlay.d.ts +1 -1
- package/dist/modules/background/overlay.d.ts.map +1 -1
- package/dist/modules/background/types.d.ts +1 -1
- package/dist/modules/background/types.d.ts.map +1 -1
- package/dist/modules/context-menu/constants.d.ts +1 -1
- package/dist/modules/context-menu/constants.d.ts.map +1 -1
- package/dist/modules/context-menu/context.d.ts.map +1 -1
- package/dist/modules/context-menu/hooks.d.ts.map +1 -1
- package/dist/modules/context-menu/index.js +135 -240
- package/dist/modules/context-menu/index.js.map +1 -1
- package/dist/modules/controls/constants.d.ts +1 -1
- package/dist/modules/controls/constants.d.ts.map +1 -1
- package/dist/modules/controls/hooks.d.ts +1 -1
- package/dist/modules/controls/index.js +31 -165
- package/dist/modules/controls/index.js.map +1 -1
- package/dist/modules/controls/types.d.ts +1 -1
- package/dist/modules/controls/types.d.ts.map +1 -1
- package/dist/modules/dock/cards.d.ts +1 -1
- package/dist/modules/dock/constants.d.ts +1 -1
- package/dist/modules/dock/constants.d.ts.map +1 -1
- package/dist/modules/dock/context.d.ts +10 -6
- package/dist/modules/dock/context.d.ts.map +1 -1
- package/dist/modules/dock/hooks.d.ts +4 -4
- package/dist/modules/dock/hooks.d.ts.map +1 -1
- package/dist/modules/dock/index.d.ts +1 -1
- package/dist/modules/dock/index.d.ts.map +1 -1
- package/dist/modules/dock/index.js +2063 -2083
- package/dist/modules/dock/index.js.map +1 -1
- package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
- package/dist/modules/dock/types.d.ts +1 -1
- package/dist/modules/dock/types.d.ts.map +1 -1
- package/dist/modules/index.js +10193 -10350
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/loading/constants.d.ts +4 -2
- package/dist/modules/loading/constants.d.ts.map +1 -1
- package/dist/modules/loading/context.d.ts +3 -0
- package/dist/modules/loading/context.d.ts.map +1 -1
- package/dist/modules/loading/hooks.d.ts +1 -1
- package/dist/modules/loading/hooks.d.ts.map +1 -1
- package/dist/modules/loading/index.d.ts +2 -2
- package/dist/modules/loading/index.d.ts.map +1 -1
- package/dist/modules/loading/index.js +121 -225
- package/dist/modules/loading/index.js.map +1 -1
- package/dist/modules/loading/types.d.ts +1 -1
- package/dist/modules/loading/types.d.ts.map +1 -1
- package/dist/modules/media/constants.d.ts +2 -1
- package/dist/modules/media/constants.d.ts.map +1 -1
- package/dist/modules/media/context.d.ts +3 -0
- package/dist/modules/media/context.d.ts.map +1 -1
- package/dist/modules/media/index.d.ts +2 -2
- package/dist/modules/media/index.d.ts.map +1 -1
- package/dist/modules/media/index.js +61 -218
- package/dist/modules/media/index.js.map +1 -1
- package/dist/modules/modal/constants.d.ts +1 -1
- package/dist/modules/modal/constants.d.ts.map +1 -1
- package/dist/modules/modal/context.d.ts.map +1 -1
- package/dist/modules/modal/hooks.d.ts +2 -2
- package/dist/modules/modal/index.js +31 -293
- package/dist/modules/modal/index.js.map +1 -1
- package/dist/modules/notification/constants.d.ts +4 -2
- package/dist/modules/notification/constants.d.ts.map +1 -1
- package/dist/modules/notification/context.d.ts +4 -0
- package/dist/modules/notification/context.d.ts.map +1 -1
- package/dist/modules/notification/hooks.d.ts +1 -1
- package/dist/modules/notification/index.d.ts +2 -3
- package/dist/modules/notification/index.d.ts.map +1 -1
- package/dist/modules/notification/index.js +65 -151
- package/dist/modules/notification/index.js.map +1 -1
- package/dist/modules/notification/module.d.ts.map +1 -1
- package/dist/provider.js +255 -257
- package/dist/provider.js.map +1 -1
- package/dist/theme.d.ts +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +2 -2
- package/dist/theme.js.map +1 -1
- package/dist/utils/dom.d.ts +2 -0
- package/dist/utils/dom.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +28 -19
- package/dist/utils/index.js.map +1 -1
- package/docs/modules/loading.md +1 -1
- package/package.json +48 -2
- package/dist/hooks/use-async-action.d.ts +0 -3
- package/dist/hooks/use-async-action.d.ts.map +0 -1
- package/dist/hooks/use-debounce.d.ts +0 -2
- package/dist/hooks/use-debounce.d.ts.map +0 -1
- package/dist/hooks/use-intersection-observer.d.ts +0 -4
- package/dist/hooks/use-intersection-observer.d.ts.map +0 -1
- package/dist/hooks/use-media-query.d.ts +0 -2
- package/dist/hooks/use-media-query.d.ts.map +0 -1
- package/dist/hooks/use-mounted.d.ts +0 -2
- package/dist/hooks/use-mounted.d.ts.map +0 -1
- package/dist/hooks/use-server-action.d.ts +0 -4
- package/dist/hooks/use-server-action.d.ts.map +0 -1
- package/dist/hooks/use-storage-state.d.ts +0 -5
- package/dist/hooks/use-storage-state.d.ts.map +0 -1
- package/dist/modules/theme.d.ts +0 -3
- package/dist/modules/theme.d.ts.map +0 -1
- package/dist/utils/json.d.ts +0 -3
- package/dist/utils/json.d.ts.map +0 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { memo, createContext, useState, useRef, useEffect, useMemo, useCallback,
|
|
2
|
+
import { memo, createContext, useState, useRef, useEffect, useMemo, useCallback, useInsertionEffect, useContext, useSyncExternalStore, useLayoutEffect, use, useId, isValidElement, cloneElement, Children } from 'react';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { Icon as Icon$1 } from '@iconify-icon/react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import '@radix-ui/react-tooltip';
|
|
8
7
|
import { AnimatePresence, motion } from 'motion/react';
|
|
9
8
|
import { usePathname } from 'next/navigation';
|
|
10
9
|
|
|
@@ -12,9 +11,6 @@ function cn(...inputs) {
|
|
|
12
11
|
return twMerge(clsx(inputs));
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
// src/utils/dom.ts
|
|
16
|
-
var isBrowser = typeof window !== "undefined";
|
|
17
|
-
|
|
18
14
|
// src/utils/string.ts
|
|
19
15
|
function trimToNull(value) {
|
|
20
16
|
if (value === null || value === void 0) return null;
|
|
@@ -22,6 +18,9 @@ function trimToNull(value) {
|
|
|
22
18
|
return trimmed.length > 0 ? trimmed : null;
|
|
23
19
|
}
|
|
24
20
|
|
|
21
|
+
// src/utils/dom.ts
|
|
22
|
+
var isBrowser = typeof window !== "undefined";
|
|
23
|
+
|
|
25
24
|
// src/utils/object.ts
|
|
26
25
|
function isObject(value) {
|
|
27
26
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -185,6 +184,58 @@ Object.freeze({
|
|
|
185
184
|
duration: DURATION_TOKENS.INSTANT,
|
|
186
185
|
ease: "linear"
|
|
187
186
|
});
|
|
187
|
+
|
|
188
|
+
// src/kernel/constants.ts
|
|
189
|
+
var DEFAULT_SOURCE = "dynamic";
|
|
190
|
+
var REGISTRY_SOURCES = Object.freeze({
|
|
191
|
+
STATIC: "static",
|
|
192
|
+
DYNAMIC: "dynamic",
|
|
193
|
+
USER: "user"
|
|
194
|
+
});
|
|
195
|
+
var REGISTRY_LIFECYCLES = Object.freeze({
|
|
196
|
+
IMMEDIATE: "immediate",
|
|
197
|
+
GRACEFUL: "graceful",
|
|
198
|
+
PERSISTENT: "persistent",
|
|
199
|
+
ROUTE: "route"
|
|
200
|
+
});
|
|
201
|
+
var REGISTRY_VALIDATION_MODES = Object.freeze({
|
|
202
|
+
WARN: "warn",
|
|
203
|
+
STRICT: "strict"
|
|
204
|
+
});
|
|
205
|
+
var REGISTRY_METADATA_KEYS = Object.freeze([
|
|
206
|
+
"cleanup",
|
|
207
|
+
"cleanupDelayMs",
|
|
208
|
+
"instanceId",
|
|
209
|
+
"lifecycle",
|
|
210
|
+
"priority",
|
|
211
|
+
"source",
|
|
212
|
+
"scope",
|
|
213
|
+
"validation"
|
|
214
|
+
]);
|
|
215
|
+
Object.freeze({
|
|
216
|
+
[REGISTRY_SOURCES.STATIC]: 100,
|
|
217
|
+
[REGISTRY_SOURCES.DYNAMIC]: 200,
|
|
218
|
+
[REGISTRY_SOURCES.USER]: 300
|
|
219
|
+
});
|
|
220
|
+
Object.freeze({
|
|
221
|
+
[REGISTRY_SOURCES.STATIC]: 10,
|
|
222
|
+
[REGISTRY_SOURCES.DYNAMIC]: 20,
|
|
223
|
+
[REGISTRY_SOURCES.USER]: 30
|
|
224
|
+
});
|
|
225
|
+
var REGISTRY_LIFECYCLE_VALUES = new Set(
|
|
226
|
+
Object.values(REGISTRY_LIFECYCLES)
|
|
227
|
+
);
|
|
228
|
+
var REGISTRY_METADATA_KEY_SET = new Set(
|
|
229
|
+
REGISTRY_METADATA_KEYS
|
|
230
|
+
);
|
|
231
|
+
var REGISTRY_SCOPE_KINDS = Object.freeze({
|
|
232
|
+
APP: "app",
|
|
233
|
+
SESSION: "session",
|
|
234
|
+
ROUTE: "route",
|
|
235
|
+
INSTANCE: "instance",
|
|
236
|
+
WORKSPACE: "workspace"
|
|
237
|
+
});
|
|
238
|
+
REGISTRY_SCOPE_KINDS.APP;
|
|
188
239
|
function getOrCreateGlobalContext(name, defaultValue) {
|
|
189
240
|
const sym = /* @__PURE__ */ Symbol.for(`@omerdlw/base-framework/context/${name}`);
|
|
190
241
|
const store = globalThis;
|
|
@@ -194,1389 +245,1225 @@ function getOrCreateGlobalContext(name, defaultValue) {
|
|
|
194
245
|
return store[sym];
|
|
195
246
|
}
|
|
196
247
|
|
|
197
|
-
// src/
|
|
198
|
-
function
|
|
199
|
-
|
|
248
|
+
// src/kernel/utils.ts
|
|
249
|
+
function parseFiniteNumber(value) {
|
|
250
|
+
const parsed = Number(value);
|
|
251
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
200
252
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
function useTheme(spec) {
|
|
204
|
-
const config = useContext(ThemeContext).get(spec.id);
|
|
205
|
-
if (!config) {
|
|
206
|
-
throw new Error(
|
|
207
|
-
`Theme "${spec.id}" is missing. Add its theme file to src/config/ and list it in src/config/index.ts.`
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
slots: config.slots,
|
|
212
|
-
styles: config.styles ?? {}
|
|
213
|
-
};
|
|
253
|
+
function getValidString(value, fallback = null) {
|
|
254
|
+
return trimToNull(value) ?? fallback;
|
|
214
255
|
}
|
|
215
256
|
|
|
216
|
-
// src/
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
width: null
|
|
244
|
-
});
|
|
245
|
-
var objectFit = (value) => ({
|
|
246
|
-
objectFit: value
|
|
247
|
-
});
|
|
248
|
-
var objectPosition = (value) => ({
|
|
249
|
-
objectPosition: value
|
|
250
|
-
});
|
|
251
|
-
var BG_TOKEN_TO_OBJECT_STYLE = Object.freeze({
|
|
252
|
-
"bg-bottom": objectPosition("bottom"),
|
|
253
|
-
"bg-center": objectPosition("center"),
|
|
254
|
-
"bg-contain": objectFit("contain"),
|
|
255
|
-
"bg-cover": objectFit("cover"),
|
|
256
|
-
"bg-fill": objectFit("fill"),
|
|
257
|
-
"bg-left": objectPosition("left"),
|
|
258
|
-
"bg-left-bottom": objectPosition("left bottom"),
|
|
259
|
-
"bg-left-top": objectPosition("left top"),
|
|
260
|
-
"bg-none": objectFit("none"),
|
|
261
|
-
"bg-right": objectPosition("right"),
|
|
262
|
-
"bg-right-bottom": objectPosition("right bottom"),
|
|
263
|
-
"bg-right-top": objectPosition("right top"),
|
|
264
|
-
"bg-scale-down": objectFit("scale-down"),
|
|
265
|
-
"bg-top": objectPosition("top")
|
|
266
|
-
});
|
|
267
|
-
var OBJECT_FITS = Object.freeze([
|
|
268
|
-
"contain",
|
|
269
|
-
"cover",
|
|
270
|
-
"fill",
|
|
271
|
-
"none",
|
|
272
|
-
"scale-down"
|
|
273
|
-
]);
|
|
274
|
-
var DEFAULT_COLOR = "var(--black, #000)";
|
|
275
|
-
var backgroundTheme = defineThemeSpec("background");
|
|
276
|
-
var BACKGROUND_REGISTRY_KEY = "page-background";
|
|
277
|
-
var BACKGROUND_MEDIA_ID = "background";
|
|
278
|
-
|
|
279
|
-
// src/modules/background/youtube/parse.ts
|
|
280
|
-
var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
|
|
281
|
-
function parseYouTubeTimeParam(value) {
|
|
282
|
-
if (value === void 0 || value === null || value === "") return 0;
|
|
283
|
-
if (typeof value === "number") {
|
|
284
|
-
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
257
|
+
// src/kernel/schema.ts
|
|
258
|
+
function resolveLifecycle(metadata, fallback) {
|
|
259
|
+
const lifecycle = metadata?.lifecycle ?? metadata?.cleanup;
|
|
260
|
+
return lifecycle && REGISTRY_LIFECYCLE_VALUES.has(lifecycle) ? lifecycle : fallback;
|
|
261
|
+
}
|
|
262
|
+
function validateRegistryMetadata(metadata) {
|
|
263
|
+
if (metadata === void 0 || metadata === null)
|
|
264
|
+
return { issues: [], valid: true };
|
|
265
|
+
if (!isObject(metadata))
|
|
266
|
+
return { issues: ["registry metadata must be an object"], valid: false };
|
|
267
|
+
const issues = [];
|
|
268
|
+
Object.keys(metadata).forEach((key) => {
|
|
269
|
+
if (!REGISTRY_METADATA_KEY_SET.has(key))
|
|
270
|
+
issues.push(`unknown registry metadata field: ${key}`);
|
|
271
|
+
});
|
|
272
|
+
if (metadata.source !== void 0 && !getValidString(metadata.source))
|
|
273
|
+
issues.push("source must be a non-empty string");
|
|
274
|
+
if (metadata.instanceId !== void 0 && !getValidString(metadata.instanceId))
|
|
275
|
+
issues.push("instanceId must be a non-empty string");
|
|
276
|
+
if (metadata.scope !== void 0 && !getValidString(metadata.scope))
|
|
277
|
+
issues.push("scope must be a non-empty string");
|
|
278
|
+
if (metadata.priority !== void 0 && parseFiniteNumber(metadata.priority) === null)
|
|
279
|
+
issues.push("priority must be a finite number");
|
|
280
|
+
if (metadata.cleanupDelayMs !== void 0) {
|
|
281
|
+
const delay = parseFiniteNumber(metadata.cleanupDelayMs);
|
|
282
|
+
if (delay === null || delay < 0)
|
|
283
|
+
issues.push("cleanupDelayMs must be a non-negative finite number");
|
|
285
284
|
}
|
|
286
|
-
const
|
|
287
|
-
if (!
|
|
288
|
-
|
|
289
|
-
|
|
285
|
+
const lifecycle = metadata.lifecycle ?? metadata.cleanup;
|
|
286
|
+
if (lifecycle !== void 0 && !REGISTRY_LIFECYCLE_VALUES.has(String(lifecycle))) {
|
|
287
|
+
issues.push(
|
|
288
|
+
`lifecycle must be one of: ${[...REGISTRY_LIFECYCLE_VALUES].join(", ")}`
|
|
289
|
+
);
|
|
290
290
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const seconds = parseFloat(hmsMatch[3] || "0");
|
|
298
|
-
return Math.max(0, hours * 3600 + minutes * 60 + seconds);
|
|
291
|
+
if (metadata.validation !== void 0 && !Object.values(REGISTRY_VALIDATION_MODES).includes(
|
|
292
|
+
metadata.validation
|
|
293
|
+
)) {
|
|
294
|
+
issues.push(
|
|
295
|
+
`validation must be one of: ${Object.values(REGISTRY_VALIDATION_MODES).join(", ")}`
|
|
296
|
+
);
|
|
299
297
|
}
|
|
300
|
-
return 0;
|
|
298
|
+
return { issues, valid: issues.length === 0 };
|
|
301
299
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
300
|
+
function normalizeRegistryMetadata(metadata, {
|
|
301
|
+
defaultCleanupDelayMs = null,
|
|
302
|
+
defaultLifecycle = null,
|
|
303
|
+
defaultSource = DEFAULT_SOURCE
|
|
304
|
+
} = {}) {
|
|
305
|
+
const registryMeta = isObject(metadata) ? metadata : {};
|
|
306
|
+
const normalizedDefaultDelay = parseFiniteNumber(defaultCleanupDelayMs);
|
|
307
|
+
const fallbackCleanupDelayMs = normalizedDefaultDelay !== null && normalizedDefaultDelay >= 0 ? normalizedDefaultDelay : null;
|
|
308
|
+
const fallbackLifecycle = defaultLifecycle && REGISTRY_LIFECYCLE_VALUES.has(defaultLifecycle) ? defaultLifecycle : null;
|
|
309
|
+
const source = getValidString(registryMeta.source) || getValidString(defaultSource, DEFAULT_SOURCE) || DEFAULT_SOURCE;
|
|
310
|
+
const scope = getValidString(registryMeta.scope);
|
|
311
|
+
const priority = parseFiniteNumber(registryMeta.priority);
|
|
312
|
+
const lifecycle = resolveLifecycle(registryMeta, fallbackLifecycle);
|
|
313
|
+
const validation = isValidationMode(registryMeta.validation) ? registryMeta.validation : null;
|
|
314
|
+
const cleanupDelayCandidate = parseFiniteNumber(registryMeta.cleanupDelayMs);
|
|
315
|
+
let cleanupDelayMs = cleanupDelayCandidate !== null && cleanupDelayCandidate >= 0 ? cleanupDelayCandidate : fallbackCleanupDelayMs;
|
|
316
|
+
if (lifecycle === REGISTRY_LIFECYCLES.IMMEDIATE) {
|
|
317
|
+
cleanupDelayMs = 0;
|
|
318
|
+
} else if ((lifecycle === REGISTRY_LIFECYCLES.GRACEFUL || lifecycle === REGISTRY_LIFECYCLES.ROUTE) && cleanupDelayMs === null) {
|
|
319
|
+
cleanupDelayMs = fallbackCleanupDelayMs;
|
|
314
320
|
}
|
|
321
|
+
return {
|
|
322
|
+
cleanupDelayMs,
|
|
323
|
+
lifecycle,
|
|
324
|
+
priority,
|
|
325
|
+
registerOptions: {
|
|
326
|
+
...priority !== null && { priority },
|
|
327
|
+
...validation === REGISTRY_VALIDATION_MODES.STRICT && { validation },
|
|
328
|
+
...scope && { scope }
|
|
329
|
+
},
|
|
330
|
+
source,
|
|
331
|
+
...scope && { scope },
|
|
332
|
+
...validation && { validation }
|
|
333
|
+
};
|
|
315
334
|
}
|
|
316
|
-
function
|
|
317
|
-
|
|
318
|
-
const segments = url.pathname.split("/").filter(Boolean);
|
|
319
|
-
if (host === "youtu.be") {
|
|
320
|
-
return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
|
|
321
|
-
}
|
|
322
|
-
if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
|
|
323
|
-
return null;
|
|
324
|
-
}
|
|
325
|
-
const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
|
|
326
|
-
if (fromQuery && YOUTUBE_ID_PATTERN.test(fromQuery)) return fromQuery;
|
|
327
|
-
const isVideoPath = segments.length >= 2 && ["embed", "shorts", "live", "v", "e", "watch"].includes(
|
|
328
|
-
segments[0].toLowerCase()
|
|
329
|
-
);
|
|
330
|
-
return isVideoPath && YOUTUBE_ID_PATTERN.test(segments[1]) ? segments[1] : null;
|
|
331
|
-
}
|
|
332
|
-
function extractYouTubeVideoId(input, options = {}) {
|
|
333
|
-
const trimmed = typeof input === "string" ? input.trim() : "";
|
|
334
|
-
if (!trimmed) return null;
|
|
335
|
-
if (options.allowBareId && YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
|
|
336
|
-
const prefixed = trimmed.match(/^(?:youtube|yt):([a-zA-Z0-9_-]{11})$/i);
|
|
337
|
-
if (prefixed) return prefixed[1];
|
|
338
|
-
const url = toUrl(trimmed, { youtubeOnly: true });
|
|
339
|
-
return url ? getIdFromUrl(url) : null;
|
|
335
|
+
function isValidationMode(value) {
|
|
336
|
+
return Object.values(REGISTRY_VALIDATION_MODES).includes(value);
|
|
340
337
|
}
|
|
341
|
-
function
|
|
342
|
-
|
|
338
|
+
function pickRegistryMetadata(options) {
|
|
339
|
+
if (!isObject(options)) return {};
|
|
340
|
+
return Object.fromEntries(
|
|
341
|
+
REGISTRY_METADATA_KEYS.filter((key) => options[key] !== void 0).map(
|
|
342
|
+
(key) => [key, options[key]]
|
|
343
|
+
)
|
|
344
|
+
);
|
|
343
345
|
}
|
|
344
|
-
function
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if (isYouTubeUrl(trimmed)) return true;
|
|
349
|
-
if (trimmed.startsWith("/api/background/youtube") || trimmed.startsWith("blob:")) {
|
|
350
|
-
return true;
|
|
346
|
+
function useRequiredContext(context, hookName, providerName) {
|
|
347
|
+
const value = use(context);
|
|
348
|
+
if (value === null) {
|
|
349
|
+
throw new Error(`${hookName} must be used within ${providerName}`);
|
|
351
350
|
}
|
|
352
|
-
|
|
353
|
-
return /\.(mp4|webm|mov|m4v|ogg|ogv|m3u8)$/i.test(cleanPath);
|
|
351
|
+
return value;
|
|
354
352
|
}
|
|
355
|
-
function
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
353
|
+
function useStore(store, selector = (state) => state, isEqual = Object.is) {
|
|
354
|
+
const cacheRef = useRef({
|
|
355
|
+
isEqual: null,
|
|
356
|
+
selected: void 0,
|
|
357
|
+
selector: null,
|
|
358
|
+
snapshot: null
|
|
359
|
+
});
|
|
360
|
+
const getSelectedSnapshot = useCallback(() => {
|
|
361
|
+
const snapshot = store.getSnapshot();
|
|
362
|
+
const cache = cacheRef.current;
|
|
363
|
+
if (cache.snapshot === snapshot && cache.selector === selector && cache.isEqual === isEqual) {
|
|
364
|
+
return cache.selected;
|
|
365
|
+
}
|
|
366
|
+
const selected = selector(snapshot);
|
|
367
|
+
if (cache.snapshot !== null && cache.isEqual === isEqual && isEqual(cache.selected, selected)) {
|
|
368
|
+
cache.snapshot = snapshot;
|
|
369
|
+
cache.selector = selector;
|
|
370
|
+
return cache.selected;
|
|
371
|
+
}
|
|
372
|
+
cacheRef.current = {
|
|
373
|
+
isEqual,
|
|
374
|
+
selected,
|
|
375
|
+
selector,
|
|
376
|
+
snapshot
|
|
377
|
+
};
|
|
378
|
+
return selected;
|
|
379
|
+
}, [isEqual, selector, store]);
|
|
380
|
+
return useSyncExternalStore(
|
|
381
|
+
store.subscribe,
|
|
382
|
+
getSelectedSnapshot,
|
|
383
|
+
getSelectedSnapshot
|
|
384
|
+
);
|
|
366
385
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return
|
|
386
|
+
var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
|
|
387
|
+
var RegistryContext = getOrCreateGlobalContext(
|
|
388
|
+
"RegistryContext",
|
|
389
|
+
null
|
|
390
|
+
);
|
|
391
|
+
function useRegistryActions() {
|
|
392
|
+
return useRequiredContext(
|
|
393
|
+
RegistryContext,
|
|
394
|
+
"useRegistryActions",
|
|
395
|
+
"RegistryProvider"
|
|
396
|
+
).actions;
|
|
374
397
|
}
|
|
375
|
-
function
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
398
|
+
function useRegistrySubscription() {
|
|
399
|
+
return useRequiredContext(
|
|
400
|
+
RegistryContext,
|
|
401
|
+
"useRegistrySubscription",
|
|
402
|
+
"RegistryProvider"
|
|
403
|
+
).subscription;
|
|
380
404
|
}
|
|
381
|
-
function
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
duration: {
|
|
393
|
-
configurable: true,
|
|
394
|
-
get: () => controller.getDuration()
|
|
395
|
-
},
|
|
396
|
-
loop: {
|
|
397
|
-
configurable: true,
|
|
398
|
-
get: () => controller.getLoop(),
|
|
399
|
-
set: (value) => {
|
|
400
|
-
controller.setLoop(Boolean(value));
|
|
401
|
-
}
|
|
402
|
-
},
|
|
403
|
-
muted: {
|
|
404
|
-
configurable: true,
|
|
405
|
-
get: () => controller.getMuted(),
|
|
406
|
-
set: (value) => {
|
|
407
|
-
controller.setMuted(Boolean(value));
|
|
408
|
-
proxyVideo.dispatchEvent(new Event("volumechange"));
|
|
409
|
-
}
|
|
410
|
-
},
|
|
411
|
-
pause: {
|
|
412
|
-
configurable: true,
|
|
413
|
-
value: () => {
|
|
414
|
-
controller.pause();
|
|
415
|
-
proxyVideo.dispatchEvent(new Event("pause"));
|
|
416
|
-
}
|
|
417
|
-
},
|
|
418
|
-
paused: {
|
|
419
|
-
configurable: true,
|
|
420
|
-
get: () => controller.getPaused()
|
|
421
|
-
},
|
|
422
|
-
play: {
|
|
423
|
-
configurable: true,
|
|
424
|
-
value: () => controller.play().then(() => {
|
|
425
|
-
proxyVideo.dispatchEvent(new Event("play"));
|
|
426
|
-
proxyVideo.dispatchEvent(new Event("playing"));
|
|
427
|
-
})
|
|
428
|
-
},
|
|
429
|
-
playbackRate: {
|
|
430
|
-
configurable: true,
|
|
431
|
-
get: () => controller.getPlaybackRate(),
|
|
432
|
-
set: (value) => {
|
|
433
|
-
controller.setPlaybackRate(Number(value) || 1);
|
|
434
|
-
proxyVideo.dispatchEvent(new Event("ratechange"));
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
volume: {
|
|
438
|
-
configurable: true,
|
|
439
|
-
get: () => controller.getVolume(),
|
|
440
|
-
set: (value) => {
|
|
441
|
-
const clamped = Math.max(0, Math.min(1, Number(value) || 0));
|
|
442
|
-
controller.setVolume(clamped);
|
|
443
|
-
proxyVideo.dispatchEvent(new Event("volumechange"));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
return proxyVideo;
|
|
405
|
+
function useRegistryValue(type, key) {
|
|
406
|
+
const { getSnapshot, subscribe } = useRegistrySubscription();
|
|
407
|
+
const subscribeToKey = useCallback(
|
|
408
|
+
(listener) => subscribe(type, key, listener),
|
|
409
|
+
[key, subscribe, type]
|
|
410
|
+
);
|
|
411
|
+
const getValue = useCallback(
|
|
412
|
+
() => getSnapshot(type, key),
|
|
413
|
+
[getSnapshot, key, type]
|
|
414
|
+
);
|
|
415
|
+
return useSyncExternalStore(subscribeToKey, getValue, getValue);
|
|
448
416
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
(input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []
|
|
455
|
-
).filter(Boolean);
|
|
456
|
-
return {
|
|
457
|
-
objectStyle: Object.assign(
|
|
458
|
-
{},
|
|
459
|
-
...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])
|
|
460
|
-
),
|
|
461
|
-
other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
|
|
462
|
-
width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
|
|
463
|
-
};
|
|
417
|
+
var EMPTY_MODULES = Object.freeze([]);
|
|
418
|
+
var ModuleHostContext = getOrCreateGlobalContext("ModuleHostContext", null);
|
|
419
|
+
function selectModuleSlice(coreModule, config) {
|
|
420
|
+
const slice = coreModule.page?.select ? coreModule.page.select(config) : config[coreModule.id];
|
|
421
|
+
return slice ?? null;
|
|
464
422
|
}
|
|
465
|
-
function
|
|
423
|
+
function createModulePayload(modules, config, metadata = {}) {
|
|
424
|
+
const payload = {};
|
|
425
|
+
let hasSlices = false;
|
|
426
|
+
for (const coreModule of modules) {
|
|
427
|
+
if (!coreModule.page?.entries) continue;
|
|
428
|
+
const slice = selectModuleSlice(coreModule, config);
|
|
429
|
+
if (slice === null) continue;
|
|
430
|
+
payload[coreModule.id] = slice;
|
|
431
|
+
hasSlices = true;
|
|
432
|
+
}
|
|
433
|
+
if (!hasSlices) return null;
|
|
466
434
|
return {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
playbackRate: options.playbackRate ?? 1,
|
|
473
|
-
quality: options.quality || "1080p",
|
|
474
|
-
shouldAutoPlay: options.autoplay ?? true,
|
|
475
|
-
showPoster: Boolean(options.showPoster),
|
|
476
|
-
showSpinner: options.showSpinner !== false
|
|
435
|
+
...payload,
|
|
436
|
+
registry: {
|
|
437
|
+
...metadata,
|
|
438
|
+
...isObject(config.registry) ? config.registry : {}
|
|
439
|
+
}
|
|
477
440
|
};
|
|
478
441
|
}
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
if (typeof patch === "string") {
|
|
482
|
-
const trimmed = patch.trim();
|
|
483
|
-
if (isYouTubeUrl(trimmed) || isDirectVideoUrl(trimmed)) {
|
|
484
|
-
return { image: null, video: trimmed };
|
|
485
|
-
}
|
|
486
|
-
return { image: trimmed };
|
|
487
|
-
}
|
|
488
|
-
const nextPatch = { ...patch };
|
|
489
|
-
if (typeof nextPatch.image === "string" && isYouTubeUrl(nextPatch.image) && !nextPatch.video) {
|
|
490
|
-
nextPatch.video = nextPatch.image;
|
|
491
|
-
nextPatch.image = null;
|
|
492
|
-
}
|
|
493
|
-
return nextPatch;
|
|
442
|
+
function useInstalledModules() {
|
|
443
|
+
return use(ModuleHostContext)?.modules ?? EMPTY_MODULES;
|
|
494
444
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
...resolvedPatch.videoOptions || {}
|
|
500
|
-
};
|
|
501
|
-
const nextVideo = resolvedPatch.video !== void 0 ? resolvedPatch.video : baseState.video;
|
|
502
|
-
const shouldAutoPlay = nextVideoOptions.autoplay !== false;
|
|
503
|
-
const resolvedIsPlaying = resolvedPatch.isPlaying !== void 0 ? resolvedPatch.isPlaying : resolvedPatch.video !== void 0 && Boolean(nextVideo) ? shouldAutoPlay : baseState.isPlaying;
|
|
504
|
-
return {
|
|
505
|
-
...baseState,
|
|
506
|
-
...resolvedPatch,
|
|
507
|
-
isPlaying: resolvedIsPlaying,
|
|
508
|
-
animation: resolvedPatch.animation !== void 0 ? resolvedPatch.animation ? {
|
|
509
|
-
...baseState.animation || {},
|
|
510
|
-
...resolvedPatch.animation
|
|
511
|
-
} : resolvedPatch.animation : baseState.animation,
|
|
512
|
-
imageStyle: {
|
|
513
|
-
...baseState.imageStyle,
|
|
514
|
-
...resolvedPatch.imageStyle || {}
|
|
515
|
-
},
|
|
516
|
-
noiseStyle: {
|
|
517
|
-
...baseState.noiseStyle,
|
|
518
|
-
...resolvedPatch.noiseStyle || {}
|
|
519
|
-
},
|
|
520
|
-
videoOptions: nextVideoOptions,
|
|
521
|
-
videoStyle: {
|
|
522
|
-
...baseState.videoStyle,
|
|
523
|
-
...resolvedPatch.videoStyle || {}
|
|
524
|
-
}
|
|
525
|
-
};
|
|
445
|
+
|
|
446
|
+
// src/kernel/handlers.ts
|
|
447
|
+
function isPersistentLifecycle(lifecycle) {
|
|
448
|
+
return lifecycle === REGISTRY_LIFECYCLES.PERSISTENT;
|
|
526
449
|
}
|
|
527
|
-
function
|
|
528
|
-
return
|
|
450
|
+
function runRegistrationBatch(context, executor) {
|
|
451
|
+
return typeof context.batch === "function" ? context.batch(executor) : executor(context);
|
|
529
452
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const {
|
|
540
|
-
className: _className,
|
|
541
|
-
leftGradient = 0,
|
|
542
|
-
rightGradient = 0,
|
|
543
|
-
...baseStyle
|
|
544
|
-
} = currentStyle;
|
|
545
|
-
return {
|
|
546
|
-
baseStyle,
|
|
547
|
-
leftGradient: Number(leftGradient) || 0,
|
|
548
|
-
rightGradient: Number(rightGradient) || 0
|
|
549
|
-
};
|
|
453
|
+
function createEntryCleanupKey(type, key, source, instanceId, scope) {
|
|
454
|
+
return JSON.stringify([
|
|
455
|
+
"entry",
|
|
456
|
+
type,
|
|
457
|
+
key,
|
|
458
|
+
scope ?? null,
|
|
459
|
+
source,
|
|
460
|
+
instanceId
|
|
461
|
+
]);
|
|
550
462
|
}
|
|
551
|
-
function
|
|
552
|
-
|
|
553
|
-
hasWidth = false,
|
|
554
|
-
leftGradient = 0,
|
|
555
|
-
rightGradient = 0
|
|
556
|
-
}) {
|
|
557
|
-
let leftPercent = 0;
|
|
558
|
-
let rightPercent = 0;
|
|
559
|
-
if (leftGradient > 0)
|
|
560
|
-
leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
|
|
561
|
-
else if (hasWidth && fadeEdges !== false) leftPercent = 20;
|
|
562
|
-
if (rightGradient > 0)
|
|
563
|
-
rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
|
|
564
|
-
else if (hasWidth && fadeEdges !== false) rightPercent = 20;
|
|
565
|
-
if (typeof fadeEdges === "number") {
|
|
566
|
-
leftPercent = fadeEdges;
|
|
567
|
-
rightPercent = fadeEdges;
|
|
568
|
-
} else if (typeof fadeEdges === "string") {
|
|
569
|
-
const parsed = parseFloat(fadeEdges);
|
|
570
|
-
if (!Number.isNaN(parsed)) {
|
|
571
|
-
leftPercent = parsed;
|
|
572
|
-
rightPercent = parsed;
|
|
573
|
-
}
|
|
574
|
-
} else if (typeof fadeEdges === "object" && fadeEdges !== null) {
|
|
575
|
-
const edgeObj = fadeEdges;
|
|
576
|
-
if (edgeObj.left !== void 0)
|
|
577
|
-
leftPercent = parseFloat(String(edgeObj.left)) || 0;
|
|
578
|
-
if (edgeObj.right !== void 0)
|
|
579
|
-
rightPercent = parseFloat(String(edgeObj.right)) || 0;
|
|
580
|
-
} else if (fadeEdges === false) {
|
|
581
|
-
leftPercent = 0;
|
|
582
|
-
rightPercent = 0;
|
|
583
|
-
}
|
|
584
|
-
const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
|
|
585
|
-
const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
|
|
586
|
-
return {
|
|
587
|
-
enabled: leftPercent > 0 || rightPercent > 0,
|
|
588
|
-
leftOpacity,
|
|
589
|
-
leftPercent,
|
|
590
|
-
rightOpacity,
|
|
591
|
-
rightPercent
|
|
592
|
-
};
|
|
463
|
+
function getCleanupScope(context) {
|
|
464
|
+
return context?.cleanupScope || /* @__PURE__ */ new Map();
|
|
593
465
|
}
|
|
594
|
-
function
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
{ s: 0.76, t: 0.75 },
|
|
601
|
-
{ s: 0.93, t: 0.9 },
|
|
602
|
-
{ s: 1, t: 1 }
|
|
603
|
-
];
|
|
604
|
-
if (direction === "in") {
|
|
605
|
-
return steps.map(
|
|
606
|
-
({ s, t }) => s === 0 ? `transparent ${(t * percent).toFixed(1)}%` : s === 1 ? `${color} ${(t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(s * 100)}%, transparent) ${(t * percent).toFixed(1)}%`
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
return steps.map(({ s, t }) => {
|
|
610
|
-
const alpha = 1 - s;
|
|
611
|
-
return alpha === 0 ? `transparent ${(100 - percent + t * percent).toFixed(1)}%` : alpha === 1 ? `${color} ${(100 - percent + t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent) ${(100 - percent + t * percent).toFixed(1)}%`;
|
|
612
|
-
});
|
|
466
|
+
function clearCleanupTimer(scope, cleanupKey) {
|
|
467
|
+
const lifecycle = scope.get(cleanupKey);
|
|
468
|
+
if (!lifecycle) return;
|
|
469
|
+
lifecycle.cancelled = true;
|
|
470
|
+
if (lifecycle.timerId !== null) clearTimeout(lifecycle.timerId);
|
|
471
|
+
scope.delete(cleanupKey);
|
|
613
472
|
}
|
|
614
|
-
function
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
473
|
+
function scheduleCleanup(scope, cleanupKey, callback, delayMs) {
|
|
474
|
+
clearCleanupTimer(scope, cleanupKey);
|
|
475
|
+
const lifecycle = {
|
|
476
|
+
cancelled: false,
|
|
477
|
+
timerId: null
|
|
478
|
+
};
|
|
479
|
+
lifecycle.timerId = setTimeout(() => {
|
|
480
|
+
if (lifecycle.cancelled || scope.get(cleanupKey) !== lifecycle) return;
|
|
481
|
+
scope.delete(cleanupKey);
|
|
482
|
+
callback();
|
|
483
|
+
}, delayMs);
|
|
484
|
+
scope.set(cleanupKey, lifecycle);
|
|
623
485
|
}
|
|
624
|
-
function
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
} catch {
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
if (!isPlaying) {
|
|
641
|
-
if (!videoElement.paused) videoElement.pause();
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
if (videoElement.readyState === 0) {
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
const playPromise = videoElement.play();
|
|
648
|
-
if (!playPromise || typeof playPromise.then !== "function") return;
|
|
649
|
-
playPromise.then(() => setVideoPlaying(true)).catch((error) => {
|
|
650
|
-
if (error?.name === "AbortError" || videoElement.readyState < 2) {
|
|
651
|
-
return;
|
|
486
|
+
function collectModuleRegistrations(coreModule, slice, pageMetadata, context) {
|
|
487
|
+
const definition = coreModule.registry;
|
|
488
|
+
const toEntries = coreModule.page?.entries;
|
|
489
|
+
if (!definition || !toEntries || slice == null || slice === false) return [];
|
|
490
|
+
const type = coreModule.id;
|
|
491
|
+
const items = Array.isArray(slice) ? slice : [slice];
|
|
492
|
+
const registrations = [];
|
|
493
|
+
for (const item of items) {
|
|
494
|
+
if (item == null || item === false) continue;
|
|
495
|
+
const itemMetadata = isObject(item) && isObject(item.registry) ? item.registry : {};
|
|
496
|
+
const metadata = { ...pageMetadata, ...itemMetadata };
|
|
497
|
+
if (metadata.validation === "strict" && !validateRegistryMetadata(metadata).valid) {
|
|
498
|
+
continue;
|
|
652
499
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
500
|
+
const payload = isObject(item) ? Object.fromEntries(
|
|
501
|
+
Object.entries(item).filter(([key]) => key !== "registry")
|
|
502
|
+
) : item;
|
|
503
|
+
const { cleanupDelayMs, lifecycle, registerOptions, scope, source } = normalizeRegistryMetadata(metadata, {
|
|
504
|
+
defaultCleanupDelayMs: definition.cleanupDelayMs ?? null,
|
|
505
|
+
defaultLifecycle: definition.lifecycle,
|
|
506
|
+
defaultSource: DEFAULT_SOURCE
|
|
507
|
+
});
|
|
508
|
+
for (const { key, value } of toEntries(payload, context) ?? []) {
|
|
509
|
+
const validation = definition.validate?.(value);
|
|
510
|
+
if (validation && !validation.valid) {
|
|
511
|
+
report(`Registry ${type} config is invalid`, validation.issues, "warn");
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
registrations.push({
|
|
515
|
+
cleanupDelayMs,
|
|
516
|
+
cleanupKey: createEntryCleanupKey(
|
|
517
|
+
type,
|
|
518
|
+
key,
|
|
519
|
+
source,
|
|
520
|
+
context.instanceId,
|
|
521
|
+
scope
|
|
522
|
+
),
|
|
523
|
+
key,
|
|
524
|
+
lifecycle,
|
|
525
|
+
registerOptions,
|
|
526
|
+
scope,
|
|
527
|
+
source,
|
|
528
|
+
type,
|
|
529
|
+
value
|
|
656
530
|
});
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
setVideoPlaying(false);
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
|
|
663
|
-
if (!videoElement) return;
|
|
664
|
-
if (nextPlaying) {
|
|
665
|
-
videoElement.muted = configuredMuted;
|
|
666
|
-
if (!configuredMuted && videoElement.volume === 0) {
|
|
667
|
-
videoElement.volume = 0.8;
|
|
668
531
|
}
|
|
669
|
-
videoElement.play().catch((err) => {
|
|
670
|
-
if (err?.name === "NotAllowedError") {
|
|
671
|
-
videoElement.muted = true;
|
|
672
|
-
videoElement.play().catch(() => {
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
});
|
|
676
|
-
} else {
|
|
677
|
-
videoElement.pause();
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
function syncVideoMutedDirect(videoElement, nextMuted) {
|
|
681
|
-
if (!videoElement) return;
|
|
682
|
-
videoElement.muted = nextMuted;
|
|
683
|
-
if (!nextMuted && videoElement.volume === 0) {
|
|
684
|
-
videoElement.volume = 0.8;
|
|
685
532
|
}
|
|
533
|
+
return registrations;
|
|
686
534
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
535
|
+
var NO_CLEANUP = () => {
|
|
536
|
+
};
|
|
537
|
+
function applyRegistryConfig(config, context) {
|
|
538
|
+
const modules = context.modules ?? [];
|
|
539
|
+
if (!config || modules.length === 0) return NO_CLEANUP;
|
|
540
|
+
const pageMetadata = isObject(config.registry) ? config.registry : {};
|
|
541
|
+
const slices = config;
|
|
542
|
+
const registrations = modules.flatMap((coreModule) => {
|
|
543
|
+
try {
|
|
544
|
+
return collectModuleRegistrations(
|
|
545
|
+
coreModule,
|
|
546
|
+
slices[coreModule.id],
|
|
547
|
+
pageMetadata,
|
|
548
|
+
context
|
|
549
|
+
);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
report(`Registry apply (${coreModule.id})`, error);
|
|
552
|
+
return [];
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
if (registrations.length === 0) return NO_CLEANUP;
|
|
556
|
+
const cleanupScope = getCleanupScope(context);
|
|
557
|
+
const owner = (registration) => ({
|
|
558
|
+
instanceId: context.instanceId,
|
|
559
|
+
scope: registration.scope,
|
|
560
|
+
source: registration.source
|
|
561
|
+
});
|
|
562
|
+
runRegistrationBatch(context, (queue) => {
|
|
563
|
+
registrations.forEach(
|
|
564
|
+
({ cleanupKey, key, registerOptions, source, type, value }) => {
|
|
565
|
+
clearCleanupTimer(cleanupScope, cleanupKey);
|
|
566
|
+
queue.register(type, key, value, source, registerOptions);
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
});
|
|
570
|
+
return () => {
|
|
571
|
+
const immediate = [];
|
|
572
|
+
registrations.forEach((registration) => {
|
|
573
|
+
if (isPersistentLifecycle(registration.lifecycle)) return;
|
|
574
|
+
const { cleanupDelayMs, cleanupKey, key, type } = registration;
|
|
575
|
+
if (typeof cleanupDelayMs === "number" && cleanupDelayMs > 0) {
|
|
576
|
+
scheduleCleanup(
|
|
577
|
+
cleanupScope,
|
|
578
|
+
cleanupKey,
|
|
579
|
+
() => context.unregister(type, key, owner(registration)),
|
|
580
|
+
cleanupDelayMs
|
|
581
|
+
);
|
|
582
|
+
} else {
|
|
583
|
+
immediate.push(registration);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
if (immediate.length === 0) return;
|
|
587
|
+
runRegistrationBatch(context, (queue) => {
|
|
588
|
+
immediate.forEach(
|
|
589
|
+
(registration) => queue.unregister(
|
|
590
|
+
registration.type,
|
|
591
|
+
registration.key,
|
|
592
|
+
owner(registration)
|
|
593
|
+
)
|
|
594
|
+
);
|
|
595
|
+
});
|
|
596
|
+
};
|
|
690
597
|
}
|
|
691
598
|
|
|
692
|
-
// src/
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}),
|
|
707
|
-
transition: Object.freeze({
|
|
708
|
-
delay: 0,
|
|
709
|
-
duration: DURATION_TOKENS.SLOW,
|
|
710
|
-
ease: EASING_CURVES.OUT_QUART
|
|
711
|
-
})
|
|
712
|
-
});
|
|
713
|
-
function getBackgroundMotionConfig(animation) {
|
|
599
|
+
// src/kernel/hooks.ts
|
|
600
|
+
function withInstanceId(instanceId, sourceOrOptions, optionsArg) {
|
|
601
|
+
if (typeof sourceOrOptions === "string") {
|
|
602
|
+
return {
|
|
603
|
+
optionsArg: { ...isObject(optionsArg) ? optionsArg : {}, instanceId },
|
|
604
|
+
sourceOrOptions
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
if (isObject(sourceOrOptions)) {
|
|
608
|
+
return {
|
|
609
|
+
optionsArg,
|
|
610
|
+
sourceOrOptions: { ...sourceOrOptions, instanceId }
|
|
611
|
+
};
|
|
612
|
+
}
|
|
714
613
|
return {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
614
|
+
optionsArg: void 0,
|
|
615
|
+
sourceOrOptions: {
|
|
616
|
+
...isObject(optionsArg) ? optionsArg : {},
|
|
617
|
+
instanceId
|
|
618
|
+
}
|
|
720
619
|
};
|
|
721
620
|
}
|
|
722
|
-
function
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
}
|
|
726
|
-
function toCssDelay(seconds) {
|
|
727
|
-
const value = Number(seconds);
|
|
728
|
-
return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
|
|
729
|
-
}
|
|
730
|
-
function toCssEasing(easing) {
|
|
731
|
-
if (Array.isArray(easing)) {
|
|
732
|
-
return `cubic-bezier(${easing.join(", ")})`;
|
|
621
|
+
function withInstanceIdForUnregister(instanceId, sourceOrOptions) {
|
|
622
|
+
if (typeof sourceOrOptions === "string") {
|
|
623
|
+
return { instanceId, source: sourceOrOptions };
|
|
733
624
|
}
|
|
734
|
-
if (
|
|
735
|
-
return
|
|
625
|
+
if (isObject(sourceOrOptions)) {
|
|
626
|
+
return { ...sourceOrOptions, instanceId };
|
|
736
627
|
}
|
|
737
|
-
return
|
|
628
|
+
return { instanceId };
|
|
738
629
|
}
|
|
739
|
-
function
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
throw new Error(`${hookName} must be used within ${providerName}`);
|
|
743
|
-
}
|
|
744
|
-
return value;
|
|
630
|
+
function resolveRegisterArgsWithInstance(instanceId, sourceOrOptions, optionsArg) {
|
|
631
|
+
const input = withInstanceId(instanceId, sourceOrOptions, optionsArg);
|
|
632
|
+
return [input.sourceOrOptions, input.optionsArg];
|
|
745
633
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
});
|
|
753
|
-
const getSelectedSnapshot = useCallback(() => {
|
|
754
|
-
const snapshot = store.getSnapshot();
|
|
755
|
-
const cache = cacheRef.current;
|
|
756
|
-
if (cache.snapshot === snapshot && cache.selector === selector && cache.isEqual === isEqual) {
|
|
757
|
-
return cache.selected;
|
|
758
|
-
}
|
|
759
|
-
const selected = selector(snapshot);
|
|
760
|
-
if (cache.snapshot !== null && cache.isEqual === isEqual && isEqual(cache.selected, selected)) {
|
|
761
|
-
cache.snapshot = snapshot;
|
|
762
|
-
cache.selector = selector;
|
|
763
|
-
return cache.selected;
|
|
634
|
+
var MAX_STABILIZATION_DEPTH = 64;
|
|
635
|
+
function createStableFunctionEntry(fn) {
|
|
636
|
+
const entry = {
|
|
637
|
+
current: fn,
|
|
638
|
+
stable(...args) {
|
|
639
|
+
return entry.current?.apply(this, args);
|
|
764
640
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
selected,
|
|
768
|
-
selector,
|
|
769
|
-
snapshot
|
|
770
|
-
};
|
|
771
|
-
return selected;
|
|
772
|
-
}, [isEqual, selector, store]);
|
|
773
|
-
return useSyncExternalStore(
|
|
774
|
-
store.subscribe,
|
|
775
|
-
getSelectedSnapshot,
|
|
776
|
-
getSelectedSnapshot
|
|
777
|
-
);
|
|
641
|
+
};
|
|
642
|
+
return entry;
|
|
778
643
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
return
|
|
792
|
-
listeners.delete(callback);
|
|
793
|
-
if (listeners.size === 0) this.events.delete(event);
|
|
794
|
-
};
|
|
644
|
+
function isDirectRegistryComponentPath(path, componentSlices) {
|
|
645
|
+
const match = /^config\.([^.[]+)\.[^.[]+$/.exec(path);
|
|
646
|
+
return Boolean(match && componentSlices.has(match[1]));
|
|
647
|
+
}
|
|
648
|
+
function isReactNodeLike(value) {
|
|
649
|
+
return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" || isValidElement(value);
|
|
650
|
+
}
|
|
651
|
+
function isStabilizableObject(value) {
|
|
652
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !isValidElement(value);
|
|
653
|
+
}
|
|
654
|
+
function hasSameObjectKeys(previousValue, nextValue) {
|
|
655
|
+
if (!isStabilizableObject(previousValue) || !isStabilizableObject(nextValue)) {
|
|
656
|
+
return false;
|
|
795
657
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
658
|
+
const previousKeys = Object.keys(previousValue);
|
|
659
|
+
const nextKeys = Object.keys(nextValue);
|
|
660
|
+
if (previousKeys.length !== nextKeys.length) return false;
|
|
661
|
+
return nextKeys.every(
|
|
662
|
+
(key) => Object.prototype.hasOwnProperty.call(previousValue, key)
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
function stabilizeRegistryValue(value, path, scope, previousValue, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
|
|
666
|
+
if (depth > MAX_STABILIZATION_DEPTH) return value;
|
|
667
|
+
if (typeof value === "function") {
|
|
668
|
+
const isComponent = value.name && /^[A-Z]/.test(value.name);
|
|
669
|
+
if (isComponent || isDirectRegistryComponentPath(path, scope.componentSlices)) {
|
|
670
|
+
return value;
|
|
806
671
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
this.debounceTimers.delete(event);
|
|
813
|
-
this.emit(event, payload);
|
|
814
|
-
}, waitMs);
|
|
815
|
-
this.debounceTimers.set(event, timer);
|
|
816
|
-
}
|
|
817
|
-
cancelDebounced(event) {
|
|
818
|
-
if (event) {
|
|
819
|
-
const timer = this.debounceTimers.get(event);
|
|
820
|
-
if (timer) {
|
|
821
|
-
clearTimeout(timer);
|
|
822
|
-
this.debounceTimers.delete(event);
|
|
823
|
-
}
|
|
672
|
+
scope.usedPaths.add(path);
|
|
673
|
+
let entry = scope.functionEntries.get(path);
|
|
674
|
+
if (!entry) {
|
|
675
|
+
entry = createStableFunctionEntry(value);
|
|
676
|
+
scope.functionEntries.set(path, entry);
|
|
824
677
|
} else {
|
|
825
|
-
|
|
826
|
-
clearTimeout(timer);
|
|
827
|
-
}
|
|
828
|
-
this.debounceTimers.clear();
|
|
678
|
+
entry.current = value;
|
|
829
679
|
}
|
|
680
|
+
return entry.stable;
|
|
830
681
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
else this.events.clear();
|
|
835
|
-
}
|
|
836
|
-
hasListeners(event) {
|
|
837
|
-
return Boolean(this.events.get(event)?.size);
|
|
838
|
-
}
|
|
839
|
-
getListenerCount(event) {
|
|
840
|
-
return this.events.get(event)?.size || 0;
|
|
682
|
+
if (value && typeof value === "object") {
|
|
683
|
+
if (seen.has(value)) return value;
|
|
684
|
+
seen.add(value);
|
|
841
685
|
}
|
|
842
|
-
|
|
843
|
-
|
|
686
|
+
if (isValidElement(value)) {
|
|
687
|
+
const nextProps = stabilizeRegistryValue(
|
|
688
|
+
value.props,
|
|
689
|
+
`${path}.props`,
|
|
690
|
+
scope,
|
|
691
|
+
isValidElement(previousValue) ? previousValue.props : void 0,
|
|
692
|
+
seen,
|
|
693
|
+
depth + 1
|
|
694
|
+
);
|
|
695
|
+
if (isValidElement(previousValue) && previousValue.type === value.type && previousValue.key === value.key && previousValue.props === nextProps) {
|
|
696
|
+
return previousValue;
|
|
697
|
+
}
|
|
698
|
+
return cloneElement(value, nextProps);
|
|
844
699
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
WARN: "warn",
|
|
865
|
-
STRICT: "strict"
|
|
866
|
-
});
|
|
867
|
-
var REGISTRY_METADATA_KEYS = Object.freeze([
|
|
868
|
-
"cleanup",
|
|
869
|
-
"cleanupDelayMs",
|
|
870
|
-
"instanceId",
|
|
871
|
-
"lifecycle",
|
|
872
|
-
"priority",
|
|
873
|
-
"source",
|
|
874
|
-
"scope",
|
|
875
|
-
"validation"
|
|
876
|
-
]);
|
|
877
|
-
Object.freeze({
|
|
878
|
-
[REGISTRY_SOURCES.STATIC]: 100,
|
|
879
|
-
[REGISTRY_SOURCES.DYNAMIC]: 200,
|
|
880
|
-
[REGISTRY_SOURCES.USER]: 300
|
|
881
|
-
});
|
|
882
|
-
Object.freeze({
|
|
883
|
-
[REGISTRY_SOURCES.STATIC]: 10,
|
|
884
|
-
[REGISTRY_SOURCES.DYNAMIC]: 20,
|
|
885
|
-
[REGISTRY_SOURCES.USER]: 30
|
|
886
|
-
});
|
|
887
|
-
var REGISTRY_LIFECYCLE_VALUES = new Set(
|
|
888
|
-
Object.values(REGISTRY_LIFECYCLES)
|
|
889
|
-
);
|
|
890
|
-
var REGISTRY_METADATA_KEY_SET = new Set(
|
|
891
|
-
REGISTRY_METADATA_KEYS
|
|
892
|
-
);
|
|
893
|
-
var REGISTRY_SCOPE_KINDS = Object.freeze({
|
|
894
|
-
APP: "app",
|
|
895
|
-
SESSION: "session",
|
|
896
|
-
ROUTE: "route",
|
|
897
|
-
INSTANCE: "instance",
|
|
898
|
-
WORKSPACE: "workspace"
|
|
899
|
-
});
|
|
900
|
-
REGISTRY_SCOPE_KINDS.APP;
|
|
901
|
-
|
|
902
|
-
// src/kernel/utils.ts
|
|
903
|
-
function parseFiniteNumber(value) {
|
|
904
|
-
const parsed = Number(value);
|
|
905
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
906
|
-
}
|
|
907
|
-
function getValidString(value, fallback = null) {
|
|
908
|
-
return trimToNull(value) ?? fallback;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
// src/kernel/schema.ts
|
|
912
|
-
function resolveLifecycle(metadata, fallback) {
|
|
913
|
-
const lifecycle = metadata?.lifecycle ?? metadata?.cleanup;
|
|
914
|
-
return lifecycle && REGISTRY_LIFECYCLE_VALUES.has(lifecycle) ? lifecycle : fallback;
|
|
915
|
-
}
|
|
916
|
-
function validateRegistryMetadata(metadata) {
|
|
917
|
-
if (metadata === void 0 || metadata === null)
|
|
918
|
-
return { issues: [], valid: true };
|
|
919
|
-
if (!isObject(metadata))
|
|
920
|
-
return { issues: ["registry metadata must be an object"], valid: false };
|
|
921
|
-
const issues = [];
|
|
922
|
-
Object.keys(metadata).forEach((key) => {
|
|
923
|
-
if (!REGISTRY_METADATA_KEY_SET.has(key))
|
|
924
|
-
issues.push(`unknown registry metadata field: ${key}`);
|
|
925
|
-
});
|
|
926
|
-
if (metadata.source !== void 0 && !getValidString(metadata.source))
|
|
927
|
-
issues.push("source must be a non-empty string");
|
|
928
|
-
if (metadata.instanceId !== void 0 && !getValidString(metadata.instanceId))
|
|
929
|
-
issues.push("instanceId must be a non-empty string");
|
|
930
|
-
if (metadata.scope !== void 0 && !getValidString(metadata.scope))
|
|
931
|
-
issues.push("scope must be a non-empty string");
|
|
932
|
-
if (metadata.priority !== void 0 && parseFiniteNumber(metadata.priority) === null)
|
|
933
|
-
issues.push("priority must be a finite number");
|
|
934
|
-
if (metadata.cleanupDelayMs !== void 0) {
|
|
935
|
-
const delay = parseFiniteNumber(metadata.cleanupDelayMs);
|
|
936
|
-
if (delay === null || delay < 0)
|
|
937
|
-
issues.push("cleanupDelayMs must be a non-negative finite number");
|
|
700
|
+
if (Array.isArray(value)) {
|
|
701
|
+
const nextValue = value.every(isReactNodeLike) ? Children.toArray(value) : value;
|
|
702
|
+
const previousArray = Array.isArray(previousValue) ? previousValue : null;
|
|
703
|
+
let hasChanged2 = !previousArray || previousArray.length !== nextValue.length;
|
|
704
|
+
const stabilizedValue2 = nextValue.map((item, index) => {
|
|
705
|
+
const nextItem = stabilizeRegistryValue(
|
|
706
|
+
item,
|
|
707
|
+
`${path}[${index}]`,
|
|
708
|
+
scope,
|
|
709
|
+
previousArray?.[index],
|
|
710
|
+
seen,
|
|
711
|
+
depth + 1
|
|
712
|
+
);
|
|
713
|
+
if (!previousArray || nextItem !== previousArray[index]) {
|
|
714
|
+
hasChanged2 = true;
|
|
715
|
+
}
|
|
716
|
+
return nextItem;
|
|
717
|
+
});
|
|
718
|
+
return !hasChanged2 ? previousArray : stabilizedValue2;
|
|
938
719
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
issues.push(
|
|
942
|
-
`lifecycle must be one of: ${[...REGISTRY_LIFECYCLE_VALUES].join(", ")}`
|
|
943
|
-
);
|
|
720
|
+
if (typeof value !== "object" || value === null) {
|
|
721
|
+
return value;
|
|
944
722
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
723
|
+
const source = value;
|
|
724
|
+
const previousRecord = previousValue;
|
|
725
|
+
const stabilizedValue = {};
|
|
726
|
+
const canReusePrevious = hasSameObjectKeys(previousValue, value);
|
|
727
|
+
let hasChanged = !canReusePrevious;
|
|
728
|
+
Object.keys(source).forEach((key) => {
|
|
729
|
+
const nextValue = stabilizeRegistryValue(
|
|
730
|
+
source[key],
|
|
731
|
+
`${path}.${key}`,
|
|
732
|
+
scope,
|
|
733
|
+
previousRecord?.[key],
|
|
734
|
+
seen,
|
|
735
|
+
depth + 1
|
|
950
736
|
);
|
|
951
|
-
|
|
952
|
-
|
|
737
|
+
stabilizedValue[key] = nextValue;
|
|
738
|
+
if (!canReusePrevious || nextValue !== previousRecord?.[key]) {
|
|
739
|
+
hasChanged = true;
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
return !hasChanged ? previousValue : stabilizedValue;
|
|
953
743
|
}
|
|
954
|
-
function
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
744
|
+
function useAppliedRegistryConfig(payload, context, componentSlices) {
|
|
745
|
+
const functionEntriesRef = useRef(/* @__PURE__ */ new Map());
|
|
746
|
+
const appliedRef = useRef(null);
|
|
747
|
+
useIsomorphicLayoutEffect(() => {
|
|
748
|
+
const previous = appliedRef.current;
|
|
749
|
+
if (previous && previous.payload === payload && previous.context === context) {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
const functionEntries = functionEntriesRef.current;
|
|
753
|
+
const usedPaths = /* @__PURE__ */ new Set();
|
|
754
|
+
const config = stabilizeRegistryValue(
|
|
755
|
+
payload,
|
|
756
|
+
"config",
|
|
757
|
+
{ componentSlices, functionEntries, usedPaths },
|
|
758
|
+
previous?.config
|
|
759
|
+
);
|
|
760
|
+
functionEntries.forEach((_entry, path) => {
|
|
761
|
+
if (!usedPaths.has(path)) functionEntries.delete(path);
|
|
762
|
+
});
|
|
763
|
+
if (previous && previous.config === config && previous.context === context) {
|
|
764
|
+
previous.payload = payload;
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
previous?.cleanup();
|
|
768
|
+
appliedRef.current = {
|
|
769
|
+
cleanup: applyRegistryConfig(config, context),
|
|
770
|
+
config,
|
|
771
|
+
context,
|
|
772
|
+
payload
|
|
773
|
+
};
|
|
774
|
+
});
|
|
775
|
+
useIsomorphicLayoutEffect(
|
|
776
|
+
() => () => {
|
|
777
|
+
appliedRef.current?.cleanup();
|
|
778
|
+
appliedRef.current = null;
|
|
983
779
|
},
|
|
984
|
-
|
|
985
|
-
...scope && { scope },
|
|
986
|
-
...validation && { validation }
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
function isValidationMode(value) {
|
|
990
|
-
return Object.values(REGISTRY_VALIDATION_MODES).includes(value);
|
|
991
|
-
}
|
|
992
|
-
function pickRegistryMetadata(options) {
|
|
993
|
-
if (!isObject(options)) return {};
|
|
994
|
-
return Object.fromEntries(
|
|
995
|
-
REGISTRY_METADATA_KEYS.filter((key) => options[key] !== void 0).map(
|
|
996
|
-
(key) => [key, options[key]]
|
|
997
|
-
)
|
|
780
|
+
[]
|
|
998
781
|
);
|
|
999
782
|
}
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
783
|
+
function createRegistryApplyContext(actions, {
|
|
784
|
+
cleanupScope = /* @__PURE__ */ new Map(),
|
|
785
|
+
instanceId,
|
|
786
|
+
modules = [],
|
|
787
|
+
pathname
|
|
788
|
+
}) {
|
|
789
|
+
const stamp = (queue) => ({
|
|
790
|
+
register: (type, key, item, sourceOrOptions, optionsArg) => queue.register(
|
|
791
|
+
type,
|
|
792
|
+
key,
|
|
793
|
+
item,
|
|
794
|
+
...resolveRegisterArgsWithInstance(
|
|
795
|
+
instanceId,
|
|
796
|
+
sourceOrOptions,
|
|
797
|
+
optionsArg
|
|
798
|
+
)
|
|
799
|
+
),
|
|
800
|
+
unregister: (type, key, sourceOrOptions) => queue.unregister(
|
|
801
|
+
type,
|
|
802
|
+
key,
|
|
803
|
+
withInstanceIdForUnregister(instanceId, sourceOrOptions)
|
|
804
|
+
)
|
|
1014
805
|
});
|
|
1015
|
-
return
|
|
806
|
+
return {
|
|
807
|
+
...stamp(actions),
|
|
808
|
+
batch: (executor) => typeof executor === "function" ? actions.batch((queue) => executor(stamp(queue))) : 0,
|
|
809
|
+
cleanupScope,
|
|
810
|
+
instanceId,
|
|
811
|
+
modules,
|
|
812
|
+
pathname
|
|
813
|
+
};
|
|
1016
814
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
)
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
815
|
+
function useRegistry(config, metadata) {
|
|
816
|
+
const { batch, register, unregister } = useRegistryActions();
|
|
817
|
+
const pathname = usePathname();
|
|
818
|
+
const modules = useInstalledModules();
|
|
819
|
+
const instanceId = `registry-instance-${useId()}`;
|
|
820
|
+
const [cleanupScope] = useState(
|
|
821
|
+
() => /* @__PURE__ */ new Map()
|
|
822
|
+
);
|
|
823
|
+
const context = useMemo(
|
|
824
|
+
() => createRegistryApplyContext(
|
|
825
|
+
{ batch, register, unregister },
|
|
826
|
+
{
|
|
827
|
+
cleanupScope,
|
|
828
|
+
instanceId,
|
|
829
|
+
modules,
|
|
830
|
+
pathname
|
|
831
|
+
}
|
|
832
|
+
),
|
|
833
|
+
[batch, cleanupScope, instanceId, modules, pathname, register, unregister]
|
|
834
|
+
);
|
|
835
|
+
const payload = useMemo(
|
|
836
|
+
() => config ? createModulePayload(modules, config, metadata) : null,
|
|
837
|
+
[config, metadata, modules]
|
|
838
|
+
);
|
|
839
|
+
const componentSlices = useMemo(
|
|
840
|
+
() => new Set(
|
|
841
|
+
modules.filter(
|
|
842
|
+
(coreModule) => coreModule.registry?.valueKind === "component"
|
|
843
|
+
).map((coreModule) => coreModule.id)
|
|
844
|
+
),
|
|
845
|
+
[modules]
|
|
846
|
+
);
|
|
847
|
+
useAppliedRegistryConfig(payload, context, componentSlices);
|
|
1028
848
|
}
|
|
1029
|
-
function
|
|
1030
|
-
return
|
|
1031
|
-
RegistryContext,
|
|
1032
|
-
"useRegistrySubscription",
|
|
1033
|
-
"RegistryProvider"
|
|
1034
|
-
).subscription;
|
|
849
|
+
function defineModule(coreModule) {
|
|
850
|
+
return Object.freeze({ ...coreModule });
|
|
1035
851
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
const getValue = useCallback(
|
|
1043
|
-
() => getSnapshot(type, key),
|
|
1044
|
-
[getSnapshot, key, type]
|
|
852
|
+
createStore(void 0);
|
|
853
|
+
|
|
854
|
+
// src/kernel/adapters.ts
|
|
855
|
+
function useModuleRegistration(id, value, options) {
|
|
856
|
+
const coreModule = useInstalledModules().find(
|
|
857
|
+
(candidate) => candidate.id === id
|
|
1045
858
|
);
|
|
1046
|
-
|
|
859
|
+
const config = coreModule && options?.enabled !== false && value != null ? { [id]: value } : null;
|
|
860
|
+
useRegistry(config, pickRegistryMetadata(options));
|
|
1047
861
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
function
|
|
1051
|
-
|
|
1052
|
-
return slice ?? null;
|
|
862
|
+
|
|
863
|
+
// src/theme.tsx
|
|
864
|
+
function defineThemeSpec(id) {
|
|
865
|
+
return Object.freeze({ id });
|
|
1053
866
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
hasSlices = true;
|
|
867
|
+
var EMPTY = /* @__PURE__ */ new Map();
|
|
868
|
+
var ThemeContext = getOrCreateGlobalContext("ThemeContext", EMPTY);
|
|
869
|
+
function useTheme(spec) {
|
|
870
|
+
const config = useContext(ThemeContext).get(spec.id);
|
|
871
|
+
if (!config) {
|
|
872
|
+
throw new Error(
|
|
873
|
+
`Theme "${spec.id}" is missing. Ensure its theme configuration is provided to <ThemeProvider themes={[...]}> (e.g. in src/config/ or your theme setup).`
|
|
874
|
+
);
|
|
1063
875
|
}
|
|
1064
|
-
if (!hasSlices) return null;
|
|
1065
876
|
return {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
...metadata,
|
|
1069
|
-
...isObject(config.registry) ? config.registry : {}
|
|
1070
|
-
}
|
|
877
|
+
slots: config.slots,
|
|
878
|
+
styles: config.styles ?? {}
|
|
1071
879
|
};
|
|
1072
880
|
}
|
|
1073
|
-
function useInstalledModules() {
|
|
1074
|
-
return use(ModuleHostContext)?.modules ?? EMPTY_MODULES;
|
|
1075
|
-
}
|
|
1076
881
|
|
|
1077
|
-
// src/
|
|
1078
|
-
|
|
1079
|
-
|
|
882
|
+
// src/modules/background/constants.ts
|
|
883
|
+
var DEFAULT_BACKGROUND = Object.freeze({
|
|
884
|
+
animation: null,
|
|
885
|
+
className: "",
|
|
886
|
+
fadeEdges: null,
|
|
887
|
+
fit: null,
|
|
888
|
+
image: null,
|
|
889
|
+
imageStyle: {},
|
|
890
|
+
isPlaying: false,
|
|
891
|
+
noiseStyle: {},
|
|
892
|
+
overlay: false,
|
|
893
|
+
overlayColor: "var(--black)",
|
|
894
|
+
overlayOpacity: 0,
|
|
895
|
+
position: "center",
|
|
896
|
+
video: null,
|
|
897
|
+
videoClassName: "",
|
|
898
|
+
videoElement: null,
|
|
899
|
+
videoOptions: {
|
|
900
|
+
autoplay: true,
|
|
901
|
+
className: "",
|
|
902
|
+
corp: 0,
|
|
903
|
+
loop: false,
|
|
904
|
+
muted: true,
|
|
905
|
+
playbackRate: 1,
|
|
906
|
+
width: null
|
|
907
|
+
},
|
|
908
|
+
videoStyle: {},
|
|
909
|
+
width: null
|
|
910
|
+
});
|
|
911
|
+
var DEFAULT_BACKGROUND_COMPUTED = Object.freeze({
|
|
912
|
+
...DEFAULT_BACKGROUND,
|
|
913
|
+
hasBackground: false,
|
|
914
|
+
isVideo: false,
|
|
915
|
+
isYouTube: false,
|
|
916
|
+
posterUrl: null,
|
|
917
|
+
youtubeVideoId: null
|
|
918
|
+
});
|
|
919
|
+
var INERT_BACKGROUND_ACTIONS = Object.freeze({
|
|
920
|
+
resetBackground: () => {
|
|
921
|
+
},
|
|
922
|
+
setBackground: () => {
|
|
923
|
+
},
|
|
924
|
+
setVideoElement: () => {
|
|
925
|
+
},
|
|
926
|
+
setVideoMuted: () => {
|
|
927
|
+
},
|
|
928
|
+
setVideoPlaying: () => {
|
|
929
|
+
},
|
|
930
|
+
toggleLoop: () => {
|
|
931
|
+
},
|
|
932
|
+
toggleMute: () => {
|
|
933
|
+
},
|
|
934
|
+
toggleVideo: () => {
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
var objectFit = (value) => ({
|
|
938
|
+
objectFit: value
|
|
939
|
+
});
|
|
940
|
+
var objectPosition = (value) => ({
|
|
941
|
+
objectPosition: value
|
|
942
|
+
});
|
|
943
|
+
var BG_TOKEN_TO_OBJECT_STYLE = Object.freeze({
|
|
944
|
+
"bg-bottom": objectPosition("bottom"),
|
|
945
|
+
"bg-center": objectPosition("center"),
|
|
946
|
+
"bg-contain": objectFit("contain"),
|
|
947
|
+
"bg-cover": objectFit("cover"),
|
|
948
|
+
"bg-fill": objectFit("fill"),
|
|
949
|
+
"bg-left": objectPosition("left"),
|
|
950
|
+
"bg-left-bottom": objectPosition("left bottom"),
|
|
951
|
+
"bg-left-top": objectPosition("left top"),
|
|
952
|
+
"bg-none": objectFit("none"),
|
|
953
|
+
"bg-right": objectPosition("right"),
|
|
954
|
+
"bg-right-bottom": objectPosition("right bottom"),
|
|
955
|
+
"bg-right-top": objectPosition("right top"),
|
|
956
|
+
"bg-scale-down": objectFit("scale-down"),
|
|
957
|
+
"bg-top": objectPosition("top")
|
|
958
|
+
});
|
|
959
|
+
var OBJECT_FITS = Object.freeze([
|
|
960
|
+
"contain",
|
|
961
|
+
"cover",
|
|
962
|
+
"fill",
|
|
963
|
+
"none",
|
|
964
|
+
"scale-down"
|
|
965
|
+
]);
|
|
966
|
+
var DEFAULT_COLOR = "var(--black, #000)";
|
|
967
|
+
var backgroundTheme = defineThemeSpec("background");
|
|
968
|
+
var BACKGROUND_REGISTRY_KEY = "page-background";
|
|
969
|
+
var BACKGROUND_MEDIA_ID = "background";
|
|
970
|
+
|
|
971
|
+
// src/modules/background/youtube/parse.ts
|
|
972
|
+
var YOUTUBE_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/;
|
|
973
|
+
function parseYouTubeTimeParam(value) {
|
|
974
|
+
if (value === void 0 || value === null || value === "") return 0;
|
|
975
|
+
if (typeof value === "number") {
|
|
976
|
+
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
977
|
+
}
|
|
978
|
+
const trimmed = String(value).trim().toLowerCase();
|
|
979
|
+
if (!trimmed) return 0;
|
|
980
|
+
if (/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
981
|
+
return Math.max(0, parseFloat(trimmed));
|
|
982
|
+
}
|
|
983
|
+
const hmsMatch = trimmed.match(
|
|
984
|
+
/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s?)?$/
|
|
985
|
+
);
|
|
986
|
+
if (hmsMatch && (hmsMatch[1] || hmsMatch[2] || hmsMatch[3])) {
|
|
987
|
+
const hours = parseInt(hmsMatch[1] || "0", 10);
|
|
988
|
+
const minutes = parseInt(hmsMatch[2] || "0", 10);
|
|
989
|
+
const seconds = parseFloat(hmsMatch[3] || "0");
|
|
990
|
+
return Math.max(0, hours * 3600 + minutes * 60 + seconds);
|
|
991
|
+
}
|
|
992
|
+
return 0;
|
|
1080
993
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
994
|
+
var YOUTUBE_HOST_PATH = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)\//i;
|
|
995
|
+
function toUrl(input, { youtubeOnly = false } = {}) {
|
|
996
|
+
let candidate = null;
|
|
997
|
+
if (/^https?:\/\//.test(input)) candidate = input;
|
|
998
|
+
else if (input.startsWith("//")) candidate = `https:${input}`;
|
|
999
|
+
else if (!youtubeOnly || YOUTUBE_HOST_PATH.test(input)) {
|
|
1000
|
+
candidate = `https://${input}`;
|
|
1001
|
+
}
|
|
1002
|
+
try {
|
|
1003
|
+
return candidate ? new URL(candidate) : null;
|
|
1004
|
+
} catch {
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1083
1007
|
}
|
|
1084
|
-
function
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1008
|
+
function getIdFromUrl(url) {
|
|
1009
|
+
const host = url.hostname.replace(/^(www\.|m\.|music\.)/i, "").toLowerCase();
|
|
1010
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
1011
|
+
if (host === "youtu.be") {
|
|
1012
|
+
return YOUTUBE_ID_PATTERN.test(segments[0] ?? "") ? segments[0] : null;
|
|
1013
|
+
}
|
|
1014
|
+
if (host !== "youtube.com" && host !== "youtube-nocookie.com" && !host.endsWith(".youtube.com")) {
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
1017
|
+
const fromQuery = url.searchParams.get("v") || url.searchParams.get("vi");
|
|
1018
|
+
if (fromQuery && YOUTUBE_ID_PATTERN.test(fromQuery)) return fromQuery;
|
|
1019
|
+
const isVideoPath = segments.length >= 2 && ["embed", "shorts", "live", "v", "e", "watch"].includes(
|
|
1020
|
+
segments[0].toLowerCase()
|
|
1021
|
+
);
|
|
1022
|
+
return isVideoPath && YOUTUBE_ID_PATTERN.test(segments[1]) ? segments[1] : null;
|
|
1023
|
+
}
|
|
1024
|
+
function extractYouTubeVideoId(input, options = {}) {
|
|
1025
|
+
const trimmed = typeof input === "string" ? input.trim() : "";
|
|
1026
|
+
if (!trimmed) return null;
|
|
1027
|
+
if (options.allowBareId && YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
|
|
1028
|
+
const prefixed = trimmed.match(/^(?:youtube|yt):([a-zA-Z0-9_-]{11})$/i);
|
|
1029
|
+
if (prefixed) return prefixed[1];
|
|
1030
|
+
const url = toUrl(trimmed, { youtubeOnly: true });
|
|
1031
|
+
return url ? getIdFromUrl(url) : null;
|
|
1093
1032
|
}
|
|
1094
|
-
function
|
|
1095
|
-
return
|
|
1033
|
+
function isYouTubeUrl(input) {
|
|
1034
|
+
return Boolean(extractYouTubeVideoId(input));
|
|
1096
1035
|
}
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
if (
|
|
1102
|
-
|
|
1036
|
+
function isDirectVideoUrl(input) {
|
|
1037
|
+
if (!input || typeof input !== "string") return false;
|
|
1038
|
+
const trimmed = input.trim();
|
|
1039
|
+
if (!trimmed) return false;
|
|
1040
|
+
if (isYouTubeUrl(trimmed)) return true;
|
|
1041
|
+
if (trimmed.startsWith("/api/background/youtube") || trimmed.startsWith("blob:")) {
|
|
1042
|
+
return true;
|
|
1043
|
+
}
|
|
1044
|
+
const cleanPath = trimmed.split("?")[0].split("#")[0].toLowerCase();
|
|
1045
|
+
return /\.(mp4|webm|mov|m4v|ogg|ogv|m3u8)$/i.test(cleanPath);
|
|
1103
1046
|
}
|
|
1104
|
-
function
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1047
|
+
function parseYouTubeUrlConfig(input, options = {}) {
|
|
1048
|
+
const videoId = extractYouTubeVideoId(input, options);
|
|
1049
|
+
if (!videoId || !input) return null;
|
|
1050
|
+
const params = toUrl(input.trim())?.searchParams;
|
|
1051
|
+
return {
|
|
1052
|
+
endTime: parseYouTubeTimeParam(params?.get("end")),
|
|
1053
|
+
listId: params?.get("list") || null,
|
|
1054
|
+
rawUrl: input,
|
|
1055
|
+
startTime: parseYouTubeTimeParam(params?.get("t") || params?.get("start")),
|
|
1056
|
+
videoId
|
|
1109
1057
|
};
|
|
1110
|
-
lifecycle.timerId = setTimeout(() => {
|
|
1111
|
-
if (lifecycle.cancelled || scope.get(cleanupKey) !== lifecycle) return;
|
|
1112
|
-
scope.delete(cleanupKey);
|
|
1113
|
-
callback();
|
|
1114
|
-
}, delayMs);
|
|
1115
|
-
scope.set(cleanupKey, lifecycle);
|
|
1116
1058
|
}
|
|
1117
|
-
function
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
if (metadata.validation === "strict" && !validateRegistryMetadata(metadata).valid) {
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
const payload = isObject(item) ? Object.fromEntries(
|
|
1132
|
-
Object.entries(item).filter(([key]) => key !== "registry")
|
|
1133
|
-
) : item;
|
|
1134
|
-
const { cleanupDelayMs, lifecycle, registerOptions, scope, source } = normalizeRegistryMetadata(metadata, {
|
|
1135
|
-
defaultCleanupDelayMs: definition.cleanupDelayMs ?? null,
|
|
1136
|
-
defaultLifecycle: definition.lifecycle,
|
|
1137
|
-
defaultSource: DEFAULT_SOURCE
|
|
1138
|
-
});
|
|
1139
|
-
for (const { key, value } of toEntries(payload, context) ?? []) {
|
|
1140
|
-
const validation = definition.validate?.(value);
|
|
1141
|
-
if (validation && !validation.valid) {
|
|
1142
|
-
report(`Registry ${type} config is invalid`, validation.issues, "warn");
|
|
1143
|
-
continue;
|
|
1144
|
-
}
|
|
1145
|
-
registrations.push({
|
|
1146
|
-
cleanupDelayMs,
|
|
1147
|
-
cleanupKey: createEntryCleanupKey(
|
|
1148
|
-
type,
|
|
1149
|
-
key,
|
|
1150
|
-
source,
|
|
1151
|
-
context.instanceId,
|
|
1152
|
-
scope
|
|
1153
|
-
),
|
|
1154
|
-
key,
|
|
1155
|
-
lifecycle,
|
|
1156
|
-
registerOptions,
|
|
1157
|
-
scope,
|
|
1158
|
-
source,
|
|
1159
|
-
type,
|
|
1160
|
-
value
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1059
|
+
function getYouTubeStreamUrl(videoId, options = {}) {
|
|
1060
|
+
const params = new URLSearchParams();
|
|
1061
|
+
params.set("id", videoId);
|
|
1062
|
+
params.set("stream", options.stream || "video");
|
|
1063
|
+
if (options.quality) params.set("quality", options.quality);
|
|
1064
|
+
if (options.codec) params.set("codec", options.codec);
|
|
1065
|
+
return `/api/background/youtube?${params.toString()}`;
|
|
1066
|
+
}
|
|
1067
|
+
function getYouTubeThumbnailUrl(videoId, proxied = true) {
|
|
1068
|
+
if (proxied) {
|
|
1069
|
+
return `/api/background/youtube?id=${encodeURIComponent(videoId)}&stream=thumbnail`;
|
|
1163
1070
|
}
|
|
1164
|
-
return
|
|
1071
|
+
return `https://i.ytimg.com/vi/${encodeURIComponent(videoId)}/maxresdefault.jpg`;
|
|
1165
1072
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
return collectModuleRegistrations(
|
|
1176
|
-
coreModule,
|
|
1177
|
-
slices[coreModule.id],
|
|
1178
|
-
pageMetadata,
|
|
1179
|
-
context
|
|
1180
|
-
);
|
|
1181
|
-
} catch (error) {
|
|
1182
|
-
report(`Registry apply (${coreModule.id})`, error);
|
|
1183
|
-
return [];
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
if (registrations.length === 0) return NO_CLEANUP;
|
|
1187
|
-
const cleanupScope = getCleanupScope(context);
|
|
1188
|
-
const owner = (registration) => ({
|
|
1189
|
-
instanceId: context.instanceId,
|
|
1190
|
-
scope: registration.scope,
|
|
1191
|
-
source: registration.source
|
|
1192
|
-
});
|
|
1193
|
-
runRegistrationBatch(context, (queue) => {
|
|
1194
|
-
registrations.forEach(
|
|
1195
|
-
({ cleanupKey, key, registerOptions, source, type, value }) => {
|
|
1196
|
-
clearCleanupTimer(cleanupScope, cleanupKey);
|
|
1197
|
-
queue.register(type, key, value, source, registerOptions);
|
|
1073
|
+
function createYouTubeVideoElementProxy(controller) {
|
|
1074
|
+
const proxyVideo = document.createElement("video");
|
|
1075
|
+
Object.defineProperties(proxyVideo, {
|
|
1076
|
+
currentTime: {
|
|
1077
|
+
configurable: true,
|
|
1078
|
+
get: () => controller.getCurrentTime(),
|
|
1079
|
+
set: (value) => {
|
|
1080
|
+
controller.seekTo(Number(value) || 0);
|
|
1081
|
+
proxyVideo.dispatchEvent(new Event("timeupdate"));
|
|
1198
1082
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
cleanupKey,
|
|
1210
|
-
() => context.unregister(type, key, owner(registration)),
|
|
1211
|
-
cleanupDelayMs
|
|
1212
|
-
);
|
|
1213
|
-
} else {
|
|
1214
|
-
immediate.push(registration);
|
|
1083
|
+
},
|
|
1084
|
+
duration: {
|
|
1085
|
+
configurable: true,
|
|
1086
|
+
get: () => controller.getDuration()
|
|
1087
|
+
},
|
|
1088
|
+
loop: {
|
|
1089
|
+
configurable: true,
|
|
1090
|
+
get: () => controller.getLoop(),
|
|
1091
|
+
set: (value) => {
|
|
1092
|
+
controller.setLoop(Boolean(value));
|
|
1215
1093
|
}
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1094
|
+
},
|
|
1095
|
+
muted: {
|
|
1096
|
+
configurable: true,
|
|
1097
|
+
get: () => controller.getMuted(),
|
|
1098
|
+
set: (value) => {
|
|
1099
|
+
controller.setMuted(Boolean(value));
|
|
1100
|
+
proxyVideo.dispatchEvent(new Event("volumechange"));
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
pause: {
|
|
1104
|
+
configurable: true,
|
|
1105
|
+
value: () => {
|
|
1106
|
+
controller.pause();
|
|
1107
|
+
proxyVideo.dispatchEvent(new Event("pause"));
|
|
1108
|
+
}
|
|
1109
|
+
},
|
|
1110
|
+
paused: {
|
|
1111
|
+
configurable: true,
|
|
1112
|
+
get: () => controller.getPaused()
|
|
1113
|
+
},
|
|
1114
|
+
play: {
|
|
1115
|
+
configurable: true,
|
|
1116
|
+
value: () => controller.play().then(() => {
|
|
1117
|
+
proxyVideo.dispatchEvent(new Event("play"));
|
|
1118
|
+
proxyVideo.dispatchEvent(new Event("playing"));
|
|
1119
|
+
})
|
|
1120
|
+
},
|
|
1121
|
+
playbackRate: {
|
|
1122
|
+
configurable: true,
|
|
1123
|
+
get: () => controller.getPlaybackRate(),
|
|
1124
|
+
set: (value) => {
|
|
1125
|
+
controller.setPlaybackRate(Number(value) || 1);
|
|
1126
|
+
proxyVideo.dispatchEvent(new Event("ratechange"));
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
volume: {
|
|
1130
|
+
configurable: true,
|
|
1131
|
+
get: () => controller.getVolume(),
|
|
1132
|
+
set: (value) => {
|
|
1133
|
+
const clamped = Math.max(0, Math.min(1, Number(value) || 0));
|
|
1134
|
+
controller.setVolume(clamped);
|
|
1135
|
+
proxyVideo.dispatchEvent(new Event("volumechange"));
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
return proxyVideo;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// src/modules/background/utils.ts
|
|
1143
|
+
var WIDTH_CLASS = /^(w-|max-w-|min-w-)/;
|
|
1144
|
+
function resolveVideoClassNames(...inputs) {
|
|
1145
|
+
const tokens = inputs.flatMap(
|
|
1146
|
+
(input) => typeof input === "string" ? input.replace(/,/g, " ").split(/\s+/) : []
|
|
1147
|
+
).filter(Boolean);
|
|
1148
|
+
return {
|
|
1149
|
+
objectStyle: Object.assign(
|
|
1150
|
+
{},
|
|
1151
|
+
...tokens.map((token) => BG_TOKEN_TO_OBJECT_STYLE[token])
|
|
1152
|
+
),
|
|
1153
|
+
other: tokens.filter((token) => !WIDTH_CLASS.test(token)).join(" "),
|
|
1154
|
+
width: tokens.filter((token) => WIDTH_CLASS.test(token)).join(" ")
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
function resolveVideoOptions(options = {}) {
|
|
1158
|
+
return {
|
|
1159
|
+
codec: options.codec || "auto",
|
|
1160
|
+
corp: options.corp ?? 0,
|
|
1161
|
+
forceIframe: Boolean(options.forceIframe),
|
|
1162
|
+
isLoop: options.loop ?? false,
|
|
1163
|
+
isMuted: options.muted ?? true,
|
|
1164
|
+
playbackRate: options.playbackRate ?? 1,
|
|
1165
|
+
quality: options.quality || "1080p",
|
|
1166
|
+
shouldAutoPlay: options.autoplay ?? true,
|
|
1167
|
+
showPoster: Boolean(options.showPoster),
|
|
1168
|
+
showSpinner: options.showSpinner !== false
|
|
1227
1169
|
};
|
|
1228
1170
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
};
|
|
1171
|
+
function normalizeBackgroundInput(patch = {}) {
|
|
1172
|
+
if (!patch) return {};
|
|
1173
|
+
if (typeof patch === "string") {
|
|
1174
|
+
const trimmed = patch.trim();
|
|
1175
|
+
if (isYouTubeUrl(trimmed) || isDirectVideoUrl(trimmed)) {
|
|
1176
|
+
return { image: null, video: trimmed };
|
|
1177
|
+
}
|
|
1178
|
+
return { image: trimmed };
|
|
1237
1179
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
};
|
|
1180
|
+
const nextPatch = { ...patch };
|
|
1181
|
+
if (typeof nextPatch.image === "string" && isYouTubeUrl(nextPatch.image) && !nextPatch.video) {
|
|
1182
|
+
nextPatch.video = nextPatch.image;
|
|
1183
|
+
nextPatch.image = null;
|
|
1243
1184
|
}
|
|
1185
|
+
return nextPatch;
|
|
1186
|
+
}
|
|
1187
|
+
function mergeBackgroundState(baseState, patch = {}) {
|
|
1188
|
+
const resolvedPatch = normalizeBackgroundInput(patch);
|
|
1189
|
+
const nextVideoOptions = {
|
|
1190
|
+
...baseState.videoOptions,
|
|
1191
|
+
...resolvedPatch.videoOptions || {}
|
|
1192
|
+
};
|
|
1193
|
+
const nextVideo = resolvedPatch.video !== void 0 ? resolvedPatch.video : baseState.video;
|
|
1194
|
+
const shouldAutoPlay = nextVideoOptions.autoplay !== false;
|
|
1195
|
+
const resolvedIsPlaying = resolvedPatch.isPlaying !== void 0 ? resolvedPatch.isPlaying : resolvedPatch.video !== void 0 && Boolean(nextVideo) ? shouldAutoPlay : baseState.isPlaying;
|
|
1244
1196
|
return {
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1197
|
+
...baseState,
|
|
1198
|
+
...resolvedPatch,
|
|
1199
|
+
isPlaying: resolvedIsPlaying,
|
|
1200
|
+
animation: resolvedPatch.animation !== void 0 ? resolvedPatch.animation ? {
|
|
1201
|
+
...baseState.animation || {},
|
|
1202
|
+
...resolvedPatch.animation
|
|
1203
|
+
} : resolvedPatch.animation : baseState.animation,
|
|
1204
|
+
imageStyle: {
|
|
1205
|
+
...baseState.imageStyle,
|
|
1206
|
+
...resolvedPatch.imageStyle || {}
|
|
1207
|
+
},
|
|
1208
|
+
noiseStyle: {
|
|
1209
|
+
...baseState.noiseStyle,
|
|
1210
|
+
...resolvedPatch.noiseStyle || {}
|
|
1211
|
+
},
|
|
1212
|
+
videoOptions: nextVideoOptions,
|
|
1213
|
+
videoStyle: {
|
|
1214
|
+
...baseState.videoStyle,
|
|
1215
|
+
...resolvedPatch.videoStyle || {}
|
|
1249
1216
|
}
|
|
1250
1217
|
};
|
|
1251
1218
|
}
|
|
1252
|
-
function
|
|
1253
|
-
|
|
1254
|
-
return { instanceId, source: sourceOrOptions };
|
|
1255
|
-
}
|
|
1256
|
-
if (isObject(sourceOrOptions)) {
|
|
1257
|
-
return { ...sourceOrOptions, instanceId };
|
|
1258
|
-
}
|
|
1259
|
-
return { instanceId };
|
|
1219
|
+
function selectPageBackground(background) {
|
|
1220
|
+
return background ? normalizeBackgroundInput(background) : null;
|
|
1260
1221
|
}
|
|
1261
|
-
|
|
1262
|
-
const
|
|
1263
|
-
return
|
|
1222
|
+
var generateBaseGradient = (direction, color) => {
|
|
1223
|
+
const to = direction === "left" ? "to right" : "to left";
|
|
1224
|
+
return `linear-gradient(${to}, ${color} 0%, color-mix(in srgb, ${color} 85%, transparent) 15%, color-mix(in srgb, ${color} 50%, transparent) 45%, color-mix(in srgb, ${color} 18%, transparent) 75%, transparent 100%)`;
|
|
1225
|
+
};
|
|
1226
|
+
var generateEdgeGradient = (direction, color) => {
|
|
1227
|
+
const to = direction === "left" ? "to right" : "to left";
|
|
1228
|
+
return `linear-gradient(${to}, color-mix(in srgb, ${color} 95%, transparent) 0%, color-mix(in srgb, ${color} 70%, transparent) 25%, color-mix(in srgb, ${color} 35%, transparent) 55%, color-mix(in srgb, ${color} 10%, transparent) 80%, transparent 100%)`;
|
|
1229
|
+
};
|
|
1230
|
+
function getVisualStyle(currentStyle = {}) {
|
|
1231
|
+
const {
|
|
1232
|
+
className: _className,
|
|
1233
|
+
leftGradient = 0,
|
|
1234
|
+
rightGradient = 0,
|
|
1235
|
+
...baseStyle
|
|
1236
|
+
} = currentStyle;
|
|
1237
|
+
return {
|
|
1238
|
+
baseStyle,
|
|
1239
|
+
leftGradient: Number(leftGradient) || 0,
|
|
1240
|
+
rightGradient: Number(rightGradient) || 0
|
|
1241
|
+
};
|
|
1264
1242
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1243
|
+
function resolveGradientSettings({
|
|
1244
|
+
fadeEdges = null,
|
|
1245
|
+
hasWidth = false,
|
|
1246
|
+
leftGradient = 0,
|
|
1247
|
+
rightGradient = 0
|
|
1248
|
+
}) {
|
|
1249
|
+
let leftPercent = 0;
|
|
1250
|
+
let rightPercent = 0;
|
|
1251
|
+
if (leftGradient > 0)
|
|
1252
|
+
leftPercent = Math.min(48, Math.max(12, leftGradient * 7.5));
|
|
1253
|
+
else if (hasWidth && fadeEdges !== false) leftPercent = 20;
|
|
1254
|
+
if (rightGradient > 0)
|
|
1255
|
+
rightPercent = Math.min(48, Math.max(12, rightGradient * 7.5));
|
|
1256
|
+
else if (hasWidth && fadeEdges !== false) rightPercent = 20;
|
|
1257
|
+
if (typeof fadeEdges === "number") {
|
|
1258
|
+
leftPercent = fadeEdges;
|
|
1259
|
+
rightPercent = fadeEdges;
|
|
1260
|
+
} else if (typeof fadeEdges === "string") {
|
|
1261
|
+
const parsed = parseFloat(fadeEdges);
|
|
1262
|
+
if (!Number.isNaN(parsed)) {
|
|
1263
|
+
leftPercent = parsed;
|
|
1264
|
+
rightPercent = parsed;
|
|
1271
1265
|
}
|
|
1266
|
+
} else if (typeof fadeEdges === "object" && fadeEdges !== null) {
|
|
1267
|
+
const edgeObj = fadeEdges;
|
|
1268
|
+
if (edgeObj.left !== void 0)
|
|
1269
|
+
leftPercent = parseFloat(String(edgeObj.left)) || 0;
|
|
1270
|
+
if (edgeObj.right !== void 0)
|
|
1271
|
+
rightPercent = parseFloat(String(edgeObj.right)) || 0;
|
|
1272
|
+
} else if (fadeEdges === false) {
|
|
1273
|
+
leftPercent = 0;
|
|
1274
|
+
rightPercent = 0;
|
|
1275
|
+
}
|
|
1276
|
+
const leftOpacity = leftGradient > 0 ? Math.min(1, leftGradient * 0.22) : 0;
|
|
1277
|
+
const rightOpacity = rightGradient > 0 ? Math.min(1, rightGradient * 0.22) : 0;
|
|
1278
|
+
return {
|
|
1279
|
+
enabled: leftPercent > 0 || rightPercent > 0,
|
|
1280
|
+
leftOpacity,
|
|
1281
|
+
leftPercent,
|
|
1282
|
+
rightOpacity,
|
|
1283
|
+
rightPercent
|
|
1272
1284
|
};
|
|
1273
|
-
return entry;
|
|
1274
|
-
}
|
|
1275
|
-
function isDirectRegistryComponentPath(path, componentSlices) {
|
|
1276
|
-
const match = /^config\.([^.[]+)\.[^.[]+$/.exec(path);
|
|
1277
|
-
return Boolean(match && componentSlices.has(match[1]));
|
|
1278
|
-
}
|
|
1279
|
-
function isReactNodeLike(value) {
|
|
1280
|
-
return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" || isValidElement(value);
|
|
1281
|
-
}
|
|
1282
|
-
function isStabilizableObject(value) {
|
|
1283
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && !isValidElement(value);
|
|
1284
1285
|
}
|
|
1285
|
-
function
|
|
1286
|
-
|
|
1287
|
-
|
|
1286
|
+
function generateSmoothstepStops(percent, direction = "in", color = "var(--black, #000)") {
|
|
1287
|
+
const steps = [
|
|
1288
|
+
{ s: 0, t: 0 },
|
|
1289
|
+
{ s: 0.06, t: 0.15 },
|
|
1290
|
+
{ s: 0.22, t: 0.35 },
|
|
1291
|
+
{ s: 0.47, t: 0.55 },
|
|
1292
|
+
{ s: 0.76, t: 0.75 },
|
|
1293
|
+
{ s: 0.93, t: 0.9 },
|
|
1294
|
+
{ s: 1, t: 1 }
|
|
1295
|
+
];
|
|
1296
|
+
if (direction === "in") {
|
|
1297
|
+
return steps.map(
|
|
1298
|
+
({ s, t }) => s === 0 ? `transparent ${(t * percent).toFixed(1)}%` : s === 1 ? `${color} ${(t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(s * 100)}%, transparent) ${(t * percent).toFixed(1)}%`
|
|
1299
|
+
);
|
|
1288
1300
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
(key) => Object.prototype.hasOwnProperty.call(previousValue, key)
|
|
1294
|
-
);
|
|
1301
|
+
return steps.map(({ s, t }) => {
|
|
1302
|
+
const alpha = 1 - s;
|
|
1303
|
+
return alpha === 0 ? `transparent ${(100 - percent + t * percent).toFixed(1)}%` : alpha === 1 ? `${color} ${(100 - percent + t * percent).toFixed(1)}%` : `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent) ${(100 - percent + t * percent).toFixed(1)}%`;
|
|
1304
|
+
});
|
|
1295
1305
|
}
|
|
1296
|
-
function
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
const nextProps = stabilizeRegistryValue(
|
|
1319
|
-
value.props,
|
|
1320
|
-
`${path}.props`,
|
|
1321
|
-
scope,
|
|
1322
|
-
isValidElement(previousValue) ? previousValue.props : void 0,
|
|
1323
|
-
seen,
|
|
1324
|
-
depth + 1
|
|
1325
|
-
);
|
|
1326
|
-
if (isValidElement(previousValue) && previousValue.type === value.type && previousValue.key === value.key && previousValue.props === nextProps) {
|
|
1327
|
-
return previousValue;
|
|
1306
|
+
function getEdgeFadeMask({
|
|
1307
|
+
color = "var(--black, #000)",
|
|
1308
|
+
leftPercent = 0,
|
|
1309
|
+
rightPercent = 0
|
|
1310
|
+
}) {
|
|
1311
|
+
if (leftPercent <= 0 && rightPercent <= 0) return void 0;
|
|
1312
|
+
const leftStops = leftPercent > 0 ? generateSmoothstepStops(leftPercent, "in", color) : [`${color} 0%`];
|
|
1313
|
+
const rightStops = rightPercent > 0 ? generateSmoothstepStops(rightPercent, "out", color) : [`${color} 100%`];
|
|
1314
|
+
return `linear-gradient(to right, ${leftStops.join(", ")}, ${rightStops.join(", ")})`;
|
|
1315
|
+
}
|
|
1316
|
+
function applyVideoPlaybackState({
|
|
1317
|
+
isPlaying,
|
|
1318
|
+
playbackRate,
|
|
1319
|
+
setVideoPlaying,
|
|
1320
|
+
videoElement
|
|
1321
|
+
}) {
|
|
1322
|
+
if (!videoElement) return;
|
|
1323
|
+
const numericPlaybackRate = Number(playbackRate);
|
|
1324
|
+
const resolvedPlaybackRate = Number.isFinite(numericPlaybackRate) && numericPlaybackRate > 0 ? numericPlaybackRate : 1;
|
|
1325
|
+
try {
|
|
1326
|
+
if (videoElement.playbackRate !== resolvedPlaybackRate) {
|
|
1327
|
+
videoElement.playbackRate = resolvedPlaybackRate;
|
|
1328
1328
|
}
|
|
1329
|
-
|
|
1329
|
+
} catch {
|
|
1330
|
+
return;
|
|
1330
1331
|
}
|
|
1331
|
-
if (
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
let hasChanged2 = !previousArray || previousArray.length !== nextValue.length;
|
|
1335
|
-
const stabilizedValue2 = nextValue.map((item, index) => {
|
|
1336
|
-
const nextItem = stabilizeRegistryValue(
|
|
1337
|
-
item,
|
|
1338
|
-
`${path}[${index}]`,
|
|
1339
|
-
scope,
|
|
1340
|
-
previousArray?.[index],
|
|
1341
|
-
seen,
|
|
1342
|
-
depth + 1
|
|
1343
|
-
);
|
|
1344
|
-
if (!previousArray || nextItem !== previousArray[index]) {
|
|
1345
|
-
hasChanged2 = true;
|
|
1346
|
-
}
|
|
1347
|
-
return nextItem;
|
|
1348
|
-
});
|
|
1349
|
-
return !hasChanged2 ? previousArray : stabilizedValue2;
|
|
1332
|
+
if (!isPlaying) {
|
|
1333
|
+
if (!videoElement.paused) videoElement.pause();
|
|
1334
|
+
return;
|
|
1350
1335
|
}
|
|
1351
|
-
if (
|
|
1352
|
-
return
|
|
1336
|
+
if (videoElement.readyState === 0) {
|
|
1337
|
+
return;
|
|
1353
1338
|
}
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
let hasChanged = !canReusePrevious;
|
|
1359
|
-
Object.keys(source).forEach((key) => {
|
|
1360
|
-
const nextValue = stabilizeRegistryValue(
|
|
1361
|
-
source[key],
|
|
1362
|
-
`${path}.${key}`,
|
|
1363
|
-
scope,
|
|
1364
|
-
previousRecord?.[key],
|
|
1365
|
-
seen,
|
|
1366
|
-
depth + 1
|
|
1367
|
-
);
|
|
1368
|
-
stabilizedValue[key] = nextValue;
|
|
1369
|
-
if (!canReusePrevious || nextValue !== previousRecord?.[key]) {
|
|
1370
|
-
hasChanged = true;
|
|
1371
|
-
}
|
|
1372
|
-
});
|
|
1373
|
-
return !hasChanged ? previousValue : stabilizedValue;
|
|
1374
|
-
}
|
|
1375
|
-
function useAppliedRegistryConfig(payload, context, componentSlices) {
|
|
1376
|
-
const functionEntriesRef = useRef(/* @__PURE__ */ new Map());
|
|
1377
|
-
const appliedRef = useRef(null);
|
|
1378
|
-
useIsomorphicLayoutEffect(() => {
|
|
1379
|
-
const previous = appliedRef.current;
|
|
1380
|
-
if (previous && previous.payload === payload && previous.context === context) {
|
|
1339
|
+
const playPromise = videoElement.play();
|
|
1340
|
+
if (!playPromise || typeof playPromise.then !== "function") return;
|
|
1341
|
+
playPromise.then(() => setVideoPlaying(true)).catch((error) => {
|
|
1342
|
+
if (error?.name === "AbortError" || videoElement.readyState < 2) {
|
|
1381
1343
|
return;
|
|
1382
1344
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
"config",
|
|
1388
|
-
{ componentSlices, functionEntries, usedPaths },
|
|
1389
|
-
previous?.config
|
|
1390
|
-
);
|
|
1391
|
-
functionEntries.forEach((_entry, path) => {
|
|
1392
|
-
if (!usedPaths.has(path)) functionEntries.delete(path);
|
|
1393
|
-
});
|
|
1394
|
-
if (previous && previous.config === config && previous.context === context) {
|
|
1395
|
-
previous.payload = payload;
|
|
1345
|
+
if (error?.name === "NotAllowedError") {
|
|
1346
|
+
videoElement.muted = true;
|
|
1347
|
+
videoElement.play().then(() => setVideoPlaying(true)).catch(() => {
|
|
1348
|
+
});
|
|
1396
1349
|
return;
|
|
1397
1350
|
}
|
|
1398
|
-
|
|
1399
|
-
appliedRef.current = {
|
|
1400
|
-
cleanup: applyRegistryConfig(config, context),
|
|
1401
|
-
config,
|
|
1402
|
-
context,
|
|
1403
|
-
payload
|
|
1404
|
-
};
|
|
1405
|
-
});
|
|
1406
|
-
useIsomorphicLayoutEffect(
|
|
1407
|
-
() => () => {
|
|
1408
|
-
appliedRef.current?.cleanup();
|
|
1409
|
-
appliedRef.current = null;
|
|
1410
|
-
},
|
|
1411
|
-
[]
|
|
1412
|
-
);
|
|
1413
|
-
}
|
|
1414
|
-
function createRegistryApplyContext(actions, {
|
|
1415
|
-
cleanupScope = /* @__PURE__ */ new Map(),
|
|
1416
|
-
instanceId,
|
|
1417
|
-
modules = [],
|
|
1418
|
-
pathname
|
|
1419
|
-
}) {
|
|
1420
|
-
const stamp = (queue) => ({
|
|
1421
|
-
register: (type, key, item, sourceOrOptions, optionsArg) => queue.register(
|
|
1422
|
-
type,
|
|
1423
|
-
key,
|
|
1424
|
-
item,
|
|
1425
|
-
...resolveRegisterArgsWithInstance(
|
|
1426
|
-
instanceId,
|
|
1427
|
-
sourceOrOptions,
|
|
1428
|
-
optionsArg
|
|
1429
|
-
)
|
|
1430
|
-
),
|
|
1431
|
-
unregister: (type, key, sourceOrOptions) => queue.unregister(
|
|
1432
|
-
type,
|
|
1433
|
-
key,
|
|
1434
|
-
withInstanceIdForUnregister(instanceId, sourceOrOptions)
|
|
1435
|
-
)
|
|
1351
|
+
setVideoPlaying(false);
|
|
1436
1352
|
});
|
|
1437
|
-
return {
|
|
1438
|
-
...stamp(actions),
|
|
1439
|
-
batch: (executor) => typeof executor === "function" ? actions.batch((queue) => executor(stamp(queue))) : 0,
|
|
1440
|
-
cleanupScope,
|
|
1441
|
-
instanceId,
|
|
1442
|
-
modules,
|
|
1443
|
-
pathname
|
|
1444
|
-
};
|
|
1445
|
-
}
|
|
1446
|
-
function useRegistry(config, metadata) {
|
|
1447
|
-
const { batch, register, unregister } = useRegistryActions();
|
|
1448
|
-
const pathname = usePathname();
|
|
1449
|
-
const modules = useInstalledModules();
|
|
1450
|
-
const instanceId = `registry-instance-${useId()}`;
|
|
1451
|
-
const [cleanupScope] = useState(
|
|
1452
|
-
() => /* @__PURE__ */ new Map()
|
|
1453
|
-
);
|
|
1454
|
-
const context = useMemo(
|
|
1455
|
-
() => createRegistryApplyContext(
|
|
1456
|
-
{ batch, register, unregister },
|
|
1457
|
-
{
|
|
1458
|
-
cleanupScope,
|
|
1459
|
-
instanceId,
|
|
1460
|
-
modules,
|
|
1461
|
-
pathname
|
|
1462
|
-
}
|
|
1463
|
-
),
|
|
1464
|
-
[batch, cleanupScope, instanceId, modules, pathname, register, unregister]
|
|
1465
|
-
);
|
|
1466
|
-
const payload = useMemo(
|
|
1467
|
-
() => config ? createModulePayload(modules, config, metadata) : null,
|
|
1468
|
-
[config, metadata, modules]
|
|
1469
|
-
);
|
|
1470
|
-
const componentSlices = useMemo(
|
|
1471
|
-
() => new Set(
|
|
1472
|
-
modules.filter(
|
|
1473
|
-
(coreModule) => coreModule.registry?.valueKind === "component"
|
|
1474
|
-
).map((coreModule) => coreModule.id)
|
|
1475
|
-
),
|
|
1476
|
-
[modules]
|
|
1477
|
-
);
|
|
1478
|
-
useAppliedRegistryConfig(payload, context, componentSlices);
|
|
1479
1353
|
}
|
|
1480
|
-
function
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1354
|
+
function triggerVideoPlaybackDirect(videoElement, nextPlaying, configuredMuted) {
|
|
1355
|
+
if (!videoElement) return;
|
|
1356
|
+
if (nextPlaying) {
|
|
1357
|
+
videoElement.muted = configuredMuted;
|
|
1358
|
+
if (!configuredMuted && videoElement.volume === 0) {
|
|
1359
|
+
videoElement.volume = 0.8;
|
|
1360
|
+
}
|
|
1361
|
+
videoElement.play().catch((err) => {
|
|
1362
|
+
if (err?.name === "NotAllowedError") {
|
|
1363
|
+
videoElement.muted = true;
|
|
1364
|
+
videoElement.play().catch(() => {
|
|
1365
|
+
});
|
|
1489
1366
|
}
|
|
1490
1367
|
});
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
const top = stack[stack.length - 1];
|
|
1495
|
-
return top?.controllerRef?.current || null;
|
|
1496
|
-
},
|
|
1497
|
-
notify,
|
|
1498
|
-
register(id, controllerRef) {
|
|
1499
|
-
stack = stack.filter((item) => item.id !== id);
|
|
1500
|
-
stack.push({ controllerRef, id });
|
|
1501
|
-
notify();
|
|
1502
|
-
},
|
|
1503
|
-
subscribe(listener) {
|
|
1504
|
-
listeners.add(listener);
|
|
1505
|
-
return () => {
|
|
1506
|
-
listeners.delete(listener);
|
|
1507
|
-
};
|
|
1508
|
-
},
|
|
1509
|
-
unregister(id) {
|
|
1510
|
-
stack = stack.filter((item) => item.id !== id);
|
|
1511
|
-
notify();
|
|
1512
|
-
}
|
|
1513
|
-
};
|
|
1368
|
+
} else {
|
|
1369
|
+
videoElement.pause();
|
|
1370
|
+
}
|
|
1514
1371
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
"PageControllerStoreContext",
|
|
1522
|
-
fallbackStandaloneStore
|
|
1523
|
-
);
|
|
1524
|
-
function defineModule(coreModule) {
|
|
1525
|
-
return Object.freeze({ ...coreModule });
|
|
1372
|
+
function syncVideoMutedDirect(videoElement, nextMuted) {
|
|
1373
|
+
if (!videoElement) return;
|
|
1374
|
+
videoElement.muted = nextMuted;
|
|
1375
|
+
if (!nextMuted && videoElement.volume === 0) {
|
|
1376
|
+
videoElement.volume = 0.8;
|
|
1377
|
+
}
|
|
1526
1378
|
}
|
|
1527
|
-
function
|
|
1528
|
-
|
|
1529
|
-
|
|
1379
|
+
function syncVideoLoopDirect(videoElement, nextLoop) {
|
|
1380
|
+
if (!videoElement) return;
|
|
1381
|
+
videoElement.loop = nextLoop;
|
|
1530
1382
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1383
|
+
|
|
1384
|
+
// src/modules/background/motion.ts
|
|
1385
|
+
var DEFAULT_MOTION = Object.freeze({
|
|
1386
|
+
animate: Object.freeze({
|
|
1387
|
+
opacity: 1
|
|
1388
|
+
}),
|
|
1389
|
+
exit: Object.freeze({
|
|
1390
|
+
opacity: 0,
|
|
1391
|
+
transition: Object.freeze({
|
|
1392
|
+
duration: DURATION_TOKENS.SLOW,
|
|
1393
|
+
ease: EASING_CURVES.IN_CUBIC
|
|
1394
|
+
})
|
|
1395
|
+
}),
|
|
1396
|
+
initial: Object.freeze({
|
|
1397
|
+
opacity: 0
|
|
1398
|
+
}),
|
|
1399
|
+
transition: Object.freeze({
|
|
1400
|
+
delay: 0,
|
|
1401
|
+
duration: DURATION_TOKENS.SLOW,
|
|
1402
|
+
ease: EASING_CURVES.OUT_QUART
|
|
1403
|
+
})
|
|
1404
|
+
});
|
|
1405
|
+
function getBackgroundMotionConfig(animation) {
|
|
1533
1406
|
return {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
isEqual
|
|
1540
|
-
)
|
|
1407
|
+
animate: animation?.animate ?? DEFAULT_MOTION.animate,
|
|
1408
|
+
exit: animation?.exit ?? DEFAULT_MOTION.exit,
|
|
1409
|
+
exitDurationFactor: Number(animation?.exitDurationFactor),
|
|
1410
|
+
initial: animation?.initial ?? DEFAULT_MOTION.initial,
|
|
1411
|
+
transition: animation?.transition ?? DEFAULT_MOTION.transition
|
|
1541
1412
|
};
|
|
1542
1413
|
}
|
|
1543
|
-
|
|
1414
|
+
function toCssDuration(seconds) {
|
|
1415
|
+
const value = Number(seconds);
|
|
1416
|
+
return `${Math.max(0, Number.isFinite(value) ? value : DURATION_TOKENS.SLOW) * 1e3}ms`;
|
|
1417
|
+
}
|
|
1418
|
+
function toCssDelay(seconds) {
|
|
1419
|
+
const value = Number(seconds);
|
|
1420
|
+
return `${Math.max(0, Number.isFinite(value) ? value : 0) * 1e3}ms`;
|
|
1421
|
+
}
|
|
1422
|
+
function toCssEasing(easing) {
|
|
1423
|
+
if (Array.isArray(easing)) {
|
|
1424
|
+
return `cubic-bezier(${easing.join(", ")})`;
|
|
1425
|
+
}
|
|
1426
|
+
if (typeof easing === "string" && easing.trim()) {
|
|
1427
|
+
return easing;
|
|
1428
|
+
}
|
|
1429
|
+
return "ease";
|
|
1430
|
+
}
|
|
1544
1431
|
|
|
1545
|
-
// src/
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1432
|
+
// src/modules/media/constants.ts
|
|
1433
|
+
var DEFAULT_MEDIA_STATE = Object.freeze({
|
|
1434
|
+
audibleElement: null,
|
|
1435
|
+
element: null,
|
|
1436
|
+
hasMedia: false,
|
|
1437
|
+
isPlaying: false,
|
|
1438
|
+
kind: null,
|
|
1439
|
+
loop: false,
|
|
1440
|
+
sourceId: null
|
|
1441
|
+
});
|
|
1442
|
+
var INERT_MEDIA_ACTIONS = Object.freeze({
|
|
1443
|
+
removeSource: () => {
|
|
1444
|
+
},
|
|
1445
|
+
setMuted: () => {
|
|
1446
|
+
},
|
|
1447
|
+
toggle: () => {
|
|
1448
|
+
},
|
|
1449
|
+
toggleLoop: () => {
|
|
1450
|
+
},
|
|
1451
|
+
upsertSource: () => {
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
var MediaContext = getOrCreateGlobalContext(
|
|
1455
|
+
"MediaContext",
|
|
1456
|
+
null
|
|
1457
|
+
);
|
|
1458
|
+
createStore(DEFAULT_MEDIA_STATE);
|
|
1459
|
+
function useOptionalMediaActions() {
|
|
1460
|
+
const ctx = useContext(MediaContext);
|
|
1461
|
+
return ctx?.actions ?? INERT_MEDIA_ACTIONS;
|
|
1552
1462
|
}
|
|
1553
1463
|
var BackgroundContext = getOrCreateGlobalContext(
|
|
1554
1464
|
"BackgroundContext",
|
|
1555
1465
|
null
|
|
1556
1466
|
);
|
|
1557
|
-
var mediaPeer = definePeer("media", {
|
|
1558
|
-
actions: {
|
|
1559
|
-
removeSource: () => {
|
|
1560
|
-
},
|
|
1561
|
-
setMuted: () => {
|
|
1562
|
-
},
|
|
1563
|
-
toggle: () => {
|
|
1564
|
-
},
|
|
1565
|
-
toggleLoop: () => {
|
|
1566
|
-
},
|
|
1567
|
-
upsertSource: () => {
|
|
1568
|
-
}
|
|
1569
|
-
},
|
|
1570
|
-
store: createStore({
|
|
1571
|
-
audibleElement: null,
|
|
1572
|
-
element: null,
|
|
1573
|
-
hasMedia: false,
|
|
1574
|
-
isPlaying: false,
|
|
1575
|
-
kind: null,
|
|
1576
|
-
loop: false,
|
|
1577
|
-
sourceId: null
|
|
1578
|
-
})
|
|
1579
|
-
});
|
|
1580
1467
|
function useBackgroundRegistration(config, options) {
|
|
1581
1468
|
useModuleRegistration("background", config, options);
|
|
1582
1469
|
}
|
|
@@ -1733,7 +1620,7 @@ function BackgroundProvider({ children }) {
|
|
|
1733
1620
|
}
|
|
1734
1621
|
};
|
|
1735
1622
|
}, [overrideStore]);
|
|
1736
|
-
const media =
|
|
1623
|
+
const media = useOptionalMediaActions();
|
|
1737
1624
|
const { isPlaying, isVideo, videoElement } = state;
|
|
1738
1625
|
const isLoop = Boolean(state.videoOptions?.loop);
|
|
1739
1626
|
useEffect(() => {
|
|
@@ -1782,6 +1669,21 @@ function useBackground(config, options) {
|
|
|
1782
1669
|
const state = useBackgroundState();
|
|
1783
1670
|
return useMemo(() => ({ ...state, ...actions }), [actions, state]);
|
|
1784
1671
|
}
|
|
1672
|
+
var NOOP_BACKGROUND_STORE = createStore(
|
|
1673
|
+
DEFAULT_BACKGROUND_COMPUTED
|
|
1674
|
+
);
|
|
1675
|
+
function useOptionalBackgroundState(selector, isEqual) {
|
|
1676
|
+
const ctx = useContext(BackgroundContext);
|
|
1677
|
+
return useStore(
|
|
1678
|
+
ctx?.store ?? NOOP_BACKGROUND_STORE,
|
|
1679
|
+
selector,
|
|
1680
|
+
isEqual
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
function useOptionalBackgroundActions() {
|
|
1684
|
+
const ctx = useContext(BackgroundContext);
|
|
1685
|
+
return ctx?.actions ?? INERT_BACKGROUND_ACTIONS;
|
|
1686
|
+
}
|
|
1785
1687
|
var PLAYER_STATE = { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3 };
|
|
1786
1688
|
var apiPromise = null;
|
|
1787
1689
|
function loadYouTubeIframeApi() {
|
|
@@ -3190,6 +3092,6 @@ function defineBackground(definition = {}) {
|
|
|
3190
3092
|
});
|
|
3191
3093
|
}
|
|
3192
3094
|
|
|
3193
|
-
export { BACKGROUND_MEDIA_ID, BackgroundContext, BackgroundOverlay, BackgroundProvider, DEFAULT_BACKGROUND, backgroundModule, backgroundTheme, defineBackground, extractYouTubeVideoId, getYouTubeStreamUrl, getYouTubeThumbnailUrl, isDirectVideoUrl, isYouTubeUrl, parseYouTubeUrlConfig, useBackground, useBackgroundActions, useBackgroundRegistration, useBackgroundState };
|
|
3095
|
+
export { BACKGROUND_MEDIA_ID, BackgroundContext, BackgroundOverlay, BackgroundProvider, DEFAULT_BACKGROUND, DEFAULT_BACKGROUND_COMPUTED, INERT_BACKGROUND_ACTIONS, backgroundModule, backgroundTheme, defineBackground, extractYouTubeVideoId, getYouTubeStreamUrl, getYouTubeThumbnailUrl, isDirectVideoUrl, isYouTubeUrl, parseYouTubeUrlConfig, useBackground, useBackgroundActions, useBackgroundRegistration, useBackgroundState, useOptionalBackgroundActions, useOptionalBackgroundState };
|
|
3194
3096
|
//# sourceMappingURL=index.js.map
|
|
3195
3097
|
//# sourceMappingURL=index.js.map
|