BOC v1.0: RS256 auth, Ledger integration, Prometheus metrics, CI/CD, backup
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
import { resolveElements } from '../../utils/resolve-elements.mjs';
|
||||
|
||||
let nameCount = 0;
|
||||
/**
|
||||
* Generated names live in their own namespace so we can tell a name we own
|
||||
* (and must clean up) from an author-defined one - and so a stale generated
|
||||
* name left behind by an interrupted transition is re-owned, not mistaken for
|
||||
* the author's and leaked.
|
||||
*/
|
||||
const generatedName = () => `motion-view-${nameCount++}`;
|
||||
const isGeneratedName = (name) => name.startsWith("motion-view-");
|
||||
/**
|
||||
* Tag a captured element with a `view-transition-class` so authors can target
|
||||
* its generated layer from CSS (e.g. `::view-transition-group(.hero)`) without
|
||||
* the opaque generated name. Tracked in `classed` - separate from the generated
|
||||
* names in `assigned` - so cleanup removes the class without ever stripping an
|
||||
* author's own inline `view-transition-name`.
|
||||
*/
|
||||
function tagClass(element, className, classed) {
|
||||
if (!className)
|
||||
return;
|
||||
element.style?.setProperty("view-transition-class", className);
|
||||
classed.push(element);
|
||||
}
|
||||
/**
|
||||
* Set the element's `view-transition-group` so its layer reconstructs the DOM
|
||||
* hierarchy in the pseudo-tree (`contain`) - or stays flat (`none`). Tracked in
|
||||
* `grouped` for cleanup. When the element clips (any non-`visible` overflow) its
|
||||
* name is recorded in `clipChildren` so the caller can clip the nested children
|
||||
* (`::view-transition-group-children(name)`), mirroring the live clip through
|
||||
* the whole transition rather than only at the live-DOM handoff.
|
||||
*
|
||||
* Ignored by browsers without nested view-transition groups, where it harmlessly
|
||||
* degrades to the flat default.
|
||||
*/
|
||||
function applyGroup(element, name, group, grouped, clipChildren) {
|
||||
if (!group)
|
||||
return;
|
||||
element.style?.setProperty("view-transition-group", group);
|
||||
grouped.push(element);
|
||||
if (group !== "none" && clipChildren) {
|
||||
const style = getComputedStyle(element);
|
||||
if (style.overflowX !== "visible" || style.overflowY !== "visible") {
|
||||
clipChildren.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolve a selector/Element to elements and ensure each one carries a
|
||||
* `view-transition-name` we can target from script.
|
||||
*
|
||||
* Author-defined names are reused as-is. Elements that are unnamed (or use
|
||||
* the browser's `auto`/`match-element`, whose generated name is not exposed
|
||||
* to script) are given a unique generated name, set inline so it's captured,
|
||||
* and tracked in `assigned` for later cleanup.
|
||||
*
|
||||
* `registry` maps each Element to its name so the same element keeps its name
|
||||
* across both captures (before and after the update), which is what allows a
|
||||
* persistent element to animate as a single `group` layer.
|
||||
*/
|
||||
function assignViewTransitionNames(definition, registry, assigned, forcedNames, className, classed = [], group, grouped = [], clipChildren) {
|
||||
const elements = resolveElements(definition);
|
||||
/**
|
||||
* The new end of a paired morph: give each element the matching name from
|
||||
* the old end (by index) so the two share one layer and morph. If the new
|
||||
* end resolves to *more* elements than the old end named, the extras have no
|
||||
* counterpart - give them a fresh name so they animate as newcomers rather
|
||||
* than being silently left unnamed. We return the names actually assigned
|
||||
* (sized to the resolved elements), not the raw `forcedNames`, so stagger
|
||||
* totals and the layer set stay in step with what's on the page.
|
||||
*/
|
||||
if (forcedNames) {
|
||||
return elements.map((element, i) => {
|
||||
const existing = registry.get(element);
|
||||
if (existing)
|
||||
return existing;
|
||||
const name = forcedNames[i] ?? generatedName();
|
||||
element.style?.setProperty("view-transition-name", name);
|
||||
assigned.push(element);
|
||||
registry.set(element, name);
|
||||
tagClass(element, className, classed);
|
||||
applyGroup(element, name, group, grouped, clipChildren);
|
||||
return name;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Read every current name up front, before assigning any. Interleaving the
|
||||
* reads with the inline `setProperty` writes below would dirty styles
|
||||
* between reads and force a style recalc per element; batching the reads
|
||||
* keeps it to one. Elements already in the registry keep their name and
|
||||
* need no read.
|
||||
*/
|
||||
const currentNames = elements.map((element) => registry.has(element)
|
||||
? undefined
|
||||
: getComputedStyle(element).getPropertyValue("view-transition-name"));
|
||||
return elements.map((element, i) => {
|
||||
const existing = registry.get(element);
|
||||
if (existing)
|
||||
return existing;
|
||||
const current = currentNames[i];
|
||||
let name;
|
||||
if (current &&
|
||||
current !== "none" &&
|
||||
current !== "auto" &&
|
||||
current !== "match-element" &&
|
||||
!isGeneratedName(current)) {
|
||||
/**
|
||||
* The author already named this layer - target it as-is and leave
|
||||
* it to them to clean up. `auto`/`match-element` are overridden
|
||||
* because their generated name is not exposed to script, and a
|
||||
* stale `motion-view-*` (e.g. left by an interrupted transition) is
|
||||
* re-owned rather than adopted as an author name and leaked.
|
||||
*/
|
||||
name = current;
|
||||
}
|
||||
else {
|
||||
name = generatedName();
|
||||
element.style?.setProperty("view-transition-name", name);
|
||||
assigned.push(element);
|
||||
}
|
||||
registry.set(element, name);
|
||||
tagClass(element, className, classed);
|
||||
applyGroup(element, name, group, grouped, clipChildren);
|
||||
return name;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Remove the `view-transition-name`s we generated and the
|
||||
* `view-transition-class`es we applied. Author-defined names are never touched
|
||||
* (they're not in `assigned`). Safe to call more than once (e.g. on both a
|
||||
* finished and an interrupted transition).
|
||||
*/
|
||||
function releaseViewTransitionNames(assigned, classed = [], grouped = []) {
|
||||
for (const element of assigned) {
|
||||
element.style?.removeProperty("view-transition-name");
|
||||
}
|
||||
for (const element of classed) {
|
||||
element.style?.removeProperty("view-transition-class");
|
||||
}
|
||||
for (const element of grouped) {
|
||||
element.style?.removeProperty("view-transition-group");
|
||||
}
|
||||
}
|
||||
|
||||
export { assignViewTransitionNames, releaseViewTransitionNames };
|
||||
//# sourceMappingURL=assign-names.mjs.map
|
||||
+1
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
function chooseLayerType(valueName) {
|
||||
if (valueName === "layout")
|
||||
return "group";
|
||||
if (valueName === "enter" || valueName === "new")
|
||||
return "new";
|
||||
return "old";
|
||||
}
|
||||
|
||||
export { chooseLayerType };
|
||||
//# sourceMappingURL=choose-layer-type.mjs.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"choose-layer-type.mjs","sources":["../../../../src/view/utils/choose-layer-type.ts"],"sourcesContent":["export function chooseLayerType(\n valueName: \"layout\" | \"enter\" | \"exit\" | \"new\" | \"old\"\n): \"group\" | \"old\" | \"new\" {\n if (valueName === \"layout\") return \"group\"\n if (valueName === \"enter\" || valueName === \"new\") return \"new\"\n return \"old\"\n}\n"],"names":[],"mappings":"AAAM,SAAU,eAAe,CAC3B,SAAsD,EAAA;IAEtD,IAAI,SAAS,KAAK,QAAQ;AAAE,QAAA,OAAO,OAAO;AAC1C,IAAA,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,KAAK;AAAE,QAAA,OAAO,KAAK;AAC9D,IAAA,OAAO,KAAK;AAChB;;;;"}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
let pendingRules = {};
|
||||
let style = null;
|
||||
const css = {
|
||||
set: (selector, values) => {
|
||||
pendingRules[selector] = values;
|
||||
},
|
||||
commit: () => {
|
||||
if (!style) {
|
||||
style = document.createElement("style");
|
||||
style.id = "motion-view";
|
||||
}
|
||||
let cssText = "";
|
||||
for (const selector in pendingRules) {
|
||||
const rule = pendingRules[selector];
|
||||
cssText += `${selector} {\n`;
|
||||
for (const [property, value] of Object.entries(rule)) {
|
||||
cssText += ` ${property}: ${value};\n`;
|
||||
}
|
||||
cssText += "}\n";
|
||||
}
|
||||
style.textContent = cssText;
|
||||
document.head.appendChild(style);
|
||||
pendingRules = {};
|
||||
},
|
||||
remove: () => {
|
||||
if (style && style.parentElement) {
|
||||
style.parentElement.removeChild(style);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export { css };
|
||||
//# sourceMappingURL=css.mjs.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"css.mjs","sources":["../../../../src/view/utils/css.ts"],"sourcesContent":["let pendingRules: Record<string, Record<string, string>> = {}\n\nlet style: HTMLStyleElement | null = null\n\nexport const css = {\n set: (selector: string, values: Record<string, string>) => {\n pendingRules[selector] = values\n },\n\n commit: () => {\n if (!style) {\n style = document.createElement(\"style\")\n style.id = \"motion-view\"\n }\n\n let cssText = \"\"\n\n for (const selector in pendingRules) {\n const rule = pendingRules[selector]\n cssText += `${selector} {\\n`\n for (const [property, value] of Object.entries(rule)) {\n cssText += ` ${property}: ${value};\\n`\n }\n cssText += \"}\\n\"\n }\n\n style.textContent = cssText\n document.head.appendChild(style)\n\n pendingRules = {}\n },\n\n remove: () => {\n if (style && style.parentElement) {\n style.parentElement.removeChild(style)\n }\n },\n}\n"],"names":[],"mappings":"AAAA,IAAI,YAAY,GAA2C,EAAE;AAE7D,IAAI,KAAK,GAA4B,IAAI;AAElC,MAAM,GAAG,GAAG;AACf,IAAA,GAAG,EAAE,CAAC,QAAgB,EAAE,MAA8B,KAAI;AACtD,QAAA,YAAY,CAAC,QAAQ,CAAC,GAAG,MAAM;IACnC,CAAC;IAED,MAAM,EAAE,MAAK;QACT,IAAI,CAAC,KAAK,EAAE;AACR,YAAA,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACvC,YAAA,KAAK,CAAC,EAAE,GAAG,aAAa;QAC5B;QAEA,IAAI,OAAO,GAAG,EAAE;AAEhB,QAAA,KAAK,MAAM,QAAQ,IAAI,YAAY,EAAE;AACjC,YAAA,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC;AACnC,YAAA,OAAO,IAAI,CAAA,EAAG,QAAQ,CAAA,IAAA,CAAM;AAC5B,YAAA,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAClD,gBAAA,OAAO,IAAI,CAAA,EAAA,EAAK,QAAQ,CAAA,EAAA,EAAK,KAAK,KAAK;YAC3C;YACA,OAAO,IAAI,KAAK;QACpB;AAEA,QAAA,KAAK,CAAC,WAAW,GAAG,OAAO;AAC3B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAEhC,YAAY,GAAG,EAAE;IACrB,CAAC;IAED,MAAM,EAAE,MAAK;AACT,QAAA,IAAI,KAAK,IAAI,KAAK,CAAC,aAAa,EAAE;AAC9B,YAAA,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC;QAC1C;IACJ,CAAC;;;;;"}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
function getViewAnimationLayerInfo(pseudoElement) {
|
||||
const match = pseudoElement.match(
|
||||
// `group-children` (nested transitions) before `group` so it wins.
|
||||
/::view-transition-(old|new|group-children|group|image-pair)\((.*?)\)/);
|
||||
if (!match)
|
||||
return null;
|
||||
return { layer: match[2], type: match[1] };
|
||||
}
|
||||
|
||||
export { getViewAnimationLayerInfo };
|
||||
//# sourceMappingURL=get-layer-info.mjs.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"get-layer-info.mjs","sources":["../../../../src/view/utils/get-layer-info.ts"],"sourcesContent":["export function getViewAnimationLayerInfo(pseudoElement: string) {\n const match = pseudoElement.match(\n // `group-children` (nested transitions) before `group` so it wins.\n /::view-transition-(old|new|group-children|group|image-pair)\\((.*?)\\)/\n )\n if (!match) return null\n\n return { layer: match[2], type: match[1] }\n}\n"],"names":[],"mappings":"AAAM,SAAU,yBAAyB,CAAC,aAAqB,EAAA;AAC3D,IAAA,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK;;AAE7B,IAAA,sEAAsE,CACzE;AACD,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,IAAI;AAEvB,IAAA,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE;AAC9C;;;;"}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
function getViewAnimations() {
|
||||
return document.getAnimations().filter((animation) => {
|
||||
const { effect } = animation;
|
||||
return (!!effect &&
|
||||
effect.target === document.documentElement &&
|
||||
effect.pseudoElement?.startsWith("::view-transition"));
|
||||
});
|
||||
}
|
||||
|
||||
export { getViewAnimations };
|
||||
//# sourceMappingURL=get-view-animations.mjs.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"get-view-animations.mjs","sources":["../../../../src/view/utils/get-view-animations.ts"],"sourcesContent":["export function getViewAnimations() {\n return document.getAnimations().filter((animation) => {\n const { effect } = animation\n return (\n !!effect &&\n effect.target === document.documentElement &&\n (effect as KeyframeEffect).pseudoElement?.startsWith(\n \"::view-transition\"\n )\n )\n })\n}\n"],"names":[],"mappings":"SAAgB,iBAAiB,GAAA;IAC7B,OAAO,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,SAAS,KAAI;AACjD,QAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS;QAC5B,QACI,CAAC,CAAC,MAAM;AACR,YAAA,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,eAAe;YACzC,MAAyB,CAAC,aAAa,EAAE,UAAU,CAChD,mBAAmB,CACtB;AAET,IAAA,CAAC,CAAC;AACN;;;;"}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
function hasTarget(target, targets) {
|
||||
return targets.has(target) && Object.keys(targets.get(target)).length > 0;
|
||||
}
|
||||
|
||||
export { hasTarget };
|
||||
//# sourceMappingURL=has-target.mjs.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"has-target.mjs","sources":["../../../../src/view/utils/has-target.ts"],"sourcesContent":["import { ViewTransitionTarget, ViewTransitionTargetDefinition } from \"../types\"\n\nexport function hasTarget(\n target: ViewTransitionTargetDefinition,\n targets: Map<ViewTransitionTargetDefinition, ViewTransitionTarget>\n) {\n return targets.has(target) && Object.keys(targets.get(target)!).length > 0\n}\n"],"names":[],"mappings":"AAEM,SAAU,SAAS,CACrB,MAAsC,EACtC,OAAkE,EAAA;IAElE,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AAC9E;;;;"}
|
||||
Reference in New Issue
Block a user