@hotelcard/ui 0.0.12 → 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.
- package/README.md +164 -54
- package/dist/index.cjs +1150 -370
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +381 -146
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +741 -79
- package/dist/index.d.ts +741 -79
- package/dist/index.js +1149 -372
- package/dist/index.js.map +1 -1
- package/package.json +15 -4
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
|
|
@@ -69,7 +94,6 @@ function App() {
|
|
|
69
94
|
| `Input` | Text input with label, helper text, and validation |
|
|
70
95
|
| `Badge` | Status and discount badges |
|
|
71
96
|
| `Card` | Hotel card component |
|
|
72
|
-
| `CompactCard` | Compact hotel card for carousels |
|
|
73
97
|
| `Chip` | Filter and tag chips |
|
|
74
98
|
| `Checkbox` | Checkbox with label |
|
|
75
99
|
| `RadioButton` | Radio button with label |
|
|
@@ -78,9 +102,16 @@ function App() {
|
|
|
78
102
|
| `Dropdown` | Select dropdown |
|
|
79
103
|
| `Modal` | Modal dialog |
|
|
80
104
|
| `SectionHeader` | Section title with "Show all" button |
|
|
81
|
-
| `
|
|
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 |
|
|
82
112
|
| `DualCalendar` | Calendar component for date range selection |
|
|
83
113
|
| `GuestContent` | Guest selector with adults, children (with ages), and pet toggle |
|
|
114
|
+
| `HotelCard` | Hotel card for search results with image carousel, rating, and pricing |
|
|
84
115
|
|
|
85
116
|
### Icons
|
|
86
117
|
|
|
@@ -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,49 @@ 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`.
|
|
251
|
+
|
|
252
|
+
### HotelCard
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { HotelCard, type HotelCardHotel } from '@hotelcard/ui';
|
|
256
|
+
|
|
257
|
+
const hotel: HotelCardHotel = {
|
|
258
|
+
id: '123',
|
|
259
|
+
name: 'Grand Hotel Belvedere',
|
|
260
|
+
slug: 'grand-hotel-belvedere',
|
|
261
|
+
stars: 5,
|
|
262
|
+
isSuperior: true,
|
|
263
|
+
rating: 4.5,
|
|
264
|
+
location: 'Lauterbrunnen, Switzerland',
|
|
265
|
+
images: ['/hotel1.jpg', '/hotel2.jpg'],
|
|
266
|
+
isFavorite: false,
|
|
267
|
+
benefits: [
|
|
268
|
+
{ id: 'free-breakfast', label: 'Free breakfast' },
|
|
269
|
+
{ id: 'free-cancellation', label: 'Free cancellation' },
|
|
270
|
+
],
|
|
271
|
+
isAvailable: true,
|
|
272
|
+
currency: 'CHF',
|
|
273
|
+
price: {
|
|
274
|
+
current: 195,
|
|
275
|
+
original: 390,
|
|
276
|
+
discount: 50,
|
|
277
|
+
},
|
|
278
|
+
usp: 'Best price guarantee',
|
|
279
|
+
badges: ['New'],
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
<HotelCard
|
|
283
|
+
hotel={hotel}
|
|
284
|
+
onFavoriteClick={() => toggleFavorite(hotel.id)}
|
|
285
|
+
onContentClick={() => navigate(`/hotel/${hotel.slug}`)}
|
|
286
|
+
/>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Translations (rating labels, price text, etc.) are handled automatically via `HotelCardUIProvider`.
|
|
239
290
|
|
|
240
291
|
### Checkbox & RadioButton
|
|
241
292
|
|
|
@@ -269,7 +320,6 @@ import type {
|
|
|
269
320
|
BadgeProps,
|
|
270
321
|
InputProps,
|
|
271
322
|
CardProps,
|
|
272
|
-
CompactCardProps,
|
|
273
323
|
CheckboxProps,
|
|
274
324
|
RadioButtonProps,
|
|
275
325
|
DropdownProps,
|
|
@@ -278,13 +328,32 @@ import type {
|
|
|
278
328
|
RatingProps,
|
|
279
329
|
DividerProps,
|
|
280
330
|
SectionHeaderProps,
|
|
331
|
+
BlockProps,
|
|
332
|
+
ReviewCardProps,
|
|
333
|
+
FAQProps,
|
|
334
|
+
FAQItem,
|
|
335
|
+
BenefitsProps,
|
|
336
|
+
BenefitItem,
|
|
337
|
+
PinProps,
|
|
338
|
+
DateSelectorProps,
|
|
281
339
|
WhenContentProps,
|
|
282
|
-
WhenContentLabels,
|
|
283
340
|
DateRange,
|
|
284
341
|
GuestContentProps,
|
|
285
|
-
GuestContentLabels,
|
|
286
342
|
GuestCounts,
|
|
287
343
|
ChildAgeError,
|
|
344
|
+
HotelCardProps,
|
|
345
|
+
HotelCardHotel,
|
|
346
|
+
HotelCardImageProps,
|
|
347
|
+
HotelCardContentProps,
|
|
348
|
+
|
|
349
|
+
// Context Types
|
|
350
|
+
UIContextValue,
|
|
351
|
+
HotelCardUIProviderProps,
|
|
352
|
+
TranslateFunction,
|
|
353
|
+
|
|
354
|
+
// Translation Types
|
|
355
|
+
Locale,
|
|
356
|
+
TranslationKeys,
|
|
288
357
|
|
|
289
358
|
// Data Types
|
|
290
359
|
Hotel,
|
|
@@ -302,7 +371,7 @@ import type {
|
|
|
302
371
|
## Hooks
|
|
303
372
|
|
|
304
373
|
```typescript
|
|
305
|
-
import { useDebounce, useResponsive, useWindowData } from '@hotelcard/ui';
|
|
374
|
+
import { useDebounce, useResponsive, useWindowData, useUIContext } from '@hotelcard/ui';
|
|
306
375
|
|
|
307
376
|
// Debounce a value
|
|
308
377
|
const debouncedSearch = useDebounce(searchTerm, 300);
|
|
@@ -312,6 +381,10 @@ const { isDesktop } = useResponsive(); // >= 1024px
|
|
|
312
381
|
|
|
313
382
|
// Window/context data
|
|
314
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
|
|
315
388
|
```
|
|
316
389
|
|
|
317
390
|
---
|
|
@@ -336,20 +409,18 @@ calculateDiscount(400, 200); // 50
|
|
|
336
409
|
|
|
337
410
|
---
|
|
338
411
|
|
|
339
|
-
##
|
|
412
|
+
## Translations
|
|
340
413
|
|
|
341
|
-
|
|
414
|
+
The package exports bundled translations that can be used directly:
|
|
342
415
|
|
|
343
|
-
```
|
|
344
|
-
import {
|
|
416
|
+
```typescript
|
|
417
|
+
import { translations } from '@hotelcard/ui';
|
|
345
418
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<App />
|
|
352
|
-
</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"
|
|
353
424
|
```
|
|
354
425
|
|
|
355
426
|
---
|
|
@@ -360,7 +431,7 @@ Components use CSS variables for theming. Import the styles once in your app ent
|
|
|
360
431
|
|
|
361
432
|
```tsx
|
|
362
433
|
// main.tsx or App.tsx
|
|
363
|
-
import '@hotelcard/ui/
|
|
434
|
+
import '@hotelcard/ui/styles.css';
|
|
364
435
|
```
|
|
365
436
|
|
|
366
437
|
### Customizing with CSS Variables
|
|
@@ -400,6 +471,45 @@ Components have built-in fallback values, so they work without custom CSS variab
|
|
|
400
471
|
|
|
401
472
|
---
|
|
402
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
|
+
|
|
403
513
|
## License
|
|
404
514
|
|
|
405
515
|
MIT
|