Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 68 additions & 10 deletions src/core/dom-renderer/domRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,14 @@ function updateNodeStyles(node: DOMNode | DOMText) {
}
hasDivBgTint = true;
}
} else if (gradient) {
// use gradient as a mask when no tint is applied
maskStyle += `mask-image: ${gradient};`;
} else {
if (gradient) {
// use gradient as a mask when no tint is applied
maskStyle += `mask-image: ${gradient};`;
}
if (props.placeholderColor !== 0) {
bgStyle += `background-color: ${colorToRgba(props.placeholderColor)};`;
}
}

const imgStyleParts = [
Expand Down Expand Up @@ -852,16 +857,29 @@ function updateNodeStyles(node: DOMNode | DOMText) {

node.imgEl.addEventListener('error', () => {
node.imageLoading = false;

const failedSrc =
node.imgEl?.dataset.pendingSrc || node.lazyImagePendingSrc || '';

const fallback = node.props.fallbackImage;
if (
fallback &&
node.imgEl &&
node.imgEl.dataset.rawSrc !== fallback
) {
node.imgEl.dataset.pendingSrc = fallback;
node.imgEl.dataset.rawSrc = fallback;
node.imgEl.src = fallback;
return;
}

node.showBackgroundLayer();
if (node.imgEl) {
node.imgEl.removeAttribute('src');
node.imgEl.style.display = 'none';
node.imgEl.removeAttribute('data-rawSrc');
}

const failedSrc =
node.imgEl?.dataset.pendingSrc || node.lazyImagePendingSrc || '';

const payload: lng.NodeTextureFailedPayload = {
type: 'texture',
error: new Error(`Failed to load image: ${failedSrc}`),
Expand Down Expand Up @@ -972,15 +990,28 @@ function updateNodeStyles(node: DOMNode | DOMText) {

node.imgEl.addEventListener('error', () => {
node.imageLoading = false;

const failedSrc =
node.imgEl?.dataset.pendingSrc || node.lazyImagePendingSrc || '';

const fallback = node.props.fallbackImage;
if (
fallback &&
node.imgEl &&
node.imgEl.dataset.rawSrc !== fallback
) {
node.imgEl.dataset.pendingSrc = fallback;
node.imgEl.dataset.rawSrc = fallback;
node.imgEl.src = fallback;
return;
}

if (node.imgEl) {
node.imgEl.removeAttribute('src');
node.imgEl.style.display = 'none';
node.imgEl.removeAttribute('data-rawSrc');
}

const failedSrc =
node.imgEl?.dataset.pendingSrc || node.lazyImagePendingSrc || '';

const payload: lng.NodeTextureFailedPayload = {
type: 'texture',
error: new Error(`Failed to load image: ${failedSrc}`),
Expand Down Expand Up @@ -1137,7 +1168,6 @@ function updateDOMTextSize(node: DOMText, emitLoaded = true): void {
w: node.w,
h: node.h,
},
trimmedHeight: node.h,
};
node.emit('loaded', payload);
node.loaded = true;
Expand Down Expand Up @@ -1244,6 +1274,7 @@ function resolveNodeDefaults(
w: props.w ?? 0,
h: props.h ?? 0,
alpha: props.alpha ?? 1,
ignoreParentAlpha: props.ignoreParentAlpha ?? false,
autosize: props.autosize ?? false,
boundsMargin: props.boundsMargin ?? null,
clipping: props.clipping ?? false,
Expand Down Expand Up @@ -1279,6 +1310,8 @@ function resolveNodeDefaults(
pivotY: props.pivotY ?? props.pivot ?? 0.5,
rotation: props.rotation ?? 0,
rtt: props.rtt ?? false,
placeholderColor: props.placeholderColor ?? 0,
fallbackImage: props.fallbackImage ?? null,
data: {},
imageType: props.imageType,
};
Expand Down Expand Up @@ -1807,6 +1840,31 @@ export class DOMNode extends EventEmitter implements IRendererNode {
this.markChildrenBoundsDirty();
}

get ignoreParentAlpha(): boolean {
return this.props.ignoreParentAlpha;
}
set ignoreParentAlpha(v: boolean) {
this.props.ignoreParentAlpha = v;
updateNodeStyles(this);
}

get placeholderColor(): number {
return this.props.placeholderColor;
}
set placeholderColor(v: number) {
this.props.placeholderColor = v;
updateNodeStyles(this);
}

get fallbackImage(): string | null {
return this.props.fallbackImage ?? null;
}

set fallbackImage(v: string | null) {
if (this.props.fallbackImage === v) return;
this.props.fallbackImage = v;
}

get absX(): number {
const parent = this.props.parent;
return (
Expand Down
24 changes: 13 additions & 11 deletions src/core/elementNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,8 @@ import {
isFunction,
spliceItem,
} from './utils.js';
import {
Config,
isDev,
SHADERS_ENABLED,
isDomRendererActive,
} from './config.js';
import { isDev, SHADERS_ENABLED } from './env.js';
import { Config, isDomRendererActive } from './config.js';
import type {
RendererMain,
INode,
Expand All @@ -55,7 +51,7 @@ import { assertTruthy } from '@solidtv/renderer/utils';
import { NodeType, TextNode } from './nodeTypes.js';
import {
ForwardFocusHandler,
setActiveElement,
setActiveElementCore,
FocusNode,
} from './focusManager.js';
import { initClickInspector } from './clickInspector.js';
Expand Down Expand Up @@ -130,15 +126,15 @@ function runPostMutation() {

// Phase 3: focus. setFocus() may have evaluated forwardFocus pre-render
// (when no children existed yet); deferredFocusElement re-runs setFocus
// here once the subtree has rendered, then setActiveElement is applied.
// here once the subtree has rendered, then setActiveElementCore is applied.
if (deferredFocusElement !== null) {
const el = deferredFocusElement;
deferredFocusElement = null;
el.setFocus();
} else if (nextActiveElement !== null) {
const element = nextActiveElement;
nextActiveElement = null;
setActiveElement(element);
setActiveElementCore(element);
}
}

Expand Down Expand Up @@ -271,13 +267,16 @@ const LightningRendererNonAnimatingProps = [
'fontStretch',
'fontStyle',
'group',
'ignoreParentAlpha',
'imageType',
'letterSpacing',
'maxHeight',
'maxLines',
'maxWidth',
'offsetY',
'overflowSuffix',
'placeholderColor',
'fallbackImage',
'preventCleanup',
'rtt',
'scrollable',
Expand Down Expand Up @@ -332,7 +331,7 @@ export interface ElementNode extends RendererNode, FocusNode {
_animationQueueSettings?: AnimationSettings;
_animationRunning?: boolean;
_animationSettings?: AnimationSettings;
_autofocus?: boolean;
_autofocus?: any;
_containsFlexGrow?: boolean | null;
_hasRenderedChildren?: boolean;
_effects?: Record<string, any>;
Expand Down Expand Up @@ -793,6 +792,9 @@ export class ElementNode {
shader: undefined,
clipping: undefined,
text: undefined,
ignoreParentAlpha: undefined,
placeholderColor: undefined,
fallbackImage: undefined,
};
this.children = [];

Expand Down Expand Up @@ -1316,7 +1318,7 @@ export class ElementNode {
* @param val - A value to determine if the element should autofocus.
* A truthy value enables autofocus, otherwise disables it.
*/
set autofocus(val: boolean | undefined) {
set autofocus(val: any) {
this._autofocus = val;
// Defer setFocus so children render first (forwardFocus needs them).
// The post-mutation focus phase calls setFocus on this element.
Expand Down
1 change: 1 addition & 0 deletions src/primitives/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ export { createBlurredImage } from './utils/createBlurredImage.js';

export type * from './types.js';
export type { KeyHandler } from '../core/focusManager.js';
export type { SpeechType } from './announcer/speech.js';