@hotelcard/ui 0.0.46 → 0.0.48
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 +182 -23
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +107 -1
- package/dist/index.js +3240 -3077
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -94,6 +94,7 @@ The package includes built-in translations for `de`, `en`, `fr`, and `it` locale
|
|
|
94
94
|
| `Input` | Text input with label, helper text, and validation |
|
|
95
95
|
| `Badge` | Status and discount badges |
|
|
96
96
|
| `Card` | Hotel card component |
|
|
97
|
+
| `BaseCard` | Composable card primitives (container, image, content) for building custom cards |
|
|
97
98
|
| `Chip` | Filter and tag chips |
|
|
98
99
|
| `Checkbox` | Checkbox with label |
|
|
99
100
|
| `RadioButton` | Radio button with label |
|
|
@@ -130,18 +131,21 @@ The package includes built-in translations for `de`, `en`, `fr`, and `it` locale
|
|
|
130
131
|
|
|
131
132
|
| Component | Description |
|
|
132
133
|
|-----------|-------------|
|
|
134
|
+
| `FilterPanel` | Complete filter sidebar with all filter sections (regions, price, category, etc.) |
|
|
135
|
+
| `FilterModal` | Modal wrapper for FilterPanel (web overlay style) |
|
|
133
136
|
| `FilterCheckboxItem` | Base checkbox item for filters |
|
|
134
137
|
| `CollapsibleFilterSection` | Expandable/collapsible filter section wrapper |
|
|
135
|
-
| `PriceRangeFilter` | Price range slider
|
|
136
|
-
| `HotelCategoryFilter` | Hotel star rating filter (1-5 stars) |
|
|
137
|
-
| `ReviewsFilter` | Guest review rating filter |
|
|
138
|
-
| `ExperienceFilter` | Experience/theme filter |
|
|
139
|
-
| `RegionsFilter` |
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
138
|
+
| `PriceRangeFilter` | Price range slider with histogram |
|
|
139
|
+
| `HotelCategoryFilter` | Hotel star rating filter (1-5 stars, Swiss Lodge, No category) |
|
|
140
|
+
| `ReviewsFilter` | Guest review rating filter (Excellent, Very Good, Good, Fair, No rating) |
|
|
141
|
+
| `ExperienceFilter` | Experience/theme filter with counts |
|
|
142
|
+
| `RegionsFilter` | Accordion-style region filter with country/sub-region hierarchy |
|
|
143
|
+
| `MealsFilter` | Meal options filter (breakfast, restaurant) |
|
|
144
|
+
| `TransportFilter` | Transport options filter (parking, EV charging) |
|
|
145
|
+
| `WellnessFilter` | Wellness amenities filter (pool, sauna, massage) |
|
|
146
|
+
| `SelectedFiltersRow` | Display row showing active filters as removable chips |
|
|
147
|
+
| `FilterMinimap` | Map preview with "View in Map" button |
|
|
148
|
+
| `FilterSkeleton` | Loading skeleton for filter panel |
|
|
145
149
|
|
|
146
150
|
### Icons
|
|
147
151
|
|
|
@@ -222,6 +226,49 @@ import { Card } from '@hotelcard/ui';
|
|
|
222
226
|
/>
|
|
223
227
|
```
|
|
224
228
|
|
|
229
|
+
### BaseCard (Composable Card Primitives)
|
|
230
|
+
|
|
231
|
+
Use `BaseCard`, `BaseCardImage`, and `BaseCardContent` to build custom cards with consistent styling:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
import { BaseCard, BaseCardImage, BaseCardContent } from '@hotelcard/ui';
|
|
235
|
+
|
|
236
|
+
// Custom booking card using BaseCard primitives
|
|
237
|
+
<BaseCard hoverable onClick={() => navigateToBooking()}>
|
|
238
|
+
<BaseCardImage
|
|
239
|
+
src={hotel.imageUrl}
|
|
240
|
+
alt={hotel.name}
|
|
241
|
+
height={200}
|
|
242
|
+
topLeftSlot={<StatusBadge status="confirmed" />}
|
|
243
|
+
topRightSlot={<FavoriteButton />}
|
|
244
|
+
/>
|
|
245
|
+
<BaseCardContent padding="large">
|
|
246
|
+
<h3>{hotel.name}</h3>
|
|
247
|
+
<p>{hotel.location}</p>
|
|
248
|
+
<div>Check-in: {checkInDate}</div>
|
|
249
|
+
</BaseCardContent>
|
|
250
|
+
</BaseCard>
|
|
251
|
+
|
|
252
|
+
// With aspect ratio instead of fixed height
|
|
253
|
+
<BaseCard borderRadius={16}>
|
|
254
|
+
<BaseCardImage
|
|
255
|
+
src={hotel.imageUrl}
|
|
256
|
+
alt={hotel.name}
|
|
257
|
+
aspectRatio="16/9"
|
|
258
|
+
showGradient={true}
|
|
259
|
+
bottomSlot={<ImageIndicatorDots count={3} active={0} />}
|
|
260
|
+
/>
|
|
261
|
+
<BaseCardContent padding="medium">
|
|
262
|
+
{/* Your content */}
|
|
263
|
+
</BaseCardContent>
|
|
264
|
+
</BaseCard>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
BaseCard provides:
|
|
268
|
+
- **BaseCard**: Container with border, radius, shadow, hover effects
|
|
269
|
+
- **BaseCardImage**: Image with overlay slots (top-left, top-right, center, bottom)
|
|
270
|
+
- **BaseCardContent**: Content area with configurable padding ('none' | 'small' | 'medium' | 'large')
|
|
271
|
+
|
|
225
272
|
### Modal
|
|
226
273
|
|
|
227
274
|
```tsx
|
|
@@ -440,7 +487,119 @@ import { SearchControlsBar, type SearchParams, type ViewMode } from '@hotelcard/
|
|
|
440
487
|
/>
|
|
441
488
|
```
|
|
442
489
|
|
|
443
|
-
### Filter
|
|
490
|
+
### FilterPanel (Complete Filter Sidebar)
|
|
491
|
+
|
|
492
|
+
```tsx
|
|
493
|
+
import {
|
|
494
|
+
FilterPanel,
|
|
495
|
+
type FilterState,
|
|
496
|
+
type FilterPanelProps,
|
|
497
|
+
type RegionOption,
|
|
498
|
+
type ThemeAggregation,
|
|
499
|
+
type FilterOption,
|
|
500
|
+
} from '@hotelcard/ui';
|
|
501
|
+
|
|
502
|
+
// FilterPanel displays filter data from search API aggregations
|
|
503
|
+
// It does NOT have default data - pass real aggregation data from your search response
|
|
504
|
+
<FilterPanel
|
|
505
|
+
// Filter change callback
|
|
506
|
+
onFilterChange={(filters: FilterState) => {
|
|
507
|
+
// filters: { regions, experiences, priceRange, discounts, options, meals, categories, ratings, transport, wellness }
|
|
508
|
+
applyFilters(filters);
|
|
509
|
+
}}
|
|
510
|
+
|
|
511
|
+
// Optional: Show map preview with "View in Map" button
|
|
512
|
+
onViewMap={() => setViewMode('map')}
|
|
513
|
+
|
|
514
|
+
// Price data from API aggregations (required for price filter to display)
|
|
515
|
+
// Round to nearest 10 for clean slider values
|
|
516
|
+
minPrice={Math.floor(aggregations.price_stats.min / 10) * 10}
|
|
517
|
+
maxPrice={Math.ceil(aggregations.price_stats.max / 10) * 10}
|
|
518
|
+
priceHistogram={aggregations.price_histogram.map(b => b.count)}
|
|
519
|
+
|
|
520
|
+
// Region data from API
|
|
521
|
+
regions={regionOptions}
|
|
522
|
+
themes={experienceThemes} // Pre-translated theme names from API
|
|
523
|
+
filterOptions={filterOptions} // Pre-translated filter options from API
|
|
524
|
+
|
|
525
|
+
// Counts for each filter option (from search aggregations)
|
|
526
|
+
// Use exact property names from API response:
|
|
527
|
+
discountCounts={aggregations.discount_counts}
|
|
528
|
+
optionsCounts={aggregations.options_counts}
|
|
529
|
+
categoryCounts={categoryCounts} // Transform from star_ratings array
|
|
530
|
+
mealsCounts={aggregations.meals_counts}
|
|
531
|
+
reviewsCounts={aggregations.reviews_counts}
|
|
532
|
+
transportCounts={aggregations.transport_counts}
|
|
533
|
+
wellnessCounts={aggregations.wellness_counts}
|
|
534
|
+
servicesCounts={aggregations.services_counts}
|
|
535
|
+
|
|
536
|
+
// Controlled selected values (sync with URL params)
|
|
537
|
+
selectedDiscounts={['50']}
|
|
538
|
+
selectedCategories={['4', '5']}
|
|
539
|
+
selectedRegions={['region_1']}
|
|
540
|
+
selectedPriceRange={{ min: 100, max: 300 }}
|
|
541
|
+
|
|
542
|
+
// Loading state - shows skeleton when true
|
|
543
|
+
isLoading={isLoading}
|
|
544
|
+
/>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### FilterModal (Modal Wrapper)
|
|
548
|
+
|
|
549
|
+
For web apps, use `FilterModal` which provides the overlay/modal styling:
|
|
550
|
+
|
|
551
|
+
```tsx
|
|
552
|
+
import { FilterModal, type FilterModalProps, type SelectedFilter } from '@hotelcard/ui';
|
|
553
|
+
|
|
554
|
+
<FilterModal
|
|
555
|
+
isOpen={isFilterModalOpen}
|
|
556
|
+
onClose={() => setIsFilterModalOpen(false)}
|
|
557
|
+
resultCount={totalResults}
|
|
558
|
+
selectedFilters={activeFilterChips}
|
|
559
|
+
onRemoveFilter={(filter: SelectedFilter) => removeFilter(filter)}
|
|
560
|
+
onClearAllFilters={() => clearAllFilters()}
|
|
561
|
+
|
|
562
|
+
// Pass through ALL FilterPanel props - data comes from search aggregations
|
|
563
|
+
onFilterChange={handleFilterChange}
|
|
564
|
+
minPrice={priceStats.minPrice}
|
|
565
|
+
maxPrice={priceStats.maxPrice}
|
|
566
|
+
priceHistogram={priceStats.histogram.length > 0 ? priceStats.histogram : undefined}
|
|
567
|
+
regions={regions}
|
|
568
|
+
themes={themes}
|
|
569
|
+
filterOptions={filterOptions}
|
|
570
|
+
discountCounts={aggregations.discount_counts}
|
|
571
|
+
optionsCounts={aggregations.options_counts}
|
|
572
|
+
categoryCounts={categoryCounts}
|
|
573
|
+
mealsCounts={aggregations.meals_counts}
|
|
574
|
+
reviewsCounts={aggregations.reviews_counts}
|
|
575
|
+
transportCounts={aggregations.transport_counts}
|
|
576
|
+
wellnessCounts={aggregations.wellness_counts}
|
|
577
|
+
servicesCounts={aggregations.services_counts}
|
|
578
|
+
selectedDiscounts={selectedDiscounts}
|
|
579
|
+
selectedCategories={selectedCategories}
|
|
580
|
+
selectedRegions={selectedRegions}
|
|
581
|
+
selectedPriceRange={selectedPriceRange}
|
|
582
|
+
// ... other selected* props
|
|
583
|
+
/>
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Important:** FilterPanel and FilterModal do NOT have hardcoded default data. All filter data (price range, counts, etc.) must come from your search API aggregations. Pass `undefined` for `priceHistogram` when data is loading to show skeleton state.
|
|
587
|
+
|
|
588
|
+
For Ionic apps, create your own `IonModal` wrapper and pass props through to `FilterPanel`:
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
import { IonModal } from '@ionic/react';
|
|
592
|
+
import { FilterPanel, type FilterPanelProps } from '@hotelcard/ui';
|
|
593
|
+
|
|
594
|
+
// Simple pass-through wrapper
|
|
595
|
+
const FilterModal = ({ isOpen, onClose, ...filterPanelProps }) => (
|
|
596
|
+
<IonModal isOpen={isOpen} onDidDismiss={onClose}>
|
|
597
|
+
<FilterPanel {...filterPanelProps} />
|
|
598
|
+
</IonModal>
|
|
599
|
+
);
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Individual Filter Components
|
|
444
603
|
|
|
445
604
|
```tsx
|
|
446
605
|
import {
|
|
@@ -501,6 +660,9 @@ import type {
|
|
|
501
660
|
BadgeProps,
|
|
502
661
|
InputProps,
|
|
503
662
|
CardProps,
|
|
663
|
+
BaseCardProps,
|
|
664
|
+
BaseCardImageProps,
|
|
665
|
+
BaseCardContentProps,
|
|
504
666
|
CheckboxProps,
|
|
505
667
|
RadioButtonProps,
|
|
506
668
|
DropdownProps,
|
|
@@ -541,21 +703,18 @@ import type {
|
|
|
541
703
|
ViewMode,
|
|
542
704
|
|
|
543
705
|
// Filter Component Props
|
|
706
|
+
FilterPanelProps,
|
|
707
|
+
FilterModalProps,
|
|
708
|
+
FilterState,
|
|
709
|
+
FilterOptions,
|
|
710
|
+
FilterOption,
|
|
711
|
+
ThemeAggregation,
|
|
712
|
+
SelectedFilter,
|
|
713
|
+
RegionOption,
|
|
544
714
|
FilterCheckboxItemProps,
|
|
545
|
-
|
|
546
|
-
PriceRangeFilterProps,
|
|
547
|
-
HotelCategoryFilterProps,
|
|
715
|
+
FilterMinimapProps,
|
|
548
716
|
CategoryOption,
|
|
549
|
-
ReviewsFilterProps,
|
|
550
717
|
ReviewOption,
|
|
551
|
-
ExperienceFilterProps,
|
|
552
|
-
ThemeAggregation,
|
|
553
|
-
RegionsFilterProps,
|
|
554
|
-
RegionOption,
|
|
555
|
-
CheckboxFilterProps,
|
|
556
|
-
FilterOption,
|
|
557
|
-
SelectedFiltersRowProps,
|
|
558
|
-
SelectedFilter,
|
|
559
718
|
|
|
560
719
|
// Context Types
|
|
561
720
|
UIContextValue,
|