@getspot/spot-widget-react 1.3.0 → 2.0.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,27 @@
1
1
  # @getspot/spot-widget-react
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 4c59d56: Typescript support
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [4c59d56]
12
+ - @getspot/spot-widget@2.0.0
13
+
14
+ ## 1.4.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 5b3eaaf: add qualifying reasons for pass/trip offers
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [5b3eaaf]
23
+ - @getspot/spot-widget@1.4.0
24
+
3
25
  ## 1.3.0
4
26
 
5
27
  ### Minor Changes
package/README.md CHANGED
@@ -1,12 +1,254 @@
1
- # Spot React Widget
1
+ # @getspot/spot-widget-react
2
2
 
3
- ## Description
4
- This is a UI component for displaying a quote offer to users in a checkout flow
3
+ React component wrapper for the Spot refund guarantee widget.
4
+
5
+ > **Note:** This React wrapper uses types from [@getspot/spot-widget](https://www.npmjs.com/package/@getspot/spot-widget).
6
+
7
+ ### Key Types
8
+ - `ApiConfig` - API configuration (environment, partnerId, customEndpoint)
9
+ - `QuoteRequestData` - Quote request data for single items or batch requests
10
+ - `SelectionData` - User selection data returned in callbacks
11
+ - `Quote` - Quote response data with pricing and terms
12
+ - `Theme` - Styling customization options
13
+
14
+ For complete type definitions, see the [@getspot/spot-widget documentation](https://www.npmjs.com/package/@getspot/spot-widget).
5
15
 
6
16
  ## Installation
7
17
 
8
18
  ```bash
9
- npm install --save @getspot/spot-widget-react
19
+ npm install @getspot/spot-widget-react
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```tsx
25
+ import React from 'react';
26
+ import ReactSpotWidget from '@getspot/spot-widget-react';
27
+
28
+ function App() {
29
+ return (
30
+ <ReactSpotWidget
31
+ apiConfig={{
32
+ environment: 'production', // or 'sandbox' for testing
33
+ partnerId: 'your-partner-id'
34
+ }}
35
+ quoteRequestData={{
36
+ startDate: '2024-01-01T00:00:00Z',
37
+ endDate: '2024-01-07T23:59:59Z',
38
+ currencyCode: 'USD',
39
+ eventType: 'Ski Trip',
40
+ productType: 'Trip',
41
+ productDuration: 'Trip',
42
+ productPrice: 500,
43
+ productId: 'ski-trip-2024',
44
+ cartId: 'cart-123',
45
+ productName: 'Aspen Ski Trip 2024'
46
+ }}
47
+ onOptIn={(data) => {
48
+ console.log('User opted in:', data);
49
+ // Handle opt-in (e.g., add to cart, track analytics)
50
+ }}
51
+ onOptOut={(data) => {
52
+ console.log('User opted out:', data);
53
+ // Handle opt-out (e.g., track analytics)
54
+ }}
55
+ onError={(error) => {
56
+ console.error('Widget error:', error);
57
+ // Handle errors (e.g., show fallback UI)
58
+ }}
59
+ />
60
+ );
61
+ }
10
62
  ```
11
63
 
12
- ## Usage
64
+ ## TypeScript Support
65
+
66
+ This package includes full TypeScript definitions. All props are typed for better development experience.
67
+
68
+ ## Props Reference
69
+
70
+ ### Required Props
71
+
72
+ | Prop | Type | Description |
73
+ |------|------|-------------|
74
+ | `apiConfig` | `ApiConfig` | Configuration for the Spot API including environment and partner ID |
75
+ | `quoteRequestData` | `QuoteRequestData` | Quote request data containing product and cart information |
76
+
77
+ ### Optional Props
78
+
79
+ | Prop | Type | Default | Description |
80
+ |------|------|---------|-------------|
81
+ | `showTable` | `boolean` | `true` | Whether to show the payout table |
82
+ | `optInSelected` | `boolean` | `false` | Whether the widget should be pre-selected for opt-in |
83
+ | `theme` | `Theme` | `undefined` | Theme customization options for styling the widget |
84
+
85
+ ### Callback Props
86
+
87
+ | Prop | Type | Description |
88
+ |------|------|-------------|
89
+ | `onQuoteRetrieved` | `(quote: Quote) => void` | Callback fired when a quote is successfully retrieved |
90
+ | `onOptIn` | `(data: SelectionData) => void` | Callback fired when user opts in to the refund guarantee |
91
+ | `onOptOut` | `(data: SelectionData) => void` | Callback fired when user opts out of the refund guarantee |
92
+ | `onError` | `(error: ErrorData) => void` | Callback fired when an error occurs during quote retrieval |
93
+ | `onNoMatchingQuote` | `(data: NoQuoteData) => void` | Callback fired when no matching quote is found |
94
+ | `onSelectionChange` | `(data: SelectionData) => void` | Callback fired when user changes their selection (opt-in or opt-out) |
95
+
96
+ ## Using Refs
97
+
98
+ You can access widget methods using React refs:
99
+
100
+ ```tsx
101
+ import React, { useRef } from 'react';
102
+ import ReactSpotWidget, { ReactSpotWidgetRef } from '@getspot/spot-widget-react';
103
+
104
+ function App() {
105
+ const widgetRef = useRef<ReactSpotWidgetRef>(null);
106
+
107
+ const handleUpdateQuote = async () => {
108
+ const success = await widgetRef.current?.updateQuote({
109
+ // new quote data
110
+ });
111
+ console.log('Quote updated:', success);
112
+ };
113
+
114
+ const handleGetSelection = () => {
115
+ const selection = widgetRef.current?.getSelection();
116
+ console.log('Current selection:', selection);
117
+ };
118
+
119
+ const handleValidateSelection = () => {
120
+ const isValid = widgetRef.current?.validateSelection();
121
+ console.log('Selection is valid:', isValid);
122
+ };
123
+
124
+ return (
125
+ <div>
126
+ <ReactSpotWidget
127
+ ref={widgetRef}
128
+ // ... props
129
+ />
130
+ <button onClick={handleUpdateQuote}>Update Quote</button>
131
+ <button onClick={handleGetSelection}>Get Selection</button>
132
+ <button onClick={handleValidateSelection}>Validate Selection</button>
133
+ </div>
134
+ );
135
+ }
136
+ ```
137
+
138
+ ## Ref Methods
139
+
140
+ | Method | Return Type | Description |
141
+ |--------|-------------|-------------|
142
+ | `updateQuote(data)` | `Promise<boolean>` | Update the quote with new request data |
143
+ | `getSelection()` | `SelectionData \| null` | Get the current user selection |
144
+ | `validateSelection()` | `boolean` | Validate that the user has made a selection |
145
+ | `destroy()` | `void` | Destroy the widget instance and clean up resources |
146
+
147
+ ## API Configuration
148
+
149
+ The `apiConfig` prop accepts the following options:
150
+
151
+ ```tsx
152
+ {
153
+ environment: 'production' | 'sandbox' | 'local',
154
+ partnerId: string,
155
+ customEndpoint?: string // Optional custom API endpoint
156
+ }
157
+ ```
158
+
159
+ ## Quote Request Data
160
+
161
+ The `quoteRequestData` prop requires the following fields:
162
+
163
+ ### Single Quote Format
164
+
165
+ ```tsx
166
+ {
167
+ startDate: string, // ISO 8601 date string
168
+ endDate: string, // ISO 8601 date string
169
+ currencyCode: 'USD' | 'CAD' | 'AUD',
170
+ eventType: string, // e.g., "Ski Trip", "Concert"
171
+ productType: 'Pass' | 'Trip' | 'Registration',
172
+ productDuration: 'Daily' | 'Seasonal' | 'Trip' | 'Event',
173
+ productPrice: number, // Price in specified currency
174
+ productId: string, // Unique product identifier
175
+ cartId: string, // Cart identifier
176
+ productName: string, // Human-readable product name
177
+ participantDescription?: string // Optional participant details
178
+ }
179
+ ```
180
+
181
+ ### Batch Quote Format
182
+
183
+ For multiple items in a cart:
184
+
185
+ ```tsx
186
+ {
187
+ cartInfo: {
188
+ cartId: string,
189
+ cartName: string,
190
+ currencyCode: 'USD' | 'CAD' | 'AUD'
191
+ },
192
+ items: Array<{
193
+ // Same fields as single quote, minus cartId and currencyCode
194
+ cartItemId?: string // Optional unique identifier for cart item
195
+ }>
196
+ }
197
+ ```
198
+
199
+ ## Styling
200
+
201
+ Customize the widget appearance using the `theme` prop:
202
+
203
+ ```tsx
204
+ <ReactSpotWidget
205
+ theme={{
206
+ primaryColor: '#007bff',
207
+ borderRadius: '8px',
208
+ fontFamily: 'Arial, sans-serif'
209
+ // Add any CSS custom properties (without -- prefix)
210
+ }}
211
+ // ... other props
212
+ />
213
+ ```
214
+
215
+ ## Error Handling
216
+
217
+ Always implement error handling for production use:
218
+
219
+ ```tsx
220
+ <ReactSpotWidget
221
+ onError={(error) => {
222
+ // Log error for debugging
223
+ console.error('Spot Widget Error:', error);
224
+
225
+ // Show user-friendly message
226
+ toast.error('Unable to load refund options. Please try again.');
227
+
228
+ // Track error in analytics
229
+ analytics.track('spot_widget_error', {
230
+ message: error.message,
231
+ status: error.status
232
+ });
233
+ }}
234
+ onNoMatchingQuote={() => {
235
+ // Handle case where no quote is available
236
+ console.log('No refund guarantee available for this product');
237
+ }}
238
+ // ... other props
239
+ />
240
+ ```
241
+
242
+ ## Compatibility
243
+
244
+ - **React**: 18.x
245
+ - **TypeScript**: 5.x
246
+ - **Node.js**: 16+
247
+
248
+ ## License
249
+
250
+ See the main package for license information.
251
+
252
+ ## Support
253
+
254
+ For support, please contact [support@getspot.com](mailto:support@getspot.com).
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ import { type SpotWidgetOptions, type SelectionData, type Quote } from "@getspot/spot-widget";
3
+ /**
4
+ * Props for the ReactSpotWidget component
5
+ */
6
+ interface ReactSpotWidgetProps extends Omit<SpotWidgetOptions, 'location' | 'callbacks'> {
7
+ /** Configuration for the Spot API including environment and partner ID */
8
+ apiConfig: SpotWidgetOptions['apiConfig'];
9
+ /** Quote request data containing product and cart information */
10
+ quoteRequestData: SpotWidgetOptions['quoteRequestData'];
11
+ /** Whether to show the payout table. Defaults to true */
12
+ showTable?: boolean;
13
+ /** Whether the widget should be pre-selected for opt-in. Defaults to false */
14
+ optInSelected?: boolean;
15
+ /** Theme customization options for styling the widget */
16
+ theme?: SpotWidgetOptions['theme'];
17
+ /** Callback fired when a quote is successfully retrieved */
18
+ onQuoteRetrieved?: (quote: Quote) => void;
19
+ /** Callback fired when user opts in to the refund guarantee */
20
+ onOptIn?: (data: SelectionData) => void;
21
+ /** Callback fired when user opts out of the refund guarantee */
22
+ onOptOut?: (data: SelectionData) => void;
23
+ /** Callback fired when an error occurs during quote retrieval */
24
+ onError?: (error: {
25
+ message: string;
26
+ status?: number;
27
+ responseBody?: any;
28
+ }) => void;
29
+ /** Callback fired when no matching quote is found */
30
+ onNoMatchingQuote?: (data: {
31
+ status: string;
32
+ data: any;
33
+ }) => void;
34
+ /** Callback fired when user changes their selection (opt-in or opt-out) */
35
+ onSelectionChange?: (data: SelectionData) => void;
36
+ /** Additional callback configuration options */
37
+ callbacks?: SpotWidgetOptions['callbacks'];
38
+ }
39
+ /**
40
+ * Methods available on the ReactSpotWidget component ref
41
+ */
42
+ export interface ReactSpotWidgetRef {
43
+ /** Update the quote with new request data */
44
+ updateQuote: (newQuoteRequestData: SpotWidgetOptions['quoteRequestData']) => Promise<boolean>;
45
+ /** Get the current user selection */
46
+ getSelection: () => SelectionData | null;
47
+ /** Validate that the user has made a selection */
48
+ validateSelection: () => boolean;
49
+ /** Destroy the widget instance and clean up resources */
50
+ destroy: () => void;
51
+ }
52
+ /**
53
+ * React component wrapper for the Spot refund guarantee widget.
54
+ *
55
+ * This component provides a React-friendly interface to the Spot Widget,
56
+ * offering refund guarantee options for e-commerce purchases.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * import ReactSpotWidget from '@getspot/spot-widget-react';
61
+ *
62
+ * function MyComponent() {
63
+ * return (
64
+ * <ReactSpotWidget
65
+ * apiConfig={{
66
+ * environment: 'production',
67
+ * partnerId: 'your-partner-id'
68
+ * }}
69
+ * quoteRequestData={{
70
+ * productPrice: 100,
71
+ * productType: 'Trip',
72
+ * // ... other required fields
73
+ * }}
74
+ * onOptIn={(data) => console.log('User opted in:', data)}
75
+ * onOptOut={(data) => console.log('User opted out:', data)}
76
+ * />
77
+ * );
78
+ * }
79
+ * ```
80
+ */
81
+ declare const ReactSpotWidget: React.ForwardRefExoticComponent<ReactSpotWidgetProps & React.RefAttributes<ReactSpotWidgetRef>>;
82
+ export default ReactSpotWidget;
83
+ //# sourceMappingURL=ReactSpotWidget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactSpotWidget.d.ts","sourceRoot":"","sources":["../src/ReactSpotWidget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAClF,OAAmB,EAAE,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE1G;;GAEG;AACH,UAAU,oBAAqB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,WAAW,CAAC;IACtF,0EAA0E;IAC1E,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC1C,iEAAiE;IACjE,gBAAgB,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IACxD,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yDAAyD;IACzD,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACnC,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,iEAAiE;IACjE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;IACpF,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAClD,gDAAgD;IAChD,SAAS,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,WAAW,EAAE,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9F,qCAAqC;IACrC,YAAY,EAAE,MAAM,aAAa,GAAG,IAAI,CAAC;IACzC,kDAAkD;IAClD,iBAAiB,EAAE,MAAM,OAAO,CAAC;IACjC,yDAAyD;IACzD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,eAAe,iGAuFnB,CAAC;AAIH,eAAe,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ReactSpotWidget.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactSpotWidget.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ReactSpotWidget.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ import { type SpotWidgetOptions, type SelectionData, type Quote } from "@getspot/spot-widget";
3
+ /**
4
+ * Props for the ReactSpotWidget component
5
+ */
6
+ interface ReactSpotWidgetProps extends Omit<SpotWidgetOptions, 'location' | 'callbacks'> {
7
+ /** Configuration for the Spot API including environment and partner ID */
8
+ apiConfig: SpotWidgetOptions['apiConfig'];
9
+ /** Quote request data containing product and cart information */
10
+ quoteRequestData: SpotWidgetOptions['quoteRequestData'];
11
+ /** Whether to show the payout table. Defaults to true */
12
+ showTable?: boolean;
13
+ /** Whether the widget should be pre-selected for opt-in. Defaults to false */
14
+ optInSelected?: boolean;
15
+ /** Theme customization options for styling the widget */
16
+ theme?: SpotWidgetOptions['theme'];
17
+ /** Callback fired when a quote is successfully retrieved */
18
+ onQuoteRetrieved?: (quote: Quote) => void;
19
+ /** Callback fired when user opts in to the refund guarantee */
20
+ onOptIn?: (data: SelectionData) => void;
21
+ /** Callback fired when user opts out of the refund guarantee */
22
+ onOptOut?: (data: SelectionData) => void;
23
+ /** Callback fired when an error occurs during quote retrieval */
24
+ onError?: (error: {
25
+ message: string;
26
+ status?: number;
27
+ responseBody?: any;
28
+ }) => void;
29
+ /** Callback fired when no matching quote is found */
30
+ onNoMatchingQuote?: (data: {
31
+ status: string;
32
+ data: any;
33
+ }) => void;
34
+ /** Callback fired when user changes their selection (opt-in or opt-out) */
35
+ onSelectionChange?: (data: SelectionData) => void;
36
+ /** Additional callback configuration options */
37
+ callbacks?: SpotWidgetOptions['callbacks'];
38
+ }
39
+ /**
40
+ * Methods available on the ReactSpotWidget component ref
41
+ */
42
+ export interface ReactSpotWidgetRef {
43
+ /** Update the quote with new request data */
44
+ updateQuote: (newQuoteRequestData: SpotWidgetOptions['quoteRequestData']) => Promise<boolean>;
45
+ /** Get the current user selection */
46
+ getSelection: () => SelectionData | null;
47
+ /** Validate that the user has made a selection */
48
+ validateSelection: () => boolean;
49
+ /** Destroy the widget instance and clean up resources */
50
+ destroy: () => void;
51
+ }
52
+ /**
53
+ * React component wrapper for the Spot refund guarantee widget.
54
+ *
55
+ * This component provides a React-friendly interface to the Spot Widget,
56
+ * offering refund guarantee options for e-commerce purchases.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * import ReactSpotWidget from '@getspot/spot-widget-react';
61
+ *
62
+ * function MyComponent() {
63
+ * return (
64
+ * <ReactSpotWidget
65
+ * apiConfig={{
66
+ * environment: 'production',
67
+ * partnerId: 'your-partner-id'
68
+ * }}
69
+ * quoteRequestData={{
70
+ * productPrice: 100,
71
+ * productType: 'Trip',
72
+ * // ... other required fields
73
+ * }}
74
+ * onOptIn={(data) => console.log('User opted in:', data)}
75
+ * onOptOut={(data) => console.log('User opted out:', data)}
76
+ * />
77
+ * );
78
+ * }
79
+ * ```
80
+ */
81
+ declare const ReactSpotWidget: React.ForwardRefExoticComponent<ReactSpotWidgetProps & React.RefAttributes<ReactSpotWidgetRef>>;
82
+ export default ReactSpotWidget;
83
+ //# sourceMappingURL=ReactSpotWidget.d.ts.map
package/dist/index.es.js CHANGED
@@ -1,70 +1,72 @@
1
- import z, { forwardRef as A, useRef as x, useImperativeHandle as B, useEffect as E } from "react";
2
- import F from "@getspot/spot-widget";
3
- const K = A(({
1
+ import { jsx as P } from "react/jsx-runtime";
2
+ import { forwardRef as b, useRef as R, useImperativeHandle as p, useEffect as z } from "react";
3
+ import A from "@getspot/spot-widget";
4
+ const B = b(({
4
5
  apiConfig: m,
5
- quoteRequestData: y,
6
- showTable: i = !0,
6
+ quoteRequestData: i,
7
+ showTable: y = !0,
7
8
  optInSelected: W = !1,
8
- theme: v,
9
- callbacks: w = {},
10
- onQuoteRetrieved: s,
11
- onOptIn: t,
12
- onOptOut: c,
9
+ theme: a,
10
+ callbacks: v = {},
11
+ onQuoteRetrieved: c,
12
+ onOptIn: s,
13
+ onOptOut: t,
13
14
  onError: f,
14
15
  onNoMatchingQuote: d,
15
16
  onSelectionChange: e,
16
- ...R
17
- }, H) => {
18
- const l = x(null), u = x(null), b = {
19
- ...w,
20
- ...s && { onQuoteRetrieved: s },
21
- ...t && {
17
+ ...w
18
+ }, j) => {
19
+ const l = R(null), u = R(null), k = {
20
+ ...v,
21
+ ...c && { onQuoteRetrieved: c },
22
+ ...s && {
22
23
  onOptIn: (r) => {
23
- t == null || t(r), e == null || e(r);
24
+ s == null || s(r), e == null || e(r);
24
25
  }
25
26
  },
26
- ...c && {
27
+ ...t && {
27
28
  onOptOut: (r) => {
28
- c == null || c(r), e == null || e(r);
29
+ t == null || t(r), e == null || e(r);
29
30
  }
30
31
  },
31
32
  ...f && { onError: f },
32
- ...d && { onNoMatchingQuote: d }
33
- }, j = {
33
+ ...d && { noMatchingQuote: d }
34
+ }, H = {
34
35
  apiConfig: m,
35
- quoteRequestData: y,
36
- showTable: i,
36
+ quoteRequestData: i,
37
+ showTable: y,
37
38
  optInSelected: W,
38
- theme: v,
39
- callbacks: b,
40
- ...R
39
+ theme: a,
40
+ callbacks: k,
41
+ ...w
41
42
  };
42
- return B(H, () => ({
43
+ return p(j, () => ({
43
44
  updateQuote: (r) => {
44
- var k;
45
- return (k = u.current) == null ? void 0 : k.updateQuote(r);
45
+ var x;
46
+ return ((x = u.current) == null ? void 0 : x.updateQuote(r)) ?? Promise.resolve(!1);
46
47
  },
47
48
  getSelection: () => {
48
49
  var r;
49
- return (r = u.current) == null ? void 0 : r.getSelection();
50
+ return ((r = u.current) == null ? void 0 : r.getSelection()) ?? null;
50
51
  },
51
52
  validateSelection: () => {
52
53
  var r;
53
- return (r = u.current) == null ? void 0 : r.validateSelection();
54
+ return ((r = u.current) == null ? void 0 : r.validateSelection()) ?? !1;
54
55
  },
55
56
  destroy: () => {
56
57
  u.current && (u.current.destroy(), u.current = null);
57
58
  }
58
- })), E(() => {
59
+ })), z(() => {
59
60
  if (l.current)
60
- return u.current && u.current.destroy(), u.current = new F({
61
+ return u.current && u.current.destroy(), u.current = new A({
61
62
  location: l.current,
62
- ...j
63
+ ...H
63
64
  }), () => {
64
65
  u.current && (u.current.destroy(), u.current = null);
65
66
  };
66
- }, [m, y, i, W, v, w, s, t, c, f, d, e, R]), /* @__PURE__ */ z.createElement("div", { ref: l });
67
+ }, [m, i, y, W, a, v, c, s, t, f, d, e, w]), /* @__PURE__ */ P("div", { ref: l });
67
68
  });
69
+ B.displayName = "ReactSpotWidget";
68
70
  export {
69
- K as default
71
+ B as default
70
72
  };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(r,s){typeof exports=="object"&&typeof module<"u"?module.exports=s(require("react"),require("@getspot/spot-widget")):typeof define=="function"&&define.amd?define(["react","@getspot/spot-widget"],s):(r=typeof globalThis<"u"?globalThis:r||self,r.ReactSpotWidget=s(r.React,r.SpotWidget))})(this,function(r,s){"use strict";return r.forwardRef(({apiConfig:y,quoteRequestData:m,showTable:W=!0,optInSelected:w=!1,theme:v,callbacks:x={},onQuoteRetrieved:c,onOptIn:d,onOptOut:f,onError:i,onNoMatchingQuote:l,onSelectionChange:u,...j},H)=>{const p=r.useRef(null),t=r.useRef(null),T={...x,...c&&{onQuoteRetrieved:c},...d&&{onOptIn:e=>{d==null||d(e),u==null||u(e)}},...f&&{onOptOut:e=>{f==null||f(e),u==null||u(e)}},...i&&{onError:i},...l&&{onNoMatchingQuote:l}},q={apiConfig:y,quoteRequestData:m,showTable:W,optInSelected:w,theme:v,callbacks:T,...j};return r.useImperativeHandle(H,()=>({updateQuote:e=>{var k;return(k=t.current)==null?void 0:k.updateQuote(e)},getSelection:()=>{var e;return(e=t.current)==null?void 0:e.getSelection()},validateSelection:()=>{var e;return(e=t.current)==null?void 0:e.validateSelection()},destroy:()=>{t.current&&(t.current.destroy(),t.current=null)}})),r.useEffect(()=>{if(p.current)return t.current&&t.current.destroy(),t.current=new s({location:p.current,...q}),()=>{t.current&&(t.current.destroy(),t.current=null)}},[y,m,W,w,v,x,c,d,f,i,l,u,j]),r.createElement("div",{ref:p})})});
1
+ (function(u,t){typeof exports=="object"&&typeof module<"u"?module.exports=t(require("react/jsx-runtime"),require("react"),require("@getspot/spot-widget")):typeof define=="function"&&define.amd?define(["react/jsx-runtime","react","@getspot/spot-widget"],t):(u=typeof globalThis<"u"?globalThis:u||self,u.ReactSpotWidget=t(u.React,u.React,u.SpotWidget))})(this,function(u,t,n){"use strict";const p=t.forwardRef(({apiConfig:y,quoteRequestData:R,showTable:x=!0,optInSelected:W=!1,theme:j,callbacks:w={},onQuoteRetrieved:i,onOptIn:d,onOptOut:f,onError:c,onNoMatchingQuote:l,onSelectionChange:s,...v},q)=>{const m=t.useRef(null),r=t.useRef(null),H={...w,...i&&{onQuoteRetrieved:i},...d&&{onOptIn:e=>{d==null||d(e),s==null||s(e)}},...f&&{onOptOut:e=>{f==null||f(e),s==null||s(e)}},...c&&{onError:c},...l&&{noMatchingQuote:l}},P={apiConfig:y,quoteRequestData:R,showTable:x,optInSelected:W,theme:j,callbacks:H,...v};return t.useImperativeHandle(q,()=>({updateQuote:e=>{var k;return((k=r.current)==null?void 0:k.updateQuote(e))??Promise.resolve(!1)},getSelection:()=>{var e;return((e=r.current)==null?void 0:e.getSelection())??null},validateSelection:()=>{var e;return((e=r.current)==null?void 0:e.validateSelection())??!1},destroy:()=>{r.current&&(r.current.destroy(),r.current=null)}})),t.useEffect(()=>{if(m.current)return r.current&&r.current.destroy(),r.current=new n({location:m.current,...P}),()=>{r.current&&(r.current.destroy(),r.current=null)}},[y,R,x,W,j,w,i,d,f,c,l,s,v]),u.jsx("div",{ref:m})});return p.displayName="ReactSpotWidget",p});
@@ -0,0 +1,2 @@
1
+ import '@testing-library/jest-dom';
2
+ //# sourceMappingURL=setupTests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupTests.d.ts","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC"}
package/package.json CHANGED
@@ -1,23 +1,52 @@
1
1
  {
2
2
  "name": "@getspot/spot-widget-react",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
7
  "main": "dist/index.umd.js",
8
8
  "module": "dist/index.es.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "CHANGELOG.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "vite build && npx -p typescript tsc --emitDeclarationOnly && cp dist/ReactSpotWidget.d.ts dist/index.d.ts",
17
+ "docs": "npx -p typedoc -p typedoc-plugin-markdown typedoc --plugin typedoc-plugin-markdown --out docs src/ReactSpotWidget.tsx",
18
+ "docs:readme": "npm run docs && node scripts/generate-readme.js",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "test:coverage": "jest --coverage",
22
+ "test:ci": "jest --ci --coverage --watchAll=false",
23
+ "prepublishOnly": "npm run build"
24
+ },
9
25
  "dependencies": {
10
- "@getspot/spot-widget": "1.3.0"
26
+ "@getspot/spot-widget": "workspace:*"
11
27
  },
12
28
  "peerDependencies": {
13
- "react": "^18.0.0",
14
- "react-dom": "^18.0.0"
29
+ "react": ">=18.0.0",
30
+ "react-dom": ">=18.0.0",
31
+ "@types/react": ">=18.0.0",
32
+ "@types/react-dom": ">=18.0.0"
15
33
  },
16
34
  "devDependencies": {
17
35
  "vite": "^5.0.0",
18
- "@vitejs/plugin-react": "^4.0.0"
19
- },
20
- "scripts": {
21
- "build": "vite build"
36
+ "@vitejs/plugin-react": "^4.0.0",
37
+ "typescript": "~5.4.0",
38
+ "@types/react": "^18.0.0",
39
+ "@types/react-dom": "^18.0.0",
40
+ "typedoc": "^0.28.0",
41
+ "typedoc-plugin-markdown": "^4.0.0",
42
+ "jest": "^29.0.0",
43
+ "@testing-library/react": "^14.0.0",
44
+ "@testing-library/jest-dom": "^6.0.0",
45
+ "@testing-library/user-event": "^14.0.0",
46
+ "@types/jest": "^29.0.0",
47
+ "jest-environment-jsdom": "^29.0.0",
48
+ "react": "^18.0.0",
49
+ "react-dom": "^18.0.0",
50
+ "ts-jest": "^29.0.0"
22
51
  }
23
- }
52
+ }
@@ -1,14 +0,0 @@
1
-
2
- > @getspot/spot-widget-react@1.3.0 build /builds/getspot/spot-widget/packages/react
3
- > vite build
4
-
5
- The CJS build of Vite's Node API is deprecated. See https://vite.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.
6
- vite v5.4.18 building for production...
7
- transforming...
8
- ✓ 1 modules transformed.
9
- No name was provided for external module "@getspot/spot-widget" in "output.globals" – guessing "SpotWidget".
10
- rendering chunks...
11
- computing gzip size...
12
- dist/index.umd.js 1.41 kB │ gzip: 0.65 kB
13
- dist/index.es.js 1.71 kB │ gzip: 0.68 kB
14
- ✓ built in 236ms
@@ -1,93 +0,0 @@
1
- import React, { useEffect, useRef, useImperativeHandle, forwardRef } from "react";
2
- import SpotWidget from "@getspot/spot-widget";
3
-
4
- const ReactSpotWidget = forwardRef(({
5
- apiConfig,
6
- quoteRequestData,
7
- showTable = true,
8
- optInSelected = false,
9
- theme,
10
- callbacks = {},
11
- onQuoteRetrieved,
12
- onOptIn,
13
- onOptOut,
14
- onError,
15
- onNoMatchingQuote,
16
- onSelectionChange,
17
- ...otherOptions
18
- }, ref) => {
19
- const widgetRef = useRef(null);
20
- const spotWidgetInstance = useRef(null);
21
-
22
- // Merge callbacks from props with callbacks object
23
- const mergedCallbacks = {
24
- ...callbacks,
25
- ...(onQuoteRetrieved && { onQuoteRetrieved }),
26
- ...(onOptIn && {
27
- onOptIn: (data) => {
28
- onOptIn?.(data);
29
- onSelectionChange?.(data);
30
- }
31
- }),
32
- ...(onOptOut && {
33
- onOptOut: (data) => {
34
- onOptOut?.(data);
35
- onSelectionChange?.(data);
36
- }
37
- }),
38
- ...(onError && { onError }),
39
- ...(onNoMatchingQuote && { onNoMatchingQuote }),
40
- };
41
-
42
- const options = {
43
- apiConfig,
44
- quoteRequestData,
45
- showTable,
46
- optInSelected,
47
- theme,
48
- callbacks: mergedCallbacks,
49
- ...otherOptions,
50
- };
51
-
52
- useImperativeHandle(ref, () => ({
53
- updateQuote: (newQuoteRequestData) => {
54
- return spotWidgetInstance.current?.updateQuote(newQuoteRequestData);
55
- },
56
- getSelection: () => {
57
- return spotWidgetInstance.current?.getSelection();
58
- },
59
- validateSelection: () => {
60
- return spotWidgetInstance.current?.validateSelection();
61
- },
62
- destroy: () => {
63
- if (spotWidgetInstance.current) {
64
- spotWidgetInstance.current.destroy();
65
- spotWidgetInstance.current = null;
66
- }
67
- },
68
- }));
69
-
70
- useEffect(() => {
71
- if (widgetRef.current) {
72
- if (spotWidgetInstance.current) {
73
- spotWidgetInstance.current.destroy();
74
- }
75
-
76
- spotWidgetInstance.current = new SpotWidget({
77
- location: widgetRef.current,
78
- ...options,
79
- });
80
-
81
- return () => {
82
- if (spotWidgetInstance.current) {
83
- spotWidgetInstance.current.destroy();
84
- spotWidgetInstance.current = null;
85
- }
86
- };
87
- }
88
- }, [apiConfig, quoteRequestData, showTable, optInSelected, theme, callbacks, onQuoteRetrieved, onOptIn, onOptOut, onError, onNoMatchingQuote, onSelectionChange, otherOptions]);
89
-
90
- return <div ref={widgetRef}></div>;
91
- });
92
-
93
- export default ReactSpotWidget;
package/vite.config.js DELETED
@@ -1,23 +0,0 @@
1
- import { defineConfig } from "vite";
2
- import path from "path";
3
-
4
- export default defineConfig({
5
- build: {
6
- outDir: "dist",
7
- lib: {
8
- entry: path.resolve(__dirname, "src/ReactSpotWidget.jsx"),
9
- name: "ReactSpotWidget",
10
- fileName: (format) => `index.${format}.js`,
11
- formats: ["umd", "es"],
12
- },
13
- rollupOptions: {
14
- external: ["react", "react-dom", "@getspot/spot-widget"],
15
- output: {
16
- globals: {
17
- react: "React",
18
- "react-dom": "ReactDOM",
19
- },
20
- },
21
- },
22
- },
23
- });