@wix/headless-bookings 0.0.13 → 0.0.15

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 (33) hide show
  1. package/cjs/dist/react/core/service-list/ServiceList.d.ts +4 -0
  2. package/cjs/dist/react/core/service-list/ServiceList.js +4 -0
  3. package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +368 -0
  4. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +357 -0
  5. package/cjs/dist/react/core/time-slot-list/TimeSlotList.d.ts +84 -0
  6. package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +68 -0
  7. package/cjs/dist/react/index.d.ts +1 -0
  8. package/cjs/dist/react/index.js +1 -0
  9. package/cjs/dist/react/service/Service.js +1 -11
  10. package/cjs/dist/react/service-list/ServiceList.d.ts +2 -0
  11. package/cjs/dist/react/service-list/ServiceList.js +23 -35
  12. package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +438 -0
  13. package/cjs/dist/react/time-slot-list/TimeSlot.js +427 -0
  14. package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +209 -0
  15. package/cjs/dist/react/time-slot-list/TimeSlotList.js +199 -0
  16. package/cjs/dist/services/time-slot-list/index.d.ts +1 -1
  17. package/dist/react/core/service-list/ServiceList.d.ts +4 -0
  18. package/dist/react/core/service-list/ServiceList.js +4 -0
  19. package/dist/react/core/time-slot-list/TimeSlot.d.ts +368 -0
  20. package/dist/react/core/time-slot-list/TimeSlot.js +357 -0
  21. package/dist/react/core/time-slot-list/TimeSlotList.d.ts +84 -0
  22. package/dist/react/core/time-slot-list/TimeSlotList.js +68 -0
  23. package/dist/react/index.d.ts +1 -0
  24. package/dist/react/index.js +1 -0
  25. package/dist/react/service/Service.js +1 -11
  26. package/dist/react/service-list/ServiceList.d.ts +2 -0
  27. package/dist/react/service-list/ServiceList.js +23 -35
  28. package/dist/react/time-slot-list/TimeSlot.d.ts +438 -0
  29. package/dist/react/time-slot-list/TimeSlot.js +427 -0
  30. package/dist/react/time-slot-list/TimeSlotList.d.ts +209 -0
  31. package/dist/react/time-slot-list/TimeSlotList.js +199 -0
  32. package/dist/services/time-slot-list/index.d.ts +1 -1
  33. package/package.json +2 -2
