@conversokit/widgets 0.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.
Files changed (65) hide show
  1. package/LICENSE +201 -0
  2. package/dist/AddToCartPanel.d.ts +11 -0
  3. package/dist/AddToCartPanel.d.ts.map +1 -0
  4. package/dist/AddToCartPanel.js +62 -0
  5. package/dist/AlertFeed.d.ts +9 -0
  6. package/dist/AlertFeed.d.ts.map +1 -0
  7. package/dist/AlertFeed.js +67 -0
  8. package/dist/AnalyticsPanel.d.ts +8 -0
  9. package/dist/AnalyticsPanel.d.ts.map +1 -0
  10. package/dist/AnalyticsPanel.js +24 -0
  11. package/dist/AvailabilityCalendar.d.ts +25 -0
  12. package/dist/AvailabilityCalendar.d.ts.map +1 -0
  13. package/dist/AvailabilityCalendar.js +104 -0
  14. package/dist/BookingCard.d.ts +9 -0
  15. package/dist/BookingCard.d.ts.map +1 -0
  16. package/dist/BookingCard.js +62 -0
  17. package/dist/CTABanner.d.ts +35 -0
  18. package/dist/CTABanner.d.ts.map +1 -0
  19. package/dist/CTABanner.js +72 -0
  20. package/dist/CheckoutSummary.d.ts +11 -0
  21. package/dist/CheckoutSummary.d.ts.map +1 -0
  22. package/dist/CheckoutSummary.js +70 -0
  23. package/dist/ConsentBanner.d.ts +30 -0
  24. package/dist/ConsentBanner.d.ts.map +1 -0
  25. package/dist/ConsentBanner.js +82 -0
  26. package/dist/DestinationRecommendations.d.ts +57 -0
  27. package/dist/DestinationRecommendations.d.ts.map +1 -0
  28. package/dist/DestinationRecommendations.js +43 -0
  29. package/dist/FlightSummary.d.ts +10 -0
  30. package/dist/FlightSummary.d.ts.map +1 -0
  31. package/dist/FlightSummary.js +50 -0
  32. package/dist/HotelCard.d.ts +10 -0
  33. package/dist/HotelCard.d.ts.map +1 -0
  34. package/dist/HotelCard.js +52 -0
  35. package/dist/ItineraryTimeline.d.ts +8 -0
  36. package/dist/ItineraryTimeline.d.ts.map +1 -0
  37. package/dist/ItineraryTimeline.js +56 -0
  38. package/dist/KPIGrid.d.ts +46 -0
  39. package/dist/KPIGrid.d.ts.map +1 -0
  40. package/dist/KPIGrid.js +53 -0
  41. package/dist/LeadCaptureForm.d.ts +14 -0
  42. package/dist/LeadCaptureForm.d.ts.map +1 -0
  43. package/dist/LeadCaptureForm.js +84 -0
  44. package/dist/MultiStepForm.d.ts +11 -0
  45. package/dist/MultiStepForm.d.ts.map +1 -0
  46. package/dist/MultiStepForm.js +60 -0
  47. package/dist/ProductCard.d.ts +17 -0
  48. package/dist/ProductCard.d.ts.map +1 -0
  49. package/dist/ProductCard.js +70 -0
  50. package/dist/ProductCarousel.d.ts +58 -0
  51. package/dist/ProductCarousel.d.ts.map +1 -0
  52. package/dist/ProductCarousel.js +31 -0
  53. package/dist/TimeSlotSelector.d.ts +10 -0
  54. package/dist/TimeSlotSelector.d.ts.map +1 -0
  55. package/dist/TimeSlotSelector.js +46 -0
  56. package/dist/TrendChart.d.ts +10 -0
  57. package/dist/TrendChart.d.ts.map +1 -0
  58. package/dist/TrendChart.js +50 -0
  59. package/dist/index.d.ts +40 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +20 -0
  62. package/dist/registry.d.ts +6 -0
  63. package/dist/registry.d.ts.map +1 -0
  64. package/dist/registry.js +50 -0
  65. package/package.json +52 -0
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { z } from 'zod';
3
+ import { defaultWidgetConfig } from '@conversokit/shared';
4
+ function bgFor(variant) {
5
+ switch (variant) {
6
+ case 'primary':
7
+ return 'var(--ck-primary)';
8
+ case 'success':
9
+ return 'var(--ck-success)';
10
+ case 'danger':
11
+ return 'var(--ck-danger)';
12
+ default:
13
+ return 'var(--ck-surface)';
14
+ }
15
+ }
16
+ function fgFor(variant) {
17
+ switch (variant) {
18
+ case 'primary':
19
+ case 'success':
20
+ case 'danger':
21
+ return 'white';
22
+ default:
23
+ return 'var(--ck-text)';
24
+ }
25
+ }
26
+ export const CTABanner = ({ title, description, primaryLabel, secondaryLabel, onPrimary, onSecondary, variant = 'info' }) => {
27
+ const bg = bgFor(variant);
28
+ const fg = fgFor(variant);
29
+ return (_jsxs("div", { role: "region", style: {
30
+ backgroundColor: bg,
31
+ color: fg,
32
+ border: '1px solid var(--ck-border)',
33
+ borderRadius: 'var(--ck-radius-md)',
34
+ padding: 'var(--ck-spacing-4)',
35
+ fontFamily: 'var(--ck-font-family)',
36
+ display: 'flex',
37
+ flexDirection: 'column',
38
+ gap: 'var(--ck-spacing-1)'
39
+ }, "data-testid": "cta-banner", children: [_jsx("strong", { style: { fontSize: 'var(--ck-font-size-lg)' }, children: title }), description && (_jsx("p", { style: { margin: 0, fontSize: 'var(--ck-font-size-sm)', opacity: 0.9 }, children: description })), (primaryLabel || secondaryLabel) && (_jsxs("div", { style: { display: 'flex', gap: 'var(--ck-spacing-2)', marginTop: 'var(--ck-spacing-2)' }, children: [primaryLabel && (_jsx("button", { type: "button", onClick: onPrimary, style: {
40
+ padding: '8px 14px',
41
+ borderRadius: 'var(--ck-radius-sm)',
42
+ border: 'none',
43
+ backgroundColor: variant === 'info' ? 'var(--ck-primary)' : 'white',
44
+ color: variant === 'info' ? 'var(--ck-primary-foreground)' : bg,
45
+ cursor: 'pointer',
46
+ fontWeight: 'var(--ck-font-weight-bold)'
47
+ }, children: primaryLabel })), secondaryLabel && (_jsx("button", { type: "button", onClick: onSecondary, style: {
48
+ padding: '8px 14px',
49
+ borderRadius: 'var(--ck-radius-sm)',
50
+ border: '1px solid currentColor',
51
+ backgroundColor: 'transparent',
52
+ color: fg,
53
+ cursor: 'pointer'
54
+ }, children: secondaryLabel }))] }))] }));
55
+ };
56
+ export const ctaBannerSchema = z.object({
57
+ title: z.string(),
58
+ description: z.string().optional(),
59
+ primaryLabel: z.string().optional(),
60
+ secondaryLabel: z.string().optional(),
61
+ variant: z.enum(['info', 'primary', 'success', 'danger']).optional()
62
+ });
63
+ export const CTABannerMeta = {
64
+ name: 'CTABanner',
65
+ category: 'core',
66
+ version: '0.1.0',
67
+ config: {
68
+ ...defaultWidgetConfig,
69
+ permissions: { allowsExternalLinks: true }
70
+ },
71
+ schema: ctaBannerSchema
72
+ };
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { type CheckoutSummary as CheckoutSummaryData, type WidgetMeta } from '@conversokit/shared';
3
+ export interface CheckoutSummaryProps {
4
+ summary: CheckoutSummaryData;
5
+ ctaLabel?: string;
6
+ onCheckout?: () => void;
7
+ onBack?: () => void;
8
+ }
9
+ export declare const CheckoutSummary: React.FC<CheckoutSummaryProps>;
10
+ export declare const CheckoutSummaryMeta: WidgetMeta;
11
+ //# sourceMappingURL=CheckoutSummary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckoutSummary.d.ts","sourceRoot":"","sources":["../src/CheckoutSummary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAGL,KAAK,eAAe,IAAI,mBAAmB,EAC3C,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AA4DD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+C1D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,UAajC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { checkoutSummarySchema, defaultWidgetConfig } from '@conversokit/shared';
3
+ const containerStyle = {
4
+ border: '1px solid var(--ck-border)',
5
+ borderRadius: 'var(--ck-radius-md)',
6
+ padding: 'var(--ck-spacing-4)',
7
+ backgroundColor: 'var(--ck-surface)',
8
+ color: 'var(--ck-text)',
9
+ fontFamily: 'var(--ck-font-family)',
10
+ display: 'flex',
11
+ flexDirection: 'column',
12
+ gap: 'var(--ck-spacing-2)',
13
+ maxWidth: 480
14
+ };
15
+ const rowStyle = {
16
+ display: 'flex',
17
+ justifyContent: 'space-between',
18
+ fontSize: 'var(--ck-font-size-sm)'
19
+ };
20
+ const lineItemStyle = {
21
+ ...rowStyle,
22
+ paddingBottom: 'var(--ck-spacing-1)',
23
+ borderBottom: '1px dashed var(--ck-border)'
24
+ };
25
+ const totalStyle = {
26
+ ...rowStyle,
27
+ fontSize: 'var(--ck-font-size-lg)',
28
+ fontWeight: 'var(--ck-font-weight-bold)',
29
+ marginTop: 'var(--ck-spacing-2)'
30
+ };
31
+ const buttonRow = {
32
+ display: 'flex',
33
+ gap: 'var(--ck-spacing-2)',
34
+ marginTop: 'var(--ck-spacing-2)'
35
+ };
36
+ const primaryBtn = {
37
+ flex: 1,
38
+ padding: '10px 14px',
39
+ borderRadius: 'var(--ck-radius-sm)',
40
+ border: 'none',
41
+ backgroundColor: 'var(--ck-primary)',
42
+ color: 'var(--ck-primary-foreground)',
43
+ cursor: 'pointer',
44
+ fontWeight: 'var(--ck-font-weight-bold)'
45
+ };
46
+ const secondaryBtn = {
47
+ padding: '10px 14px',
48
+ borderRadius: 'var(--ck-radius-sm)',
49
+ border: '1px solid var(--ck-border)',
50
+ backgroundColor: 'transparent',
51
+ color: 'var(--ck-text)',
52
+ cursor: 'pointer'
53
+ };
54
+ export const CheckoutSummary = ({ summary, ctaLabel = 'Checkout', onCheckout, onBack }) => {
55
+ return (_jsxs("div", { style: containerStyle, "data-testid": "checkout-summary", children: [_jsx("h3", { style: { margin: 0 }, children: "Order summary" }), summary.items.map((item) => (_jsxs("div", { style: lineItemStyle, children: [_jsxs("span", { children: [item.title, " \u00D7 ", item.quantity] }), _jsx("span", { children: item.price ?? 'โ€”' })] }, item.id))), summary.taxes && (_jsxs("div", { style: rowStyle, children: [_jsx("span", { style: { color: 'var(--ck-muted)' }, children: "Taxes" }), _jsx("span", { children: summary.taxes })] })), summary.shipping && (_jsxs("div", { style: rowStyle, children: [_jsx("span", { style: { color: 'var(--ck-muted)' }, children: "Shipping" }), _jsx("span", { children: summary.shipping })] })), _jsxs("div", { style: totalStyle, children: [_jsx("span", { children: "Total" }), _jsx("span", { children: summary.total })] }), _jsxs("div", { style: buttonRow, children: [onBack && (_jsx("button", { type: "button", style: secondaryBtn, onClick: onBack, children: "Back" })), onCheckout && (_jsx("button", { type: "button", style: primaryBtn, onClick: onCheckout, children: ctaLabel }))] })] }));
56
+ };
57
+ export const CheckoutSummaryMeta = {
58
+ name: 'CheckoutSummary',
59
+ category: 'commerce',
60
+ version: '0.1.0',
61
+ config: {
62
+ ...defaultWidgetConfig,
63
+ permissions: {
64
+ collectPersonalData: false,
65
+ requiresConsent: true,
66
+ allowsExternalLinks: true
67
+ }
68
+ },
69
+ schema: checkoutSummarySchema
70
+ };
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { z } from 'zod';
3
+ import { type ConsentRecord, type ConsentScope, type WidgetMeta } from '@conversokit/shared';
4
+ export interface ConsentBannerProps {
5
+ scopes: ConsentScope[];
6
+ privacyUrl?: string;
7
+ termsUrl?: string;
8
+ message?: string;
9
+ onAccept?: (record: ConsentRecord) => void;
10
+ children: React.ReactNode;
11
+ }
12
+ export declare const ConsentBanner: React.FC<ConsentBannerProps>;
13
+ export declare const consentBannerSchema: z.ZodObject<{
14
+ scopes: z.ZodArray<z.ZodString, "many">;
15
+ privacyUrl: z.ZodOptional<z.ZodString>;
16
+ termsUrl: z.ZodOptional<z.ZodString>;
17
+ message: z.ZodOptional<z.ZodString>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ scopes: string[];
20
+ message?: string | undefined;
21
+ privacyUrl?: string | undefined;
22
+ termsUrl?: string | undefined;
23
+ }, {
24
+ scopes: string[];
25
+ message?: string | undefined;
26
+ privacyUrl?: string | undefined;
27
+ termsUrl?: string | undefined;
28
+ }>;
29
+ export declare const ConsentBannerMeta: WidgetMeta;
30
+ //# sourceMappingURL=ConsentBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsentBanner.d.ts","sourceRoot":"","sources":["../src/ConsentBanner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAoB7B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAiFtD,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;EAK9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,EAAE,UAa/B,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { z } from 'zod';
4
+ import { consentRecordSchema, defaultWidgetConfig } from '@conversokit/shared';
5
+ const STORAGE_KEY = 'conversokit:consent';
6
+ function readStored() {
7
+ if (typeof window === 'undefined')
8
+ return null;
9
+ try {
10
+ const raw = window.sessionStorage.getItem(STORAGE_KEY);
11
+ if (!raw)
12
+ return null;
13
+ return consentRecordSchema.parse(JSON.parse(raw));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ function writeStored(record) {
20
+ if (typeof window === 'undefined')
21
+ return;
22
+ window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(record));
23
+ }
24
+ export const ConsentBanner = ({ scopes, privacyUrl, termsUrl, message = 'This app may collect personal data to provide the requested experience.', onAccept, children }) => {
25
+ const [record, setRecord] = useState(() => readStored());
26
+ useEffect(() => {
27
+ if (record && onAccept)
28
+ onAccept(record);
29
+ }, [record, onAccept]);
30
+ if (record)
31
+ return _jsx(_Fragment, { children: children });
32
+ const handleAccept = () => {
33
+ const next = {
34
+ scopes,
35
+ acceptedAt: new Date().toISOString()
36
+ };
37
+ writeStored(next);
38
+ setRecord(next);
39
+ };
40
+ return (_jsxs("div", { role: "dialog", "aria-live": "polite", style: {
41
+ position: 'fixed',
42
+ inset: 'auto 16px 16px 16px',
43
+ zIndex: 9999,
44
+ backgroundColor: 'var(--ck-surface)',
45
+ color: 'var(--ck-text)',
46
+ border: '1px solid var(--ck-border)',
47
+ borderRadius: 'var(--ck-radius-md)',
48
+ padding: 'var(--ck-spacing-4)',
49
+ boxShadow: '0 10px 25px rgba(0,0,0,0.1)',
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ gap: 'var(--ck-spacing-2)'
53
+ }, children: [_jsx("p", { style: { margin: 0, fontSize: 'var(--ck-font-size-sm)' }, children: message }), _jsxs("p", { style: { margin: 0, fontSize: 'var(--ck-font-size-sm)', color: 'var(--ck-muted)' }, children: ["Scopes: ", scopes.join(', '), privacyUrl && (_jsxs(_Fragment, { children: [' ยท ', _jsx("a", { href: privacyUrl, target: "_blank", rel: "noreferrer", children: "Privacy" })] })), termsUrl && (_jsxs(_Fragment, { children: [' ยท ', _jsx("a", { href: termsUrl, target: "_blank", rel: "noreferrer", children: "Terms" })] }))] }), _jsx("button", { type: "button", onClick: handleAccept, style: {
54
+ alignSelf: 'flex-start',
55
+ padding: '6px 14px',
56
+ borderRadius: 'var(--ck-radius-sm)',
57
+ border: 'none',
58
+ backgroundColor: 'var(--ck-primary)',
59
+ color: 'var(--ck-primary-foreground)',
60
+ cursor: 'pointer'
61
+ }, children: "Accept and continue" })] }));
62
+ };
63
+ export const consentBannerSchema = z.object({
64
+ scopes: z.array(z.string()),
65
+ privacyUrl: z.string().url().optional(),
66
+ termsUrl: z.string().url().optional(),
67
+ message: z.string().optional()
68
+ });
69
+ export const ConsentBannerMeta = {
70
+ name: 'ConsentBanner',
71
+ category: 'core',
72
+ version: '0.1.0',
73
+ config: {
74
+ ...defaultWidgetConfig,
75
+ permissions: {
76
+ collectPersonalData: false,
77
+ requiresConsent: false,
78
+ allowsExternalLinks: true
79
+ }
80
+ },
81
+ schema: consentBannerSchema
82
+ };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { z } from 'zod';
3
+ import { type Destination, type WidgetMeta } from '@conversokit/shared';
4
+ export interface DestinationRecommendationsProps {
5
+ destinations: Destination[];
6
+ onSelect?: (destination: Destination) => void;
7
+ }
8
+ export declare const DestinationRecommendations: React.FC<DestinationRecommendationsProps>;
9
+ export declare const destinationRecommendationsSchema: z.ZodObject<{
10
+ destinations: z.ZodArray<z.ZodObject<{
11
+ id: z.ZodString;
12
+ name: z.ZodString;
13
+ country: z.ZodOptional<z.ZodString>;
14
+ imageUrl: z.ZodOptional<z.ZodString>;
15
+ tagline: z.ZodOptional<z.ZodString>;
16
+ bestSeason: z.ZodOptional<z.ZodString>;
17
+ averagePrice: z.ZodOptional<z.ZodString>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ id: string;
20
+ name: string;
21
+ imageUrl?: string | undefined;
22
+ country?: string | undefined;
23
+ tagline?: string | undefined;
24
+ bestSeason?: string | undefined;
25
+ averagePrice?: string | undefined;
26
+ }, {
27
+ id: string;
28
+ name: string;
29
+ imageUrl?: string | undefined;
30
+ country?: string | undefined;
31
+ tagline?: string | undefined;
32
+ bestSeason?: string | undefined;
33
+ averagePrice?: string | undefined;
34
+ }>, "many">;
35
+ }, "strip", z.ZodTypeAny, {
36
+ destinations: {
37
+ id: string;
38
+ name: string;
39
+ imageUrl?: string | undefined;
40
+ country?: string | undefined;
41
+ tagline?: string | undefined;
42
+ bestSeason?: string | undefined;
43
+ averagePrice?: string | undefined;
44
+ }[];
45
+ }, {
46
+ destinations: {
47
+ id: string;
48
+ name: string;
49
+ imageUrl?: string | undefined;
50
+ country?: string | undefined;
51
+ tagline?: string | undefined;
52
+ bestSeason?: string | undefined;
53
+ averagePrice?: string | undefined;
54
+ }[];
55
+ }>;
56
+ export declare const DestinationRecommendationsMeta: WidgetMeta;
57
+ //# sourceMappingURL=DestinationRecommendations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DestinationRecommendations.d.ts","sourceRoot":"","sources":["../src/DestinationRecommendations.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,+BAA+B;IAC9C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAED,eAAO,MAAM,0BAA0B,EAAE,KAAK,CAAC,EAAE,CAAC,+BAA+B,CA8EhF,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE3C,CAAC;AAEH,eAAO,MAAM,8BAA8B,EAAE,UAM5C,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { z } from 'zod';
3
+ import { defaultWidgetConfig, destinationSchema } from '@conversokit/shared';
4
+ export const DestinationRecommendations = ({ destinations, onSelect }) => {
5
+ return (_jsx("div", { "data-testid": "destination-recommendations", style: {
6
+ display: 'grid',
7
+ gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))',
8
+ gap: 'var(--ck-spacing-2)',
9
+ fontFamily: 'var(--ck-font-family)'
10
+ }, children: destinations.map((dest) => (_jsxs("button", { type: "button", onClick: () => onSelect?.(dest), style: {
11
+ textAlign: 'left',
12
+ cursor: onSelect ? 'pointer' : 'default',
13
+ border: '1px solid var(--ck-border)',
14
+ borderRadius: 'var(--ck-radius-md)',
15
+ backgroundColor: 'var(--ck-surface)',
16
+ color: 'var(--ck-text)',
17
+ padding: 0,
18
+ overflow: 'hidden',
19
+ display: 'flex',
20
+ flexDirection: 'column'
21
+ }, children: [dest.imageUrl && (_jsx("img", { src: dest.imageUrl, alt: dest.name, style: { width: '100%', height: 120, objectFit: 'cover' } })), _jsxs("div", { style: {
22
+ padding: 'var(--ck-spacing-3)',
23
+ display: 'flex',
24
+ flexDirection: 'column',
25
+ gap: 4
26
+ }, children: [_jsx("strong", { children: dest.name }), dest.country && (_jsx("span", { style: {
27
+ fontSize: 'var(--ck-font-size-sm)',
28
+ color: 'var(--ck-muted)'
29
+ }, children: dest.country })), dest.tagline && (_jsx("span", { style: { fontSize: 'var(--ck-font-size-sm)' }, children: dest.tagline })), (dest.bestSeason || dest.averagePrice) && (_jsx("span", { style: {
30
+ fontSize: 'var(--ck-font-size-sm)',
31
+ color: 'var(--ck-muted)'
32
+ }, children: [dest.bestSeason, dest.averagePrice].filter(Boolean).join(' ยท ') }))] })] }, dest.id))) }));
33
+ };
34
+ export const destinationRecommendationsSchema = z.object({
35
+ destinations: z.array(destinationSchema)
36
+ });
37
+ export const DestinationRecommendationsMeta = {
38
+ name: 'DestinationRecommendations',
39
+ category: 'travel',
40
+ version: '0.1.0',
41
+ config: { ...defaultWidgetConfig, permissions: {} },
42
+ schema: destinationRecommendationsSchema
43
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { type FlightSummary as FlightSummaryData, type WidgetMeta } from '@conversokit/shared';
3
+ export interface FlightSummaryProps {
4
+ flight: FlightSummaryData;
5
+ onAction?: (flight: FlightSummaryData) => void;
6
+ ctaLabel?: string;
7
+ }
8
+ export declare const FlightSummary: React.FC<FlightSummaryProps>;
9
+ export declare const FlightSummaryMeta: WidgetMeta;
10
+ //# sourceMappingURL=FlightSummary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlightSummary.d.ts","sourceRoot":"","sources":["../src/FlightSummary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAIL,KAAK,aAAa,IAAI,iBAAiB,EACvC,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoCD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0DtD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,UAM/B,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { format } from 'date-fns';
3
+ import { defaultWidgetConfig, flightSummarySchema } from '@conversokit/shared';
4
+ const LegRow = ({ leg, label }) => (_jsxs("div", { style: {
5
+ display: 'flex',
6
+ justifyContent: 'space-between',
7
+ alignItems: 'center',
8
+ padding: 'var(--ck-spacing-2) 0',
9
+ borderBottom: '1px dashed var(--ck-border)',
10
+ gap: 'var(--ck-spacing-2)'
11
+ }, children: [_jsxs("div", { children: [_jsxs("div", { style: { fontSize: 'var(--ck-font-size-sm)', color: 'var(--ck-muted)' }, children: [label, " \u00B7 ", leg.airline, " ", leg.flightNumber] }), _jsxs("div", { style: {
12
+ fontSize: 'var(--ck-font-size-lg)',
13
+ fontWeight: 'var(--ck-font-weight-bold)'
14
+ }, children: [leg.origin, " \u2192 ", leg.destination] })] }), _jsxs("div", { style: { textAlign: 'right', fontSize: 'var(--ck-font-size-sm)' }, children: [_jsx("div", { children: format(new Date(leg.departsAt), 'MMM d, HH:mm') }), _jsxs("div", { style: { color: 'var(--ck-muted)' }, children: ["arr ", format(new Date(leg.arrivesAt), 'HH:mm'), leg.durationMinutes ? ` ยท ${Math.round(leg.durationMinutes / 60)}h ${leg.durationMinutes % 60}m` : ''] })] })] }));
15
+ export const FlightSummary = ({ flight, onAction, ctaLabel = 'Select flight' }) => {
16
+ return (_jsxs("div", { "data-testid": "flight-summary", style: {
17
+ border: '1px solid var(--ck-border)',
18
+ borderRadius: 'var(--ck-radius-md)',
19
+ backgroundColor: 'var(--ck-surface)',
20
+ color: 'var(--ck-text)',
21
+ fontFamily: 'var(--ck-font-family)',
22
+ padding: 'var(--ck-spacing-4)',
23
+ maxWidth: 480,
24
+ display: 'flex',
25
+ flexDirection: 'column',
26
+ gap: 'var(--ck-spacing-1)'
27
+ }, children: [_jsx(LegRow, { leg: flight.outbound, label: "Outbound" }), flight.return && _jsx(LegRow, { leg: flight.return, label: "Return" }), _jsxs("div", { style: {
28
+ display: 'flex',
29
+ justifyContent: 'space-between',
30
+ alignItems: 'center',
31
+ marginTop: 'var(--ck-spacing-2)'
32
+ }, children: [_jsxs("span", { style: { color: 'var(--ck-muted)', fontSize: 'var(--ck-font-size-sm)' }, children: [flight.bookingClass ?? 'Economy', typeof flight.stops === 'number'
33
+ ? ` ยท ${flight.stops === 0 ? 'Nonstop' : `${flight.stops} stop${flight.stops > 1 ? 's' : ''}`}`
34
+ : ''] }), _jsx("strong", { style: { fontSize: 'var(--ck-font-size-lg)' }, children: flight.price })] }), onAction && (_jsx("button", { type: "button", onClick: () => onAction(flight), style: {
35
+ marginTop: 'var(--ck-spacing-2)',
36
+ padding: '8px 12px',
37
+ borderRadius: 'var(--ck-radius-sm)',
38
+ border: 'none',
39
+ backgroundColor: 'var(--ck-primary)',
40
+ color: 'var(--ck-primary-foreground)',
41
+ cursor: 'pointer'
42
+ }, children: ctaLabel }))] }));
43
+ };
44
+ export const FlightSummaryMeta = {
45
+ name: 'FlightSummary',
46
+ category: 'travel',
47
+ version: '0.1.0',
48
+ config: { ...defaultWidgetConfig, permissions: {} },
49
+ schema: flightSummarySchema
50
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { type Hotel, type WidgetMeta } from '@conversokit/shared';
3
+ export interface HotelCardProps {
4
+ hotel: Hotel;
5
+ ctaLabel?: string;
6
+ onAction?: (hotel: Hotel) => void;
7
+ }
8
+ export declare const HotelCard: React.FC<HotelCardProps>;
9
+ export declare const HotelCardMeta: WidgetMeta;
10
+ //# sourceMappingURL=HotelCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HotelCard.d.ts","sourceRoot":"","sources":["../src/HotelCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAkG9C,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAS3B,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { defaultWidgetConfig, hotelSchema } from '@conversokit/shared';
3
+ export const HotelCard = ({ hotel, ctaLabel = 'Book', onAction }) => {
4
+ return (_jsxs("div", { "data-testid": "hotel-card", style: {
5
+ border: '1px solid var(--ck-border)',
6
+ borderRadius: 'var(--ck-radius-md)',
7
+ backgroundColor: 'var(--ck-surface)',
8
+ color: 'var(--ck-text)',
9
+ fontFamily: 'var(--ck-font-family)',
10
+ width: 280,
11
+ overflow: 'hidden',
12
+ display: 'flex',
13
+ flexDirection: 'column'
14
+ }, children: [hotel.imageUrl && (_jsx("img", { src: hotel.imageUrl, alt: hotel.name, style: { width: '100%', height: 160, objectFit: 'cover' } })), _jsxs("div", { style: {
15
+ padding: 'var(--ck-spacing-4)',
16
+ display: 'flex',
17
+ flexDirection: 'column',
18
+ gap: 'var(--ck-spacing-1)'
19
+ }, children: [_jsx("strong", { style: { fontSize: 'var(--ck-font-size-lg)' }, children: hotel.name }), _jsxs("span", { style: { color: 'var(--ck-muted)', fontSize: 'var(--ck-font-size-sm)' }, children: [hotel.city, hotel.country ? `, ${hotel.country}` : ''] }), hotel.rating !== undefined && (_jsxs("span", { style: { fontSize: 'var(--ck-font-size-sm)' }, children: ["\u2B50 ", hotel.rating.toFixed(1)] })), hotel.amenities && hotel.amenities.length > 0 && (_jsx("div", { style: {
20
+ display: 'flex',
21
+ flexWrap: 'wrap',
22
+ gap: 4,
23
+ marginTop: 'var(--ck-spacing-1)'
24
+ }, children: hotel.amenities.map((a) => (_jsx("span", { style: {
25
+ fontSize: 'var(--ck-font-size-sm)',
26
+ border: '1px solid var(--ck-border)',
27
+ borderRadius: 'var(--ck-radius-sm)',
28
+ padding: '2px 6px',
29
+ color: 'var(--ck-muted)'
30
+ }, children: a }, a))) })), _jsxs("span", { style: {
31
+ marginTop: 'var(--ck-spacing-2)',
32
+ fontWeight: 'var(--ck-font-weight-bold)'
33
+ }, children: [hotel.pricePerNight, " ", _jsx("span", { style: { color: 'var(--ck-muted)', fontWeight: 400 }, children: "/ night" })] }), onAction && (_jsx("button", { type: "button", onClick: () => onAction(hotel), style: {
34
+ marginTop: 'var(--ck-spacing-2)',
35
+ padding: '8px 12px',
36
+ borderRadius: 'var(--ck-radius-sm)',
37
+ border: 'none',
38
+ backgroundColor: 'var(--ck-primary)',
39
+ color: 'var(--ck-primary-foreground)',
40
+ cursor: 'pointer'
41
+ }, children: ctaLabel }))] })] }));
42
+ };
43
+ export const HotelCardMeta = {
44
+ name: 'HotelCard',
45
+ category: 'travel',
46
+ version: '0.1.0',
47
+ config: {
48
+ ...defaultWidgetConfig,
49
+ permissions: { allowsExternalLinks: true }
50
+ },
51
+ schema: hotelSchema
52
+ };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type Itinerary, type WidgetMeta } from '@conversokit/shared';
3
+ export interface ItineraryTimelineProps {
4
+ itinerary: Itinerary;
5
+ }
6
+ export declare const ItineraryTimeline: React.FC<ItineraryTimelineProps>;
7
+ export declare const ItineraryTimelineMeta: WidgetMeta;
8
+ //# sourceMappingURL=ItineraryTimeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItineraryTimeline.d.ts","sourceRoot":"","sources":["../src/ItineraryTimeline.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC;CACtB;AASD,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA2F9D,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,UAMnC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { format } from 'date-fns';
3
+ import { defaultWidgetConfig, itinerarySchema } from '@conversokit/shared';
4
+ const KIND_ICON = {
5
+ flight: 'โœˆ๏ธ',
6
+ hotel: '๐Ÿจ',
7
+ activity: '๐ŸŽŸ๏ธ',
8
+ transfer: '๐Ÿš•'
9
+ };
10
+ export const ItineraryTimeline = ({ itinerary }) => {
11
+ return (_jsxs("div", { "data-testid": "itinerary-timeline", style: {
12
+ border: '1px solid var(--ck-border)',
13
+ borderRadius: 'var(--ck-radius-md)',
14
+ backgroundColor: 'var(--ck-surface)',
15
+ color: 'var(--ck-text)',
16
+ fontFamily: 'var(--ck-font-family)',
17
+ padding: 'var(--ck-spacing-4)',
18
+ maxWidth: 520
19
+ }, children: [_jsx("h3", { style: { margin: 0, marginBottom: 'var(--ck-spacing-2)' }, children: itinerary.title }), _jsx("ol", { style: {
20
+ listStyle: 'none',
21
+ margin: 0,
22
+ padding: 0,
23
+ display: 'flex',
24
+ flexDirection: 'column',
25
+ gap: 'var(--ck-spacing-2)'
26
+ }, children: itinerary.stops.map((stop, idx) => (_jsxs("li", { style: {
27
+ display: 'grid',
28
+ gridTemplateColumns: '24px 1fr',
29
+ gap: 'var(--ck-spacing-2)',
30
+ alignItems: 'flex-start'
31
+ }, children: [_jsxs("div", { "aria-hidden": true, style: {
32
+ width: 24,
33
+ textAlign: 'center',
34
+ position: 'relative',
35
+ paddingTop: 2
36
+ }, children: [_jsx("span", { children: stop.kind ? KIND_ICON[stop.kind] : 'โ€ข' }), idx < itinerary.stops.length - 1 && (_jsx("div", { style: {
37
+ width: 1,
38
+ height: 28,
39
+ backgroundColor: 'var(--ck-border)',
40
+ margin: '4px auto 0'
41
+ } }))] }), _jsxs("div", { children: [_jsx("div", { style: {
42
+ fontWeight: 'var(--ck-font-weight-bold)'
43
+ }, children: stop.title }), _jsxs("div", { style: {
44
+ fontSize: 'var(--ck-font-size-sm)',
45
+ color: 'var(--ck-muted)'
46
+ }, children: [format(new Date(stop.startsAt), 'EEE MMM d, HH:mm'), stop.endsAt
47
+ ? ` โ€” ${format(new Date(stop.endsAt), 'HH:mm')}`
48
+ : '', stop.location ? ` ยท ${stop.location}` : ''] }), stop.description && (_jsx("p", { style: { margin: '4px 0 0', fontSize: 'var(--ck-font-size-sm)' }, children: stop.description }))] })] }, stop.id))) })] }));
49
+ };
50
+ export const ItineraryTimelineMeta = {
51
+ name: 'ItineraryTimeline',
52
+ category: 'travel',
53
+ version: '0.1.0',
54
+ config: { ...defaultWidgetConfig, permissions: {} },
55
+ schema: itinerarySchema
56
+ };
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { z } from 'zod';
3
+ import { type KPI, type WidgetMeta } from '@conversokit/shared';
4
+ export interface KPIGridProps {
5
+ kpis: KPI[];
6
+ }
7
+ export declare const KPIGrid: React.FC<KPIGridProps>;
8
+ export declare const kpiGridSchema: z.ZodObject<{
9
+ kpis: z.ZodArray<z.ZodObject<{
10
+ id: z.ZodString;
11
+ label: z.ZodString;
12
+ value: z.ZodString;
13
+ delta: z.ZodOptional<z.ZodNumber>;
14
+ trend: z.ZodOptional<z.ZodEnum<["up", "down", "flat"]>>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ value: string;
17
+ id: string;
18
+ label: string;
19
+ delta?: number | undefined;
20
+ trend?: "flat" | "up" | "down" | undefined;
21
+ }, {
22
+ value: string;
23
+ id: string;
24
+ label: string;
25
+ delta?: number | undefined;
26
+ trend?: "flat" | "up" | "down" | undefined;
27
+ }>, "many">;
28
+ }, "strip", z.ZodTypeAny, {
29
+ kpis: {
30
+ value: string;
31
+ id: string;
32
+ label: string;
33
+ delta?: number | undefined;
34
+ trend?: "flat" | "up" | "down" | undefined;
35
+ }[];
36
+ }, {
37
+ kpis: {
38
+ value: string;
39
+ id: string;
40
+ label: string;
41
+ delta?: number | undefined;
42
+ trend?: "flat" | "up" | "down" | undefined;
43
+ }[];
44
+ }>;
45
+ export declare const KPIGridMeta: WidgetMeta;
46
+ //# sourceMappingURL=KPIGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KPIGrid.d.ts","sourceRoot":"","sources":["../src/KPIGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,GAAG,EACR,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAcD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAsD1C,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAyC,CAAC;AAEpE,eAAO,MAAM,WAAW,EAAE,UAMzB,CAAC"}