Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@stackla/public-types",
"version": "1.0.8",
"version": "1.0.10",
"description": "Public types for UGC Widgets",
"types": "dist/src/widgets/index.d.ts",
"types": "dist/widgets/index.d.ts",
"repository": "https://github.com/Stackla/public-types",
"publishConfig": {
"registry": "https://npm.pkg.github.com/@stackla"
Expand Down
1 change: 1 addition & 0 deletions src/widgets/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ugc.component';
8 changes: 8 additions & 0 deletions src/widgets/components/ugc.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { IPlacement } from "../core/placement";

export interface IUgcComponent extends HTMLElement {
placement?: IPlacement;
getShadowRoot(): ShadowRoot;
getPlacement(): IPlacement;
getWidgetService(): any;
}
4 changes: 4 additions & 0 deletions src/widgets/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './placement';
export * from './sdk';
export * from './tile';
export * from './widget-request';
56 changes: 56 additions & 0 deletions src/widgets/core/placement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ITransformedWidgetRequest } from "./widget-request";
import { IUgcComponent } from "../components/ugc.component";
import { ITilesService } from "../services/tiles.service";
import { IEventService } from "../services/event.service";
import { Template } from "../types";
import { Config, ExpandedTileOptions, Style, WidgetOptions, WidgetResponse } from "../widgets";

export interface IPlacement {
readonly selector: string;
readonly widgetContainer: WidgetResponse;
readonly widgetRequest: ITransformedWidgetRequest;
ugcComponent?: IUgcComponent;
tiles?: ITilesService;
sharedCssStyles: any; // Define a more specific type if possible
custom: any; // Define a more specific type if possible
events?: IEventService;
loadedComponents: string[];

attachServices(): void;
getStateFromGlobal(): any;
getEvents(): IEventService;
getLoadedComponents(): string[];
addLoadedComponent(component: string): void;
addLoadedComponents(components: string[]): void;
getSelector(): string;
getWidgetId(): string;
getNodeName(): string;
getWidgetContainer(): WidgetResponse;
updateWidgetOptionsProperties(mutatedWidgetOptions: Partial<WidgetOptions>): void;
updateWidgetStyle(mutatedStyle: Partial<Style>): void;
updateExpandedTileOptions(mutatedExpandedTileOptions: Partial<ExpandedTileOptions>): void;
updateWidgetConfig(mutatedConfig: Partial<Config>): void;
updateInlineTileOptions(mutatedInlineTileOptions: Partial<ExpandedTileOptions>): void;
updateFilterId(filterId: string): void;
getPluginsSettings(): Record<string, { config: Record<string, never> }>;
getElement(): Element;
attachUGC(): void;
loadComponents(): Promise<void>;
getTilesService(): ITilesService;
getAllTilesInDom(): any[] | NodeListOf<HTMLElement>;
getShadowRoot(): ShadowRoot;
querySelector<T extends Element = HTMLElement>(className: string): T;
querySelectorAll<T extends Element = HTMLElement>(className: string): NodeListOf<T>;
appendModuleScript(src: string): Promise<unknown>;
getRootCSSImports(): string[];
setRootCSSImports(content: string[]): void;
getCustomStyles(component: string): string[];
setCustomStyles(component: string, content: string): void;
getWidgetCustomStyles(): string[];
setWidgetCustomStyles(content: string): void;
hasSharedStyles(componentName: string): boolean;
setSharedCssCustomStyles(key: string, content: string, componentNames: string[]): void;
getSharedCssStyleSheets(componentName: string): CSSStyleSheet[];
getCustomTemplate(component: string): Template;
setCustomTemplate(component: string, template: Template): void;
}
42 changes: 42 additions & 0 deletions src/widgets/core/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { IWidgetService } from "../services/widget.service";
import { IPlacement } from "./placement";
import { ITilesService } from "../services/tiles.service";
import { IEventService } from "../services/event.service";
import { EventMapping, EventName } from "../services/events/event-consts";
import { ClaimConfig, ExpandedTileOptions, InlineTileOptions, Style, WidgetOptions, WidgetResponse } from "../widgets";

type Template = (sdk: ISdk) => string | HTMLElement;

export interface ISdk {
widget: IWidgetService;
placement: IPlacement;
events: IEventService;
tiles: ITilesService;

querySelector<T extends Element = HTMLElement>(selector: string): T;
querySelectorAll<T extends Element = HTMLElement>(selector: string): NodeListOf<T>;
getEmittedEvents(): EventName[];
getRegisteredEvents(): EventName[];
addEventListener<T extends EventName>(event: T, callback: (event: EventMapping[T]) => void, htmlSelector?: NodeListOf<Element> | Element): void;
triggerEvent<T extends EventName>(event: T, data?: object): void;
getWidgetContainer(): WidgetResponse;
getWidgetOptions(): WidgetOptions & {
plugins?: Record<string, { config: Record<string, never> }>;
};
addLoadedComponents(components: string[]): void;
getLoadedComponents(): string[];
isComponentLoaded(component: string): boolean;
addWidgetCustomStyles(content: string): void;
addSharedCssCustomStyles(key: string, content: string, componentNames: string[]): void;
addCSSImportUrl(url: string): Promise<void>;
addCSSToComponent(css: string, componentName: string): void;
addTemplateToComponent(template: Template, componentName: string): void;
setState(key: string, value: any): void;
getState(key: string): any;
getNodeId(): string;
loadTemplate(templateType: string): Promise<void>;
getExpandedTileConfig(): ExpandedTileOptions;
getInlineTileConfig(): InlineTileOptions;
getClaimTileConfig(): ClaimConfig;
getStyleConfig(): Style;
}
4 changes: 4 additions & 0 deletions src/widgets/core/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ITemplateService {
loadTemplate(node: string | undefined, root: ShadowRoot | HTMLElement, templateType: string): Promise<unknown>;
getGlobalCSSTemplate(node: string | undefined, templateType: string): string;
}
138 changes: 138 additions & 0 deletions src/widgets/core/tile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
interface Variant {
id: string
availability: string
brand: string
condition: string
description: string
google_product_category: string
group: string
image_link: string
item_group_id: string
link: string
price: string
title: string
via_feed: number | null
}