@@ -0,0 +1,357 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Core TimeSlot Components
4
+ * Provides low-level access to TimeSlot data via render props
5
+ *
6
+ * Note: These components must be used within TimeSlotList.TimeSlotRepeater
7
+ * which provides the TimeSlotProvider context.
8
+ */
9
+ import React from 'react';
10
+ import { useTimeSlotListService } from './TimeSlotList.js';
11
+ const TimeSlotContext = React.createContext(null);
12
+ /**
13
+ * Hook to access TimeSlot context
14
+ * @throws Error if used outside of TimeSlotProvider
15
+ */
16
+ export function useTimeSlotContext() {
17
+ const context = React.useContext(TimeSlotContext);
18
+ if (!context) {
19
+ throw new Error('TimeSlot components must be used within TimeSlotList.TimeSlotRepeater');
20
+ }
21
+ return context;
22
+ }
23
+ /**
24
+ * Provider component used by TimeSlotRepeater to provide context.
25
+ * Not used directly by consumers - only by TimeSlotList.TimeSlotRepeater.
26
+ */
27
+ export function TimeSlotProvider(props) {
28
+ const { children, slot } = props;
29
+ const service = useTimeSlotListService();
30
+ const selection = service.selection.get();
31
+ const isSelected = selection?.slot?.id === slot.id;
32
+ const selectSlot = () => {
33
+ service.actions.selectSlot(slot);
34
+ };
35
+ const contextValue = {
36
+ slot,
37
+ isSelected,
38
+ selectSlot,
39
+ };
40
+ return (_jsx(TimeSlotContext.Provider, { value: contextValue, children: children }));
41
+ }
42
+ const LocationContext = React.createContext(null);
43
+ /**
44
+ * Hook to access Location context
45
+ * @throws Error if used outside of LocationProvider
46
+ */
47
+ export function useLocationContext() {
48
+ const context = React.useContext(LocationContext);
49
+ if (!context) {
50
+ throw new Error('Location components must be used within LocationProvider');
51
+ }
52
+ return context;
53
+ }
54
+ /**
55
+ * Provider component used by LocationRepeater to provide context.
56
+ * Not used directly by consumers - only by TimeSlot.LocationRepeater.
57
+ */
58
+ export function LocationProvider(props) {
59
+ const { children, location } = props;
60
+ const service = useTimeSlotListService();
61
+ const selectLocation = () => {
62
+ service.actions.selectLocation(location.id);
63
+ };
64
+ const contextValue = {
65
+ location,
66
+ selectLocation,
67
+ };
68
+ return (_jsx(LocationContext.Provider, { value: contextValue, children: children }));
69
+ }
70
+ const StaffMemberContext = React.createContext(null);
71
+ /**
72
+ * Hook to access StaffMember context
73
+ * @throws Error if used outside of StaffMemberProvider
74
+ */
75
+ export function useStaffMemberContext() {
76
+ const context = React.useContext(StaffMemberContext);
77
+ if (!context) {
78
+ throw new Error('StaffMember components must be used within StaffMemberProvider');
79
+ }
80
+ return context;
81
+ }
82
+ /**
83
+ * Provider component used by StaffMemberRepeater to provide context.
84
+ * Not used directly by consumers - only by TimeSlot.StaffMemberRepeater.
85
+ */
86
+ export function StaffMemberProvider(props) {
87
+ const { children, staffMember } = props;
88
+ const service = useTimeSlotListService();
89
+ const selectStaffMember = () => {
90
+ service.actions.selectStaffMember(staffMember.id);
91
+ };
92
+ const contextValue = {
93
+ staffMember,
94
+ selectStaffMember,
95
+ };
96
+ return (_jsx(StaffMemberContext.Provider, { value: contextValue, children: children }));
97
+ }
98
+ /**
99
+ * Core component that provides access to time slot info via render props.
100
+ * Includes start/end dates, duration, bookable status, and selection state.
101
+ *
102
+ * @component
103
+ * @example
104
+ * ```tsx
105
+ * <TimeSlot.Info>
106
+ * {({ startDate, endDate, durationInMinutes, bookable, isSelected }) => (
107
+ * <div>
108
+ * <span>{startDate}</span>
109
+ * <span>{durationInMinutes} min</span>
110
+ * </div>
111
+ * )}
112
+ * </TimeSlot.Info>
113
+ * ```
114
+ */
115
+ export function Info(props) {
116
+ const { slot, isSelected } = useTimeSlotContext();
117
+ const startDate = slot.localStartDate ?? undefined;
118
+ const endDate = slot.localEndDate ?? undefined;
119
+ const bookable = slot.bookable ?? false;
120
+ // Calculate duration from start and end dates
121
+ let durationInMinutes = null;
122
+ if (startDate && endDate) {
123
+ const startTime = new Date(startDate).getTime();
124
+ const endTime = new Date(endDate).getTime();
125
+ durationInMinutes = Math.round((endTime - startTime) / (1000 * 60));
126
+ }
127
+ return props.children({
128
+ startDate,
129
+ endDate,
130
+ durationInMinutes,
131
+ bookable,
132
+ isSelected,
133
+ slot,
134
+ });
135
+ }
136
+ /**
137
+ * Core component that provides slot actions via render props.
138
+ *
139
+ * @component
140
+ * @example
141
+ * ```tsx
142
+ * <TimeSlot.Actions>
143
+ * {({ selectSlot, isSelected, bookable, clearPreferences, shouldShowClearPreferences }) => (
144
+ * <div>
145
+ * <button onClick={selectSlot} disabled={!bookable}>
146
+ * {isSelected ? 'Selected' : 'Select'}
147
+ * </button>
148
+ * {shouldShowClearPreferences && (
149
+ * <button onClick={clearPreferences}>Change</button>
150
+ * )}
151
+ * </div>
152
+ * )}
153
+ * </TimeSlot.Actions>
154
+ * ```
155
+ */
156
+ export function Actions(props) {
157
+ const { selectSlot, slot, isSelected } = useTimeSlotContext();
158
+ const service = useTimeSlotListService();
159
+ const selection = service.selection.get();
160
+ const bookable = slot.bookable ?? false;
161
+ // Check if at least one preference is selected
162
+ const hasPreferenceSelected = !!selection?.locationId || !!selection?.staffMemberId;
163
+ // Check if there are multiple options
164
+ const locationCount = slot.staffByLocation.length;
165
+ const staffCount = new Set(slot.staffByLocation.flatMap(({ staffMembers }) => staffMembers.map((s) => s.id))).size;
166
+ const hasMultipleOptions = locationCount > 1 || staffCount > 1;
167
+ const shouldShowClearPreferences = hasPreferenceSelected && hasMultipleOptions;
168
+ const clearPreferences = shouldShowClearPreferences
169
+ ? service.actions.clearPreferences
170
+ : undefined;
171
+ return props.children({
172
+ selectSlot,
173
+ clearPreferences,
174
+ slot,
175
+ bookable,
176
+ isSelected,
177
+ });
178
+ }
179
+ /**
180
+ * Core component that provides access to time slot locations via render props.
181
+ * Extracts locations from slot.staffByLocation and enriches with name from originalSlots.
182
+ * Each location includes isSelected and isSelectable based on current selection state.
183
+ *
184
+ * @component
185
+ * @example
186
+ * ```tsx
187
+ * <CoreTimeSlot.Locations>
188
+ * {({ locations, locationsCount, selectLocation }) => (
189
+ * <GenericList.Root items={locations}>
190
+ * {children}
191
+ * </GenericList.Root>
192
+ * )}
193
+ * </CoreTimeSlot.Locations>
194
+ * ```
195
+ */
196
+ export function Locations(props) {
197
+ const { slot } = useTimeSlotContext();
198
+ const service = useTimeSlotListService();
199
+ const selection = service.selection.get();
200
+ const selectedLocationId = selection?.locationId ?? null;
201
+ const selectedStaffMemberId = selection?.staffMemberId ?? null;
202
+ // Build locations array from staffByLocation (names already included)
203
+ const locations = slot.staffByLocation.map(({ location, staffMembers }) => {
204
+ // Check if this location is selectable based on selected staff
205
+ // If no staff selected, all locations are selectable
206
+ // If staff selected, only locations where that staff works are selectable
207
+ const isSelectable = selectedStaffMemberId
208
+ ? staffMembers.some((s) => s.id === selectedStaffMemberId)
209
+ : true;
210
+ return {
211
+ id: location.id,
212
+ name: location.name,
213
+ isSelected: selectedLocationId === location.id,
214
+ isSelectable,
215
+ };
216
+ });
217
+ return props.children({
218
+ locations,
219
+ selectLocation: service.actions.selectLocation,
220
+ });
221
+ }
222
+ /**
223
+ * Core component that provides access to location info via render props.
224
+ * Must be used within LocationProvider.
225
+ *
226
+ * @component
227
+ * @example
228
+ * ```tsx
229
+ * <LocationInfo>
230
+ * {({ name, isSelected, isSelectable }) => (
231
+ * <span>{name}</span>
232
+ * )}
233
+ * </LocationInfo>
234
+ * ```
235
+ */
236
+ export function LocationInfo(props) {
237
+ const { location } = useLocationContext();
238
+ return props.children({
239
+ name: location.name,
240
+ isSelected: location.isSelected,
241
+ isSelectable: location.isSelectable,
242
+ location,
243
+ });
244
+ }
245
+ /**
246
+ * Core component that provides location actions via render props.
247
+ * Must be used within LocationProvider.
248
+ *
249
+ * @component
250
+ * @example
251
+ * ```tsx
252
+ * <LocationActions>
253
+ * {({ selectLocation, isSelected, isSelectable }) => (
254
+ * <button onClick={selectLocation} disabled={!isSelectable}>
255
+ * {isSelected ? 'Selected' : 'Select'}
256
+ * </button>
257
+ * )}
258
+ * </LocationActions>
259
+ * ```
260
+ */
261
+ export function LocationActions(props) {
262
+ const { location, selectLocation } = useLocationContext();
263
+ return props.children({
264
+ selectLocation,
265
+ isSelected: location.isSelected,
266
+ isSelectable: location.isSelectable,
267
+ location,
268
+ });
269
+ }
270
+ /**
271
+ * Core component that provides access to time slot staff members via render props.
272
+ * Extracts unique staff members from slot.staffByLocation (names already included).
273
+ * Each staff member includes isSelected and isSelectable based on current selection state.
274
+ *
275
+ * @component
276
+ * @example
277
+ * ```tsx
278
+ * <CoreTimeSlot.StaffMembers>
279
+ * {({ staffMembers, selectStaffMember }) => (
280
+ * <GenericList.Root items={staffMembers}>
281
+ * {children}
282
+ * </GenericList.Root>
283
+ * )}
284
+ * </CoreTimeSlot.StaffMembers>
285
+ * ```
286
+ */
287
+ export function StaffMembers(props) {
288
+ const { slot } = useTimeSlotContext();
289
+ const service = useTimeSlotListService();
290
+ const selection = service.selection.get();
291
+ const selectedStaffMemberId = selection?.staffMemberId ?? null;
292
+ const selectedLocationId = selection?.locationId ?? null;
293
+ // Build unique staff members array from staffByLocation
294
+ // Flatten all staff members with their location IDs, then dedupe by ID
295
+ const allStaff = slot.staffByLocation.flatMap(({ location, staffMembers }) => staffMembers.map((s) => ({ ...s, locationId: location.id })));
296
+ // Group by staff ID to get all locations per staff member
297
+ const grouped = Object.groupBy(allStaff, (s) => s.id);
298
+ const staffMembers = Object.entries(grouped).map(([id, entries]) => ({
299
+ id,
300
+ name: entries[0].name,
301
+ isSelected: selectedStaffMemberId === id,
302
+ isSelectable: !selectedLocationId ||
303
+ entries.some((e) => e.locationId === selectedLocationId),
304
+ }));
305
+ return props.children({
306
+ staffMembers,
307
+ selectStaffMember: service.actions.selectStaffMember,
308
+ });
309
+ }
310
+ /**
311
+ * Core component that provides access to staff member info via render props.
312
+ * Must be used within StaffMemberProvider.
313
+ *
314
+ * @component
315
+ * @example
316
+ * ```tsx
317
+ * <StaffMemberInfo>
318
+ * {({ name, isSelected, isSelectable }) => (
319
+ * <span>{name}</span>
320
+ * )}
321
+ * </StaffMemberInfo>
322
+ * ```
323
+ */
324
+ export function StaffMemberInfo(props) {
325
+ const { staffMember } = useStaffMemberContext();
326
+ return props.children({
327
+ name: staffMember.name,
328
+ isSelected: staffMember.isSelected,
329
+ isSelectable: staffMember.isSelectable,
330
+ staffMember,
331
+ });
332
+ }
333
+ /**
334
+ * Core component that provides staff member actions via render props.
335
+ * Must be used within StaffMemberProvider.
336
+ *
337
+ * @component
338
+ * @example
339
+ * ```tsx
340
+ * <StaffMemberActions>
341
+ * {({ selectStaffMember, isSelected, isSelectable }) => (
342
+ * <button onClick={selectStaffMember} disabled={!isSelectable}>
343
+ * {isSelected ? 'Selected' : 'Select'}
344
+ * </button>
345
+ * )}
346
+ * </StaffMemberActions>
347
+ * ```
348
+ */
349
+ export function StaffMemberActions(props) {
350
+ const { staffMember, selectStaffMember } = useStaffMemberContext();
351
+ return props.children({
352
+ selectStaffMember,
353
+ isSelected: staffMember.isSelected,
354
+ isSelectable: staffMember.isSelectable,
355
+ staffMember,
356
+ });
357
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Core TimeSlotList Components
3
+ * Provides low-level access to TimeSlotListService via render props
4
+ */
5
+ import React from 'react';
6
+ import { type TimeSlotListServiceAPI, type TimeSlotListServiceConfig, type TimeSlot } from '../../../services/time-slot-list/index.js';
7
+ /**
8
+ * Hook to access TimeSlotListService from within TimeSlotList.Root
9
+ */
10
+ export declare const useTimeSlotListService: () => TimeSlotListServiceAPI;
11
+ /**
12
+ * Props for Root component
13
+ */
14
+ export interface RootProps {
15
+ children: React.ReactNode;
16
+ config?: TimeSlotListServiceConfig;
17
+ }
18
+ /**
19
+ * Root component that provides TimeSlotListService context to its children.
20
+ *
21
+ * @component
22
+ * @example
23
+ * ```tsx
24
+ * <Root config={{ services, timeSlots, timezone }}>
25
+ * {children}
26
+ * </Root>
27
+ * ```
28
+ */
29
+ export declare function Root(props: RootProps): React.ReactNode;
30
+ /**
31
+ * Props for Timezone render prop component
32
+ */
33
+ export interface TimezoneProps {
34
+ children: (data: {
35
+ timezone: string | undefined;
36
+ }) => React.ReactNode;
37
+ }
38
+ /**
39
+ * Core component that provides access to the current timezone via render props.
40
+ *
41
+ * @component
42
+ * @example
43
+ * ```tsx
44
+ * <Timezone>
45
+ * {({ timezone }) => (
46
+ * <span>{timezone}</span>
47
+ * )}
48
+ * </Timezone>
49
+ * ```
50
+ */
51
+ export declare function Timezone(props: TimezoneProps): React.ReactNode;
52
+ /**
53
+ * Render props for ListData component
54
+ */
55
+ export interface ListDataRenderProps {
56
+ timeSlots: TimeSlot[];
57
+ hasMore: boolean;
58
+ isLoading: boolean;
59
+ error: string | null;
60
+ loadMore: () => Promise<void>;
61
+ }
62
+ /**
63
+ * Props for ListData render prop component
64
+ */
65
+ export interface ListDataProps {
66
+ children: (data: ListDataRenderProps) => React.ReactNode;
67
+ }
68
+ /**
69
+ * Core component that provides access to time slots list data via render props.
70
+ * Use this to build list containers with GenericList.
71
+ *
72
+ * @component
73
+ * @example
74
+ * ```tsx
75
+ * <ListData>
76
+ * {({ timeSlots, hasMore, isLoading, loadMore }) => (
77
+ * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
78
+ * {children}
79
+ * </GenericList.Root>
80
+ * )}
81
+ * </ListData>
82
+ * ```
83
+ */
84
+ export declare function ListData(props: ListDataProps): React.ReactNode;
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useService, WixServices } from '@wix/services-manager-react';
3
+ import { createServicesMap } from '@wix/services-manager';
4
+ import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
5
+ /**
6
+ * Hook to access TimeSlotListService from within TimeSlotList.Root
7
+ */
8
+ export const useTimeSlotListService = () => {
9
+ return useService(TimeSlotListServiceDefinition);
10
+ };
11
+ /**
12
+ * Root component that provides TimeSlotListService context to its children.
13
+ *
14
+ * @component
15
+ * @example
16
+ * ```tsx
17
+ * <Root config={{ services, timeSlots, timezone }}>
18
+ * {children}
19
+ * </Root>
20
+ * ```
21
+ */
22
+ export function Root(props) {
23
+ return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config || {}), children: props.children }));
24
+ }
25
+ /**
26
+ * Core component that provides access to the current timezone via render props.
27
+ *
28
+ * @component
29
+ * @example
30
+ * ```tsx
31
+ * <Timezone>
32
+ * {({ timezone }) => (
33
+ * <span>{timezone}</span>
34
+ * )}
35
+ * </Timezone>
36
+ * ```
37
+ */
38
+ export function Timezone(props) {
39
+ const service = useTimeSlotListService();
40
+ const timezone = service.timezone.get();
41
+ return props.children({ timezone });
42
+ }
43
+ /**
44
+ * Core component that provides access to time slots list data via render props.
45
+ * Use this to build list containers with GenericList.
46
+ *
47
+ * @component
48
+ * @example
49
+ * ```tsx
50
+ * <ListData>
51
+ * {({ timeSlots, hasMore, isLoading, loadMore }) => (
52
+ * <GenericList.Root items={timeSlots} hasMore={hasMore} isLoading={isLoading} loadMore={loadMore}>
53
+ * {children}
54
+ * </GenericList.Root>
55
+ * )}
56
+ * </ListData>
57
+ * ```
58
+ */
59
+ export function ListData(props) {
60
+ const service = useTimeSlotListService();
61
+ return props.children({
62
+ timeSlots: service.timeSlots.get(),
63
+ hasMore: service.hasMore.get(),
64
+ isLoading: service.isLoading.get(),
65
+ error: service.error.get(),
66
+ loadMore: service.actions.loadMore,
67
+ });
68
+ }
@@ -1,4 +1,5 @@
1
1
  export * as Booking from './booking/Booking.js';
