@arkipay/booking-widget 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.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @arkipay/booking-widget
2
+
3
+ Embeddable React booking widget for the ArkiPay / EasyAppts appointment platform. Drop
4
+ `<BookingProvider>` + `<BookingWidget>` into any React app and your customers can book
5
+ appointments against your tenant — service → provider → date/time → details → confirmation,
6
+ including the online-payment redirect. The widget **inherits your site's theme** automatically.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @arkipay/booking-widget
12
+ # or: pnpm add @arkipay/booking-widget
13
+ ```
14
+
15
+ `react` and `react-dom` (v18.3+ or v19) are peer dependencies you already have.
16
+
17
+ ## Quick start
18
+
19
+ ```tsx
20
+ import { BookingProvider, BookingWidget } from "@arkipay/booking-widget";
21
+ import "@arkipay/booking-widget/styles.css";
22
+
23
+ export default function BookingPage() {
24
+ return (
25
+ <BookingProvider publishableKey="pk_live_xxx">
26
+ <BookingWidget />
27
+ </BookingProvider>
28
+ );
29
+ }
30
+ ```
31
+
32
+ Use your **publishable** key (`pk_live_…` / `pk_test_…`) — never a secret key. The widget talks
33
+ only to the public API, so the key is safe to ship in browser code.
34
+
35
+ ### Next.js App Router
36
+
37
+ The package ships with a `"use client"` directive, so you can import it directly into a Server
38
+ Component — no wrapper needed.
39
+
40
+ ## Theming
41
+
42
+ The widget is fully tokenised. Every visual value resolves in this order (highest wins):
43
+
44
+ 1. an explicit `theme` prop on `<BookingProvider>`
45
+ 2. **your site's own CSS design-system token** (e.g. `--brand`, `--fg`) — inherited automatically
46
+ 3. tenant config (brand colour, configured in the platform)
47
+ 4. a built-in default
48
+
49
+ ### Inherit your site's theme (zero config)
50
+
51
+ If your site already defines any of these CSS variables on an ancestor element, the widget picks
52
+ them up with no props at all:
53
+
54
+ | Host token | Controls | Widget token |
55
+ | ----------------- | -------------------------------- | -------------- |
56
+ | `--brand` / `--accent` | Primary / call-to-action colour | `--ea-brand` |
57
+ | `--fg` | Body text | `--ea-text` |
58
+ | `--fg-muted` | Secondary / hint text | `--ea-muted` |
59
+ | `--border` | Card & input borders | `--ea-border` |
60
+ | `--bg-elevated` | Card / input / surface background | `--ea-surface` |
61
+ | `--danger` | Error / validation colour | `--ea-error` |
62
+ | `--radius-md` | Corner radius | `--ea-radius` |
63
+ | `--font-sans` | Font stack | `--ea-font` |
64
+
65
+ ```tsx
66
+ // Your app already sets these on :root or a wrapper — the widget just follows.
67
+ <div style={{ "--brand": "#ff6b35", "--font-sans": "Inter, sans-serif" }}>
68
+ <BookingProvider publishableKey="pk_live_xxx">
69
+ <BookingWidget />
70
+ </BookingProvider>
71
+ </div>
72
+ ```
73
+
74
+ ### Explicit `theme` prop
75
+
76
+ For one-off overrides without a design system:
77
+
78
+ ```tsx
79
+ <BookingProvider
80
+ publishableKey="pk_live_xxx"
81
+ theme={{
82
+ brandColor: "#0f6b8c",
83
+ fontFamily: "Geist, system-ui, sans-serif",
84
+ borderRadius: "12px",
85
+ colorScheme: "system", // "light" | "dark" | "system"
86
+ }}
87
+ >
88
+ <BookingWidget />
89
+ </BookingProvider>
90
+ ```
91
+
92
+ Full `theme` surface: `brandColor`, `onBrandColor`, `textColor`, `mutedColor`, `borderColor`,
93
+ `surfaceColor`, `errorColor`, `borderRadius`, `fontFamily`, `maxWidth`, `colorScheme`.
94
+
95
+ ### Dark mode
96
+
97
+ Pass `theme={{ colorScheme: "dark" }}` (or `"system"` to follow `prefers-color-scheme`). If your
98
+ host already flips its own `--fg` / `--bg-elevated` tokens, the widget follows those instead — no
99
+ extra config needed.
100
+
101
+ ### Override via plain CSS
102
+
103
+ Because every element is scoped under `.ea-booking-widget`, you can override any token from your
104
+ own stylesheet without collisions:
105
+
106
+ ```css
107
+ .ea-booking-widget {
108
+ --ea-radius: 4px;
109
+ }
110
+ .ea-booking-widget .ea-btn-primary {
111
+ font-weight: 600;
112
+ }
113
+ ```
114
+
115
+ ## `BookingProvider` props
116
+
117
+ | Prop | Type | Default | Notes |
118
+ | ------------------ | -------------------------------------- | --------------------------- | ----- |
119
+ | `publishableKey` | `string` | — | Required. `pk_live_…` / `pk_test_…` |
120
+ | `apiUrl` | `string` | `https://api.easyappts.com` | Override for self-hosted / sandbox |
121
+ | `theme` | `BookingTheme` | `{}` | See Theming |
122
+ | `locale` | `string` | tenant default | e.g. `"en"` |
123
+ | `onBooked` | `(appointment) => void` | — | Fires on successful booking |
124
+ | `initialServiceId` / `initialProviderId` | `string` | URL `?service=`/`?provider=` | Pre-select a step |
125
+ | `className` / `style` | `string` / `CSSProperties` | — | Applied to the widget root |
126
+ | `botProtection` | `boolean` | `true` | See below |
127
+
128
+ ### Bot protection
129
+
130
+ The widget uses [Vercel BotID](https://vercel.com/docs/botid) on the booking request. Full
131
+ protection requires the Vercel BotID proxy on your host. If you're **not** on Vercel, set
132
+ `botProtection={false}` — the API's server-side rate limiter remains the backstop.
133
+
134
+ ## Composing your own flow
135
+
136
+ Prefer your own layout? Import the step components and drive them with `useBooking()`:
137
+
138
+ ```tsx
139
+ import {
140
+ BookingProvider, ServicePicker, ProviderPicker, DatePicker,
141
+ TimeSlotPicker, CustomerForm, ConfirmStep, BookedSummary, useBooking,
142
+ } from "@arkipay/booking-widget";
143
+ ```
144
+
145
+ A non-React / server integration can use the bundled API client directly:
146
+
147
+ ```ts
148
+ import { createBookingClient } from "@arkipay/booking-widget";
149
+ const client = createBookingClient({ publishableKey: "pk_live_xxx" });
150
+ const config = await client.getTenantConfig();
151
+ ```
152
+
153
+ ## License
154
+
155
+ UNLICENSED — for use by ArkiPay customers integrating the booking platform.