export interface Video {
standard_resolution: {
url: string
}
}

export interface VideoFile {
url: string
mime: string
size: number
width: number
height: number
duration: number
}

export interface TagExtended {
active?: boolean
auto_apply?: boolean
availability: number
availability_status?: string
brand?: string
categories?: string
created_at?: string
cta_text?: string
currency?: string
custom_fields?: string
custom_slug?: string
custom_url: string
description?: string
ext_product_id?: string
id: string
image?: string
image_medium_height?: string
image_medium_url?: string
image_medium_width?: string
image_small_height?: string
image_small_url?: string
image_small_width?: string
ingested_at?: string
is_from_nosto?: number
lock_cta_text?: number
merchant_id?: string
migrated_from_variant?: number
original_price?: string
price: string
priority?: string
processed?: number
publicly_visible?: number
rm_id?: string
slug?: string
stack_id?: number
system_tag?: number
is_cross_seller: boolean
tag: string
tag_sanitized?: string
target?: string
tracking_tile_clicks?: string
tracking_tile_impressions?: string
type: string
ugc_update_required?: string
ugc_update_required_created_at?: string
updated_at?: string
variant?: Variant[]
}

export type Tile = {
id: string
preloaded?: boolean
_id?: { $id: string }
carousel: number
created_at: number
disabled: boolean
hotspots?: Hotspot[]
image: string
avatar: string
image_expire_at: number
lang_detection_type?: string
media: string
message: string
name: null | string
original_url: string
original_link: string
page_post: boolean
parent_url: string
queued: boolean
reviewed: boolean
scheduled: boolean
score: number
source: string
source_id: string
source_created_at: number
source_unique_id: string
stackla_sentiment_score: number
status: string
tags: string[]
tags_extended?: TagExtended[]
terms: string[]
updated_at: number
user: string
video: Video
video_files: VideoFile[]
original_image_url: string
embed_url: string
youtube_id: string
title: string
full_embed_html: string
attrs: string[]
[key: string]: undefined | object | null | string | string[] | number | number[] | boolean | TagExtended[]
}

export type Hotspot = {
id: number
x: number
y: number
width: number
height: number
type: string
custom_url: string
product_link_attribute: string
tag: TagExtended
coords: number[]
} & TagExtended
75 changes: 75 additions & 0 deletions src/widgets/core/widget-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
type Template = {
display_name: string
html_id: string
mandatory: number
use_default_template: number
template: string
created: string
modified: string
}

type Templates = {
layout: Template
tile: Template
}

export type Draft = {
style?: string
config?: string | null
css?: string
filter_id?: number
custom_css?: string
lightbox_custom_css?: string
source_css?: string
lightbox_source_css?: string
use_default_css?: number
custom_js?: string
lightbox_custom_js?: string
use_default_js?: number
custom_tile?: string
external_js?: string
draft_id?: string
short_name?: string
custom_templates?: Templates
[key: string]: string | number | undefined | null | Templates | Record<string, never>
}

export default interface IWidgetRequest {
// TODO - Document new properties (draft,visible_tiles_count, uid);
// Allow uid if the user wants to differ 2 widgets with the same filter_id (i.e. preview mode)
uid?: string
visible_tiles_count?: number
draft?: Draft
hash?: string
wid?: string
filter_id: number
tags?: string
tag_group?: string
available_products_only?: boolean
limit?: number
page?: number
ttl?: number
visible_on?: string
domain?: string
tags_grouped_as?: string
data_tags?: string
brand?: string
categories?: string
fallbacks?: string
fallback_filter_id?: number
product_link_attribute?: string
search?: string
geohash?: string
tile_id?: string
style?: string
media?: string
exclude?: boolean
status?: string
filter?: string
[key: string]: string | boolean | number | Draft | undefined | null | Templates | Record<string, never>
}

export interface ITransformedWidgetRequest extends IWidgetRequest {
wid: string
hash?: string
}
6 changes: 5 additions & 1 deletion src/widgets/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from './widgets';
export * from './widgets';
export * from './types';
export * from './components';
export * from './core';
export * from './services';
9 changes: 9 additions & 0 deletions src/widgets/services/base.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IPlacement } from "../core/placement";
import { IEventService } from "./event.service";
export declare abstract class IBaseService {
protected placement: IPlacement;
setState(key: string, value: any): void;
getState(key: string): any;
getPlacement(): IPlacement;
getEvents(): IEventService;
}
11 changes: 11 additions & 0 deletions src/widgets/services/event.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { IBaseService } from "./base.service";
import { EventMapping, EventName } from "./events/event-consts";

export interface IEventService extends IBaseService {
listenOrFindEvent<T extends EventName>(eventType: T, callback: (event: EventMapping[T]) => void): void;
removeListeners(listenersForRemoval: EventName[], scope?: string): void;
addUgcEventListener<T extends EventName>(eventType: T, callback: (event: EventMapping[T]) => void, scope?: string): void;
getUniqueSelector(): string;
dispatchUgcEvent(event: CustomEvent, scope?: string): void;
getEmittedEvents(): EventName[];
}
Loading