2
2
  export * as Service from './service/Service.js';
3
+ export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
3
4
  export * as ServiceList from './service-list/ServiceList.js';
4
5
  export * as Location from './location/Location.js';
@@ -1,4 +1,5 @@
1
1
  export * as Booking from './booking/Booking.js';
2
2
  export * as Service from './service/Service.js';
3
+ export * as TimeSlotList from './time-slot-list/TimeSlotList.js';
3
4
  export * as ServiceList from './service-list/ServiceList.js';
4
5
  export * as Location from './location/Location.js';
@@ -535,17 +535,7 @@ export const StaffMemberRepeater = React.forwardRef((props, ref) => {
535
535
  const staffMemberItemWrapper = ({ item: member, children: itemChildren, }) => {
536
536
  return (_jsxs(React.Fragment, { children: [_jsx("span", { "data-testid": TestIds.serviceStaffMemberRepeater, children: member.name }), itemChildren] }, member.id));
537
537
  };
538
- // When asChild is true, provide custom render props
539
- if (asChild && typeof children === 'function') {
540
- return (_jsx(GenericList.Repeater, { ref: ref, asChild: true, itemWrapper: staffMemberItemWrapper, children: (genericProps) => {
541
- const renderProps = {
542
- items: genericProps.items,
543
- itemWrapper: staffMemberItemWrapper,
544
- };
545
- return children(renderProps);
546
- } }));
547
- }
548
- return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: staffMemberItemWrapper, children: children }));
538
+ return (_jsx(GenericList.Repeater, { ref: ref, itemWrapper: staffMemberItemWrapper, asChild: asChild, children: children }));
549
539
  });
