Skip to content
Merged
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
26 changes: 9 additions & 17 deletions src/managers/message-component-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Gist from '../gist';
import { log } from '../utilities/log';
import { findElement } from '../utilities/dom';
import { resolveMessageProperties } from './gist-properties-manager';
import { embedHTMLTemplate } from '../templates/embed';
import { messageHTMLTemplate } from '../templates/message';
Expand Down Expand Up @@ -36,7 +37,7 @@ export function loadEmbedComponent(
options: MessageOptions,
stepName: string | null = null
): void {
const element = safelyFetchElement(elementId);
const element = findElement(elementId);
if (element) {
const messageElementId = getMessageElementId(message.instanceId ?? '');
element.classList.add(messageElementId);
Expand All @@ -59,14 +60,14 @@ export function loadEmbedComponent(
}

export function showEmbedComponent(elementId: string): void {
const element = safelyFetchElement(elementId);
const element = findElement(elementId);
if (element) {
element.classList.add('gist-visible');
}
}

export function hideEmbedComponent(elementId: string): void {
const element = safelyFetchElement(elementId);
const element = findElement(elementId);
if (element) {
element.classList.remove('gist-visible');
const classesToRemove = Array.from(element.classList).filter((cls) => cls.startsWith('gist-'));
Expand All @@ -78,7 +79,7 @@ export function hideEmbedComponent(elementId: string): void {
}

export function elementHasHeight(elementId: string): boolean | undefined {
const element = safelyFetchElement(elementId);
const element = findElement(elementId);
if (element) {
return !!(element.style && element.style.height && element.style.height !== '0px');
}
Expand All @@ -91,7 +92,7 @@ export function resizeComponent(
const elementId = message.elementId
? message.elementId
: getMessageElementId(message.instanceId ?? '');
const element = safelyFetchElement(elementId);
const element = findElement(elementId);
if (element) {
const style = element.style;
if (size.height > 0) {
Expand Down Expand Up @@ -256,7 +257,7 @@ export async function showTooltipComponent(message: GistMessage): Promise<boolea
const instanceId = message.instanceId ?? '';
const messageProperties = resolveMessageProperties(message);
const wrapperId = `gist-tooltip-${instanceId}`;
const wrapper = safelyFetchElement(wrapperId);
const wrapper = findElement(wrapperId);
if (!wrapper) {
log(`Tooltip wrapper not found for instance ${instanceId}`);
return false;
Expand Down Expand Up @@ -327,7 +328,7 @@ export function hideTooltipComponent(message: GistMessage): void {
}

const wrapperId = `gist-tooltip-${instanceId}`;
const wrapper = safelyFetchElement(wrapperId);
const wrapper = findElement(wrapperId);
if (wrapper) {
wrapper.parentNode?.removeChild(wrapper);
}
Expand Down Expand Up @@ -360,7 +361,7 @@ export function resizeTooltipComponent(
}

export function changeOverlayTitle(instanceId: string, title: string): void {
const element = safelyFetchElement(getMessageElementId(instanceId));
const element = findElement(getMessageElementId(instanceId));
if (element) {
element.title = title;
}
Expand All @@ -387,12 +388,3 @@ function component(url: string, message: GistMessage): string {
const messageProperties = resolveMessageProperties(message);
return messageHTMLTemplate(getMessageElementId(message.instanceId ?? ''), messageProperties, url);
}

function safelyFetchElement(elementId: string): HTMLElement | null {
try {
const element = document.getElementById(elementId) ?? document.querySelector(elementId);
return (element as HTMLElement) || null;
} catch {
return null;
}
}
2 changes: 1 addition & 1 deletion src/managers/tooltip-position-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('tooltip-position-manager', () => {

it('returns null and logs warning for invalid selector', () => {
expect(findTargetElement('[invalid')).toBeNull();
expect(log).toHaveBeenCalledWith('Invalid selector for tooltip target: [invalid');
expect(log).toHaveBeenCalledWith('Tooltip target element not found for selector: [invalid');
});
});

Expand Down
14 changes: 5 additions & 9 deletions src/managers/tooltip-position-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { log } from '../utilities/log';
import { findElement } from '../utilities/dom';
import { ARROW_SIZE } from '../templates/tooltip';

export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
Expand All @@ -23,16 +24,11 @@ const ARROW_CLASS_FOR_POSITION: Record<TooltipPosition, string> = {
};

export function findTargetElement(selector: string): Element | null {
try {
const element = document.querySelector(selector);
if (!element) {
log(`Tooltip target element not found for selector: ${selector}`);
}
return element;
} catch {
log(`Invalid selector for tooltip target: ${selector}`);
return null;
const element = findElement(selector);
if (!element) {
log(`Tooltip target element not found for selector: ${selector}`);
}
return element;
}

function calculatePosition(
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface DisplaySettings {
overlayPosition?: string;
elementSelector?: string;
tooltipPosition?: string;
tooltipArrowColor?: string;
maxWidth?: number;
overlayColor?: string;
dismissOutsideClick?: boolean;
Expand Down
8 changes: 8 additions & 0 deletions src/utilities/dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function findElement(selector: string): HTMLElement | null {
try {
const element = document.getElementById(selector) ?? document.querySelector(selector);
return (element as HTMLElement) || null;
} catch {
return null;
}
}
91 changes: 91 additions & 0 deletions src/utilities/message-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ vi.mock('../managers/gist-properties-manager', () => ({
persistent: false,
exitClick: !!gist?.exitClick,
hasCustomWidth: (gist?.messageWidth ?? 0) > 0,
tooltipArrowColor: gist?.tooltipArrowColor || '#fff',
};
}),
}));
Expand Down Expand Up @@ -337,6 +338,22 @@ describe('hasDisplayChanged', () => {
).toBe(true);
});

it('returns true when tooltip arrow color changes', () => {
const msg = makeMessage({
tooltipPosition: 'top',
elementId: 'my-element',
properties: { gist: { tooltipArrowColor: '#fff' } },
});
expect(
hasDisplayChanged(msg, {
displayType: 'tooltip',
tooltipPosition: 'top',
elementSelector: 'my-element',
tooltipArrowColor: '#FF5733',
})
).toBe(true);
});

it('returns false when nothing changed for tooltip', () => {
const msg = makeMessage({ tooltipPosition: 'top', elementId: 'my-element' });
expect(
Expand All @@ -348,6 +365,21 @@ describe('hasDisplayChanged', () => {
).toBe(false);
});

it('returns false when tooltip arrow color is not in display settings', () => {
const msg = makeMessage({
tooltipPosition: 'top',
elementId: 'my-element',
properties: { gist: { tooltipArrowColor: '#FF5733' } },
});
expect(
hasDisplayChanged(msg, {
displayType: 'tooltip',
tooltipPosition: 'top',
elementSelector: 'my-element',
})
).toBe(false);
});

it('returns true when maxWidth changes', () => {
const msg = makeMessage({
overlay: true,
Expand Down Expand Up @@ -406,6 +438,32 @@ describe('applyDisplaySettings', () => {
expect(msg.position).toBeNull();
});

it('sets tooltipArrowColor for tooltip type when provided', () => {
const msg = makeMessage({ overlay: true });
applyDisplaySettings(msg, {
displayType: 'tooltip',
elementSelector: 'my-element',
tooltipPosition: 'top',
tooltipArrowColor: '#FF5733',
});

expect(msg.properties?.gist?.tooltipArrowColor).toBe('#FF5733');
});

it('does not set tooltipArrowColor when not provided in display settings', () => {
const msg = makeMessage({
overlay: true,
properties: { gist: { tooltipArrowColor: '#original' } },
});
applyDisplaySettings(msg, {
displayType: 'tooltip',
elementSelector: 'my-element',
tooltipPosition: 'top',
});

expect(msg.properties?.gist?.tooltipArrowColor).toBe('#original');
});

it('clears tooltipPosition when switching from tooltip to modal', () => {
const msg = makeMessage({ tooltipPosition: 'top', elementId: 'my-element' });
applyDisplaySettings(msg, { displayType: 'modal' });
Expand Down Expand Up @@ -433,6 +491,39 @@ describe('applyDisplaySettings', () => {
expect(getCurrentDisplayType(msg)).toBe('inline');
});

it('clears tooltipArrowColor when switching from tooltip to modal', () => {
const msg = makeMessage({
tooltipPosition: 'top',
elementId: 'my-element',
properties: { gist: { tooltipArrowColor: '#FF5733' } },
});
applyDisplaySettings(msg, { displayType: 'modal' });

expect(msg.properties?.gist?.tooltipArrowColor).toBeUndefined();
});

it('clears tooltipArrowColor when switching from tooltip to overlay', () => {
const msg = makeMessage({
tooltipPosition: 'top',
elementId: 'my-element',
properties: { gist: { tooltipArrowColor: '#FF5733' } },
});
applyDisplaySettings(msg, { displayType: 'overlay', overlayPosition: 'topCenter' });

expect(msg.properties?.gist?.tooltipArrowColor).toBeUndefined();
});

it('clears tooltipArrowColor when switching from tooltip to inline', () => {
const msg = makeMessage({
tooltipPosition: 'top',
elementId: 'my-element',
properties: { gist: { tooltipArrowColor: '#FF5733' } },
});
applyDisplaySettings(msg, { displayType: 'inline', elementSelector: 'my-container' });

expect(msg.properties?.gist?.tooltipArrowColor).toBeUndefined();
});

it('clears custom width for wide overlay positions', () => {
const msg = makeMessage({
overlay: false,
Expand Down
12 changes: 12 additions & 0 deletions src/utilities/message-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ export function hasDisplayChanged(
if (currentMessage.elementId !== displaySettings.elementSelector) {
return true;
}
if (
displaySettings.tooltipArrowColor !== undefined &&
resolvedProps.tooltipArrowColor !== displaySettings.tooltipArrowColor
) {
return true;
}
break;
}
}
Expand Down Expand Up @@ -172,6 +178,7 @@ export function applyDisplaySettings(message: GistMessage, displaySettings: Disp
message.properties.gist.position = displaySettings.modalPosition || 'center';
message.tooltipPosition = undefined;
message.properties.gist.tooltipPosition = undefined;
message.properties.gist.tooltipArrowColor = undefined;
} else if (displaySettings.displayType === 'overlay') {
message.overlay = false;
const elementId = mapOverlayPositionToElementId(displaySettings.overlayPosition);
Expand All @@ -181,6 +188,7 @@ export function applyDisplaySettings(message: GistMessage, displaySettings: Disp
message.properties.gist.position = null;
message.tooltipPosition = undefined;
message.properties.gist.tooltipPosition = undefined;
message.properties.gist.tooltipArrowColor = undefined;
} else if (displaySettings.displayType === 'inline') {
message.overlay = false;
message.elementId = displaySettings.elementSelector;
Expand All @@ -189,6 +197,7 @@ export function applyDisplaySettings(message: GistMessage, displaySettings: Disp
message.properties.gist.position = null;
message.tooltipPosition = undefined;
message.properties.gist.tooltipPosition = undefined;
message.properties.gist.tooltipArrowColor = undefined;
} else if (displaySettings.displayType === 'tooltip') {
message.overlay = false;
message.elementId = displaySettings.elementSelector;
Expand All @@ -197,6 +206,9 @@ export function applyDisplaySettings(message: GistMessage, displaySettings: Disp
message.properties.gist.tooltipPosition = displaySettings.tooltipPosition;
message.position = null;
message.properties.gist.position = null;
if (displaySettings.tooltipArrowColor !== undefined) {
message.properties.gist.tooltipArrowColor = displaySettings.tooltipArrowColor;
}
}

const isWideOverlayPosition =
Expand Down
Loading