@circlesquare/embedding-next 2.0.0 → 2.1.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/README.md +203 -80
- package/dist/embedded-frame.js +8 -1
- package/dist/frame-url.d.ts +3 -3
- package/dist/frame-url.js +14 -4
- package/dist/types.d.ts +16 -0
- package/dist/types.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,119 +1,242 @@
|
|
|
1
1
|
# @circlesquare/embedding-next
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Next.js components for embedding your club's events and court availability, in your website's
|
|
4
|
+
colors, corners and typeface.
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
npm install @circlesquare/embedding-next
|
|
10
|
+
# or
|
|
11
|
+
yarn add @circlesquare/embedding-next
|
|
10
12
|
```
|
|
11
13
|
|
|
12
|
-
React 18 or later.
|
|
13
|
-
page can render them directly.
|
|
14
|
+
The package needs React 18 or later.
|
|
14
15
|
|
|
15
16
|
## Usage
|
|
16
17
|
|
|
18
|
+
The components are client components (`'use client'`). You can render them from a Server
|
|
19
|
+
Component page or from your own client component.
|
|
20
|
+
|
|
21
|
+
Every component needs your merchant id. It looks like `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, and
|
|
22
|
+
you find it in the manager under
|
|
23
|
+
[**Settings** > **Developer**](https://manager.circlesquare.app/settings/developer).
|
|
24
|
+
|
|
25
|
+
### Config provider (optional)
|
|
26
|
+
|
|
27
|
+
The provider holds the options every component below it shares, so you set your merchant id and
|
|
28
|
+
your look once, for example in your root layout. A component's own props override the provider's
|
|
29
|
+
for that component only.
|
|
30
|
+
|
|
17
31
|
```tsx
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
CSEvents,
|
|
22
|
-
CsEventType,
|
|
23
|
-
} from '@circlesquare/embedding-next'
|
|
24
|
-
|
|
25
|
-
export default function ClubPage() {
|
|
32
|
+
import { CircleSquareEmbeddingConfigProvider } from '@circlesquare/embedding-next'
|
|
33
|
+
|
|
34
|
+
export default function RootLayout({ children }) {
|
|
26
35
|
return (
|
|
27
36
|
<CircleSquareEmbeddingConfigProvider
|
|
28
37
|
merchantId="your-merchant-id"
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
backgroundColor="#FFFFFF"
|
|
39
|
+
language="en"
|
|
31
40
|
>
|
|
32
|
-
|
|
33
|
-
<CSCourtAvailability sportIds={[1]} />
|
|
34
|
-
<h2>Events</h2>
|
|
35
|
-
<CSEvents eventTypes={[CsEventType.OpenPlay, CsEventType.Training]} />
|
|
41
|
+
<>{children}</>
|
|
36
42
|
</CircleSquareEmbeddingConfigProvider>
|
|
37
43
|
)
|
|
38
44
|
}
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
value wins. A component left without `merchantId` (or, for events, without `hostId`) renders
|
|
43
|
-
nothing and says why in the console.
|
|
47
|
+
_Note: With React 19, wrapping children in `<></>` might be required._
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
#### Provider props
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
| Prop | Required | Description |
|
|
52
|
+
| ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| `merchantId` | No | Your CircleSquare merchant ID, for every component below |
|
|
54
|
+
| `backgroundColor` | No | Background color for the embedded content |
|
|
55
|
+
| `language` | No | Language of the embedded content (`en` / `de`). Will otherwise be selected automatically. |
|
|
56
|
+
| Look options | No | `appearance`, `surfaceColor`, `textColor` and the others in [Match the widgets to your website](#match-the-widgets-to-your-website) |
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
| ------------ | --------------------------------- | ------------------------------------------------------------------------ |
|
|
51
|
-
| `merchantId` | provider, both | Your club. Required, except for an organizer's events listed by `hostId` |
|
|
52
|
-
| `hostId` | `CSEvents` | The organizer whose events are listed |
|
|
53
|
-
| `eventTypes` | `CSEvents` | The kinds of event to list (`CsEventType`); all of them by default |
|
|
54
|
-
| `sportIds` | `CSEvents`, `CSCourtAvailability` | The sports to show; all of the club's by default |
|
|
55
|
-
| `language` | provider, both | `en` or `de`; without it, the visitor's language |
|
|
58
|
+
### Events component
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
```tsx
|
|
61
|
+
import { CSEvents, CsEventType } from '@circlesquare/embedding-next'
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
export default function EventsPage() {
|
|
64
|
+
return (
|
|
65
|
+
<div>
|
|
66
|
+
<h1>Events</h1>
|
|
67
|
+
<CSEvents
|
|
68
|
+
merchantId="your-merchant-id"
|
|
69
|
+
eventTypes={[CsEventType.OpenPlay, CsEventType.Training]}
|
|
70
|
+
backgroundColor="#F5F5F5"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
```
|
|
62
76
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
77
|
+
#### CSEvents props
|
|
78
|
+
|
|
79
|
+
| Prop | Required | Description |
|
|
80
|
+
| ----------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `merchantId` | Unless set in a provider | Your CircleSquare merchant ID. With only `hostId`, the component lists that host's events. |
|
|
82
|
+
| `hostId` | No | Filter events by host ID |
|
|
83
|
+
| `eventTypes` | No | Array of event types to filter, from `CsEventType` (below). All types by default. |
|
|
84
|
+
| `sports` | No | Array of sports to filter, from `CsSport` (below). All of your club's sports by default. |
|
|
85
|
+
| `sportIds` | No | Deprecated, use `sports`. Array of sport IDs to filter. |
|
|
86
|
+
| `backgroundColor` | No | Background color for the embedded content |
|
|
87
|
+
| `language` | No | Language of the embedded content (`en` / `de`). Will otherwise be selected automatically. |
|
|
88
|
+
| Look options | No | See [Match the widgets to your website](#match-the-widgets-to-your-website) |
|
|
89
|
+
| `className` | No | Additional CSS class for the element that holds the widget |
|
|
90
|
+
| `fallback` | No | A component to display in case the widget can not be loaded or displayed. If not provided, the default is used. |
|
|
91
|
+
| `timeoutMs` | No | Time after which the fallback component is displayed. Defaults to 8000 (8 seconds). |
|
|
92
|
+
|
|
93
|
+
`CsEventType` values:
|
|
94
|
+
|
|
95
|
+
- `OpenPlay`
|
|
96
|
+
- `Training`
|
|
97
|
+
- `Other`
|
|
98
|
+
- `League`
|
|
99
|
+
- `Americano`
|
|
100
|
+
- `AmericanoTournament`
|
|
101
|
+
- `RoundRobinTournament`
|
|
102
|
+
- `Tournament`
|
|
103
|
+
- `LevelingSession`
|
|
104
|
+
|
|
105
|
+
`CsSport` values:
|
|
106
|
+
|
|
107
|
+
- `Tennis`
|
|
108
|
+
- `Padel`
|
|
109
|
+
- `Pickleball`
|
|
110
|
+
- `BeachVolleyball`
|
|
111
|
+
- `Football`
|
|
112
|
+
- `Badminton`
|
|
113
|
+
- `Squash`
|
|
74
114
|
|
|
75
|
-
|
|
115
|
+
```tsx
|
|
116
|
+
<CSEvents sports={[CsSport.Padel, CsSport.Pickleball]} />
|
|
117
|
+
```
|
|
76
118
|
|
|
77
|
-
|
|
119
|
+
A sport the widget doesn't know is left out, and the browser console names it. If no sport you
|
|
120
|
+
named is left, the widget shows all of them.
|
|
78
121
|
|
|
79
|
-
|
|
80
|
-
| ----------- | ----- | --------------------------------------------------------------------------------------- |
|
|
81
|
-
| `className` | both | A class for the element that holds the frame |
|
|
82
|
-
| `fallback` | both | Shown instead of the default notice when the frame does not show in time |
|
|
83
|
-
| `timeoutMs` | both | How long the frame may take to show before the fallback replaces it; 8000 ms by default |
|
|
122
|
+
### Court availability component
|
|
84
123
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
CircleSquare. The frame keeps loading behind it and replaces the notice once it shows. A content
|
|
88
|
-
security policy needs `frame-src https://circlesquare.app`.
|
|
124
|
+
```tsx
|
|
125
|
+
import { CSCourtAvailability } from '@circlesquare/embedding-next'
|
|
89
126
|
|
|
90
|
-
|
|
127
|
+
export default function CourtsPage() {
|
|
128
|
+
return (
|
|
129
|
+
<div>
|
|
130
|
+
<h1>Court Availability</h1>
|
|
131
|
+
<CSCourtAvailability merchantId="your-merchant-id" backgroundColor="#F5F5F5" />
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
```
|
|
91
136
|
|
|
92
|
-
|
|
93
|
-
`eventColor`, `borderRadius` and `fontFamily`, in the provider or on each component.
|
|
94
|
-
- `sportIds` on both components; `hostId` alone lists an organizer's events.
|
|
95
|
-
- `CsEventType.Tournament` and `CsEventType.LevelingSession`.
|
|
96
|
-
- `CsEventType.KnockOutTournament` is gone.
|
|
97
|
-
- The frame stays behind the fallback notice until it shows, and replaces the notice then.
|
|
98
|
-
The default `timeoutMs` is 8000 instead of 3000.
|
|
99
|
-
- `className` goes on the element that holds the frame, not on the iframe itself.
|
|
100
|
-
- The package is an ES module with an `exports` map, and needs no `next` peer.
|
|
137
|
+
#### CSCourtAvailability props
|
|
101
138
|
|
|
102
|
-
|
|
139
|
+
| Prop | Required | Description |
|
|
140
|
+
| ----------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| `merchantId` | Unless set in a provider | Your CircleSquare merchant ID |
|
|
142
|
+
| `sports` | No | Array of sports to show, from `CsSport` as for `CSEvents`. All of your club's sports by default. |
|
|
143
|
+
| `sportIds` | No | Deprecated, use `sports`. Array of sport IDs to show. |
|
|
144
|
+
| `language` | No | Language of the embedded content (`en` / `de`). Will otherwise be selected automatically. |
|
|
145
|
+
| `backgroundColor` | No | Background color for the embedded content |
|
|
146
|
+
| Look options | No | See [Match the widgets to your website](#match-the-widgets-to-your-website) |
|
|
147
|
+
| `className` | No | Additional CSS class for the element that holds the widget |
|
|
148
|
+
| `fallback` | No | A component to display in case the widget can not be loaded or displayed. If not provided, the default is used. |
|
|
149
|
+
| `timeoutMs` | No | Time after which the fallback component is displayed. Defaults to 8000 (8 seconds). |
|
|
103
150
|
|
|
104
|
-
|
|
105
|
-
|
|
151
|
+
A component without a merchant ID (or, for `CSEvents`, without a host ID) renders nothing and logs
|
|
152
|
+
the reason in the browser console.
|
|
106
153
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
154
|
+
## Match the widgets to your website
|
|
155
|
+
|
|
156
|
+
You can give the widgets your website's colors, corners and typeface. Every option is optional.
|
|
157
|
+
Without them, the widgets use CircleSquare's own look on a white background. Set them on the
|
|
158
|
+
provider for every widget, or on a single component.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
<CircleSquareEmbeddingConfigProvider
|
|
162
|
+
merchantId="your-merchant-id"
|
|
163
|
+
appearance="dark"
|
|
164
|
+
backgroundColor="transparent"
|
|
165
|
+
surfaceColor="#0E1828"
|
|
166
|
+
textColor="#FFFFFF"
|
|
167
|
+
accentColor="#C6F432"
|
|
168
|
+
accentTextColor="#0A1220"
|
|
169
|
+
eventColor="#38BDF8"
|
|
170
|
+
borderRadius={24}
|
|
171
|
+
fontFamily="Inter"
|
|
172
|
+
>
|
|
173
|
+
{children}
|
|
174
|
+
</CircleSquareEmbeddingConfigProvider>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
| Option | What it changes | Default |
|
|
178
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
179
|
+
| `appearance` | `"light"` or `"dark"`. Use `"dark"` on a website with a dark background. | `"light"` |
|
|
180
|
+
| `backgroundColor` | The background behind the widget. `"transparent"` lets your page show through. | White, or none with `appearance="dark"` |
|
|
181
|
+
| `surfaceColor` | The widget's own surfaces: the card around the court grid, popovers and dialogs. | CircleSquare's |
|
|
182
|
+
| `textColor` | The text. Secondary text, lines and unavailable time slots are lighter shades of it. | CircleSquare's |
|
|
183
|
+
| `accentColor` | Your brand color: the visitor's own bookings, the selected time slot, the main button and the focus outline. | CircleSquare's |
|
|
184
|
+
| `accentTextColor` | Text on the accent color, such as the label of the main button. | Black or white, whichever is easier to read on `accentColor` |
|
|
185
|
+
| `eventColor` | Events shown in the court grid. | CircleSquare's |
|
|
186
|
+
| `borderRadius` | The corners of cards and buttons. A number is in pixels (`8`). A string in `px` or `rem` works too (`"0.5rem"`). Smaller elements such as grid cells scale with it, and `0` gives square corners. | `12` |
|
|
187
|
+
| `fontFamily` | The typeface, one from the list below. | `"Inter"` |
|
|
188
|
+
|
|
189
|
+
Colors can be written as hex (`#C6F432`), with a color function such as `rgb(198, 244, 50)`,
|
|
190
|
+
`hsl()` or `oklch()`, or as a CSS color name (`white`). `backgroundColor` also takes a CSS
|
|
191
|
+
gradient. CSS variables such as `var(--brand)` don't work, because the widget runs in a frame that
|
|
192
|
+
can't read your page's styles.
|
|
193
|
+
|
|
194
|
+
The widget ignores a value it can't read and keeps its own color, corner or typeface. For colors,
|
|
195
|
+
the browser console also shows a warning such as
|
|
196
|
+
`[CircleSquare] accentColor "#C6F43" is not a colour, leaving the widget's own`.
|
|
197
|
+
|
|
198
|
+
**Typefaces.** The widget can't use the fonts your website loads, so `fontFamily` takes one of the
|
|
199
|
+
typefaces CircleSquare serves: `Barlow`, `DM Sans`, `Inter`, `Lato`, `Manrope`, `Montserrat`,
|
|
200
|
+
`Nunito`, `Open Sans`, `Oswald`, `Poppins` or `Roboto`. CircleSquare serves the font files itself,
|
|
201
|
+
so the widget sends no requests to Google Fonts and needs no cookie consent.
|
|
202
|
+
|
|
203
|
+
### Settings for a single widget
|
|
204
|
+
|
|
205
|
+
Each component takes the same options as props, and they override the provider's for that widget
|
|
206
|
+
only:
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<CSEvents accentColor="#B33E25" />
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## When a widget can't load
|
|
213
|
+
|
|
214
|
+
If a widget hasn't loaded after 8 seconds, for example because the visitor's ad blocker drops it,
|
|
215
|
+
a notice with a link to your club's page on CircleSquare takes its place. The notice uses your
|
|
216
|
+
colors and corners. If the widget loads later, it replaces the notice. `timeoutMs` changes how long
|
|
217
|
+
the component waits, and `fallback` replaces the notice with your own:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
<CSCourtAvailability timeoutMs={12000} fallback={<p>Book your court at the front desk.</p>} />
|
|
113
221
|
```
|
|
114
222
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
223
|
+
If your website has a content security policy, it needs `frame-src https://circlesquare.app`.
|
|
224
|
+
|
|
225
|
+
## Changes in 2.1
|
|
226
|
+
|
|
227
|
+
- `sports` names the sports with `CsSport` (`[CsSport.Padel]`), so you no longer need our sport
|
|
228
|
+
IDs.
|
|
229
|
+
- `sportIds` is deprecated. It still works, alongside `sports`, until 3.0.
|
|
230
|
+
|
|
231
|
+
## Changes in 2.0
|
|
232
|
+
|
|
233
|
+
- The look: `appearance`, `surfaceColor`, `textColor`, `accentColor`, `accentTextColor`,
|
|
234
|
+
`eventColor`, `borderRadius` and `fontFamily`, on the provider or on each component.
|
|
235
|
+
- `sportIds` on both components; `hostId` alone lists a host's events.
|
|
236
|
+
- `CsEventType.Tournament` and `CsEventType.LevelingSession`.
|
|
237
|
+
- `CsEventType.KnockOutTournament` is gone.
|
|
238
|
+
- The widget keeps loading behind the fallback notice and replaces it once it shows. The default
|
|
239
|
+
`timeoutMs` is 8000 instead of 3000.
|
|
240
|
+
- `className` goes on the element that holds the widget, not on the iframe itself.
|
|
241
|
+
- The components are client components themselves, so a Server Component can render them.
|
|
242
|
+
- The package is an ES module with an `exports` map, and needs no `next` peer.
|
package/dist/embedded-frame.js
CHANGED
|
@@ -22,6 +22,13 @@ const isSetHeightMessage = (data, containerId) => {
|
|
|
22
22
|
typeof message.height === 'number' &&
|
|
23
23
|
Number.isFinite(message.height));
|
|
24
24
|
};
|
|
25
|
+
/* The frame's name for a screen reader. The server renders it, where the
|
|
26
|
+
visitor's language is unknown, so only a configured language changes it. */
|
|
27
|
+
const FRAME_TITLES = {
|
|
28
|
+
courts: { en: 'CircleSquare court availability', de: 'CircleSquare-Platzverfügbarkeit' },
|
|
29
|
+
events: { en: 'CircleSquare events', de: 'CircleSquare-Events' },
|
|
30
|
+
};
|
|
31
|
+
const getFrameTitle = (widget, { language }) => FRAME_TITLES[widget][language?.toLowerCase() === 'de' ? 'de' : 'en'];
|
|
25
32
|
const isBrowserColour = (value) => typeof CSS === 'undefined' || CSS.supports('color', value);
|
|
26
33
|
/** One framed page on the host's page, as tall as its content. */
|
|
27
34
|
export function EmbeddedFrame({ widget, config, className, fallback, timeoutMs = DEFAULT_TIMEOUT_MS, }) {
|
|
@@ -73,7 +80,7 @@ export function EmbeddedFrame({ widget, config, className, fallback, timeoutMs =
|
|
|
73
80
|
document.removeEventListener('click', handleHostPress, true);
|
|
74
81
|
};
|
|
75
82
|
}, [href, origin, containerId, widget, timeoutMs]);
|
|
76
|
-
return (_jsxs("div", { className: className, style: { width: '100%' }, children: [_jsx("iframe", { ref: frameRef, style: {
|
|
83
|
+
return (_jsxs("div", { className: className, style: { width: '100%' }, children: [_jsx("iframe", { ref: frameRef, title: getFrameTitle(widget, config), style: {
|
|
77
84
|
display: 'block',
|
|
78
85
|
width: '100%',
|
|
79
86
|
border: 'none',
|
package/dist/frame-url.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CsEventsConfig } from './types.js';
|
|
2
2
|
export declare const DEFAULT_CS_BASE_URL = "https://circlesquare.app";
|
|
3
3
|
export type EmbeddedWidget = 'courts' | 'events';
|
|
4
4
|
/** A widget's configuration once the provider's and the component's are merged. */
|
|
5
5
|
export type FrameConfig = CsEventsConfig;
|
|
6
6
|
/**
|
|
7
|
-
* The frame's address. `csEmbedded`
|
|
8
|
-
* framed
|
|
7
|
+
* The frame's address. `csEmbedded` is sent as the loader sends it; the framed page knows it is
|
|
8
|
+
* framed from its path.
|
|
9
9
|
*/
|
|
10
10
|
export declare function getFrameUrl({ widget, containerId, config, }: {
|
|
11
11
|
widget: EmbeddedWidget;
|
package/dist/frame-url.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
here, and it ignores the theme options it does not know. */
|
|
1
|
+
import { CsSport } from './types.js';
|
|
3
2
|
export const DEFAULT_CS_BASE_URL = 'https://circlesquare.app';
|
|
4
3
|
const WIDGET_PATHS = {
|
|
5
4
|
courts: '/embedded/court-availability',
|
|
6
5
|
events: '/embedded/events',
|
|
7
6
|
};
|
|
8
7
|
const SUPPORTED_LANGUAGES = ['en', 'de'];
|
|
8
|
+
/* The page matches a sport's key without spaces, `_` and `-` and in any
|
|
9
|
+
case (the clubs domain's sport.model.ts), and drops one it does not know. */
|
|
10
|
+
const normaliseSportKey = (value) => value.replace(/[\s_-]/g, '').toLowerCase();
|
|
11
|
+
const KNOWN_SPORTS = Object.values(CsSport).map(normaliseSportKey);
|
|
9
12
|
/** Each theme option by the parameter the framed page reads. */
|
|
10
13
|
const THEME_PARAMETERS = {
|
|
11
14
|
appearance: 'appearance',
|
|
@@ -27,8 +30,8 @@ const isSupportedLanguage = (language) => SUPPORTED_LANGUAGES.includes(language.
|
|
|
27
30
|
const getLocalizedPath = (path, { language }) => language && isSupportedLanguage(language) ? `/${language.toLowerCase()}${path}` : path;
|
|
28
31
|
const joinList = (values) => (values ?? []).map(String).join(',');
|
|
29
32
|
/**
|
|
30
|
-
* The frame's address. `csEmbedded`
|
|
31
|
-
* framed
|
|
33
|
+
* The frame's address. `csEmbedded` is sent as the loader sends it; the framed page knows it is
|
|
34
|
+
* framed from its path.
|
|
32
35
|
*/
|
|
33
36
|
export function getFrameUrl({ widget, containerId, config, }) {
|
|
34
37
|
const url = new URL(getLocalizedPath(WIDGET_PATHS[widget], config), getBaseUrl(config));
|
|
@@ -41,6 +44,7 @@ export function getFrameUrl({ widget, containerId, config, }) {
|
|
|
41
44
|
append('hostId', config.hostId);
|
|
42
45
|
append('clubId', config.merchantId);
|
|
43
46
|
append('eventTypes', joinList(config.eventTypes));
|
|
47
|
+
append('sports', joinList(config.sports));
|
|
44
48
|
append('sportIds', joinList(config.sportIds));
|
|
45
49
|
append('background', config.backgroundColor);
|
|
46
50
|
for (const [option, parameter] of Object.entries(THEME_PARAMETERS)) {
|
|
@@ -71,6 +75,12 @@ export function getConfigWarning(config, { isColour }) {
|
|
|
71
75
|
const value = config[option];
|
|
72
76
|
return value && !isColour(value) ? [`${option} "${value}" is not a colour, leaving the widget's own`] : [];
|
|
73
77
|
});
|
|
78
|
+
/* A key the types allow is always known; this is for a plain JavaScript caller or a cast. */
|
|
79
|
+
for (const sport of config.sports ?? []) {
|
|
80
|
+
if (!KNOWN_SPORTS.includes(normaliseSportKey(String(sport)))) {
|
|
81
|
+
warnings.push(`sport "${sport}" is not one of ${Object.values(CsSport).join(', ')}, leaving it out`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
74
84
|
if (config.language && !isSupportedLanguage(config.language)) {
|
|
75
85
|
warnings.push(`unsupported language "${config.language}", falling back to automatic selection`);
|
|
76
86
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -10,6 +10,16 @@ export declare enum CsEventType {
|
|
|
10
10
|
LevelingSession = "LEVELING_SESSION",
|
|
11
11
|
Other = "OTHER"
|
|
12
12
|
}
|
|
13
|
+
/** The sports a widget can be limited to, by the keys the framed page reads. */
|
|
14
|
+
export declare enum CsSport {
|
|
15
|
+
Tennis = "TENNIS",
|
|
16
|
+
Padel = "PADEL",
|
|
17
|
+
Pickleball = "PICKLEBALL",
|
|
18
|
+
BeachVolleyball = "BEACH_VOLLEYBALL",
|
|
19
|
+
Football = "FOOTBALL",
|
|
20
|
+
Badminton = "BADMINTON",
|
|
21
|
+
Squash = "SQUASH"
|
|
22
|
+
}
|
|
13
23
|
export type CsLanguage = 'en' | 'de';
|
|
14
24
|
export type CsAppearance = 'light' | 'dark';
|
|
15
25
|
/** The typefaces the framed page serves itself; a frame cannot use the fonts of the page around it. */
|
|
@@ -46,9 +56,15 @@ export interface CsEventsConfig extends CsEmbeddingBaseConfig {
|
|
|
46
56
|
/** The organizer whose events are listed; replaces `merchantId` for an organizer's own list. */
|
|
47
57
|
hostId?: string;
|
|
48
58
|
eventTypes?: CsEventType[];
|
|
59
|
+
/** The sports whose events are listed; every sport by default. */
|
|
60
|
+
sports?: CsSport[];
|
|
61
|
+
/** @deprecated Name the sports with `sports` instead. The page still reads the ids beside it. */
|
|
49
62
|
sportIds?: number[];
|
|
50
63
|
}
|
|
51
64
|
export interface CsCourtAvailabilityConfig extends CsEmbeddingBaseConfig {
|
|
65
|
+
/** The sports the court grid offers; every sport of the club by default. */
|
|
66
|
+
sports?: CsSport[];
|
|
67
|
+
/** @deprecated Name the sports with `sports` instead. The page still reads the ids beside it. */
|
|
52
68
|
sportIds?: number[];
|
|
53
69
|
}
|
|
54
70
|
export interface CircleSquareEmbeddingConfigContextType {
|
package/dist/types.js
CHANGED
|
@@ -16,3 +16,14 @@ export var CsEventType;
|
|
|
16
16
|
CsEventType["LevelingSession"] = "LEVELING_SESSION";
|
|
17
17
|
CsEventType["Other"] = "OTHER";
|
|
18
18
|
})(CsEventType || (CsEventType = {}));
|
|
19
|
+
/** The sports a widget can be limited to, by the keys the framed page reads. */
|
|
20
|
+
export var CsSport;
|
|
21
|
+
(function (CsSport) {
|
|
22
|
+
CsSport["Tennis"] = "TENNIS";
|
|
23
|
+
CsSport["Padel"] = "PADEL";
|
|
24
|
+
CsSport["Pickleball"] = "PICKLEBALL";
|
|
25
|
+
CsSport["BeachVolleyball"] = "BEACH_VOLLEYBALL";
|
|
26
|
+
CsSport["Football"] = "FOOTBALL";
|
|
27
|
+
CsSport["Badminton"] = "BADMINTON";
|
|
28
|
+
CsSport["Squash"] = "SQUASH";
|
|
29
|
+
})(CsSport || (CsSport = {}));
|
package/package.json
CHANGED