550
540
  StaffMemberRepeater.displayName = 'Service.StaffMembers.StaffMemberRepeater';
551
541
  /**
@@ -15,6 +15,8 @@ export interface ServiceListRootProps {
15
15
  serviceListConfig?: ServiceListServiceConfig;
16
16
  className?: string;
17
17
  variant?: ListVariant;
18
+ /** Number of items to load per page. Defaults to config limit or 100 */
19
+ pageSize?: number;
18
20
  }
19
21
  /**
20
22
  * Root component that provides the ServiceList service context for rendering services lists.
@@ -5,8 +5,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
5
5
  */
6
6
  import React from 'react';
7
7
  import { GenericList, } from '@wix/headless-components/react';
8
- import { useService } from '@wix/services-manager-react';
9
- import { ServiceListServiceDefinition } from '../../services/service-list/service-list.js';
10
8
  import * as CoreServiceList from '../core/service-list/ServiceList.js';
11
9
  import * as Service from '../service/Service.js';
12
10
  /**
@@ -44,7 +42,7 @@ var TestIds;
44
42
  * ```
45
43
  */
46
44
  export const Root = React.forwardRef((props, ref) => {
47
- const { children, serviceListConfig, className, variant } = props;
45
+ const { children, serviceListConfig, className, variant, pageSize } = props;
48
46
  const serviceConfig = serviceListConfig || {
49
47
  services: [],
50
48
  options: {
@@ -56,22 +54,29 @@ export const Root = React.forwardRef((props, ref) => {
56
54
  },
57
55
  },
58
56
  };
59
- return (_jsx(CoreServiceList.Root, { serviceListConfig: serviceConfig, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }));
57
+ // Calculate effective page size: prop > config limit > default
58
+ const effectivePageSize = pageSize ??
59
+ serviceListConfig?.options?.pagingMetadata?.limit ??
60
+ DEFAULT_PAGE_SIZE;
61
+ return (_jsx(CoreServiceList.Root, { serviceListConfig: serviceConfig, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, pageSize: effectivePageSize, children: children }) }));
60
62
  });
