@asdp/ferryui 0.1.0 → 0.1.3

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/dist/index.d.ts CHANGED
@@ -1,6 +1,24 @@
1
- import React from 'react';
1
+ import React$1, { ReactNode } from 'react';
2
+ import { CarouselAnnouncerFunction } from '@fluentui/react-components';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { FieldValues, Path, Control } from 'react-hook-form';
2
5
 
3
- interface ModalRadiusProps {
6
+ interface ModalIllustrationButton {
7
+ /**
8
+ * Button text
9
+ */
10
+ text: string;
11
+ /**
12
+ * Button click handler
13
+ */
14
+ onClick: () => void;
15
+ /**
16
+ * Button appearance
17
+ * @default "primary"
18
+ */
19
+ appearance?: 'primary' | 'outline' | 'secondary' | 'subtle' | 'transparent';
20
+ }
21
+ interface ModalIllustrationProps {
4
22
  /**
5
23
  * Whether the modal is open
6
24
  */
@@ -11,22 +29,25 @@ interface ModalRadiusProps {
11
29
  onClose: () => void;
12
30
  /**
13
31
  * Modal title
14
- * @default "Anda berada di luar area pemesanan"
15
32
  */
16
- title?: string;
33
+ title: string;
17
34
  /**
18
35
  * Modal message content
19
- * @default "Pemesanan tiket tidak dapat dilakukan dari lokasi Anda saat ini..."
36
+ * Can be a string or React node for more complex content
20
37
  */
21
- message?: string;
38
+ message: string | ReactNode;
22
39
  /**
23
40
  * Image source URL
24
41
  * @default "/assets/images/illustrations/radius.svg"
42
+ * @remarks
43
+ * When using this component in your application, ensure the asset is available at this path
44
+ * in your public directory, or provide a custom imageSrc prop pointing to your own image.
45
+ * The asset is included in the published package at `node_modules/@asdp/ferryui/dist/assets/images/illustrations/`
25
46
  */
26
47
  imageSrc?: string;
27
48
  /**
28
49
  * Image alt text
29
- * @default "Radius Illustration"
50
+ * @default "Illustration"
30
51
  */
31
52
  imageAlt?: string;
32
53
  /**
@@ -40,15 +61,496 @@ interface ModalRadiusProps {
40
61
  */
41
62
  imageHeight?: number;
42
63
  /**
43
- * Button text
44
- * @default "Tutup & Coba Lagi"
64
+ * Primary button configuration
65
+ */
66
+ primaryButton: ModalIllustrationButton;
67
+ /**
68
+ * Optional secondary button configuration
69
+ * If provided, buttons will be displayed side by side
70
+ */
71
+ secondaryButton?: ModalIllustrationButton;
72
+ }
73
+ declare const ModalIllustration: React$1.FC<ModalIllustrationProps>;
74
+
75
+ /**
76
+ * Preset configurations for common modal use cases
77
+ */
78
+ declare const MODAL_PRESETS: {
79
+ /**
80
+ * Modal for radius/location restriction
81
+ */
82
+ readonly RADIUS: {
83
+ readonly title: "Anda berada di luar area pemesanan";
84
+ readonly message: "Pemesanan tiket tidak dapat dilakukan dari lokasi Anda saat ini. Fitur pembatasan wilayah sedang aktif untuk mencegah pemesanan tidak sah.";
85
+ readonly imageSrc: "/assets/images/illustrations/radius.svg";
86
+ readonly imageAlt: "Radius Limitation Illustration";
87
+ };
88
+ /**
89
+ * Modal for expired session
90
+ */
91
+ readonly SESSION_EXPIRED: {
92
+ readonly title: "Sesi anda telah berakhir";
93
+ readonly message: "Waktu sesi Anda telah habis untuk alasan keamanan. Silakan klik tombol dibawah untuk masuk kembali.";
94
+ readonly imageSrc: "/assets/images/illustrations/sessionexp.svg";
95
+ readonly imageAlt: "Session Expired Illustration";
96
+ };
97
+ /**
98
+ * Modal for purchase period expired
99
+ */
100
+ readonly PURCHASE_PERIOD_EXPIRED: {
101
+ readonly title: "Waktu pembelian telah berakhir";
102
+ readonly message: "Pemesanan tiket ditutup 1 jam sebelum jadwal keberangkatan. Silakan pilih jadwal keberangkatan lain yang masih tersedia.";
103
+ readonly imageSrc: "/assets/images/illustrations/pay.svg";
104
+ readonly imageAlt: "Purchase Period Expired Illustration";
105
+ };
106
+ /**
107
+ * Modal for transaction limit reached
108
+ */
109
+ readonly TRANSACTION_LIMIT: {
110
+ readonly title: "Anda mencapai batas transaksi tertunda";
111
+ readonly message: "Anda telah mencapai batas transaksi tertunda. Pemesanan dapat dilakukan kembali setelah transaksi sebelumnya diselesaikan.";
112
+ readonly imageSrc: "/assets/images/illustrations/mobile-pay.svg";
113
+ readonly imageAlt: "Transaction Limit Illustration";
114
+ };
115
+ };
116
+ /**
117
+ * Type for preset keys
118
+ */
119
+ type ModalPresetKey = keyof typeof MODAL_PRESETS;
120
+ /**
121
+ * Helper function to get preset configuration
122
+ */
123
+ declare const getModalPreset: (presetKey: ModalPresetKey) => Partial<ModalIllustrationProps>;
124
+
125
+ interface CarouselWithCustomNavProps {
126
+ /**
127
+ * Carousel items/children
128
+ */
129
+ children: ReactNode;
130
+ /**
131
+ * Whether carousel should loop (circular)
132
+ * @default true
133
+ */
134
+ circular?: boolean;
135
+ /**
136
+ * Whether carousel is draggable
137
+ * @default true
138
+ */
139
+ draggable?: boolean;
140
+ /**
141
+ * Alignment of carousel items
142
+ * @default "start"
143
+ */
144
+ align?: 'start' | 'center' | 'end';
145
+ /**
146
+ * Whether to remove whitespace between items
147
+ * @default false
148
+ */
149
+ whitespace?: boolean;
150
+ /**
151
+ * Announcement function for accessibility
152
+ */
153
+ announcement?: CarouselAnnouncerFunction;
154
+ /**
155
+ * Active index (controlled)
156
+ */
157
+ activeIndex?: number;
158
+ /**
159
+ * Callback when active index changes
160
+ */
161
+ onActiveIndexChange?: (index: number) => void;
162
+ /**
163
+ * ARIA label for the carousel slider
164
+ * @default "Carousel"
165
+ */
166
+ ariaLabel?: string;
167
+ /**
168
+ * Whether to use dark background for navigation
169
+ * @default true
170
+ */
171
+ darkNavBackground?: boolean;
172
+ /**
173
+ * Additional className for carousel container
174
+ */
175
+ className?: string;
176
+ /**
177
+ * Whether to enable card focus mode
178
+ * @default false
179
+ */
180
+ cardFocus?: boolean;
181
+ }
182
+ declare const CarouselWithCustomNav: React$1.FC<CarouselWithCustomNavProps>;
183
+
184
+ interface CardPromoProps {
185
+ /**
186
+ * Image URL for the promo
187
+ */
188
+ imageUrl: string;
189
+ /**
190
+ * Promo title/heading
191
+ */
192
+ title: string;
193
+ /**
194
+ * Promo description/subtitle
195
+ */
196
+ description: string;
197
+ /**
198
+ * Image alt text
199
+ * @default "Promo image"
200
+ */
201
+ imageAlt?: string;
202
+ /**
203
+ * Index of the card (for accessibility)
204
+ */
205
+ index?: number;
206
+ /**
207
+ * Total number of cards (for accessibility)
208
+ */
209
+ totalCards?: number;
210
+ /**
211
+ * Click handler for the card
212
+ */
213
+ onClick?: () => void;
214
+ }
215
+ declare const CardPromo: React$1.FC<CardPromoProps>;
216
+
217
+ interface CardBannerProps {
218
+ /**
219
+ * Banner image URL
220
+ */
221
+ imageUrl: string;
222
+ /**
223
+ * Banner alt text
224
+ */
225
+ alt: string;
226
+ /**
227
+ * Index of the banner (for accessibility)
228
+ */
229
+ index?: number;
230
+ /**
231
+ * Total number of banners (for accessibility)
232
+ */
233
+ totalBanners?: number;
234
+ /**
235
+ * Click handler for the banner
236
+ */
237
+ onClick?: () => void;
238
+ }
239
+ declare const CardBanner: React$1.FC<CardBannerProps>;
240
+
241
+ interface CardTicketButton {
242
+ label: string;
243
+ icon?: JSX.Element;
244
+ onClick?: () => void;
245
+ }
246
+ interface CardTicketProps {
247
+ /**
248
+ * Ship type badge configuration
249
+ */
250
+ shipType: {
251
+ label: string;
252
+ color: 'brand' | 'danger' | 'important' | 'informative' | 'severe' | 'subtle' | 'success' | 'warning';
253
+ tooltip?: string;
254
+ };
255
+ /**
256
+ * Logo image source
257
+ * @default "/assets/logo/asdp-default.svg"
258
+ */
259
+ logoSrc?: string;
260
+ /**
261
+ * Ship name
262
+ */
263
+ shipName: string;
264
+ /**
265
+ * Available seats configuration
266
+ */
267
+ availableSeats: {
268
+ count: number;
269
+ threshold?: number;
270
+ };
271
+ /**
272
+ * Departure information
273
+ */
274
+ departure: {
275
+ day: string;
276
+ time: string;
277
+ location: string;
278
+ };
279
+ /**
280
+ * Arrival information
281
+ */
282
+ arrival: {
283
+ day: string;
284
+ time: string;
285
+ location: string;
286
+ };
287
+ /**
288
+ * Duration text
289
+ */
290
+ duration: string;
291
+ /**
292
+ * Middle section action buttons (max 2)
293
+ */
294
+ actionButtons?: CardTicketButton[];
295
+ /**
296
+ * Price display (formatted string)
297
+ */
298
+ price: string;
299
+ /**
300
+ * Primary button configuration
301
+ */
302
+ primaryButton: CardTicketButton;
303
+ /**
304
+ * List of facilities
305
+ */
306
+ facilities: string[];
307
+ /**
308
+ * Custom icon for ship indicator
309
+ */
310
+ shipIcon?: JSX.Element;
311
+ /**
312
+ * Custom icon for facilities checkmark
313
+ */
314
+ facilityIcon?: JSX.Element;
315
+ }
316
+ declare const CardTicket: React$1.FC<CardTicketProps>;
317
+
318
+ /**
319
+ * Horizontal ticket card background with decorative perforated edges
320
+ * Use this for desktop/landscape layouts
321
+ */
322
+ declare const BackgroundTicketCard: (props: React$1.SVGProps<SVGSVGElement>) => react_jsx_runtime.JSX.Element;
323
+
324
+ /**
325
+ * Vertical ticket card background with decorative perforated edges
326
+ * Use this for mobile/portrait layouts
327
+ */
328
+ declare const BackgroundTicketCardVertical: (props: React$1.SVGProps<SVGSVGElement>) => react_jsx_runtime.JSX.Element;
329
+
330
+ interface ServiceMenuItem {
331
+ id: string;
332
+ label: string;
333
+ logo?: string;
334
+ description?: string;
335
+ customStyle?: React$1.CSSProperties;
336
+ }
337
+ interface CardServiceMenuProps {
338
+ /**
339
+ * Array of menu items to display
340
+ */
341
+ items: ServiceMenuItem[];
342
+ /**
343
+ * Currently active item ID
344
+ */
345
+ activeItemId?: string;
346
+ /**
347
+ * Callback when an item is clicked
348
+ */
349
+ onItemClick?: (itemId: string) => void;
350
+ /**
351
+ * Whether to show descriptions on desktop
352
+ * @default true
353
+ */
354
+ showDescriptions?: boolean;
355
+ /**
356
+ * Custom className for the card
357
+ */
358
+ className?: string;
359
+ }
360
+ declare const CardServiceMenu: React$1.FC<CardServiceMenuProps>;
361
+
362
+ type InputType = 'checkbox' | 'date' | 'datetime-local' | 'email' | 'file' | 'identity' | 'emailOrPhone' | 'number' | 'otp' | 'passport' | 'password' | 'phone' | 'radio' | 'radiobutton' | 'select' | 'switch' | 'tel' | 'text' | 'textarea' | 'time' | 'url';
363
+ interface SelectOption {
364
+ value: string;
365
+ label: string;
366
+ disabled?: boolean;
367
+ }
368
+ interface RadioOption {
369
+ value: string;
370
+ label: string;
371
+ disabled?: boolean;
372
+ }
373
+ interface CountryCode {
374
+ code: string;
375
+ name: string;
376
+ dialCode: string;
377
+ flag?: string;
378
+ passportRegex?: string;
379
+ }
380
+ interface InputDynamicProps<T extends FieldValues = FieldValues> {
381
+ name: Path<T>;
382
+ control: Control<T>;
383
+ label?: string;
384
+ type: InputType;
385
+ placeholder?: string;
386
+ required?: boolean;
387
+ disabled?: boolean;
388
+ options?: SelectOption[] | RadioOption[];
389
+ multiple?: boolean;
390
+ accept?: string;
391
+ rows?: number;
392
+ min?: number | string;
393
+ max?: number | string;
394
+ step?: number | string;
395
+ isMultiSelect?: boolean;
396
+ selectScrollbarColor?: string;
397
+ contentBefore?: React.ReactNode;
398
+ appearance?: 'outline' | 'underline' | 'filled-darker' | 'filled-lighter' | 'filled-darker-shadow' | 'filled-lighter-shadow';
399
+ validationRules?: {
400
+ required?: string | boolean;
401
+ minLength?: {
402
+ value: number;
403
+ message: string;
404
+ };
405
+ maxLength?: {
406
+ value: number;
407
+ message: string;
408
+ };
409
+ pattern?: {
410
+ value: RegExp;
411
+ message: string;
412
+ };
413
+ min?: {
414
+ value: number;
415
+ message: string;
416
+ };
417
+ max?: {
418
+ value: number;
419
+ message: string;
420
+ };
421
+ validate?: (value: any) => string | boolean;
422
+ };
423
+ helperText?: string;
424
+ className?: string;
425
+ layout?: 'horizontal' | 'vertical';
426
+ size?: 'small' | 'medium' | 'large';
427
+ onClick?: () => void;
428
+ style?: React.CSSProperties;
429
+ countryCodes?: CountryCode[];
430
+ defaultCountry?: string;
431
+ maxLength?: number;
432
+ autoAdvance?: boolean;
433
+ otpIndex?: number;
434
+ hasError?: boolean;
435
+ autoComplete?: string;
436
+ onInput?: (e: React.FormEvent<HTMLInputElement>) => void;
437
+ contentAfter?: React.ReactNode;
438
+ onChange?: (value: any) => void;
439
+ }
440
+
441
+ declare function InputDynamic<T extends FieldValues = FieldValues>({ name, control, label, type, placeholder, required, disabled, options, multiple, accept, rows, min, max, step, isMultiSelect, selectScrollbarColor, contentBefore, appearance, validationRules, helperText, className, layout, size, onClick, style, countryCodes, defaultCountry, maxLength, autoAdvance, otpIndex, hasError, autoComplete, onInput, contentAfter, onChange, }: InputDynamicProps<T>): react_jsx_runtime.JSX.Element;
442
+
443
+ declare const DEFAULT_COUNTRY_CODES: CountryCode[];
444
+
445
+ /**
446
+ * Harbor item interface
447
+ */
448
+ interface HarborItem {
449
+ /**
450
+ * Unique identifier for the harbor
451
+ */
452
+ id: number;
453
+ /**
454
+ * Display name of the harbor
455
+ */
456
+ name: string;
457
+ }
458
+ /**
459
+ * Props for ModalSearchHarbor component
460
+ */
461
+ interface ModalSearchHarborProps {
462
+ /**
463
+ * Whether the modal is open
464
+ */
465
+ open: boolean;
466
+ /**
467
+ * Callback when modal should close
468
+ */
469
+ onClose: () => void;
470
+ /**
471
+ * Modal title
472
+ * @default "Pilih Pelabuhan"
473
+ */
474
+ title?: string;
475
+ /**
476
+ * Type of modal - origin or destination
477
+ * @default "origin"
478
+ */
479
+ modalType?: 'origin' | 'destination';
480
+ /**
481
+ * List of harbors to display
482
+ */
483
+ harbors: HarborItem[];
484
+ /**
485
+ * List of favorite harbors
486
+ */
487
+ favoriteHarbors: HarborItem[];
488
+ /**
489
+ * List of last searched harbors
490
+ */
491
+ lastSearchedHarbors: HarborItem[];
492
+ /**
493
+ * Loading state
494
+ * @default false
495
+ */
496
+ isLoading?: boolean;
497
+ /**
498
+ * Current search query value
499
+ */
500
+ searchQuery: string;
501
+ /**
502
+ * Callback when search query changes
503
+ */
504
+ onSearchChange: (query: string) => void;
505
+ /**
506
+ * Callback when a harbor is selected
507
+ */
508
+ onSelectHarbor: (harbor: HarborItem) => void;
509
+ /**
510
+ * Callback when favorite is toggled
511
+ */
512
+ onToggleFavorite: (harbor: HarborItem) => void;
513
+ /**
514
+ * Callback when adding to last searched
515
+ */
516
+ onAddLastSearched: (harbor: HarborItem) => void;
517
+ /**
518
+ * Callback when removing from last searched
45
519
  */
46
- buttonText?: string;
520
+ onRemoveLastSearched: (harborId: number) => void;
47
521
  /**
48
- * Button click handler (if not provided, uses onClose)
522
+ * Callback when clearing all last searched
49
523
  */
50
- onButtonClick?: () => void;
524
+ onClearLastSearched: () => void;
51
525
  }
52
- declare const ModalRadius: React.FC<ModalRadiusProps>;
526
+ /**
527
+ * ModalSearchHarbor - A reusable modal component for searching and selecting harbors
528
+ *
529
+ * This component provides a searchable modal interface for selecting harbors with features like:
530
+ * - Search functionality
531
+ * - Favorite harbors quick access
532
+ * - Last searched history
533
+ * - Loading states
534
+ *
535
+ * @example
536
+ * ```tsx
537
+ * <ModalSearchHarbor
538
+ * open={isOpen}
539
+ * onClose={() => setIsOpen(false)}
540
+ * title="Pilih Pelabuhan Asal"
541
+ * harbors={harborList}
542
+ * favoriteHarbors={favorites}
543
+ * lastSearchedHarbors={history}
544
+ * searchQuery={search}
545
+ * onSearchChange={setSearch}
546
+ * onSelectHarbor={handleSelect}
547
+ * onToggleFavorite={handleToggleFavorite}
548
+ * onAddLastSearched={handleAddHistory}
549
+ * onRemoveLastSearched={handleRemoveHistory}
550
+ * onClearLastSearched={handleClearHistory}
551
+ * />
552
+ * ```
553
+ */
554
+ declare const ModalSearchHarbor: React.FC<ModalSearchHarborProps>;
53
555
 
54
- export { ModalRadius, ModalRadius as ModalRadiusDefault, type ModalRadiusProps };
556
+ export { BackgroundTicketCard, BackgroundTicketCardVertical, CardBanner, type CardBannerProps, CardPromo, type CardPromoProps, CardServiceMenu, type CardServiceMenuProps, CardTicket, type CardTicketButton, type CardTicketProps, CarouselWithCustomNav, type CarouselWithCustomNavProps, type CountryCode, DEFAULT_COUNTRY_CODES, type HarborItem, InputDynamic, type InputDynamicProps, type InputType, MODAL_PRESETS, ModalIllustration, type ModalIllustrationButton, type ModalIllustrationProps, type ModalPresetKey, ModalSearchHarbor, type ModalSearchHarborProps, type RadioOption, type SelectOption, type ServiceMenuItem, getModalPreset };