@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 +23 -0
- package/README.md +112 -0
- package/dist/index.cjs +413 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +404 -186
- package/dist/index.js.map +1 -1
- package/dist/styles.css +46 -1
- package/package.json +2 -2
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.
|