61
63
  Root.displayName = 'ServiceList.Root';
64
+ /**
65
+ * Default page size for load more
66
+ */
67
+ const DEFAULT_PAGE_SIZE = 100;
62
68
  /**
63
69
  * Internal component to handle the Root content with service access
64
70
  */
65
71
  const RootContent = React.forwardRef((props, ref) => {
66
- const { children, className, variant } = props;
67
- const serviceListService = useService(ServiceListServiceDefinition);
68
- const items = serviceListService.servicesSignal
69
- .get()
70
- .map((service) => ({
71
- ...service,
72
- id: service._id,
73
- }));
74
- return (_jsx(GenericList.Root, { items: items, loadMore: () => serviceListService.actions.loadMore(10), hasMore: serviceListService.hasMoreServicesSignal.get(), isLoading: serviceListService.isLoadingSignal.get(), className: className, ref: ref, "data-testid": TestIds.serviceListRoot, variant: variant, children: children }));
72
+ const { children, className, variant, pageSize = DEFAULT_PAGE_SIZE } = props;
73
+ return (_jsx(CoreServiceList.Services, { children: ({ services: servicesList, isLoading, hasMore, loadMore }) => {
74
+ const items = servicesList.map((service) => ({
75
+ ...service,
76
+ id: service._id,
77
+ }));
78
+ return (_jsx(GenericList.Root, { items: items, loadMore: () => loadMore(pageSize), hasMore: hasMore, isLoading: isLoading, className: className, ref: ref, "data-testid": TestIds.serviceListRoot, variant: variant, children: children }));
79
+ } }));
75
80
  });
