@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 CHANGED
@@ -29,36 +29,61 @@ npm install react react-dom
29
29
  ## Quick Start
30
30
 
31
31
  ```tsx
32
- import { Button, Card, Badge } from '@hotelcard/ui';
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/dist/index.css';
35
+ import '@hotelcard/ui/styles.css';
36
36
 
37
37
  function App() {
38
38
  return (
39
- <div>
39
+ <HotelCardUIProvider locale="de" currency="CHF">
40
40
  <Button variant="primary" onClick={() => alert('Clicked!')}>
41
41
  Book Now
42
42
  </Button>
43
43
 
44
- <Card
45
- image="https://example.com/hotel.jpg"
46
- title="Hotel Schweizerhof"
47
- location="Luzern, Switzerland"
48
- stars={5}
49
- price="CHF 195"
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
- | `WhenContent` | Date/month picker for search (accepts labels as props) |
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
- **Note**: All text labels are passed as props. The consuming app provides translated strings.
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
- **Note**: All text labels are passed as props. The consuming app provides translated strings.
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
- ## Context Provider (Optional)
412
+ ## Translations
340
413
 
341
- For apps that need shared configuration:
414
+ The package exports bundled translations that can be used directly:
342
415
 
343
- ```tsx
344
- import { HotelCardUIProvider } from '@hotelcard/ui';
416
+ ```typescript
417
+ import { translations } from '@hotelcard/ui';
345
418
 
346
- <HotelCardUIProvider
347
- locale="de"
348
- currency="CHF"
349
- isDesktop={false}
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/dist/index.css';
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