<goma-casino-games>
A compact, host-fed casino games rail: a titled section (flame glyph before "Casino Games", an optional "All slots" quick link) over a horizontal strip of portrait game tiles, a next-tile peek, and opt-in prev/next arrows plus a dot indicator (both on by default). Purely presentational: no WAMP/RPC/REST. Data arrives via the games property; tapping a tile emits goma:casino-game-select and the host owns navigation.
Two tile presentations, picked with the variant property:
'premium'(default): artwork with the game name always visible and a "Play" pill on hover.'simplified': artwork (a still image, an animated GIF, or a video that plays only while its tile is on screen) alone at rest; the name, provider and a pulsing play icon reveal on hover, staying permanently visible on touch instead.
Live demo
Open in the playground →: toggle Casino games in the widget rail.
Element tag
html
<goma-casino-games></goma-casino-games>Installation
bash
pnpm add @gomagaming/casino-games vue pinia vue-router vue-i18n @vueuse/core swiperThe framework packages are peer dependencies installed once at the app level; bundlers dedup them across every @gomagaming/* widget. See Installation for the one-time .npmrc token setup.
Configuration
el.config = { locale, theme, messages, debug }: the standard widget config bag. This widget makes no network calls, so there is no apiBaseUrl/socketUrl.
| Key | Type | Description |
|---|---|---|
locale | string | Active i18n locale ('en' / 'fr' / 'pt'). Defaults to 'en'. |
theme | Record<string,string> | --goma-* token overrides. |
messages | object | Optional i18n phrase overrides. |
debug | boolean | Defaults to false. |
Data sources
Host-fed via the games property (or games attribute as JSON):
ts
interface CasinoGame {
id: string // stable identity; echoed back on select
name: string // overlaid on the tile; also its aria-label
imageUrl: string // portrait artwork; fills the tile
ctaUrl?: string // optional deep link; passed through on select (not navigated)
provider?: string // studio name; shown under the name in the 'simplified' variant only
previewUrl?: string // animated preview shown instead of imageUrl in the 'simplified' variant: a GIF, or an .mp4/.webm/.mov/.m4v URL, rendered as a muted looping <video>; falls back to imageUrl when absent
}This is the only data path: there's no dataSource prop, no RPC, no subscription. games accepts either a live array (JS property) or a JSON string (HTML attribute / the playground's JSON control); a malformed JSON string or a non-array value renders the empty state rather than throwing.
Props / attributes
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
games | games (JSON) | CasinoGame[] | [] | Host-fed tiles. |
heading | heading | string | '' | Title override. Blank, or spaces only, gives the localized default ("Casino Games"). |
showTitle | show-title | boolean | true | Header row. |
showFireIcon | show-fire-icon | boolean | true | Flame glyph beside the title. |
showArrows | show-arrows | boolean | true | Prev/next arrows. |
showDots | show-dots | boolean | true | Dot pagination row. |
tileWidth | tile-width | number | 120 | Fixed tile width in px; the rail shows more tiles with a peek of the next as the container widens. |
spaceBetween | space-between | number | 12 | Tile gap (px). |
enableSwipe | enable-swipe | boolean | true | Touch/drag panning. |
loop | loop | boolean | false | Rewind to the start after the last tile (via Swiper's rewind; disabled for ≤1 tile). |
maxDots | max-dots | number | 0 | Cap on the dot row. 0 keeps one dot per snap position. With N >= 2 and more snaps than N, N dots stand for the whole track: the active dot is the current snap's proportional position (first and last dots are the two ends) and a dot tap jumps to the matching snap. Values below 2 are ignored. |
variant | variant | 'premium' | 'simplified' | 'premium' | Tile presentation. See Variants. Any unrecognised value renders 'premium'. |
showAllSlots | show-all-slots | boolean | false | Show an "All slots" link on the right of the header. |
allSlotsUrl | all-slots-url | string | '' | URL echoed in the goma:casino-games-all-select payload when the "All slots" link is activated. |
appearance | appearance (JSON) | object | {} | Structure-only pagination-dot sizes: see Appearance. |
Variants
variant swaps the tile's rendering without touching data, layout, or the goma:casino-game-select payload: a host can flip the property at runtime and its listener never notices.
js
el.variant = 'simplified'html
<goma-casino-games variant="simplified"></goma-casino-games>Any value other than 'simplified' renders 'premium', so a typo degrades to the default rather than blanking the widget.
'premium': the shipped tile (default)
Artwork fills the tile with a bottom scrim and the game name always visible at the bottom edge; hovering or focusing reveals a centred "Play" pill. This is the original rendering and it is unchanged.
'simplified': artwork-first
At rest the tile shows only the artwork (or an animated previewUrl when the game carries one): no name, no scrim. On a hover-capable pointer, hovering or focusing the tile fades in a near-opaque (--goma-allDark at 98% opacity) veil carrying the game name, its provider (when present), and a centred play icon that pulses between 1.0 and 1.12 scale on a 1200 ms ease-in-out loop.
A previewUrl ending in .mp4, .webm, .mov or .m4v (a query string after the extension is fine) renders as a muted, looped <video> instead of an <img>, with imageUrl as its poster. The clip is never set to autoplay outright: an IntersectionObserver starts it only while the tile is actually scrolled into view and pauses it the moment it leaves, so a rail of several previews doesn't decode video it isn't showing. Anything else. A GIF, a still image, or no previewUrl at all. Renders through the same <img loading="lazy"> path as before.
Differences from 'premium':
- Nothing shown at rest. The name and provider are hidden until hover/focus reveals them;
'premium'always shows the name. providerrenders.'premium'never displays it.previewUrlrenders, as a video or a GIF depending on its extension (falling back toimageUrlwhen absent);'premium'always usesimageUrl.- On touch, the reveal is permanent, not hover-triggered. Touch pointers have no hover state, and the first tap already navigates: a hover-only label would leave the name unreachable. Under
(hover: none)the veil degrades to a bottom scrim gradient and the name + provider stay visible at all times, matching'premium''s always-visible name; only the pulsing play icon is dropped there.
html
<goma-casino-games id="cg" variant="simplified"></goma-casino-games>Events
All events bubble and are composed: true (cross the Shadow DOM boundary).
| Event | detail | Notes |
|---|---|---|
goma:casino-game-select | { id: string | null, name: string | null, ctaUrl: string | null } | Tile tapped. A game with no id, name or ctaUrl sends null for it. Emit-only: the host owns navigation. No shipped widget listens for it. |
goma:casino-games-all-select | { url: string | null } | The header's "All slots" link was activated (only rendered when showAllSlots is true). url echoes allSlotsUrl. Emit-only: the host owns navigation. |
goma:seo-data | { widget: 'casino-games', type: 'casino-game', items: object[] } | Fired once the fed games catalogue resolves to at least one game, and again only when an item's id/name/provider/url changes. See SEO data for the payload contract. |
ready | {} | Widget mounted. |
goma:error | { message, code, component? } | Fires on an error raised in the widget's own outermost component (its setup, its render, its lifecycle hooks or its watchers), where code is the error's name, e.g. 'TypeError' ('RUNTIME_ERROR' when it has none). Errors raised inside the widget's child components do not reach this event: the in-shadow error boundary catches those and shows the retry banner instead, emitting only goma:retry. The connection-layer path other widgets document (code: 'API_INIT_ERROR') does not exist here: casino-games is purely host-fed (games prop only), with no WAMP/RPC/REST connection that could fail. |
goma:retry | {} | User clicked Retry on the render-error banner. |
Empty / loading / error states
There is no loading state: games is host-fed and synchronous, so the widget renders its final state on the first tick.
- Empty:
gamesis[](the default), a non-array value, or an unparseable JSON string: rendersEmptyState(a dice glyph + thecasino_games_emptymessage) instead of the carousel. - Populated: one
GameTileper entry, in array order. - Render error: an
onErrorCapturedboundary inCasinoGamesAppcatches a Vue render/runtime error, shows arole="alert"banner (theerror_prefixcopy, "ERROR:" in English, then the message) with a Retry button (clears the error and emitsgoma:retry) and a dismiss×button named "Close" (theclosecopy), and auto-clears after 8000 ms even without user interaction. - Forced error:
el.forceError(message)shows the same banner with no timer: it stays until the user dismisses it or taps Retry, or the host callsel.clearError().
Theming
All colours map to existing --goma-* tokens, plus two optional nav-arrow overrides (--goma-navArrowBackground / --goma-navArrowIcon, unset by default; themeTokens.js lists as their default what the fallback paints with core's values, #ffffff99 and #03061b):
| Token | Role |
|---|---|
--goma-textPrimary | Tile name, active pagination dot |
--goma-textSecondary | Empty-state icon + message |
--goma-iconPrimary | Flame glyph |
--goma-backgroundCards | Tile placeholder background |
--goma-backgroundSecondary | Tile bottom-fade scrim |
--goma-separatorLine | Inactive dot |
--goma-highlightTertiary → --goma-highlightPrimary | Tile bottom-edge gradient bar |
--goma-highlightPrimary | Tile hover/focus top glow, focus rings |
--goma-highlightGradientStart | Hover "Play" pill background, "All slots" link |
--goma-buttonTextPrimary | Hover "Play" pill text |
--goma-allWhite | Top-glow rim line, hover title glow, and the nav arrow disc (painted at 60% opacity) |
--goma-navArrowBackground | Optional nav arrow disc override. Unset (default), the disc is --goma-allWhite at 60%. For a palette where that does not pair with the caret, e.g. a light theme that wants a dark disc. |
--goma-navArrowIcon | Optional nav arrow caret override. Unset (default), the caret is --goma-highlightSecondaryContrast. |
--goma-alertError | Error banner background |
--goma-highlightPrimaryContrast | Error banner Retry text and focus ring |
--goma-highlightSecondaryContrast | Nav arrow caret |
--goma-allDark | 'simplified' variant: the hover veil (98% opacity) behind the info block, and the touch-fallback bottom scrim |
--goma-widgetInset | Horizontal gutter: see Widget gutter |
Each tile is portrait (3:4), has an 8 px radius, a 2 px gradient bottom accent, and a transparent-to-dark bottom scrim so the name stays legible over bright artwork. The widget root is transparent: the host owns the surrounding panel.
--goma-widgetInset sets the HORIZONTAL gutter between the rail's content and the edge of the element: 8px here. Widgets differ, so a page stacking several of them can set the token once to line them all up, or 0 to hand the gutter to the page. It does not touch vertical padding, and leaving it unset keeps the value above. See Widget gutter.
Appearance (styling object)
appearance carries structure only. Each key is a single value (identical in light and dark) that maps to one --goma-* CSS custom property on the host. Set it via el.appearance = {...} or the appearance attribute (a JSON string); unset keys keep the default, so an empty {} (the default) reproduces the current look. Colours stay in theme.
| Key | CSS variable | Default | Affects |
|---|---|---|---|
dotSize | --goma-casinoDotSize | 7px | Diameter of each pagination dot. |
dotGap | --goma-casinoDotGap | 6px | Space between pagination dots. |
activeDotWidth | --goma-casinoActiveDotWidth | 18px | Width of the active dot, a pill by default. Set it equal to dotSize for a round active dot that differs from the others by colour only. |
i18n / message overrides
| Key | Default (en) | Used by |
|---|---|---|
casino_games | "Casino Games" | Section title fallback when heading is blank. |
casino_games_empty | "No games available" | Empty-state message. |
casino_games_play | "Play" | Hover/focus "Play" pill label on a tile. |
casino_games_all_slots | "All slots" | Header quick link, shown when showAllSlots is true. |
retry | "Retry" | Render-error banner's retry button (shared key). |
error_prefix | "ERROR:" | Render-error banner's prefix, before the message (shared key). |
close | "Close" | Accessible name of the banner's dismiss × (shared key). |
previous / next | "Previous" / "Next" | Accessible names of the arrows (shared keys). |
go_to_page | "Go to page {page}" | Accessible name of each dot, {page} counting from 1 (shared key). |
Embedding examples
Vanilla / CDN
html
<goma-casino-games id="cg"></goma-casino-games>
<script type="module">
import '@gomagaming/casino-games'
const el = document.getElementById('cg')
el.config = { locale: 'en' }
el.games = [
{ id: 'g1', name: 'Gates of Olympus', imageUrl: 'https://…/olympus.jpg', ctaUrl: 'https://…/play' },
{ id: 'g2', name: 'Sweet Bonanza', imageUrl: 'https://…/bonanza.jpg' },
]
el.addEventListener('goma:casino-game-select', (e) => {
// e.detail = { id, name, ctaUrl }
window.location.href = e.detail.ctaUrl ?? `/casino/${e.detail.id}`
})
</script>React
jsx
import '@gomagaming/casino-games'
import { useRef, useEffect } from 'react'
export function CasinoGames({ games }) {
const ref = useRef(null)
useEffect(() => {
const el = ref.current
if (!el) return
el.config = { locale: 'en' }
el.games = games
const onSelect = (e) => { /* route to e.detail.ctaUrl */ }
el.addEventListener('goma:casino-game-select', onSelect)
return () => el.removeEventListener('goma:casino-game-select', onSelect)
}, [games])
return <goma-casino-games ref={ref} />
}Vue
vue
<script setup>
import '@gomagaming/casino-games'
import { ref, watchEffect } from 'vue'
const props = defineProps(['games'])
const el = ref(null)
watchEffect(() => {
if (!el.value) return
el.value.config = { locale: 'en' }
el.value.games = props.games
})
</script>
<template>
<goma-casino-games ref="el" @goma:casino-game-select="$emit('select', $event.detail)" />
</template>Accessibility
- Each tile is a native
<button>witharia-labelset to the game name; its artwork<img>carries a matchingalt. Thearia-labelis present in both variants, so in'simplified', where the visible name label is hover-only, the accessible name still survives for assistive tech. - The flame and empty-state dice glyphs are
aria-hidden="true"(decorative). - Prev/next arrows are
<button>s named from theprevious/nextcopy ("Previous" / "Next" in English); disabled Swiper navigation state fades them toopacity: 0and disables pointer events. - The dot row is
role="tablist"with each dotrole="tab", named from thego_to_pagecopy ("Go to page 1", counting from 1), andaria-selectedtracking the active snap position. - The error banner's dismiss
×is a<button>named from theclosecopy ("Close"). - Tiles, arrows, and dots all carry a visible
focus-visiblering (--goma-highlightPrimary).
Integration Caveats
SSR/webview: importing this package outside a browser previously threw immediately; fixed with a guard on the shared element factory.
Tokens/Theming:
themeTokens.jsdeclared an unused--goma-highlightGradientEnd(only--goma-highlightGradientStartis actually used); removed.Initialization: this widget shares
@gomagaming/core's i18n singleton with every other widget on the page; mounting two widgets with differentlocalevalues on one page is not currently isolated per instance (a known constraint, not fixed in this pass).Configuring before the definition loads. Assigning
config(or any property) while the element is still an unknown element is safe: the value is replayed through the widget when it upgrades. That matters when loading from the CDN, whose loader imports widget modules asynchronously, so your script usually runs first. On release sets at 0.34.0 and earlier the value was silently discarded and the widget mounted with no configuration and a clean console: there, awaitwindow.__gomaCdn.readyfirst, or configure through attributes. See Setting a property before the widget's definition has loaded.
See Integration Caveats for the cross-widget picture.
Changelog
Current release: 0.37.11. Every GomaPulse package shares one version number and they are published together, so a release that changes nothing here still bumps this widget. Only the releases that changed it are listed below.
Every release that changed this widget, newest first. The latest is open; the rest expand.
0.37.0
<goma-multi-banners>and<goma-casino-games>take anappearanceobject. On multi-banners it sets the rail's top and bottom padding, the card header and start-date type, the team-name line height and spacing, the CTA button's padding, line height and icon gap, and the gap between pagination dots. On casino-games it sets the pagination dots' size, gap and the active dot's width, so a design can draw the active dot as a circle instead of the default pill. Every key is optional and an empty object keeps today's look.@gomagaming/coreis bumped for the new utilities in its compiled sheet.<goma-multi-banners>gains twoappearancekeys:prevArrowDisplay(nonekeeps only the next arrow) andedgeFadeWidth(a fade over the cards' right edge into the page background, none by default).<goma-casino-games>gains amaxDotsproperty (max-dotsattribute) that caps the pagination row: with more snap positions thanmaxDots, that many dots stand for the whole track, the active one at the current position's proportional place, and a tap jumps to the matching position. The default,0, keeps one dot per snap position. Both widgets look and behave as before unless a host sets the new options.Casino games and time filter: the error bar's dismiss
×is now a button named "Close", so keyboard and screen-reader users can reach it, and its "ERROR:" prefix comes from the newerror_prefixcopy key and follows the widget's locale. In casino games, the carousel arrows' names and the dots' names ("Go to page 1") also come from copy keys (previous,next, and the newgo_to_page).clearError()now removes an error bar thatforceError()showed, and forcing the same message again after a dismiss shows the bar again.Casino games: a heading of spaces only now shows the default title, like a blank one.
custom-elements.jsonnow declares thegoma:seo-dataandgoma:retryevents the widget already emitted, and types a tapped game'sidandnameas possiblynull. The theme token list now names the flame's own token (iconPrimary) and the error bar's, and the two optional arrow tokens (navArrowBackground,navArrowIcon) now list a default, also in multi-banners and sports navigation (horizontal).Core: the Portuguese "Next" label read "Prximo"; it now reads "Próximo".
0.36.1
Playground manifests (
@gomagaming/<widget>/playground) now offer a control for every setting each widget really has. Settings that cannot be a form field (raw provider data, read-only state mirrors, props a widget never reads) are recorded with a reason in the repo instead of being silently missing.Controls that never reached the widget are fixed:
- The betslips'
placeBetHeadersJson/placeBetBodyJson/quickAddAmountsJsonare nowplaceBetHeaders/placeBetBody/quickAddAmounts. - The time-filter and filters-settings ticks editors set
ticks. - live-chat's layout control writes
position, the config key the element reads. - The sports-navigation widgets drop the unread
sportsJson. - JSON-typed defaults are real objects and arrays instead of serialized strings. The top-competitions
highlightedImagesstring default was indexed character by character and requested bad image URLs on every load. The missions-hubemptyStateImagesillustrations now show.
No widget runtime behaviour changes.
- The betslips'
0.36.0
- The carousel navigation arrow accepts two optional theme tokens:
--goma-navArrowBackground(the disc) and--goma-navArrowIcon(the caret). Unset, the arrow looks exactly as before (anallWhitedisc at 60% with ahighlightSecondaryContrastcaret) so only a palette where those two do not pair (for example a light theme that wants a dark disc) needs to set them.
0.34.0
Stop a region list fetched for the wrong sport from overwriting the right one, and parse numeric strings assigned to numeric widget properties instead of silently replacing them with the widget's default
A
<goma-region-filter>configured for any sport other than Football issued two location requests instead of one: its own, correctly scoped to the configured sport, and a second one (scoped to Football) that nothing had asked for. Both wrote the same place, so the pills the widget rendered were whichever response happened to come back last. The same race reached<goma-competitions-list>, which groups its competitions by the same region data.The unrequested request came from the per-widget boot routine, which fetched locations with no sport at all and so fell back to sport
1. Locations are scoped to a sport on the server, and boot has no sport to scope them by, so it no longer fetches them: the only readers of that data are the widgets above, and each of them already fetches it for the sport it is showing.That removes the collision at its source. As a second line of defence, a locations payload now records which sport it was fetched for, and a widget ignores one belonging to a sport it is not showing. This matters whenever two scoped fetches can overlap (switching sport while a request is still in flight, for instance) and it is deliberately narrow: a payload with no recorded sport is still rendered, so the guard can only ever suppress data it can positively identify as belonging to somewhere else.
Separately, every numeric property on every widget (
sportId,skeletonCount,pageSize,spaceBetween,autoplayIntervaland the rest) used to accept a JavaScript number and nothing else. A numeric string was not parsed; it was discarded and quietly replaced by the property's default value.el.sportId = '8'therefore left the widget on sport1and fetched the wrong data, with nothing logged to say so. Three ordinary integration paths hand over a string: a router parameter, a value read out of a CMS or JSON configuration, and a framework re-render that stringifies its props. Numeric strings are now parsed. Values that are not a finite number and not a numeric string (null,undefined,'', booleans, objects,NaN,Infinity) still fall back to the default, as before. HTML attributes (sport-id="8") and theconfigobject were never affected by this and are unchanged.
0.32.0
Widgets no longer dispatch a bare
errorevent alongsidegoma:error.Every factory-built widget's app-level Vue error handler dispatched two events for the same failure:
goma:error, and an un-namespacederror. The bare one is gone;goma:erroris unchanged and still carries the same{ message, code, component? }detail.Like every GomaPulse event it was
composedand bubbling, so it did not stop at the widget. It crossed the shadow root, crossed the document, and arrived at whatever the host had onwindow.addEventListener('error', …): as aCustomEventwithmessage,errorandfilenameallundefined, since those areErrorEventfields aCustomEventdoes not have. A host with error reporting installed received a malformed error record it could neither read nor attribute.That had been written off as harmless on the grounds that the handler behind it could never fire. It can. Vue begins its
errorCapturedwalk at the throwing component's parent, so theonErrorCapturedboundary each widget installs in its own root component cannot see that component's own errors, and being the root, there is nothing above it to catch them either. Anything raised in a widget's root scope (its setup, its render, its lifecycle hooks, its watchers) skips the boundary and reaches the app-level handler every time. Only errors from child components are caught by the boundary, which is what it is for: those show the in-shadow banner and emitgoma:retry.Hosts listening for
goma:errorneed no change. A host listening for bareerroron a widget element should move togoma:error; it was documented as unreachable, so in practice it delivered nothing until now.
0.31.0
Added
--goma-widgetInset, one CSS custom property that settles how far a widget's content sits from the edge of its element.Widgets had each grown their own horizontal padding (8px around the multi-banners and casino-games rails, none on the sports-navigation strip or the event feeds) so stacking them in a column started content at different offsets, and the only way to line them up was to cancel the difference with negative margins on the host side.
Set
--goma-widgetInsetonce and every widget that has a gutter adopts it; set it to0and they all run flush to their element, handing the gutter back to the page. Widgets that were already flush are unaffected: the token does not add padding where there was none.It governs horizontal padding only. Vertical padding is the space between sections, which a host already controls with margins, so folding it into the same token would mean setting the gutter to
8pxsilently added8pxof top padding to rails that had none.Panel widgets are deliberately not governed by it:
<goma-competitions-list>and<goma-top-competitions>(list variant) keep a fixed 16px interior, because that padding is the inside of a rounded box the widget paints rather than a page gutter.Nothing changes for existing embeds. There is no global default: each widget falls back to exactly what it renders today, so the token only takes effect once a host sets it.
0.29.0
Add
goma:seo-data: widgets emit their resolved event data so hosts can build their own meta tags and structured data.Eight widgets emit the event:
game-details,events-horizontal,competitions-list,hero-card,highlight-card,pros-choice,multi-banners(sport banners only), andcasino-games. The payload is{ widget, type, items }, wheretypeis'sports-event'or'casino-game'. The event bubbles and is composed, so a single listener ondocumentcatches every widget on the page.Emission fires once when data resolves and again only when the data's identity changes:
markets,scoreandclockare excluded from the identity signature, so odds ticks do not re-fire it. An emptyitemsarray is never emitted. Hosts must replace their structured data on each event rather than append.Widgets carrying a signed-in user's own data, private content, or page chrome deliberately do not emit.
Integration caveats: fixes from a cross-widget review of every shipped widget from an integrator's point of view.
Cross-cutting fixes:
@gomagaming/core'screateWidgetElement()factory, andlive-chat's andmessenger's own element classes, now guard against importing a widget package in a non-browser context (SSR): theHTMLElementsubclass was previously defined at module top level in every widget package, so importing any of them under server-side rendering threw aReferenceErrorimmediately.
Per-package fixes:
favorites: addedsrc/themeTokens.jsand a:hoststylesheet (previously the package had neither, so it silently rendered core's base theme instead of its documented dark-navy/cyan/amber theme).suggested-bet. Fixed a leaked WAMP subscription: switching a mounted widget'sdataSourceaway fromrpc/subscribenever released the open topic.filters-settings: fixed a dead:host{display:inline-block}CSS rule (the shared element factory's inlinedisplay:blockalways won), so the widget always rendered full-width instead of the intended compact inline trigger.game-details: added amin-heightfallback for the inert/no-eventIdstate in an unsized container.betslip-sidebar,my-bets,competition-filter,suggested-bet,events-horizontal,top-competitions,top-competitions-pills,competitions-list,multi-banners,casino-games,sports-navigation-horizontal. CorrectedthemeTokens.jsregistries that had drifted from actual token usage, added missinggoma:retryEvents-table rows, and other small doc/registry corrections.region-filter: added a missingtypeof window !== 'undefined'guard on a window listener.live-chat: correctedcustom-elements.json'smembersarray (missingtheme/configaccessors, and an inaccurate description).sports-domain: corrected a stale code comment that seeded a documentation error in two Missions widgets.
Three fixes (
favorites,game-details,filters-settings) change real rendering and are flagged indocs/guide/integration-caveats.mdas needing human visual verification before release.Visual corrections across the game card, the casino rail and every carousel arrow.
- Game cards. Team names on the large card variant were clipped: an 18px font was set on a 16px line box, which sheared the ascenders and the descenders of names like
Puerto Rico (W). The line box now fits the font's ink, and the home row's bottom margin is pulled in so the painted distance between the two team names is unchanged. Affects every widget rendering the shared game card, plus<goma-highlight-card>'s team rows. <goma-casino-games>: the'simplified'tile now matches its design source: a 23:30 portrait tile, and the name/provider block and play glyph laid out as one centred stack so the gap between them no longer changes with the number of lines the game name wraps to.- Navigation arrows:
<goma-casino-games>,<goma-multi-banners>and<goma-sports-navigation-horizontal>now draw one identical arrow: a 24px disc of--goma-allWhiteat 60% carrying a full-strength--goma-highlightSecondaryContrastcaret on a 1px stroke. Previously the three diverged in disc colour, glyph size (14–18px) and stroke weight. Hosts that restyled these arrows through--goma-textPrimaryor--goma-backgroundBordershould move to the two tokens above; both are declared in each widget's theme-token registry and documented in its theming table. <goma-top-competitions>: the list header's type now matches the section headers around it instead of running a size larger at a lighter weight.
- Game cards. Team names on the large card variant were clipped: an 18px font was set on a 16px line box, which sheared the ascenders and the descenders of names like
0.28.1
<goma-casino-games>: bring thesimplifiedtile's hover overlay onto the design frame.The provider line was 12px in the muted
--goma-textSecondary; the design sets it at 10px and binds it to the same colour variable as the game title, so it is now full-strength--goma-textPrimary. Both lines take the design's exact 16px line-height.The play glyph was a 28px generic triangle; it is now the design's own exported glyph at its native 40px.
Enlarging the glyph alone would have overlapped the provider text: the old 38%/61% offsets were tuned around the smaller icon. Both are re-derived from the design's layout instead: its overlay pads 2px top / 12px bottom, and the 50px title block and 60px icon frame centre as one stack inside the remainder, putting their centres at 30.6% and 61.1% of the tile. They stay percentages because tile height follows the host's
tileWidththrough the 3:4 aspect ratio.
0.28.0
- Casino games: add a
variantprop ('premium' | 'simplified').premiumis the default and renders exactly what shipped before.simplifiedshows the game artwork, or an animatedpreviewUrl(a GIF, or an .mp4/.webm/.mov/.m4v clip rendered as a muted, looped video that only plays while its tile is on screen), alone, revealing the name, provider and a pulsing play icon on hover; on touch, where there is no hover, the name and provider stay permanently visible. The header now places the flame before the title and can show an opt-in "All slots" link.
0.26.0
Stop publishing source maps and package source.
dist/*.js.mapwas emitted by the shared Vite preset and swept into every tarball byfiles: ["dist/", "src/"], with the original source inlined insourcesContent.src/shipped the same source again, in the clear. Both are one URL away from a browser once a package is served from a CDN, so the preset now builds withsourcemap: falseandfilesno longer carriessrc/.@gomagaming/corekeeps the two paths its export map actually points at:src/styles/main.cssandsrc/types/index.d.ts. Its tarball drops from 1741 files to 576, which also brings it back under the 900-file limit a per-request unpacker can handle.Deep imports of
@gomagaming/<pkg>/src/*from an installed package no longer resolve. Nothing documented used them; imports inside the monorepo are unaffected.
0.16.0
GomaPulse UX review (round 3):
- Sport icons: dedicated glyphs for the eSports titles (FIFA, NBA2k, Counter-Strike, DOTA 2, Overwatch) plus a shared outline-controller default for every other eSports category, replacing the legacy generic gamepad; corrected Beach Volleyball and Hurling glyphs.
- Casino card: nav-arrow disc uses
backgroundBorder; restyled Play pill (8px radius, 14px, weight 600,buttonTextPrimary, outline play icon); title gains a soft white glow on hover; added the design's top-edge line + radial top glow (driven byhighlightPrimary); removed the hover lift. - Multi-banners: favourite star now matches the app's outline star.
- Country flag ring (shared): uses the theme-fixed
allWhitetoken so the ring stays white under any consumer theme. - tabPill pressed state: added the 80%-opacity pressed treatment on the My Bets and Game Details pills.
- Sports selector: the widget host now carries a default 8px corner radius.
- Suggested-bet leg: sport-icon colour uses
iconPrimary.
0.15.2
GomaPulse UX-review round 2: visual/token fixes:
- core: official flat sports-icon set (46 mainstream/virtual/eSports-category glyphs across dark + light modes, keyed by sport id). Inherited app-wide via
SbIcon; newcasino_games_playi18n key (en/fr/pt). - casino-games: official flame glyph, hover "Play" overlay on tiles, title→tiles / tiles→dots spacing.
- multi-banners: header now self-resolves the sport glyph from the event's sport id, renders the country flag via the shared
CountryFlagcomponent (newflagBaseUrloption, defaults to the OM flag CDN), and gains a 1px card border. - sports-navigation-horizontal: the rounded container now clips its content so the 8px corners render.
- suggested-bet: leg sport icons use the flat bundled icon set.
- game-details / missions-hub / sports-domain (My Bets): tabPill hover + pressed states (violet ring); My Bets ticket icon sizing (12px sport + flag) and centered totals summary.
- core: official flat sports-icon set (46 mainstream/virtual/eSports-category glyphs across dark + light modes, keyed by sport id). Inherited app-wide via
0.15.0
UI fixes from the a separate change design review (Sports Pages, items 1.1–1.19):
- Suspended odds pill text uses
inputTextTitleDisabled(legible on lightened themes) and game-card team/player names render at 16px. - Brand font: Open Sans is bundled and registered via the
document.fontsAPI so widgets paint the intended typeface inside the shadow root. - Game-card market pill colours corrected (live
separatorLine, prelivehighlightPrimary); sports-navigation tile sizing + rounded container; multi-banners overlay gradient; casino-games flame colour + tile gradient border; filters-settings radio-row divider. - competition-filter: edge-trigger icon size, pill padding, and hover/pressed states.
- competitions-list: inset row divider (original colour) + corrected accordion caret orientation.
- game-details: header sport-icon/flag + rounded top corners; market-tab horizontal paging arrows with click-to-centre; long-market "See All" cap; corrected collapse-caret orientation.
- top-competitions: white sport icon + featured-card neon divider moved to the card bottom and thickened.
- suggested-bet: Bet / Total Odds / Winnings summary centre-aligned.
- Suspended odds pill text uses
0.13.0
- Add
<goma-casino-games>: a compact, host-fed casino games rail (titled section + flame, portrait artwork tiles with name overlay, next-tile peek, arrows, dot pagination). Emitsgoma:casino-game-selecton tile tap. Core-only, no WAMP; Swiper-based carousel.