76
81
  /**
77
82
  * Container for the services list with empty state support.
@@ -126,37 +131,20 @@ Services.displayName = 'ServiceList.Services';
126
131
  */
127
132
  export const ServiceRepeater = React.forwardRef((props, ref) => {
128
133
  const { children, asChild } = props;
129
- const serviceListService = useService(ServiceListServiceDefinition);
130
- const appId = serviceListService.queryOptionsSignal.get().appId;
131
134
  // Check if children is a function that matches ServiceRootChildren pattern
132
135
  // (function with single parameter that receives { selected, bookable })
133
136
  const isServiceRootFunction = typeof children === 'function' && children.length === 1 && !asChild;
134
137
  // Custom itemWrapper that matches ItemWrapperProps signature
135
138
  const serviceItemWrapper = (wrapperProps) => {
136
139
  const { item: service, children: itemChildren } = wrapperProps;
137
- return (_jsx(Service.Root, { service: service, appId: appId, "data-testid": TestIds.serviceListService, "data-service-id": service._id, "data-item-id": service._id, children: isServiceRootFunction
140
+ return (_jsx(Service.Root, { service: service, "data-testid": TestIds.serviceListService, "data-service-id": service._id, "data-item-id": service._id, children: isServiceRootFunction
138
141
  ? children
139
142
  : itemChildren }, service._id));
140
143
  };
141
- // Transform children for asChild pattern to provide custom render props
142
- const transformedChildren = asChild && typeof children === 'function'
143
- ? (genericProps) => {
144
- // Create properly typed render props for the consumer
145
- const renderProps = {
146
- items: genericProps.items,
147
- variant: genericProps.variant,
148
- itemWrapper: (props) => serviceItemWrapper({
149
- item: props.item,
150
- index: props.index ?? 0,
151
- children: props.children,
152
- }),
153
- };
154
- return children(renderProps, ref);
155
- }
156
- : isServiceRootFunction
157
- ? undefined
158
- : children;
159
- return (_jsx(GenericList.Repeater, { ref: ref, asChild: asChild, itemWrapper: serviceItemWrapper, children: transformedChildren }));
144
+ // When isServiceRootFunction is true, children is a function for Service.Root (not repeater render props)
145
+ // so we pass undefined and let itemWrapper handle the children
146
+ const repeaterChildren = isServiceRootFunction ? undefined : children;
147
+ return (_jsx(GenericList.Repeater, { ref: ref, asChild: asChild, itemWrapper: serviceItemWrapper, children: repeaterChildren }));
160
148
  });
161
149
  ServiceRepeater.displayName = 'ServiceList.ServiceRepeater';
162
150
  /**