@sensiblestats/widget-react 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.37.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8d25f74: Match odds accordion: pinned matches on the Matches tab now show a browsable accordion of every priced market instead of a single 1X2 card. Odds load lazily on expand and refresh live while open; each market surfaces its value insight. Adds `conversation.getMarketOdds` and `availableMarkets` on the live-monitor snapshot; removes the snapshot's `mainMarket`.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [8d25f74]
12
+ - @sensiblestats/widget-sdk@0.30.0
13
+
14
+ ## 0.36.0
15
+
16
+ ### Minor Changes
17
+
18
+ - Add a `pinIcon` config option (`'pin' | 'star' | 'bookmark'`, default `'pin'`, embed `data-pin-icon`) to choose the glyph used for the match/odds save toggle. All three render as an outline when unpinned and fill on the accent circle when pinned; the default pin keeps its existing shape.
19
+
20
+ ## 0.35.1
21
+
22
+ ### Patch Changes
23
+
24
+ - 1210539: Add a one-shot launcher attention animation: on first load the chat icon nudges, then the greeting bubble types itself in, then everything settles. Runs once per page (a refresh replays it) and is fully suppressed under `prefers-reduced-motion`, where the greeting is shown statically. No config or API change.
25
+
3
26
  ## 0.35.0
4
27
 
5
28
  ### Minor Changes
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # @sensiblestats/widget-react
2
+
3
+ React component for the SensibleStats operator chat widget. Renders a floating
4
+ launcher and chat panel, built on `@sensiblestats/widget-sdk`.
5
+
6
+ ## Install
7
+
8
+ `yarn add @sensiblestats/widget-react`
9
+
10
+ Peer dependencies: `react` and `react-dom` (18 or 19).
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { StatsWidget } from '@sensiblestats/widget-react'
16
+
17
+ export function App() {
18
+ return (
19
+ <StatsWidget
20
+ config={{
21
+ operatorId: 'sandbox1',
22
+ publicKey: 'wgk_…',
23
+ baseUrl: 'https://widget.sensiblestats.com',
24
+ locale: 'en',
25
+ }}
26
+ />
27
+ )
28
+ }
29
+ ```
30
+
31
+ Common `config` fields:
32
+
33
+ - `operatorId`, `publicKey` — your gateway credentials (both browser-safe; the
34
+ public key is origin-gated at the gateway).
35
+ - `baseUrl` — the widget gateway URL.
36
+ - `locale` — `'en'` or `'tr'` for the widget's own chrome text.
37
+ - `userContext` — `{ operatorUserId, defaultLanguage }` to tie the conversation
38
+ and personalization to your signed-in user.
39
+ - White-label branding — `logoUrl`, `headerTitle`, `accent`, `cta`, `surface`,
40
+ `ink`. Absent → the default SensibleStats look.
41
+
42
+ ## Integration: persisting the conversation across SPA navigation
43
+
44
+ The conversation (messages, conversation id, open/closed state) lives in the
45
+ component's in-memory React state. It survives for exactly as long as the
46
+ `<StatsWidget>` instance stays mounted:
47
+
48
+ - **In-app (client-side) navigation** keeps it — as long as the component is not
49
+ unmounted.
50
+ - **A hard page refresh** tears down the React tree and remounts the widget, so
51
+ the conversation starts fresh. This is intentional.
52
+
53
+ To keep the active conversation across route changes in a single-page app,
54
+ **mount `<StatsWidget>` once in a component that stays mounted across
55
+ navigation** — your app shell / persistent layout — not inside a routed page.
56
+
57
+ ### React Router (v6)
58
+
59
+ Render the widget in the layout route element, alongside `<Outlet />`, so it
60
+ persists while pages swap underneath it:
61
+
62
+ ```tsx
63
+ // AppLayout.tsx
64
+ import { Outlet } from 'react-router-dom'
65
+ import { StatsWidget } from '@sensiblestats/widget-react'
66
+
67
+ // Define config once, outside render, so its identity is stable across renders.
68
+ const widgetConfig = {
69
+ operatorId: 'sandbox1',
70
+ publicKey: 'wgk_…',
71
+ baseUrl: 'https://widget.sensiblestats.com',
72
+ }
73
+
74
+ export function AppLayout() {
75
+ return (
76
+ <>
77
+ <Header />
78
+ <Outlet /> {/* pages render here and swap on navigation */}
79
+ <StatsWidget config={widgetConfig} /> {/* stays mounted across route changes */}
80
+ </>
81
+ )
82
+ }
83
+ ```
84
+
85
+ ```tsx
86
+ // routes — AppLayout wraps the routed pages, so it is not remounted per route
87
+ <Route element={<AppLayout />}>
88
+ <Route path="/" element={<Home />} />
89
+ <Route path="/matches" element={<Matches />} />
90
+ </Route>
91
+ ```
92
+
93
+ ### Next.js App Router
94
+
95
+ Render `<StatsWidget>` in the root `app/layout.tsx` (a client component, or a
96
+ small `'use client'` wrapper). The root layout is not re-rendered on route
97
+ navigation, so the conversation persists; a full reload resets it.
98
+
99
+ ### What breaks persistence
100
+
101
+ Both of these force React to unmount and remount the widget, wiping the
102
+ conversation on every navigation — avoid them:
103
+
104
+ - **Rendering `<StatsWidget>` inside a per-route page component.** React Router
105
+ unmounts the page (and the widget with it) on navigation.
106
+ - **Changing the component's `key`, or passing a `config` object rebuilt on
107
+ every render, in a way that remounts the subtree.** Keep the widget's place in
108
+ the tree and its `config` reference stable — define `config` at module scope or
109
+ memoize it with `useMemo`.
110
+
111
+ The launcher is fixed-position, so the app-shell mount is also the correct place
112
+ for it visually — it does not belong to any single page.