hotel-datepicker-responsive
Version:
Un selector de fechas moderno y flexible para reservas de hotel y vuelos con soporte para calendario de precios y diseño responsive
581 lines (442 loc) • 17.3 kB
Markdown
# Hotel DatePicker Responsive
Un selector de fechas moderno y flexible para reservas de hotel y vuelos con soporte para calendario de precios y diseño responsive.
**Sitio web:** [https://calendario-arg4qzs55-ramons-projects-e601971a.vercel.app/](https://calendario-arg4qzs55-ramons-projects-e601971a.vercel.app/)
## Características
- **Diseño Responsive**: Adaptado para dispositivos móviles y escritorio
- **Selección de Rangos**: Permite seleccionar rangos de fechas (check-in y check-out)
- **Modo Fecha Única**: Opción para seleccionar una sola fecha
- **Calendario de Precios**: Integración con APIs de precios para mostrar tarifas
- **Personalizable**: Múltiples opciones de configuración y estilos
- **Variables CSS Personalizables**: Personalización completa de colores y estilos mediante variables CSS
- **Shadow DOM**: Aislamiento de estilos para evitar conflictos con CSS externo
- **Internacionalización**: Soporte para múltiples idiomas
- **Standalone**: Incluye Luxon y CSS directamente en el bundle
- **Sin Dependencias Externas**: No requiere jQuery ni otras bibliotecas
- **Optimizado para Rendimiento**: Caché de tarifas y renderizado eficiente
- **Iconos SVG Inline**: No requiere bibliotecas de iconos externas
- **Selección del Mismo Día**: Opción para permitir seleccionar el mismo día como fecha de inicio y fin (ideal para vuelos)
- **Conteo Flexible**: Opción para mostrar "días" en lugar de "noches" en el tooltip
## Mejoras recientes
### Nuevas Funcionalidades
#### Personalización de Estilos CSS
El calendario ahora permite personalizar completamente los colores y estilos mediante variables CSS:
```javascript
const datepicker = new HotelDatePicker('container-id', {
// Colores principales
primaryColor: '#3498db',
primaryLight: '#ebf5fb',
primaryDark: '#2980b9',
// Colores para precios
priceBest: '#27ae60',
priceGood: '#f2faf0',
priceBestLow: '#bbe5b3',
// Colores de texto
textPrimary: '#2c3e50',
textSecondary: '#7f8c8d',
textLight: '#ffffff',
// Colores de fondo
bgPrimary: '#ffffff',
bgSecondary: '#f5f5f5',
bgDisabled: '#e9ecef',
// Colores de borde
borderColor: '#bdc3c7',
borderFocus: '#95a5a6',
// Tamaños
daySize: '40px',
fontSizeNormal: '14px',
fontSizeSmall: '12px',
fontSizeXsmall: '10px',
// Espaciado
spacingXs: '2px',
spacingSm: '5px',
spacingMd: '10px',
spacingLg: '15px',
spacingXl: '20px'
});
```
También puedes actualizar los estilos después de la inicialización:
```javascript
datepicker.updateCSSVars({
primaryColor: '#e74c3c',
primaryLight: '#fadbd8',
priceBest: '#2ecc71'
});
```
#### Shadow DOM para Aislamiento de Estilos
El calendario ahora utiliza Shadow DOM para aislar sus estilos del resto de la página, evitando conflictos con CSS externo:
```html
<div id="calendar-container" style="position: relative;">
<!-- El calendario se renderizará aquí dentro de un Shadow DOM -->
</div>
```
Es importante que el contenedor tenga `position: relative` para que el calendario se posicione correctamente.
#### Inyección de CSS Personalizado
Ahora puedes inyectar CSS personalizado directamente en el calendario de dos formas:
1. **Al inicializar el calendario**:
```javascript
const datepicker = new HotelDatePicker('container-id', {
// Otras opciones...
customCSS: `
.day.selected {
background-color: #3498db ;
border-radius: 50% ;
}
.day.in-range {
background-color: #e0f7fa ;
}
`
});
```
2. **Después de la inicialización**:
```javascript
datepicker.injectCSS(`
.day.selected {
background-color: #3498db ;
border-radius: 50% ;
}
.day.in-range {
background-color: #e0f7fa ;
}
`);
```
#### Variables CSS en CSS Personalizado
También puedes definir variables CSS directamente en el CSS personalizado, y estas tendrán prioridad sobre las variables predeterminadas:
1. **Usando el selector `:host`**:
```javascript
datepicker.injectCSS(`
:host {
--hdp-primary-color: #3498db;
--hdp-primary-light: #ebf5fb;
--hdp-primary-dark: #2980b9;
}
.day.selected {
background-color: var(--hdp-primary-color) ;
border-radius: 50% ;
}
`);
```
2. **Definiendo variables directamente sin selectores**:
```javascript
datepicker.injectCSS(`
--hdp-primary-color: #3498db;
--hdp-primary-light: #ebf5fb;
--hdp-primary-dark: #2980b9;
`);
```
Estas funcionalidades te permiten personalizar completamente el aspecto del calendario sin tener que modificar el archivo CSS original.
#### Selección del Mismo Día
La opción `allowSameDaySelection` permite seleccionar el mismo día como fecha de inicio y fin, lo que es útil para vuelos o reservas de un solo día:
```javascript
const datepicker = new HotelDatePicker('container-id', {
allowSameDaySelection: true
});
```
Cuando esta opción está habilitada:
- Se puede seleccionar el mismo día como fecha de inicio y fin
- El día se muestra como un círculo completo sin flechas de dirección
- El conteo de días comienza desde 1 (el mismo día cuenta como 1 día)
#### Mostrar Días en lugar de Noches
La opción `displayDaysInsteadOfNights` permite mostrar "días" en lugar de "noches" en el tooltip:
```javascript
const datepicker = new HotelDatePicker('container-id', {
displayDaysInsteadOfNights: true
});
```
Cuando esta opción está habilitada:
- El tooltip muestra "días" en lugar de "noches"
- El conteo se ajusta para reflejar días en lugar de noches
### Estructura modular
El código ha sido reorganizado en módulos independientes para facilitar el mantenimiento y la extensión:
- `calendar.js`: Funciones para generar y manipular el calendario
- `config.js`: Configuración por defecto
- `dom.js`: Manipulación del DOM
- `events.js`: Manejo de eventos
- `initializer.js`: Inicialización del calendario
- `mobile.js`: Funcionalidades específicas para móvil
- `navigation.js`: Navegación entre meses
- `rates.js`: Gestión de tarifas
- `renderer.js`: Renderización del calendario
- `utils.js`: Funciones de utilidad
### Optimización de rendimiento
- Caché de tarifas para evitar cargas innecesarias
- Renderizado optimizado para evitar parpadeos
- Detección inteligente de meses visibles en móvil
- Aplicación eficiente de estilos
### Mejoras en la vista móvil
- Mejor respuesta táctil
- Scroll más suave
- Mejor visualización de los botones
- Optimización del espacio en pantalla
- Carga de tarifas solo para meses visibles
## Instalación
```bash
npm install hotel-datepicker-responsive --save
```
## Uso Básico
```html
<div id="datepicker"></div>
<script>
const datepicker = new HotelDatePicker('datepicker', {
minNights: 1,
maxNights: 30,
format: 'dd/MM/yyyy',
lang: 'es'
});
</script>
```
### Versión Standalone (Recomendada)
Esta versión incluye Luxon y CSS directamente en el bundle, por lo que solo necesitas incluir un archivo:
```html
<!-- Incluir Hotel DatePicker (con Luxon y CSS incluidos) -->
<script src="dist/hotel-datepicker.standalone.js"></script>
```
Para generar estos archivos, ejecuta:
```
npm run build
```
Esto creará en la carpeta `dist`:
- `hotel-datepicker.standalone.js`: Librería completa con Luxon y CSS incluidos
### Inicialización del componente
Una vez incluidos los archivos necesarios, inicializa el componente:
```javascript
const datePicker = new HotelDatePicker('container-id', {
minNights: 1,
maxNights: 30,
onDateSelect: function(dates) {
console.log('Fechas seleccionadas:', dates);
}
});
```
## Servidor Python incluido
Para facilitar la visualización del calendario, se incluye un servidor Python simple:
1. Ejecuta `start_server.bat` o `python server.py` desde la línea de comandos
2. Abre tu navegador en http://localhost:8000/HotelDatePicker.html
## Ejemplos incluidos
Puedes ver ejemplos en vivo en: [https://calendario-arg4qzs55-ramons-projects-e601971a.vercel.app/examples/basic.html](https://calendario-arg4qzs55-ramons-projects-e601971a.vercel.app/examples/basic.html)
El proyecto incluye varios ejemplos para mostrar diferentes funcionalidades:
### Ejemplo básico
Muestra el uso básico del calendario con opciones para ocultar leyenda y atajos.
```
examples/basic.html
```
### Ejemplo con tarifas
Muestra cómo integrar el calendario con una API de tarifas.
```
examples/with-rates.html
```
### Ejemplo móvil
Muestra el calendario optimizado para dispositivos móviles.
```
examples/mobile.html
```
### Ejemplo para vuelos (selección del mismo día)
Muestra cómo configurar el calendario para reservas de vuelos, permitiendo seleccionar el mismo día y mostrando días en lugar de noches.
```javascript
const datepicker = new HotelDatePicker('container-id', {
isRange: true,
allowSameDaySelection: true,
displayDaysInsteadOfNights: true,
i18n: {
day: 'día',
days: 'días'
}
});
```
### Ejemplo de modo fecha única
Muestra cómo configurar el calendario para seleccionar una sola fecha.
```javascript
const datepicker = new HotelDatePicker('container-id', {
isRange: false
});
```
## Opciones de configuración
| Opción | Tipo | Valor por defecto | Descripción |
|--------|------|-------------------|-------------|
| minNights | Number | 1 | Número mínimo de noches |
| maxNights | Number | 30 | Número máximo de noches |
| initialStartDate | String | null | Fecha de inicio inicial (formato ISO) |
| initialEndDate | String | null | Fecha de fin inicial (formato ISO) |
| format | String | 'dd LLL yyyy' | Formato de fecha (usando Luxon) |
| hideLegend | Boolean | false | Oculta la leyenda |
| hideShortcuts | Boolean | false | Oculta los atajos rápidos |
| mobileBreakpoint | Number | 768 | Punto de quiebre para vista móvil (en píxeles) |
| onDateSelect | Function | () => {} | Callback cuando se seleccionan fechas |
| onMonthChange | Function | () => {} | Callback cuando cambia el mes visible |
| onView | Function | () => {} | Callback cuando se abre el calendario |
| priceCalendar | Object | { enabled: false } | Configuración del calendario de precios |
| i18n | Object | { ... } | Textos para internacionalización |
| isRange | Boolean | true | Si es true, permite seleccionar un rango de fechas. Si es false, solo permite seleccionar una fecha |
| allowSameDaySelection | Boolean | false | Si es true, permite seleccionar el mismo día como fecha de inicio y fin (útil para vuelos) |
| displayDaysInsteadOfNights | Boolean | false | Si es true, muestra "días" en lugar de "noches" en el tooltip |
| currency | String | 'MXN' | Moneda para mostrar en la leyenda de precios |
| primaryColor | String | '#db006e' | Color principal del calendario |
| primaryLight | String | '#fcf5f9' | Color principal claro (para días en rango) |
| primaryDark | String | '#800d46' | Color principal oscuro |
| priceBest | String | '#1c8207' | Color para los mejores precios |
| priceGood | String | '#f2faf0' | Color para buenos precios |
| priceBestLow | String | '#bbe5b3' | Color para mejores precios bajos |
| textPrimary | String | '#333333' | Color de texto principal |
| textSecondary | String | '#696770' | Color de texto secundario |
| textLight | String | '#ffffff' | Color de texto claro |
| bgPrimary | String | '#ffffff' | Color de fondo principal |
| bgSecondary | String | '#f5f5f5' | Color de fondo secundario |
| bgDisabled | String | '#e9ecef' | Color de fondo para elementos deshabilitados |
| borderColor | String | '#e6e6e6' | Color de borde |
| borderFocus | String | '#adb5bd' | Color de borde para elementos enfocados |
| daySize | String | '40px' | Tamaño de los días en el calendario |
| fontSizeNormal | String | '14px' | Tamaño de fuente normal |
| fontSizeSmall | String | '12px' | Tamaño de fuente pequeña |
| fontSizeXsmall | String | '10px' | Tamaño de fuente muy pequeña |
| spacingXs | String | '2px' | Espaciado extra pequeño |
| spacingSm | String | '5px' | Espaciado pequeño |
| spacingMd | String | '10px' | Espaciado mediano |
| spacingLg | String | '15px' | Espaciado grande |
| spacingXl | String | '20px' | Espaciado extra grande |
| customCSS | String | '' | CSS personalizado para inyectar directamente en el Shadow DOM |
## Métodos disponibles
### open()
Abre el calendario.
```javascript
datePicker.open();
```
### close()
Cierra el calendario.
```javascript
datePicker.close();
```
### toggle()
Alterna entre abrir y cerrar el calendario.
```javascript
datePicker.toggle();
```
### setRates(year, month, rates)
Establece las tarifas para un mes específico.
```javascript
// Formato simple de tarifas
const rates = {
'2023-05-01': 1200,
'2023-05-02': 1500,
'2023-05-03': 1800,
'2023-05-04': 1000,
'2023-05-05': 900
};
datePicker.setRates(2023, 5, rates);
```
### getSelectedDates()
Obtiene las fechas seleccionadas.
```javascript
const dates = datePicker.getSelectedDates();
console.log(dates.startDate, dates.endDate, dates.nights);
```
### setSelectedDates(startDate, endDate)
Establece las fechas seleccionadas.
```javascript
datePicker.setSelectedDates('2023-05-01', '2023-05-05');
```
### clearSelectedDates()
Limpia las fechas seleccionadas.
```javascript
datePicker.clearSelectedDates();
```
### clearRatesCache()
Limpia la caché de tarifas.
```javascript
datePicker.clearRatesCache();
```
### updateCSSVars(cssVars)
Actualiza las variables CSS personalizadas.
```javascript
datePicker.updateCSSVars({
primaryColor: '#3498db',
primaryLight: '#ebf5fb',
priceBest: '#27ae60'
});
```
### injectCSS(css)
Inyecta CSS personalizado en el Shadow DOM.
```javascript
datePicker.injectCSS(`
.day.selected {
background-color: #3498db ;
border-radius: 50% ;
}
.day.in-range {
background-color: #e0f7fa ;
}
`);
```
## Estructura del proyecto
```
hotel-date-picker/
├── dist/ # Archivos compilados
│ ├── hotel-date-picker.js
│ ├── hotel-date-picker.min.js
│ └── luxon.min.js
├── examples/ # Ejemplos de uso
│ ├── basic.html
│ ├── with-rates.html
│ └── mobile.html
├── src/ # Código fuente
│ ├── modules/ # Módulos
│ │ ├── calendar.js
│ │ ├── config.js
│ │ ├── dom.js
│ │ ├── events.js
│ │ ├── index.js
│ │ ├── initializer.js
│ │ ├── mobile.js
│ │ ├── navigation.js
│ │ ├── rates.js
│ │ ├── renderer.js
│ │ └── utils.js
│ ├── HotelDatePicker.js
│ ├── HotelDatePicker.modular.js
│ ├── HotelDatePicker.css
│ ├── HotelDatePicker.combined.css
│ └── styles.css
├── package.json
└── README.md
```
## Publicación en npm
Para publicar la librería en npm:
1. Actualiza la información en `package.json` (nombre, autor, repositorio, etc.)
2. Ejecuta `npm run build` para generar los archivos
3. Ejecuta `npm login` para iniciar sesión en npm
4. Ejecuta `npm publish` para publicar el paquete
Los usuarios podrán instalar tu paquete con:
```
npm install hotel-datepicker-responsive
```
Y usarlo en sus proyectos:
```html
<!-- Incluir Hotel DatePicker (con Luxon y CSS incluidos) -->
<script src="node_modules/hotel-datepicker-responsive/dist/hotel-datepicker.standalone.js"></script>
<script>
const datepicker = new HotelDatePicker('container-id', {
// opciones...
});
</script>
```
## Internacionalización
El calendario soporta múltiples idiomas para los nombres de meses, días y textos:
```javascript
const datepicker = new HotelDatePicker('container-id', {
lang: 'es', // Código de idioma (es, en, fr, etc.)
i18n: {
night: 'noche',
nights: 'noches',
day: 'día', // Nuevo: para displayDaysInsteadOfNights
days: 'días', // Nuevo: para displayDaysInsteadOfNights
apply: 'Aplicar',
cancel: 'Cancelar',
selectDate: 'Seleccionar fecha',
selectCheckout: 'Seleccionar salida',
selectCheckin: 'Seleccionar entrada'
}
});
```
## Repositorio
El código fuente está disponible en GitHub:
[https://github.com/JoseRamonGraciaCalderon/HotelDatePicker](https://github.com/JoseRamonGraciaCalderon/HotelDatePicker)
## Licencia
MIT