@hotelcard/ui 0.0.13 → 0.0.16
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 +121 -68
- package/dist/index.cjs +1510 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +607 -17
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +857 -79
- package/dist/index.d.ts +857 -79
- package/dist/index.js +1488 -105
- package/dist/index.js.map +1 -1
- package/package.json +22 -11
package/README.md
CHANGED
|
@@ -29,36 +29,61 @@ npm install react react-dom
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
31
|
```tsx
|
|
32
|
-
import {
|
|
32
|
+
import { HotelCardUIProvider, Button, HotelCard } from '@hotelcard/ui';
|
|
33
33
|
|
|
34
34
|
// Import styles (required - do this once in your app entry)
|
|
35
|
-
import '@hotelcard/ui/
|
|
35
|
+
import '@hotelcard/ui/styles.css';
|
|
36
36
|
|
|
37
37
|
function App() {
|
|
38
38
|
return (
|
|
39
|
-
<
|
|
39
|
+
<HotelCardUIProvider locale="de" currency="CHF">
|
|
40
40
|
<Button variant="primary" onClick={() => alert('Clicked!')}>
|
|
41
41
|
Book Now
|
|
42
42
|
</Button>
|
|
43
43
|
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
originalPrice="CHF 390"
|
|
51
|
-
onClick={() => console.log('Card clicked')}
|
|
52
|
-
>
|
|
53
|
-
<Badge color="primary" size="small">-50%</Badge>
|
|
54
|
-
</Card>
|
|
55
|
-
</div>
|
|
44
|
+
<HotelCard
|
|
45
|
+
hotel={hotelData}
|
|
46
|
+
onFavoriteClick={() => toggleFavorite()}
|
|
47
|
+
onContentClick={() => navigate('/hotel/123')}
|
|
48
|
+
/>
|
|
49
|
+
</HotelCardUIProvider>
|
|
56
50
|
);
|
|
57
51
|
}
|
|
58
52
|
```
|
|
59
53
|
|
|
60
54
|
---
|
|
61
55
|
|
|
56
|
+
## Context Provider (Required for Translations)
|
|
57
|
+
|
|
58
|
+
Wrap your app with `HotelCardUIProvider` to enable translations and configuration:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { HotelCardUIProvider } from '@hotelcard/ui';
|
|
62
|
+
|
|
63
|
+
<HotelCardUIProvider
|
|
64
|
+
locale="de" // 'de' | 'en' | 'fr' | 'it'
|
|
65
|
+
currency="CHF" // Currency code
|
|
66
|
+
isDesktop={false} // Responsive mode
|
|
67
|
+
>
|
|
68
|
+
<App />
|
|
69
|
+
</HotelCardUIProvider>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Translations
|
|
73
|
+
|
|
74
|
+
The package includes built-in translations for `de`, `en`, `fr`, and `it` locales. These are automatically applied based on the `locale` prop. Components like `HotelCard`, `GuestContent`, and `WhenContent` use these translations internally.
|
|
75
|
+
|
|
76
|
+
**Custom translations** (optional):
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<HotelCardUIProvider
|
|
80
|
+
locale="de"
|
|
81
|
+
t={(key, fallback) => myI18n.t(key) || fallback} // Custom translation function
|
|
82
|
+
>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
62
87
|
## Available Components
|
|
63
88
|
|
|
64
89
|
### UI Components
|
|
@@ -77,7 +102,13 @@ function App() {
|
|
|
77
102
|
| `Dropdown` | Select dropdown |
|
|
78
103
|
| `Modal` | Modal dialog |
|
|
79
104
|
| `SectionHeader` | Section title with "Show all" button |
|
|
80
|
-
| `
|
|
105
|
+
| `Block` | Content block with title and optional icon |
|
|
106
|
+
| `ReviewCard` | Guest review card with rating and text |
|
|
107
|
+
| `FAQ` | Expandable FAQ accordion |
|
|
108
|
+
| `Benefits` | Benefits list with icons |
|
|
109
|
+
| `Pin` | Location pin marker |
|
|
110
|
+
| `DateSelector` | Date selector container component |
|
|
111
|
+
| `WhenContent` | Date/month picker for search |
|
|
81
112
|
| `DualCalendar` | Calendar component for date range selection |
|
|
82
113
|
| `GuestContent` | Guest selector with adults, children (with ages), and pet toggle |
|
|
83
114
|
| `HotelCard` | Hotel card for search results with image carousel, rating, and pricing |
|
|
@@ -189,18 +220,11 @@ import { WhenContent } from '@hotelcard/ui';
|
|
|
189
220
|
variant="dropdown"
|
|
190
221
|
showApplyButton={true}
|
|
191
222
|
onApply={() => closeDropdown()}
|
|
192
|
-
labels={{
|
|
193
|
-
dates: 'Dates', // Tab label
|
|
194
|
-
flexible: 'Flexible', // Tab label
|
|
195
|
-
anytime: 'Anytime', // Button label
|
|
196
|
-
selectMonths: 'When do you want to travel?',
|
|
197
|
-
apply: 'Apply', // Button label
|
|
198
|
-
}}
|
|
199
223
|
locale="de" // Optional: 'de', 'en', 'fr', 'it'
|
|
200
224
|
/>
|
|
201
225
|
```
|
|
202
226
|
|
|
203
|
-
|
|
227
|
+
Translations (dates, flexible, anytime, etc.) are handled automatically via `HotelCardUIProvider`.
|
|
204
228
|
|
|
205
229
|
### GuestContent (Guest Selector)
|
|
206
230
|
|
|
@@ -220,22 +244,10 @@ const [petFilter, setPetFilter] = useState(0);
|
|
|
220
244
|
petFilter={petFilter}
|
|
221
245
|
onPetChange={setPetFilter}
|
|
222
246
|
showPetToggle={true}
|
|
223
|
-
labels={{
|
|
224
|
-
adults: 'Adults',
|
|
225
|
-
children: 'Children',
|
|
226
|
-
pet: 'Pet',
|
|
227
|
-
ageOfChild: 'Age of child',
|
|
228
|
-
age: 'Age',
|
|
229
|
-
decreaseAdults: 'Decrease adults',
|
|
230
|
-
increaseAdults: 'Increase adults',
|
|
231
|
-
decreaseChildren: 'Decrease children',
|
|
232
|
-
increaseChildren: 'Increase children',
|
|
233
|
-
togglePets: 'Toggle pets',
|
|
234
|
-
}}
|
|
235
247
|
/>
|
|
236
248
|
```
|
|
237
249
|
|
|
238
|
-
|
|
250
|
+
Translations (Adults, Children, Pet, etc.) are handled automatically via `HotelCardUIProvider`.
|
|
239
251
|
|
|
240
252
|
### HotelCard
|
|
241
253
|
|
|
@@ -271,24 +283,10 @@ const hotel: HotelCardHotel = {
|
|
|
271
283
|
hotel={hotel}
|
|
272
284
|
onFavoriteClick={() => toggleFavorite(hotel.id)}
|
|
273
285
|
onContentClick={() => navigate(`/hotel/${hotel.slug}`)}
|
|
274
|
-
labels={{
|
|
275
|
-
priceFrom: t('hotel.priceFrom'),
|
|
276
|
-
notAvailable: t('hotel.notAvailable'),
|
|
277
|
-
ratingExcellent: t('rating.excellent'),
|
|
278
|
-
ratingVeryGood: t('rating.veryGood'),
|
|
279
|
-
ratingGood: t('rating.good'),
|
|
280
|
-
ratingFair: t('rating.fair'),
|
|
281
|
-
rating: t('rating.rating'),
|
|
282
|
-
swissLodge: t('hotel.swissLodge'),
|
|
283
|
-
removeFromFavorites: t('favorites.remove'),
|
|
284
|
-
addToFavorites: t('favorites.add'),
|
|
285
|
-
previousImage: t('navigation.previous'),
|
|
286
|
-
nextImage: t('navigation.next'),
|
|
287
|
-
}}
|
|
288
286
|
/>
|
|
289
287
|
```
|
|
290
288
|
|
|
291
|
-
|
|
289
|
+
Translations (rating labels, price text, etc.) are handled automatically via `HotelCardUIProvider`.
|
|
292
290
|
|
|
293
291
|
### Checkbox & RadioButton
|
|
294
292
|
|
|
@@ -330,19 +328,33 @@ import type {
|
|
|
330
328
|
RatingProps,
|
|
331
329
|
DividerProps,
|
|
332
330
|
SectionHeaderProps,
|
|
331
|
+
BlockProps,
|
|
332
|
+
ReviewCardProps,
|
|
333
|
+
FAQProps,
|
|
334
|
+
FAQItem,
|
|
335
|
+
BenefitsProps,
|
|
336
|
+
BenefitItem,
|
|
337
|
+
PinProps,
|
|
338
|
+
DateSelectorProps,
|
|
333
339
|
WhenContentProps,
|
|
334
|
-
WhenContentLabels,
|
|
335
340
|
DateRange,
|
|
336
341
|
GuestContentProps,
|
|
337
|
-
GuestContentLabels,
|
|
338
342
|
GuestCounts,
|
|
339
343
|
ChildAgeError,
|
|
340
344
|
HotelCardProps,
|
|
341
|
-
HotelCardLabels,
|
|
342
345
|
HotelCardHotel,
|
|
343
346
|
HotelCardImageProps,
|
|
344
347
|
HotelCardContentProps,
|
|
345
348
|
|
|
349
|
+
// Context Types
|
|
350
|
+
UIContextValue,
|
|
351
|
+
HotelCardUIProviderProps,
|
|
352
|
+
TranslateFunction,
|
|
353
|
+
|
|
354
|
+
// Translation Types
|
|
355
|
+
Locale,
|
|
356
|
+
TranslationKeys,
|
|
357
|
+
|
|
346
358
|
// Data Types
|
|
347
359
|
Hotel,
|
|
348
360
|
Booking,
|
|
@@ -359,7 +371,7 @@ import type {
|
|
|
359
371
|
## Hooks
|
|
360
372
|
|
|
361
373
|
```typescript
|
|
362
|
-
import { useDebounce, useResponsive, useWindowData } from '@hotelcard/ui';
|
|
374
|
+
import { useDebounce, useResponsive, useWindowData, useUIContext } from '@hotelcard/ui';
|
|
363
375
|
|
|
364
376
|
// Debounce a value
|
|
365
377
|
const debouncedSearch = useDebounce(searchTerm, 300);
|
|
@@ -369,6 +381,10 @@ const { isDesktop } = useResponsive(); // >= 1024px
|
|
|
369
381
|
|
|
370
382
|
// Window/context data
|
|
371
383
|
const { locale, currency } = useWindowData();
|
|
384
|
+
|
|
385
|
+
// UI Context with translation function
|
|
386
|
+
const { locale, currency, isDesktop, t } = useUIContext();
|
|
387
|
+
t('label.rating-excellent', 'Excellent'); // Returns translated string
|
|
372
388
|
```
|
|
373
389
|
|
|
374
390
|
---
|
|
@@ -393,20 +409,18 @@ calculateDiscount(400, 200); // 50
|
|
|
393
409
|
|
|
394
410
|
---
|
|
395
411
|
|
|
396
|
-
##
|
|
412
|
+
## Translations
|
|
397
413
|
|
|
398
|
-
|
|
414
|
+
The package exports bundled translations that can be used directly:
|
|
399
415
|
|
|
400
|
-
```
|
|
401
|
-
import {
|
|
416
|
+
```typescript
|
|
417
|
+
import { translations } from '@hotelcard/ui';
|
|
402
418
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
<App />
|
|
409
|
-
</HotelCardUIProvider>
|
|
419
|
+
// Access translations for a specific locale
|
|
420
|
+
console.log(translations.de.form.adults); // "Erwachsene"
|
|
421
|
+
console.log(translations.en.form.adults); // "Adults"
|
|
422
|
+
console.log(translations.fr.form.adults); // "Adultes"
|
|
423
|
+
console.log(translations.it.form.adults); // "Adulti"
|
|
410
424
|
```
|
|
411
425
|
|
|
412
426
|
---
|
|
@@ -417,7 +431,7 @@ Components use CSS variables for theming. Import the styles once in your app ent
|
|
|
417
431
|
|
|
418
432
|
```tsx
|
|
419
433
|
// main.tsx or App.tsx
|
|
420
|
-
import '@hotelcard/ui/
|
|
434
|
+
import '@hotelcard/ui/styles.css';
|
|
421
435
|
```
|
|
422
436
|
|
|
423
437
|
### Customizing with CSS Variables
|
|
@@ -457,6 +471,45 @@ Components have built-in fallback values, so they work without custom CSS variab
|
|
|
457
471
|
|
|
458
472
|
---
|
|
459
473
|
|
|
474
|
+
## Platform Safeguards
|
|
475
|
+
|
|
476
|
+
This package is designed to work in both web (Next.js) and mobile (Ionic/Capacitor) environments. To maintain platform-agnosticism, the following safeguards are in place:
|
|
477
|
+
|
|
478
|
+
### Forbidden Imports
|
|
479
|
+
|
|
480
|
+
ESLint and pre-publish checks will block:
|
|
481
|
+
|
|
482
|
+
| Import | Reason |
|
|
483
|
+
|--------|--------|
|
|
484
|
+
| `next/router`, `next/image` | Web-only Next.js APIs |
|
|
485
|
+
| `@ionic/react`, `@capacitor/*` | Mobile-only Ionic/Capacitor APIs |
|
|
486
|
+
| `@/*` path aliases | App-specific configuration |
|
|
487
|
+
| `react-native` | Mobile-only framework |
|
|
488
|
+
|
|
489
|
+
### Forbidden Patterns
|
|
490
|
+
|
|
491
|
+
| Pattern | Reason | Alternative |
|
|
492
|
+
|---------|--------|-------------|
|
|
493
|
+
| `localStorage.*` | Not available everywhere | Use callback props |
|
|
494
|
+
| `window.location` | Web-only | Use `onNavigate` callback |
|
|
495
|
+
| `useRouter()` | Platform-specific | Use `onClick` callback |
|
|
496
|
+
| `useNavigate()` | Platform-specific | Use `onClick` callback |
|
|
497
|
+
|
|
498
|
+
### Running Checks
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
pnpm check-imports # Scan for forbidden patterns
|
|
502
|
+
pnpm lint # Run ESLint
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
These checks run automatically before `pnpm publish`.
|
|
506
|
+
|
|
507
|
+
### Contributing
|
|
508
|
+
|
|
509
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on keeping components platform-agnostic.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
460
513
|
## License
|
|
461
514
|
|
|
462
515
|
MIT
|