mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-01 10:22:25 +00:00
Merge pull request #1207 from PR0M3TH3AN/codex/audit-and-refactor-.style-usages
Replace inline .style usage with CSS classes/variables and stylesheet-driven state
This commit is contained in:
14 files changed
+579
-224
No files matched your search
+71
-3
@@ -448,6 +448,11 @@
|
||||
.popover-panel,
|
||||
.popover__panel {
|
||||
@apply focus-ring pointer-events-none z-overlay-popover min-w-menu max-w-popover-safe scale-95 rounded-overlay border border-border border-opacity-40 bg-overlay-panel px-overlay-panel-inline py-overlay-panel-block text-sm text-text opacity-0 shadow-overlay-panel transition-opacity transition-transform duration-base ease-out;
|
||||
position: var(--popover-strategy, fixed);
|
||||
left: var(--popover-left, 0px);
|
||||
top: var(--popover-top, 0px);
|
||||
max-width: var(--popover-max-width, none);
|
||||
max-height: var(--popover-max-height, none);
|
||||
}
|
||||
|
||||
.popover-panel[data-state="open"],
|
||||
@@ -460,6 +465,13 @@
|
||||
@apply pointer-events-none scale-95 opacity-0;
|
||||
}
|
||||
|
||||
[data-popover-arrow="true"] {
|
||||
left: var(--popover-arrow-left, auto);
|
||||
right: var(--popover-arrow-right, auto);
|
||||
top: var(--popover-arrow-top, auto);
|
||||
bottom: var(--popover-arrow-bottom, auto);
|
||||
}
|
||||
|
||||
.p-overlay-panel {
|
||||
@apply px-overlay-panel-inline py-overlay-panel-block;
|
||||
}
|
||||
@@ -808,6 +820,10 @@
|
||||
@apply inline-flex flex-col items-start gap-sm rounded-xl border px-3 py-1.5 text-xs font-semibold normal-case tracking-tight shadow-sm;
|
||||
}
|
||||
|
||||
.moderation-badge--interactive {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.moderation-badge__actions {
|
||||
@apply inline-flex flex-nowrap items-center gap-sm;
|
||||
}
|
||||
@@ -2104,6 +2120,9 @@
|
||||
@apply relative block shrink-0 overflow-hidden rounded-lg bg-surface-alt;
|
||||
width: 168px;
|
||||
aspect-ratio: 16 / 9;
|
||||
background-image: var(--similar-card-thumb-url, none);
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@media (max-width: theme("screens.sm")) {
|
||||
@@ -2126,6 +2145,7 @@
|
||||
|
||||
.player-modal__similar-card-title {
|
||||
@apply text-sm font-semibold leading-snug text-text transition-colors duration-base ease-out;
|
||||
min-width: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
@@ -2160,6 +2180,7 @@
|
||||
|
||||
.player-modal__similar-card-meta {
|
||||
@apply flex flex-wrap items-center gap-1 text-2xs text-muted-strong;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.player-modal__similar-card-timestamp {
|
||||
@@ -2442,6 +2463,8 @@
|
||||
inset-block-start: 0;
|
||||
block-size: 100%;
|
||||
max-inline-size: 100%;
|
||||
inline-size: var(--video-modal-reaction-fill, 0%);
|
||||
width: var(--video-modal-reaction-fill, 0%);
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
var(--color-accent) 0%,
|
||||
@@ -3338,6 +3361,7 @@
|
||||
.qr-code__table {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
margin: var(--qr-code-table-margin, 0);
|
||||
}
|
||||
|
||||
.qr-code__cell {
|
||||
@@ -3354,6 +3378,22 @@
|
||||
background-color: var(--qr-code-color-dark);
|
||||
}
|
||||
|
||||
.qr-code__container[data-qr-code-mode="image"] .qr-code__canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.qr-code__container[data-qr-code-mode="image"] .qr-code__image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.qr-code__container[data-qr-code-mode="canvas"] .qr-code__canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.qr-code__container[data-qr-code-mode="canvas"] .qr-code__image {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
animation: interface-fade-in 280ms ease-out forwards;
|
||||
@@ -3568,18 +3608,26 @@
|
||||
z-index: var(--z-modal-content);
|
||||
}
|
||||
|
||||
#modalContainer > #profileModal {
|
||||
#modalContainer > #profileModal,
|
||||
#profileModal[data-modal-stack="top"] {
|
||||
z-index: var(--z-modal-top-root);
|
||||
}
|
||||
|
||||
#modalContainer > #profileModal > .bv-modal-backdrop {
|
||||
#modalContainer > #profileModal > .bv-modal-backdrop,
|
||||
#profileModal[data-modal-stack="top"] > .bv-modal-backdrop {
|
||||
z-index: var(--z-modal-top-overlay);
|
||||
}
|
||||
|
||||
#modalContainer > #profileModal .bv-modal__panel {
|
||||
#modalContainer > #profileModal .bv-modal__panel,
|
||||
#profileModal[data-modal-stack="top"] .bv-modal__panel {
|
||||
z-index: var(--z-modal-top-content);
|
||||
}
|
||||
|
||||
.bv-modal[data-nested-modal-active="true"] {
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#modalContainer > #loginModal {
|
||||
z-index: var(--z-modal-peak-root);
|
||||
}
|
||||
@@ -4389,6 +4437,26 @@
|
||||
scrollbar-gutter: stable both-edges;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel__inner.is-measuring {
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
max-width: none;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
left: -9999px;
|
||||
right: auto;
|
||||
top: auto;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.sidebar-dropup-measure {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel__inner > * {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
|
||||
@@ -34,6 +34,16 @@
|
||||
color: #cbd5f5;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.fixture-toggle {
|
||||
margin-top: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: #cbd5f5;
|
||||
}
|
||||
.fixture-toggle__label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-ds="new">
|
||||
@@ -581,14 +591,10 @@
|
||||
|
||||
if (fixture.blockToggle && fixture.blockToggle.pubkey) {
|
||||
const toggleWrapper = document.createElement("div");
|
||||
toggleWrapper.style.marginTop = "0.75rem";
|
||||
toggleWrapper.style.fontSize = "0.875rem";
|
||||
toggleWrapper.style.color = "#cbd5f5";
|
||||
toggleWrapper.classList.add("fixture-toggle");
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.style.display = "inline-flex";
|
||||
label.style.alignItems = "center";
|
||||
label.style.gap = "0.5rem";
|
||||
label.classList.add("fixture-toggle__label");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "checkbox";
|
||||
|
||||
+48
-4
@@ -90,6 +90,53 @@ const channelModerationBadgeState = {
|
||||
};
|
||||
|
||||
const channelVideoCardsById = new Map();
|
||||
let channelBannerStyleCounter = 0;
|
||||
const channelBannerStyleRegistry = new WeakMap();
|
||||
|
||||
function getChannelBannerStyleState(doc) {
|
||||
if (!doc || typeof doc.createElement !== "function") {
|
||||
return null;
|
||||
}
|
||||
const existing = channelBannerStyleRegistry.get(doc);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
let styleNode = doc.getElementById?.("channelBannerStyles") || null;
|
||||
if (!(styleNode instanceof HTMLStyleElement)) {
|
||||
styleNode = doc.createElement("style");
|
||||
styleNode.id = "channelBannerStyles";
|
||||
doc.head?.appendChild(styleNode);
|
||||
}
|
||||
const state = {
|
||||
styleNode,
|
||||
rules: new Map(),
|
||||
};
|
||||
channelBannerStyleRegistry.set(doc, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
function updateChannelBannerBackground(el, url) {
|
||||
const doc = el?.ownerDocument || (typeof document !== "undefined" ? document : null);
|
||||
const state = getChannelBannerStyleState(doc);
|
||||
if (!state || !el) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!el.dataset.channelBannerStyleId) {
|
||||
channelBannerStyleCounter += 1;
|
||||
el.dataset.channelBannerStyleId = `channel-banner-${channelBannerStyleCounter}`;
|
||||
}
|
||||
const selector = `[data-channel-banner-style-id="${el.dataset.channelBannerStyleId}"]`;
|
||||
|
||||
if (url) {
|
||||
const escaped = url.replace(/(["\\])/g, "\\$1");
|
||||
state.rules.set(selector, `${selector} { background-image: url("${escaped}"); }`);
|
||||
} else {
|
||||
state.rules.set(selector, `${selector} { background-image: none; }`);
|
||||
}
|
||||
|
||||
state.styleNode.textContent = [...state.rules.values()].join("\n");
|
||||
}
|
||||
|
||||
export function clearChannelVideoCardRegistry() {
|
||||
channelVideoCardsById.clear();
|
||||
@@ -1432,10 +1479,7 @@ function setBannerVisual(el, url, { referrerPolicy } = {}) {
|
||||
el.src = resolvedUrl;
|
||||
}
|
||||
} else {
|
||||
const value = resolvedUrl ? `url("${resolvedUrl}")` : "";
|
||||
if (el.style.backgroundImage !== value) {
|
||||
el.style.backgroundImage = value;
|
||||
}
|
||||
updateChannelBannerBackground(el, resolvedUrl || "");
|
||||
}
|
||||
|
||||
if (el.dataset.bannerSrc !== resolvedUrl) {
|
||||
|
||||
+55
-46
@@ -885,22 +885,67 @@ async function bootstrapInterface() {
|
||||
};
|
||||
};
|
||||
|
||||
const sidebarDropupStyleState = (() => {
|
||||
let styleNode = null;
|
||||
let rootWidthRule = "";
|
||||
const measureRules = new Map();
|
||||
|
||||
const ensureStyleNode = () => {
|
||||
if (styleNode && styleNode.isConnected) {
|
||||
return styleNode;
|
||||
}
|
||||
styleNode = document.getElementById("sidebarDropupStyles");
|
||||
if (!(styleNode instanceof HTMLStyleElement)) {
|
||||
styleNode = document.createElement("style");
|
||||
styleNode.id = "sidebarDropupStyles";
|
||||
document.head.appendChild(styleNode);
|
||||
}
|
||||
return styleNode;
|
||||
};
|
||||
|
||||
const updateStyles = () => {
|
||||
const node = ensureStyleNode();
|
||||
const rules = [rootWidthRule, ...measureRules.values()].filter(Boolean);
|
||||
node.textContent = rules.join("\n");
|
||||
};
|
||||
|
||||
return {
|
||||
setRootWidth: (value) => {
|
||||
rootWidthRule = `:root { --sidebar-dropup-content-width: ${value}; }`;
|
||||
updateStyles();
|
||||
},
|
||||
setMeasureWidth: (id, value) => {
|
||||
measureRules.set(
|
||||
id,
|
||||
`.sidebar-dropup-measure[data-measure-id="${id}"] { width: ${value}; }`,
|
||||
);
|
||||
updateStyles();
|
||||
},
|
||||
clearMeasure: (id) => {
|
||||
measureRules.delete(id);
|
||||
updateStyles();
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
let sidebarDropupMeasureId = 0;
|
||||
|
||||
const resolveCssLengthToPixels = (value, container) => {
|
||||
if (!(container instanceof HTMLElement) || typeof value !== "string") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const measurementNode = container.ownerDocument.createElement("div");
|
||||
measurementNode.style.position = "absolute";
|
||||
measurementNode.style.visibility = "hidden";
|
||||
measurementNode.style.pointerEvents = "none";
|
||||
measurementNode.style.height = "0";
|
||||
measurementNode.style.width = value;
|
||||
measurementNode.style.overflow = "hidden";
|
||||
sidebarDropupMeasureId += 1;
|
||||
const measureId = `sidebar-dropup-measure-${sidebarDropupMeasureId}`;
|
||||
measurementNode.classList.add("sidebar-dropup-measure");
|
||||
measurementNode.dataset.measureId = measureId;
|
||||
sidebarDropupStyleState.setMeasureWidth(measureId, value);
|
||||
|
||||
container.appendChild(measurementNode);
|
||||
const pixels = measurementNode.getBoundingClientRect().width;
|
||||
container.removeChild(measurementNode);
|
||||
sidebarDropupStyleState.clearMeasure(measureId);
|
||||
|
||||
return Number.isFinite(pixels) ? pixels : 0;
|
||||
};
|
||||
@@ -910,46 +955,13 @@ async function bootstrapInterface() {
|
||||
const panel = panelInner?.closest(".sidebar-dropup-panel");
|
||||
|
||||
if (!(panelInner instanceof HTMLElement) || !(panel instanceof HTMLElement)) {
|
||||
document.documentElement.style.setProperty(
|
||||
"--sidebar-dropup-content-width",
|
||||
"0px",
|
||||
);
|
||||
sidebarDropupStyleState.setRootWidth("0px");
|
||||
return;
|
||||
}
|
||||
|
||||
const originalStyles = {
|
||||
position: panelInner.style.position,
|
||||
width: panelInner.style.width,
|
||||
maxWidth: panelInner.style.maxWidth,
|
||||
visibility: panelInner.style.visibility,
|
||||
pointerEvents: panelInner.style.pointerEvents,
|
||||
left: panelInner.style.left,
|
||||
right: panelInner.style.right,
|
||||
top: panelInner.style.top,
|
||||
bottom: panelInner.style.bottom,
|
||||
};
|
||||
|
||||
panelInner.style.position = "absolute";
|
||||
panelInner.style.width = "max-content";
|
||||
panelInner.style.maxWidth = "none";
|
||||
panelInner.style.visibility = "hidden";
|
||||
panelInner.style.pointerEvents = "none";
|
||||
panelInner.style.left = "-9999px";
|
||||
panelInner.style.right = "auto";
|
||||
panelInner.style.top = "auto";
|
||||
panelInner.style.bottom = "auto";
|
||||
|
||||
panelInner.classList.add("is-measuring");
|
||||
const measuredInnerWidth = Math.ceil(panelInner.scrollWidth);
|
||||
|
||||
panelInner.style.position = originalStyles.position;
|
||||
panelInner.style.width = originalStyles.width;
|
||||
panelInner.style.maxWidth = originalStyles.maxWidth;
|
||||
panelInner.style.visibility = originalStyles.visibility;
|
||||
panelInner.style.pointerEvents = originalStyles.pointerEvents;
|
||||
panelInner.style.left = originalStyles.left;
|
||||
panelInner.style.right = originalStyles.right;
|
||||
panelInner.style.top = originalStyles.top;
|
||||
panelInner.style.bottom = originalStyles.bottom;
|
||||
panelInner.classList.remove("is-measuring");
|
||||
|
||||
const panelStyles = window.getComputedStyle(panel);
|
||||
const paddingInlineStart = Number.parseFloat(panelStyles.paddingInlineStart) || 0;
|
||||
@@ -965,10 +977,7 @@ async function bootstrapInterface() {
|
||||
measuredInnerWidth + paddingInlineStart + paddingInlineEnd + scrollReserve,
|
||||
);
|
||||
|
||||
document.documentElement.style.setProperty(
|
||||
"--sidebar-dropup-content-width",
|
||||
`${Math.ceil(totalWidth)}px`,
|
||||
);
|
||||
sidebarDropupStyleState.setRootWidth(`${Math.ceil(totalWidth)}px`);
|
||||
};
|
||||
|
||||
const debouncedSidebarDropupResize = debounce(updateSidebarDropupContentWidth, 150);
|
||||
|
||||
@@ -6,6 +6,48 @@ import { buildModerationBadgeText } from "../moderationCopy.js";
|
||||
|
||||
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
||||
const DEFAULT_PROFILE_AVATAR = "assets/svg/default-profile.svg";
|
||||
let similarCardIdCounter = 0;
|
||||
const similarCardStyleRegistry = new WeakMap();
|
||||
|
||||
function getSimilarCardStyleState(doc) {
|
||||
if (!doc || typeof doc.createElement !== "function") {
|
||||
return null;
|
||||
}
|
||||
const existing = similarCardStyleRegistry.get(doc);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
let styleNode = doc.getElementById?.("similarContentCardStyles") || null;
|
||||
if (!(styleNode instanceof HTMLStyleElement)) {
|
||||
styleNode = doc.createElement("style");
|
||||
styleNode.id = "similarContentCardStyles";
|
||||
doc.head?.appendChild(styleNode);
|
||||
}
|
||||
const state = {
|
||||
styleNode,
|
||||
rules: new Map(),
|
||||
};
|
||||
similarCardStyleRegistry.set(doc, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
function updateSimilarCardBackdrop(doc, cardId, url) {
|
||||
const state = getSimilarCardStyleState(doc);
|
||||
if (!state || !cardId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
state.rules.set(
|
||||
cardId,
|
||||
`[data-similar-card-id="${cardId}"] { --similar-card-thumb-url: url("${url}"); }`,
|
||||
);
|
||||
} else {
|
||||
state.rules.delete(cardId);
|
||||
}
|
||||
|
||||
state.styleNode.textContent = [...state.rules.values()].join("\n");
|
||||
}
|
||||
|
||||
export class SimilarContentCard {
|
||||
constructor({
|
||||
@@ -60,6 +102,7 @@ export class SimilarContentCard {
|
||||
this.callbacks = { onPlay: null };
|
||||
|
||||
this.root = null;
|
||||
this.cardStyleId = "";
|
||||
this.mediaLinkEl = null;
|
||||
this.thumbnailEl = null;
|
||||
this.contentEl = null;
|
||||
@@ -330,6 +373,9 @@ export class SimilarContentCard {
|
||||
if (this.video.id) {
|
||||
root.dataset.videoId = this.video.id;
|
||||
}
|
||||
similarCardIdCounter += 1;
|
||||
this.cardStyleId = `similar-card-${similarCardIdCounter}`;
|
||||
root.dataset.similarCardId = this.cardStyleId;
|
||||
const dsMode = this.designSystem?.getMode?.();
|
||||
if (dsMode) {
|
||||
root.setAttribute("data-ds", dsMode);
|
||||
@@ -378,14 +424,11 @@ export class SimilarContentCard {
|
||||
}
|
||||
|
||||
const badge = this.document.createElement("div");
|
||||
badge.className = "moderation-badge opacity-95";
|
||||
badge.className = "moderation-badge moderation-badge--interactive opacity-95";
|
||||
badge.dataset.variant = "warning";
|
||||
badge.dataset.moderationBadge = "true";
|
||||
badge.dataset.moderationState = "trusted-mute";
|
||||
|
||||
// Position it centrally over the thumbnail like in VideoCard
|
||||
badge.style.pointerEvents = "auto";
|
||||
|
||||
const label = this.document.createElement("span");
|
||||
label.className = "moderation-badge__label inline-flex items-center gap-xs";
|
||||
|
||||
@@ -556,14 +599,12 @@ export class SimilarContentCard {
|
||||
buildContentSection() {
|
||||
const content = this.document.createElement("div");
|
||||
content.classList.add("player-modal__similar-card-content");
|
||||
content.style.minWidth = "0";
|
||||
|
||||
const titleLink = this.document.createElement("a");
|
||||
titleLink.classList.add("player-modal__similar-card-title");
|
||||
titleLink.href = this.shareUrl;
|
||||
titleLink.textContent = this.video.title || "Untitled";
|
||||
titleLink.title = this.video.title || "Untitled";
|
||||
titleLink.style.minWidth = "0";
|
||||
|
||||
const authorStack = this.buildAuthorStack();
|
||||
const metaRow = this.buildMetaRow();
|
||||
@@ -588,11 +629,9 @@ export class SimilarContentCard {
|
||||
buildAuthorStack() {
|
||||
const wrapper = this.document.createElement("div");
|
||||
wrapper.classList.add("player-modal__similar-card-author");
|
||||
wrapper.style.minWidth = "0";
|
||||
|
||||
const textWrapper = this.document.createElement("span");
|
||||
textWrapper.classList.add("player-modal__similar-card-author-meta");
|
||||
textWrapper.style.minWidth = "0";
|
||||
|
||||
const nameEl = this.document.createElement("span");
|
||||
nameEl.classList.add("author-name", "player-modal__similar-card-author-name");
|
||||
@@ -653,7 +692,6 @@ export class SimilarContentCard {
|
||||
buildMetaRow() {
|
||||
const row = this.document.createElement("div");
|
||||
row.classList.add("player-modal__similar-card-meta");
|
||||
row.style.minWidth = "0";
|
||||
|
||||
const timeEl = this.document.createElement("time");
|
||||
timeEl.classList.add("player-modal__similar-card-timestamp");
|
||||
@@ -870,12 +908,10 @@ export class SimilarContentCard {
|
||||
}
|
||||
|
||||
setCardBackdropImage(src) {
|
||||
if (!this.root || !this.root.style) {
|
||||
if (!this.root || !this.cardStyleId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const style = this.root.style;
|
||||
|
||||
const normalizeSource = (raw) => {
|
||||
if (typeof raw !== "string") {
|
||||
return "";
|
||||
@@ -919,12 +955,9 @@ export class SimilarContentCard {
|
||||
const sanitized = normalizeSource(src);
|
||||
if (sanitized) {
|
||||
const escaped = sanitized.replace(/(["\\])/g, "\\$1");
|
||||
style.setProperty(
|
||||
"--similar-card-thumb-url",
|
||||
`url("${escaped}")`
|
||||
);
|
||||
updateSimilarCardBackdrop(this.document, this.cardStyleId, escaped);
|
||||
} else {
|
||||
style.removeProperty("--similar-card-thumb-url");
|
||||
updateSimilarCardBackdrop(this.document, this.cardStyleId, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,6 +153,7 @@ export class VideoModal {
|
||||
"+": null,
|
||||
"-": null,
|
||||
};
|
||||
this.reactionMeterStyleNode = null;
|
||||
this.reactionState = {
|
||||
counts: { "+": 0, "-": 0 },
|
||||
total: 0,
|
||||
@@ -3116,9 +3117,32 @@ export class VideoModal {
|
||||
this.reactionMeterAssistive.textContent = assistiveLabel;
|
||||
}
|
||||
|
||||
if (this.reactionMeterFill) {
|
||||
this.reactionMeterFill.style.inlineSize = `${likeRatio}%`;
|
||||
this.reactionMeterFill.style.width = `${likeRatio}%`;
|
||||
this.updateReactionMeterFill(likeRatio);
|
||||
}
|
||||
|
||||
updateReactionMeterFill(likeRatio) {
|
||||
const doc = this.playerModal?.ownerDocument || this.document;
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clamped = Math.max(0, Math.min(100, Math.round(likeRatio)));
|
||||
const widthValue = `${clamped}%`;
|
||||
if (!this.reactionMeterStyleNode || !this.reactionMeterStyleNode.isConnected) {
|
||||
const existing = doc.getElementById?.("videoModalReactionStyles");
|
||||
if (existing instanceof HTMLStyleElement) {
|
||||
this.reactionMeterStyleNode = existing;
|
||||
} else {
|
||||
const styleNode = doc.createElement("style");
|
||||
styleNode.id = "videoModalReactionStyles";
|
||||
doc.head?.appendChild(styleNode);
|
||||
this.reactionMeterStyleNode = styleNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.reactionMeterStyleNode) {
|
||||
this.reactionMeterStyleNode.textContent =
|
||||
`#playerModal { --video-modal-reaction-fill: ${widthValue}; }`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4021,9 +4045,6 @@ export class VideoModal {
|
||||
this.videoTitle.textContent = titleText;
|
||||
// Ensure element is visible
|
||||
this.videoTitle.hidden = false;
|
||||
if (this.videoTitle.style) {
|
||||
this.videoTitle.style.display = "";
|
||||
}
|
||||
} else {
|
||||
// Log for debugging if element cannot be found
|
||||
this.logger?.log?.(
|
||||
|
||||
+140
-19
@@ -20,6 +20,7 @@ const DEFAULT_MAX_WIDTH_TOKEN = "--popover-inline-safe-max";
|
||||
const MENU_TYPEAHEAD_RESET_MS = 500;
|
||||
|
||||
let popoverPanelIdCounter = 0;
|
||||
let popoverArrowIdCounter = 0;
|
||||
|
||||
let activePopoverInstance = null;
|
||||
|
||||
@@ -115,22 +116,39 @@ function resolveArrow(option, panel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function applyArrowStyles({ arrowElement, placement, middlewareData }) {
|
||||
function ensureArrowId(arrowElement) {
|
||||
if (!arrowElement) {
|
||||
return "";
|
||||
}
|
||||
if (arrowElement.id) {
|
||||
return arrowElement.id;
|
||||
}
|
||||
popoverArrowIdCounter += 1;
|
||||
const arrowId = `popover-arrow-${popoverArrowIdCounter}`;
|
||||
arrowElement.id = arrowId;
|
||||
return arrowId;
|
||||
}
|
||||
|
||||
function buildArrowStyleState({ arrowElement, placement, middlewareData }) {
|
||||
const state = {
|
||||
basePlacement: "",
|
||||
values: {
|
||||
left: "auto",
|
||||
right: "auto",
|
||||
top: "auto",
|
||||
bottom: "auto",
|
||||
},
|
||||
};
|
||||
|
||||
if (!arrowElement || typeof placement !== "string") {
|
||||
return;
|
||||
return state;
|
||||
}
|
||||
|
||||
const basePlacement = placement.split("-")[0];
|
||||
const arrowData = middlewareData?.arrow || null;
|
||||
|
||||
arrowElement.style.left = "";
|
||||
arrowElement.style.right = "";
|
||||
arrowElement.style.top = "";
|
||||
arrowElement.style.bottom = "";
|
||||
|
||||
if (!arrowData || !basePlacement) {
|
||||
delete arrowElement.dataset.popoverArrowSide;
|
||||
return;
|
||||
return state;
|
||||
}
|
||||
|
||||
const staticSideMap = {
|
||||
@@ -141,11 +159,11 @@ function applyArrowStyles({ arrowElement, placement, middlewareData }) {
|
||||
};
|
||||
|
||||
if (Number.isFinite(arrowData.x)) {
|
||||
arrowElement.style.left = `${Math.round(arrowData.x)}px`;
|
||||
state.values.left = `${Math.round(arrowData.x)}px`;
|
||||
}
|
||||
|
||||
if (Number.isFinite(arrowData.y)) {
|
||||
arrowElement.style.top = `${Math.round(arrowData.y)}px`;
|
||||
state.values.top = `${Math.round(arrowData.y)}px`;
|
||||
}
|
||||
|
||||
const staticSide = staticSideMap[basePlacement] || null;
|
||||
@@ -161,10 +179,11 @@ function applyArrowStyles({ arrowElement, placement, middlewareData }) {
|
||||
basePlacement === "top" || basePlacement === "bottom"
|
||||
? arrowHeight
|
||||
: arrowWidth;
|
||||
arrowElement.style[staticSide] = `${-Math.round(offsetValue)}px`;
|
||||
state.values[staticSide] = `${-Math.round(offsetValue)}px`;
|
||||
}
|
||||
|
||||
arrowElement.dataset.popoverArrowSide = basePlacement;
|
||||
state.basePlacement = basePlacement;
|
||||
return state;
|
||||
}
|
||||
|
||||
function containsTarget(root, target) {
|
||||
@@ -238,6 +257,67 @@ export function createPopover(trigger, render, options = {}) {
|
||||
typeaheadBuffer: "",
|
||||
typeaheadTimeout: null,
|
||||
};
|
||||
let popoverStyleNode = null;
|
||||
let arrowStyleState = {
|
||||
left: "auto",
|
||||
right: "auto",
|
||||
top: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
let panelStyleState = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
strategy,
|
||||
maxWidth: "none",
|
||||
maxHeight: "none",
|
||||
};
|
||||
let arrowId = "";
|
||||
|
||||
function ensurePopoverStyleNode(panelId) {
|
||||
if (popoverStyleNode && popoverStyleNode.isConnected) {
|
||||
return popoverStyleNode;
|
||||
}
|
||||
const styleId = `popover-style-${panelId}`;
|
||||
const existing = documentRef?.getElementById?.(styleId) || null;
|
||||
if (existing instanceof HTMLStyleElement) {
|
||||
popoverStyleNode = existing;
|
||||
return popoverStyleNode;
|
||||
}
|
||||
if (!documentRef?.createElement) {
|
||||
return null;
|
||||
}
|
||||
const styleNode = documentRef.createElement("style");
|
||||
styleNode.id = styleId;
|
||||
documentRef.head?.appendChild(styleNode);
|
||||
popoverStyleNode = styleNode;
|
||||
return popoverStyleNode;
|
||||
}
|
||||
|
||||
function syncPopoverStyles() {
|
||||
if (!panel || !panel.id) {
|
||||
return;
|
||||
}
|
||||
const styleNode = ensurePopoverStyleNode(panel.id);
|
||||
if (!styleNode) {
|
||||
return;
|
||||
}
|
||||
const panelRule = `#${panel.id}{` +
|
||||
`--popover-left:${Math.round(panelStyleState.left)}px;` +
|
||||
`--popover-top:${Math.round(panelStyleState.top)}px;` +
|
||||
`--popover-strategy:${panelStyleState.strategy || strategy};` +
|
||||
`--popover-max-width:${panelStyleState.maxWidth || "none"};` +
|
||||
`--popover-max-height:${panelStyleState.maxHeight || "none"};` +
|
||||
`}`;
|
||||
const arrowRule = arrowId
|
||||
? `#${arrowId}{` +
|
||||
`--popover-arrow-left:${arrowStyleState.left};` +
|
||||
`--popover-arrow-right:${arrowStyleState.right};` +
|
||||
`--popover-arrow-top:${arrowStyleState.top};` +
|
||||
`--popover-arrow-bottom:${arrowStyleState.bottom};` +
|
||||
`}`
|
||||
: "";
|
||||
styleNode.textContent = [panelRule, arrowRule].filter(Boolean).join("\n");
|
||||
}
|
||||
|
||||
function getView() {
|
||||
return documentRef?.defaultView || globalThis;
|
||||
@@ -610,13 +690,21 @@ export function createPopover(trigger, render, options = {}) {
|
||||
|
||||
if (maxWidthToken) {
|
||||
const widthValue = resolveTokenValue(maxWidthToken, documentRef);
|
||||
panel.style.maxWidth = widthValue || "";
|
||||
panelStyleState = {
|
||||
...panelStyleState,
|
||||
maxWidth: widthValue || "none",
|
||||
};
|
||||
}
|
||||
|
||||
if (maxHeightToken) {
|
||||
const heightValue = resolveTokenValue(maxHeightToken, documentRef);
|
||||
panel.style.maxHeight = heightValue || "";
|
||||
panelStyleState = {
|
||||
...panelStyleState,
|
||||
maxHeight: heightValue || "none",
|
||||
};
|
||||
}
|
||||
|
||||
syncPopoverStyles();
|
||||
}
|
||||
|
||||
function ensurePanel() {
|
||||
@@ -672,6 +760,12 @@ export function createPopover(trigger, render, options = {}) {
|
||||
|
||||
applyPanelTokens();
|
||||
|
||||
if (arrowElement) {
|
||||
arrowElement.dataset.popoverArrow = "true";
|
||||
arrowId = ensureArrowId(arrowElement);
|
||||
syncPopoverStyles();
|
||||
}
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@@ -720,18 +814,39 @@ export function createPopover(trigger, render, options = {}) {
|
||||
? resolvedPlacement
|
||||
: placement;
|
||||
|
||||
panel.style.position = resolvedStrategy || strategy;
|
||||
panel.style.left = `${Math.round(nextX)}px`;
|
||||
panel.style.top = `${Math.round(nextY)}px`;
|
||||
panelStyleState = {
|
||||
...panelStyleState,
|
||||
left: nextX,
|
||||
top: nextY,
|
||||
strategy: resolvedStrategy || strategy,
|
||||
};
|
||||
panel.dataset.popoverPlacement = finalPlacement;
|
||||
|
||||
if (arrowElement) {
|
||||
applyArrowStyles({
|
||||
const arrowState = buildArrowStyleState({
|
||||
arrowElement,
|
||||
placement: finalPlacement,
|
||||
middlewareData,
|
||||
});
|
||||
arrowStyleState = { ...arrowState.values };
|
||||
if (arrowState.basePlacement) {
|
||||
arrowElement.dataset.popoverArrowSide = arrowState.basePlacement;
|
||||
} else {
|
||||
delete arrowElement.dataset.popoverArrowSide;
|
||||
}
|
||||
arrowElement.dataset.popoverArrow = "true";
|
||||
arrowId = ensureArrowId(arrowElement);
|
||||
} else {
|
||||
arrowStyleState = {
|
||||
left: "auto",
|
||||
right: "auto",
|
||||
top: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
arrowId = "";
|
||||
}
|
||||
|
||||
syncPopoverStyles();
|
||||
} catch (error) {
|
||||
logger.user.error("[popover] positioning failed", error);
|
||||
}
|
||||
@@ -908,8 +1023,14 @@ export function createPopover(trigger, render, options = {}) {
|
||||
portal.parentNode.removeChild(portal);
|
||||
}
|
||||
|
||||
if (popoverStyleNode?.parentNode) {
|
||||
popoverStyleNode.parentNode.removeChild(popoverStyleNode);
|
||||
}
|
||||
|
||||
panel = null;
|
||||
arrowElement = null;
|
||||
popoverStyleNode = null;
|
||||
arrowId = "";
|
||||
|
||||
if (anchor) {
|
||||
anchor.removeAttribute("aria-controls");
|
||||
|
||||
@@ -1135,8 +1135,7 @@ export class ProfileModalController {
|
||||
this.focusTrapSuspended = false;
|
||||
this.focusTrapSuspendCount = 0;
|
||||
this.focusTrapAriaHiddenBeforeSuspend = null;
|
||||
this.focusTrapPointerEventsBeforeSuspend = null;
|
||||
this.focusTrapVisibilityBeforeSuspend = null;
|
||||
this.focusTrapNestedModalActiveBeforeSuspend = null;
|
||||
this.profileSwitcherSelectionPubkey = null;
|
||||
this.previouslyFocusedElement = null;
|
||||
this.largeLayoutQuery = null;
|
||||
@@ -8332,25 +8331,16 @@ export class ProfileModalController {
|
||||
this.focusTrapAriaHiddenBeforeSuspend = modalRoot.getAttribute(
|
||||
"aria-hidden",
|
||||
);
|
||||
this.focusTrapPointerEventsBeforeSuspend =
|
||||
typeof modalRoot.style.pointerEvents === "string" &&
|
||||
modalRoot.style.pointerEvents
|
||||
? modalRoot.style.pointerEvents
|
||||
: null;
|
||||
this.focusTrapVisibilityBeforeSuspend =
|
||||
typeof modalRoot.style.visibility === "string" &&
|
||||
modalRoot.style.visibility
|
||||
? modalRoot.style.visibility
|
||||
this.focusTrapNestedModalActiveBeforeSuspend =
|
||||
typeof modalRoot.dataset.nestedModalActive === "string"
|
||||
? modalRoot.dataset.nestedModalActive
|
||||
: null;
|
||||
|
||||
modalRoot.dataset.nestedModalActive = "true";
|
||||
modalRoot.setAttribute("aria-hidden", "true");
|
||||
modalRoot.style.setProperty("pointer-events", "none");
|
||||
modalRoot.style.setProperty("visibility", "hidden");
|
||||
} else {
|
||||
this.focusTrapAriaHiddenBeforeSuspend = null;
|
||||
this.focusTrapPointerEventsBeforeSuspend = null;
|
||||
this.focusTrapVisibilityBeforeSuspend = null;
|
||||
this.focusTrapNestedModalActiveBeforeSuspend = null;
|
||||
}
|
||||
|
||||
const panel = this.getModalPanelElement();
|
||||
@@ -8391,30 +8381,11 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.focusTrapPointerEventsBeforeSuspend === null ||
|
||||
this.focusTrapPointerEventsBeforeSuspend === undefined ||
|
||||
this.focusTrapPointerEventsBeforeSuspend === ""
|
||||
) {
|
||||
modalRoot.style.removeProperty("pointer-events");
|
||||
if (this.focusTrapNestedModalActiveBeforeSuspend === null) {
|
||||
delete modalRoot.dataset.nestedModalActive;
|
||||
} else {
|
||||
modalRoot.style.setProperty(
|
||||
"pointer-events",
|
||||
this.focusTrapPointerEventsBeforeSuspend,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.focusTrapVisibilityBeforeSuspend === null ||
|
||||
this.focusTrapVisibilityBeforeSuspend === undefined ||
|
||||
this.focusTrapVisibilityBeforeSuspend === ""
|
||||
) {
|
||||
modalRoot.style.removeProperty("visibility");
|
||||
} else {
|
||||
modalRoot.style.setProperty(
|
||||
"visibility",
|
||||
this.focusTrapVisibilityBeforeSuspend,
|
||||
);
|
||||
modalRoot.dataset.nestedModalActive =
|
||||
this.focusTrapNestedModalActiveBeforeSuspend;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8424,8 +8395,7 @@ export class ProfileModalController {
|
||||
}
|
||||
|
||||
this.focusTrapAriaHiddenBeforeSuspend = null;
|
||||
this.focusTrapPointerEventsBeforeSuspend = null;
|
||||
this.focusTrapVisibilityBeforeSuspend = null;
|
||||
this.focusTrapNestedModalActiveBeforeSuspend = null;
|
||||
|
||||
this.updateFocusTrap();
|
||||
|
||||
@@ -8503,21 +8473,7 @@ export class ProfileModalController {
|
||||
: null;
|
||||
|
||||
if (modalRoot) {
|
||||
modalRoot.style.setProperty("z-index", "var(--z-modal-top-root)");
|
||||
}
|
||||
|
||||
if (this.profileModalBackdrop instanceof HTMLElement) {
|
||||
this.profileModalBackdrop.style.setProperty(
|
||||
"z-index",
|
||||
"var(--z-modal-top-overlay)",
|
||||
);
|
||||
}
|
||||
|
||||
if (this.profileModalPanel instanceof HTMLElement) {
|
||||
this.profileModalPanel.style.setProperty(
|
||||
"z-index",
|
||||
"var(--z-modal-top-content)",
|
||||
);
|
||||
modalRoot.dataset.modalStack = "top";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8685,8 +8641,7 @@ export class ProfileModalController {
|
||||
modalElement.classList.add("hidden");
|
||||
modalElement.setAttribute("aria-hidden", "true");
|
||||
delete modalElement.dataset.nestedModalActive;
|
||||
modalElement.style.removeProperty("pointer-events");
|
||||
modalElement.style.removeProperty("visibility");
|
||||
delete modalElement.dataset.modalStack;
|
||||
this.setGlobalModalState("profile", false);
|
||||
this.setMobileView("menu", { skipFocusTrap: true });
|
||||
|
||||
@@ -8712,8 +8667,7 @@ export class ProfileModalController {
|
||||
this.focusTrapSuspendCount = 0;
|
||||
this.focusTrapSuspended = false;
|
||||
this.focusTrapAriaHiddenBeforeSuspend = null;
|
||||
this.focusTrapPointerEventsBeforeSuspend = null;
|
||||
this.focusTrapVisibilityBeforeSuspend = null;
|
||||
this.focusTrapNestedModalActiveBeforeSuspend = null;
|
||||
|
||||
if (
|
||||
this.boundProfileHistoryVisibility &&
|
||||
|
||||
+107
-9
@@ -235,6 +235,88 @@ if (hasDocument) {
|
||||
})();
|
||||
|
||||
var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
|
||||
var qrCodeStyleRegistry = new WeakMap();
|
||||
var qrCodeStyleCounter = 0;
|
||||
|
||||
function ensureQrCodeStyleState(doc) {
|
||||
if (!doc || typeof doc.createElement !== "function") {
|
||||
return null;
|
||||
}
|
||||
var existing = qrCodeStyleRegistry.get(doc);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
var styleNode = doc.getElementById("qrCodeStyles");
|
||||
if (!(styleNode instanceof HTMLStyleElement)) {
|
||||
styleNode = doc.createElement("style");
|
||||
styleNode.id = "qrCodeStyles";
|
||||
doc.head && doc.head.appendChild(styleNode);
|
||||
}
|
||||
var state = {
|
||||
styleNode: styleNode,
|
||||
values: new Map()
|
||||
};
|
||||
qrCodeStyleRegistry.set(doc, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
function buildQrCodeRule(selector, values) {
|
||||
var declarations = [];
|
||||
if (values.colorDark) {
|
||||
declarations.push("--qr-code-color-dark: " + values.colorDark + ";");
|
||||
}
|
||||
if (values.colorLight) {
|
||||
declarations.push("--qr-code-color-light: " + values.colorLight + ";");
|
||||
}
|
||||
if (values.cellWidth) {
|
||||
declarations.push("--qr-code-cell-width: " + values.cellWidth + ";");
|
||||
}
|
||||
if (values.cellHeight) {
|
||||
declarations.push("--qr-code-cell-height: " + values.cellHeight + ";");
|
||||
}
|
||||
if (values.tableMargin) {
|
||||
declarations.push("--qr-code-table-margin: " + values.tableMargin + ";");
|
||||
}
|
||||
return selector + " { " + declarations.join(" ") + " }";
|
||||
}
|
||||
|
||||
function updateQrCodeContainerStyles(el, values) {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
var doc = el.ownerDocument || document;
|
||||
var state = ensureQrCodeStyleState(doc);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
if (!el.dataset.qrCodeStyleId) {
|
||||
qrCodeStyleCounter += 1;
|
||||
el.dataset.qrCodeStyleId = "qr-code-" + qrCodeStyleCounter;
|
||||
}
|
||||
var selector = "[data-qr-code-style-id=\"" + el.dataset.qrCodeStyleId + "\"]";
|
||||
var currentValues = state.values.get(selector) || {};
|
||||
var nextValues = Object.assign({}, currentValues, values || {});
|
||||
state.values.set(selector, nextValues);
|
||||
var rules = [];
|
||||
state.values.forEach(function (entryValues, entrySelector) {
|
||||
rules.push(buildQrCodeRule(entrySelector, entryValues));
|
||||
});
|
||||
state.styleNode.textContent = rules.join("\n");
|
||||
}
|
||||
|
||||
function setQrCodeMode(el, mode) {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
if (el.classList) {
|
||||
el.classList.add("qr-code__container");
|
||||
}
|
||||
if (mode) {
|
||||
el.dataset.qrCodeMode = mode;
|
||||
} else {
|
||||
delete el.dataset.qrCodeMode;
|
||||
}
|
||||
}
|
||||
|
||||
// Drawing in DOM by using Table tag
|
||||
var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {
|
||||
@@ -256,10 +338,13 @@ if (hasDocument) {
|
||||
var nHeight = Math.floor(_htOption.height / nCount);
|
||||
var aHTML = ['<table class="qr-code__table">'];
|
||||
|
||||
_el.style.setProperty("--qr-code-color-dark", _htOption.colorDark);
|
||||
_el.style.setProperty("--qr-code-color-light", _htOption.colorLight);
|
||||
_el.style.setProperty("--qr-code-cell-width", nWidth + "px");
|
||||
_el.style.setProperty("--qr-code-cell-height", nHeight + "px");
|
||||
updateQrCodeContainerStyles(_el, {
|
||||
colorDark: _htOption.colorDark,
|
||||
colorLight: _htOption.colorLight,
|
||||
cellWidth: nWidth + "px",
|
||||
cellHeight: nHeight + "px",
|
||||
tableMargin: "0px"
|
||||
});
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
aHTML.push('<tr>');
|
||||
@@ -283,7 +368,9 @@ if (hasDocument) {
|
||||
var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
|
||||
|
||||
if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
|
||||
elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
|
||||
updateQrCodeContainerStyles(_el, {
|
||||
tableMargin: nTopMarginTable + "px " + nLeftMarginTable + "px"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -298,8 +385,7 @@ if (hasDocument) {
|
||||
})() : (function () { // Drawing in Canvas
|
||||
function _onMakeImage() {
|
||||
this._elImage.src = this._elCanvas.toDataURL("image/png");
|
||||
this._elImage.style.display = "block";
|
||||
this._elCanvas.style.display = "none";
|
||||
setQrCodeMode(this._el, "image");
|
||||
}
|
||||
|
||||
// Android 2.1 bug workaround
|
||||
@@ -398,13 +484,22 @@ if (hasDocument) {
|
||||
this._elCanvas.height = htOption.height;
|
||||
el.appendChild(this._elCanvas);
|
||||
this._el = el;
|
||||
if (this._el && this._el.classList) {
|
||||
this._el.classList.add("qr-code__container");
|
||||
}
|
||||
this._oContext = this._elCanvas.getContext("2d");
|
||||
this._bIsPainted = false;
|
||||
this._elImage = document.createElement("img");
|
||||
this._elImage.alt = "Scan me!";
|
||||
this._elImage.style.display = "none";
|
||||
if (this._elImage.classList) {
|
||||
this._elImage.classList.add("qr-code__image");
|
||||
}
|
||||
if (this._elCanvas && this._elCanvas.classList) {
|
||||
this._elCanvas.classList.add("qr-code__canvas");
|
||||
}
|
||||
this._el.appendChild(this._elImage);
|
||||
this._bSupportDataURI = null;
|
||||
setQrCodeMode(this._el, "canvas");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -423,7 +518,7 @@ if (hasDocument) {
|
||||
var nRoundedWidth = Math.round(nWidth);
|
||||
var nRoundedHeight = Math.round(nHeight);
|
||||
|
||||
_elImage.style.display = "none";
|
||||
setQrCodeMode(this._el, "canvas");
|
||||
this.clear();
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
@@ -604,6 +699,9 @@ if (hasDocument) {
|
||||
|
||||
this._android = _getAndroid();
|
||||
this._el = el;
|
||||
if (this._el && this._el.classList) {
|
||||
this._el.classList.add("qr-code__container");
|
||||
}
|
||||
this._oQRCode = null;
|
||||
this._oDrawing = new Drawing(this._el, this._htOption);
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ test.describe("popover layout scenarios", () => {
|
||||
.getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--popover-inline-safe-max")
|
||||
.trim();
|
||||
const popoverMaxWidth = window
|
||||
.getComputedStyle(node)
|
||||
.getPropertyValue("--popover-max-width")
|
||||
.trim();
|
||||
|
||||
return {
|
||||
rect: {
|
||||
@@ -29,7 +33,7 @@ test.describe("popover layout scenarios", () => {
|
||||
viewport: { width: viewportWidth, height: viewportHeight },
|
||||
placement: node.dataset.popoverPlacement || "",
|
||||
state: node.dataset.popoverState || "",
|
||||
inlineMaxWidth: node.style.maxWidth,
|
||||
popoverMaxWidth,
|
||||
tokenMaxWidth: tokenValue,
|
||||
};
|
||||
});
|
||||
@@ -51,6 +55,10 @@ test.describe("popover layout scenarios", () => {
|
||||
.getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--popover-inline-safe-max")
|
||||
.trim();
|
||||
const popoverMaxWidth = window
|
||||
.getComputedStyle(node)
|
||||
.getPropertyValue("--popover-max-width")
|
||||
.trim();
|
||||
|
||||
return {
|
||||
rect: {
|
||||
@@ -72,7 +80,7 @@ test.describe("popover layout scenarios", () => {
|
||||
viewport: { width: viewportWidth, height: viewportHeight },
|
||||
placement: node.dataset.popoverPlacement || "",
|
||||
state: node.dataset.popoverState || "",
|
||||
inlineMaxWidth: node.style.maxWidth,
|
||||
popoverMaxWidth,
|
||||
tokenMaxWidth: tokenValue,
|
||||
};
|
||||
}, triggerHandle);
|
||||
@@ -102,7 +110,7 @@ test.describe("popover layout scenarios", () => {
|
||||
assertWithinViewport(metrics);
|
||||
expect(metrics.state).toBe("open");
|
||||
expect(metrics.placement.startsWith("top")).toBeTruthy();
|
||||
expect(metrics.inlineMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.popoverMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.tokenMaxWidth.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -119,7 +127,7 @@ test.describe("popover layout scenarios", () => {
|
||||
assertWithinViewport(metrics);
|
||||
expect(metrics.state).toBe("open");
|
||||
expect(metrics.placement.includes("bottom")).toBeTruthy();
|
||||
expect(metrics.inlineMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.popoverMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.tokenMaxWidth.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -137,7 +145,7 @@ test.describe("popover layout scenarios", () => {
|
||||
|
||||
assertWithinViewport(metrics);
|
||||
expect(metrics.state).toBe("open");
|
||||
expect(metrics.inlineMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.popoverMaxWidth).toBe(metrics.tokenMaxWidth);
|
||||
expect(metrics.tokenMaxWidth.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,14 +81,15 @@ beforeEach(async () => {
|
||||
global.PointerEvent = windowRef.PointerEvent || windowRef.Event;
|
||||
}
|
||||
windowRef.scrollTo = () => {};
|
||||
documentRef.documentElement.style.setProperty(
|
||||
"--popover-inline-safe-max",
|
||||
"calc(100vw - var(--space-xl))",
|
||||
);
|
||||
documentRef.documentElement.style.setProperty(
|
||||
"--overlay-panel-padding-block",
|
||||
"240px",
|
||||
);
|
||||
const rootStyle = documentRef.createElement("style");
|
||||
rootStyle.id = "testRootVars";
|
||||
rootStyle.textContent = `
|
||||
:root {
|
||||
--popover-inline-safe-max: calc(100vw - var(--space-xl));
|
||||
--overlay-panel-padding-block: 240px;
|
||||
}
|
||||
`;
|
||||
documentRef.head.appendChild(rootStyle);
|
||||
|
||||
setMockedPosition();
|
||||
|
||||
@@ -205,16 +206,20 @@ test("flips placement when bottom placement would collide with viewport", async
|
||||
|
||||
const panel = documentRef.querySelector('[data-test-panel="collision"]');
|
||||
assert.ok(panel, "panel should render");
|
||||
const panelStyles = windowRef.getComputedStyle(panel);
|
||||
assert.equal(panel.dataset.popoverState, "open");
|
||||
assert.equal(panel.dataset.state, "open");
|
||||
assert.equal(panel.dataset.popoverPlacement, "top-start");
|
||||
assert.equal(panel.style.position, "fixed");
|
||||
assert.equal(panel.style.left, "96px");
|
||||
assert.equal(panel.style.top, "81px");
|
||||
assert.equal(panel.style.maxWidth, "calc(100vw - var(--space-xl))");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-strategy").trim(), "fixed");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-left").trim(), "96px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-top").trim(), "81px");
|
||||
assert.equal(
|
||||
panelStyles.getPropertyValue("--popover-max-width").trim(),
|
||||
"calc(100vw - var(--space-xl))",
|
||||
);
|
||||
|
||||
const top = Number.parseInt(panel.style.top, 10);
|
||||
const left = Number.parseInt(panel.style.left, 10);
|
||||
const top = Number.parseInt(panelStyles.getPropertyValue("--popover-top"), 10);
|
||||
const left = Number.parseInt(panelStyles.getPropertyValue("--popover-left"), 10);
|
||||
assert.ok(Number.isFinite(top));
|
||||
assert.ok(Number.isFinite(left));
|
||||
assert.ok(top >= 0, "top should stay within viewport");
|
||||
|
||||
@@ -458,17 +458,6 @@ for (const _ of [0]) {
|
||||
profileModalRoot?.querySelector('.bv-modal__panel') || profileModalRoot;
|
||||
assert.ok(panel?.hasAttribute('inert'));
|
||||
|
||||
assert.equal(
|
||||
profileModalRoot?.style.visibility,
|
||||
'hidden',
|
||||
'profile modal should hide visually while login modal is active',
|
||||
);
|
||||
assert.equal(
|
||||
profileModalRoot?.style.pointerEvents,
|
||||
'none',
|
||||
'profile modal should not intercept pointer events while login modal is active',
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
container.lastElementChild,
|
||||
loginModal,
|
||||
@@ -491,16 +480,6 @@ for (const _ of [0]) {
|
||||
'profile modal should restore aria-hidden',
|
||||
);
|
||||
assert.equal(panel?.hasAttribute('inert'), false);
|
||||
assert.equal(
|
||||
profileModalRoot?.style.visibility ?? '',
|
||||
'',
|
||||
'profile modal visibility should restore after login',
|
||||
);
|
||||
assert.equal(
|
||||
profileModalRoot?.style.pointerEvents ?? '',
|
||||
'',
|
||||
'profile modal pointer events should restore after login',
|
||||
);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
@@ -1292,4 +1271,3 @@ test('history pane lazily initializes the watch history renderer', async () => {
|
||||
assert.equal(controller.profileHistoryRenderer, null);
|
||||
assert.equal(controller.boundProfileHistoryVisibility, null);
|
||||
});
|
||||
|
||||
@@ -176,9 +176,10 @@ test("opens a popover in the overlay root and positions the panel", async () =>
|
||||
assert.equal(panel.dataset.popoverState, "open");
|
||||
assert.equal(panel.dataset.state, "open");
|
||||
assert.equal(panel.dataset.popoverPlacement, "bottom-start");
|
||||
assert.equal(panel.style.position, "fixed");
|
||||
assert.equal(panel.style.left, "173px");
|
||||
assert.equal(panel.style.top, "248px");
|
||||
const panelStyles = documentRef.defaultView.getComputedStyle(panel);
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-strategy").trim(), "fixed");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-left").trim(), "173px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-top").trim(), "248px");
|
||||
assert.equal(panel.getAttribute("role"), "menu");
|
||||
assert.equal(documentRef.activeElement, panel);
|
||||
assert.equal(trigger.getAttribute("aria-expanded"), "true");
|
||||
@@ -238,12 +239,15 @@ test("positions bottom-end panels flush with the trigger's right edge", async ()
|
||||
|
||||
const panel = documentRef.getElementById("popover-bottom-end");
|
||||
assert.ok(panel);
|
||||
const panelStyles = documentRef.defaultView.getComputedStyle(panel);
|
||||
assert.equal(panel.dataset.popoverPlacement, "bottom-end");
|
||||
assert.equal(panel.style.left, "120px");
|
||||
assert.equal(panel.style.top, "265px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-left").trim(), "120px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-top").trim(), "265px");
|
||||
|
||||
const triggerRight = Math.round(trigger.getBoundingClientRect().right);
|
||||
const panelRight = Number.parseInt(panel.style.left, 10) + panel.offsetWidth;
|
||||
const panelRight =
|
||||
Number.parseInt(panelStyles.getPropertyValue("--popover-left"), 10) +
|
||||
panel.offsetWidth;
|
||||
assert.equal(panelRight, triggerRight);
|
||||
|
||||
popover.destroy();
|
||||
@@ -687,8 +691,14 @@ test("applies token-based sizing and arrow positioning", async () => {
|
||||
height: 40,
|
||||
});
|
||||
|
||||
documentRef.documentElement.style.setProperty("--popover-inline-safe-max", "320px");
|
||||
documentRef.documentElement.style.setProperty("--overlay-panel-padding-block", "240px");
|
||||
const rootStyle = documentRef.createElement("style");
|
||||
rootStyle.textContent = `
|
||||
:root {
|
||||
--popover-inline-safe-max: 320px;
|
||||
--overlay-panel-padding-block: 240px;
|
||||
}
|
||||
`;
|
||||
documentRef.head.appendChild(rootStyle);
|
||||
|
||||
const popover = createPopover(
|
||||
trigger,
|
||||
@@ -742,8 +752,8 @@ test("applies token-based sizing and arrow positioning", async () => {
|
||||
const arrow = panel.querySelector(".arrow");
|
||||
|
||||
const panelStyles = getComputedStyle(panel);
|
||||
assert.equal(panelStyles.maxWidth, "320px");
|
||||
assert.equal(panelStyles.maxHeight, "240px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-max-width").trim(), "320px");
|
||||
assert.equal(panelStyles.getPropertyValue("--popover-max-height").trim(), "240px");
|
||||
assert.equal(arrow.dataset.popoverArrowSide, "bottom");
|
||||
const arrowStyles = getComputedStyle(arrow);
|
||||
assert.notEqual(arrowStyles.top, "");
|
||||
|
||||
@@ -34,7 +34,7 @@ test("cached thumbnails reuse existing src without lazy-loading", (t) => {
|
||||
const cachedSrc = "https://cdn.example.com/thumb.jpg";
|
||||
const cache = new Map([["video-123", cachedSrc]]);
|
||||
|
||||
const { card } = renderCard(t, {
|
||||
const { card, window } = renderCard(t, {
|
||||
thumbnailCache: cache,
|
||||
fallbackThumbnailSrc: "https://cdn.example.com/fallback.jpg",
|
||||
});
|
||||
@@ -46,7 +46,7 @@ test("cached thumbnails reuse existing src without lazy-loading", (t) => {
|
||||
assert.equal(img.src, cachedSrc);
|
||||
assert.equal(img.dataset.lazy, undefined);
|
||||
assert.equal(
|
||||
root.style.getPropertyValue("--similar-card-thumb-url"),
|
||||
window.getComputedStyle(root).getPropertyValue("--similar-card-thumb-url").trim(),
|
||||
`url("${cachedSrc}")`,
|
||||
);
|
||||
});
|
||||
@@ -75,7 +75,7 @@ test("uncached thumbnails use fallback, cache on load, and retain blur state", (
|
||||
assert.equal(img.dataset.lazy, remoteThumb);
|
||||
assert.equal(img.dataset.thumbnailState, "blurred");
|
||||
assert.equal(
|
||||
root.style.getPropertyValue("--similar-card-thumb-url"),
|
||||
window.getComputedStyle(root).getPropertyValue("--similar-card-thumb-url").trim(),
|
||||
`url("${fallbackSrc}")`,
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ test("uncached thumbnails use fallback, cache on load, and retain blur state", (
|
||||
|
||||
assert.equal(cache.get("video-456"), remoteThumb);
|
||||
assert.equal(
|
||||
root.style.getPropertyValue("--similar-card-thumb-url"),
|
||||
window.getComputedStyle(root).getPropertyValue("--similar-card-thumb-url").trim(),
|
||||
`url("${remoteThumb}")`,
|
||||
);
|
||||
assert.equal(img.dataset.thumbnailState, "blurred");
|
||||
|
||||
Reference in new issue
Block a user