Estudia las escalas de color y espaciado de LocalTapiola en Duet mediante un flujo de trabajo de intervalo de fechas, con valores de fecha ISO, validación explícita del intervalo, métodos de foco de componentes y un límite claramente diferenciado para el selector de código abierto.
Interpretación sin conexión HTML con campos de fecha nativos y valores verificados del tema predeterminado de Duet; no es el calendario en tiempo de ejecución de Duet. · Referencia de implementación
02
Referencia de diseño sistema de diseño Duet
Instantánea de la documentación pública de Duet: componentes principales del sistema, tokens predeterminados de LocalTapiola e integración documentada con 10.7.0/CDN. No es el paquete independiente @duetds/date-picker 1.x. Algunos tokens de radio siguen marcados como En revisión.
Sistema de diseño Duet El sistema principal de Duet y el selector de código abierto son independientes
Mantén el contrato del paquete asociado al ejemplo
Duet ofrece componentes y fundamentos con temas para LocalTapiola y Turva. El proyecto @duetds/date-picker, publicado por separado, es una distribución de código abierto más acotada. Que compartan el nombre de una etiqueta no significa que sus propiedades, configuración de localización o variables CSS sean intercambiables con las del sistema de diseño principal actual.
El código de integración de esta página está dirigido al sistema principal. Su vista previa sin conexión usa campos de fecha nativos y estilos originales basados en los tokens de Duet enlazados. Muestra las reglas del intervalo, pero no pretende ejecutar la ventana emergente del calendario de Duet ni su modelo de teclado.
Sistema de diseño Duet El azul de marca y el rojo de estado cumplen funciones distintas
Usa un tema en lugar de cambiar un solo color de acento
El tema predeterminado de LocalTapiola combina una acción azul con texto del cuerpo azul oscuro. Turva tiene su propia acción roja y un rol de texto secundario. Cambiar solo el color de acción omitiría las demás relaciones del tema. La tabla actual también marca como obsoletos los tintes antiguos de Turva; copiar todas las entradas históricas de la paleta mantendría indicaciones obsoletas.
Nuestro ejemplo original para fechas de viaje usa el azul para la siguiente acción y reserva el rojo para cuando sea necesario corregir un periodo seleccionado. Es una demostración de planificación, no una recomendación de seguros, un presupuesto ni una compra.
Sistema de diseño Duet Un texto de cuerpo de 16px sirve de base a la jerarquía
La escala no exige un título enorme en todas partes
La tabla de Duet avanza por los tamaños de 16, 20, 24, 36, 48 y 72px en los niveles mayores. Un panel de planificación integrado usa el nivel de 24px para que la acción y las etiquetas de fecha sigan destacando. El nivel de 72px, pensado para marketing, no es el predeterminado para un formulario compacto.
Los paquetes de fuentes de LocalTapiola y Turva son recursos independientes. La interpretación sin conexión usa una fuente alternativa del sistema; no incluye los archivos de fuentes de esas marcas. Una aplicación autorizada debe cargar la familia elegida mediante la ruta de fuentes documentada y usar después los tokens de peso correspondientes.
Sistema de diseño Duet Usa los pasos reales de 20px y 28px
Duet no sigue una escala genérica de ocho píxeles
La escala incluye 12, 20, 28 y 36px, además de las potencias de dos habituales. Estos intervalos intermedios son importantes para reproducir el ritmo de los formularios del sistema. En el diseño ancho, usa una separación de 20px entre los dos campos y, al apilarlos, mantén cada etiqueta junto a su campo. El punto de corte del ejemplo es una decisión de la aplicación.
Los controles predeterminados tienen esquinas de 4px, mientras que los botones usan el radio de píldora. Algunos valores más recientes de radio para contenedores en la referencia de tokens están marcados explícitamente como En revisión; esta guía conserva ese estado en lugar de presentar como aprobados todos los tokens enumerados.
Sistema de diseño Duet Almacena valores ISO y describe el formato visible
No analices las cadenas de visualización localizadas como datos
El valor y los límites del componente usan el formato YYYY-MM-DD. El evento de fecha seleccionada incluye una cadena y un objeto Date. Conserva la cadena para comparar y almacenar; la visualización localizada del campo es una cuestión de presentación. El idioma del documento es el punto de entrada actual para la localización, mientras que la propiedad de idioma antigua está obsoleta.
El ejemplo solo permite fechas de junio de 2027. Este intervalo fijo hace que las pruebas sean deterministas y constituye una restricción explícita del ejemplo. Un formulario de producción obtendría el intervalo permitido de la regla del producto y la explicaría junto al campo.
Sistema de diseño Duet Una fecha válida no implica que el intervalo sea válido
Comprueba la relación cuando ambos campos sean válidos
El objeto de validez del componente describe los errores de cada campo. Una fecha de regreso anterior a la de salida aún puede ser una fecha válida del calendario, así que la aplicación debe comprobar por separado la relación entre ambas. El ejemplo nativo asigna un error claro y usa setFocus(), el método documentado que enfoca el campo de entrada interno.
El recuento es inclusivo: la salida y el regreso el mismo día equivalen a un día natural. Convertir las fechas ISO a medianoche UTC evita que un cambio de horario de verano convierta un intervalo del calendario en una duración fraccionaria. Este cálculo es lógica original de la aplicación, no una regla de precios de Duet.
Rechaza los extremos ausentes, con formato incorrecto o fuera de los límites.
Rechaza una fecha de regreso anterior a la de salida.
Mueve el foco al campo que necesita corregirse.
Prepara el intervalo inclusivo solo después de superar ambas comprobaciones.
Sistema de diseño Duet Una acción principal no implica el envío del formulario
Duet usa una propiedad explícita para el envío
El botón del sistema principal activa el envío del formulario con submit; su valor predeterminado es false. La composición proporcionada usa una acción de clic que prepara un resultado local, así que no necesita esa propiedad. La URL de destino se define en url, lo que genera semántica de ancla.
La vista previa borra el mensaje preparado cada vez que cambia cualquiera de los campos. De lo contrario, el mensaje podría parecer confirmar valores que la persona ya ha sustituido. No se muestra ningún indicador de carga porque no hay ninguna operación asíncrona.
Usa una sola acción principal de preparación.
Indica que el resultado es local.
No reutilices expresiones de éxito para dar a entender que se ha creado una póliza.
Sistema de diseño Duet Fija los recursos del sistema principal como un conjunto compatible
El ejemplo es una instantánea documentada, no una promesa de que sea la versión más reciente
La página de uso inspeccionada proporciona los componentes 10.7.0 con CSS 5.1.4; las instantáneas del índice de búsqueda ya mencionan versiones posteriores. El ejemplo mantiene deliberadamente juntas las versiones inspeccionadas directamente. Para su adopción en producción, selecciona una versión y verifica que sean compatibles CSS, las fuentes y el comportamiento de los componentes.
Los campos de fecha son elementos personalizados. Espera a que se definan antes de llamar a sus métodos, añade listeners a duetChange y lee los datos documentados en lugar de dar por sentado que se trata de un evento change nativo. No mezcles en la misma página el módulo CDN del sistema principal con el selector independiente: ambos definen la misma etiqueta.
Sistema de diseño Duet Ejemplos de componentes del sistema de diseño
Muestra interactiva independiente completa
Guarda el documento completo como index.html y ábrelo en un navegador. Interpretación sin conexión de HTML mediante campos de fecha nativos y valores del tema predeterminado de Duet verificados; no es el entorno de ejecución del calendario de Duet.
HTML
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Duet travel period interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#f0f7fa;color:#082a4d;font:16px/1.5 system-ui,sans-serif}main{max-width:1000px;margin:auto;padding:36px 28px}.eyebrow{font-size:12px;letter-spacing:2px;text-transform:uppercase;margin-bottom:12px}h1{font-size:36px;line-height:1.2;font-weight:600;margin:0 0 20px}p{margin:0 0 20px}.hero{display:grid;grid-template-columns:1fr 300px;gap:28px;align-items:center;margin-bottom:28px}.art{height:170px;position:relative;overflow:hidden;border-radius:50%;background:#c6e1ee}.sun{position:absolute;top:25px;right:60px;width:36px;height:36px;border-radius:50%;background:white}.hill{position:absolute;background:#0077b3;width:210px;height:170px;bottom:-95px;left:-10px;transform:rotate(25deg);border-radius:24px}.hill.two{left:135px;background:#00619b;bottom:-110px;transform:rotate(-25deg)}.road{position:absolute;width:150px;height:200px;border:12px solid white;border-radius:50%;top:65px;left:95px;transform:rotate(25deg)}.card{background:white;border-radius:4px;padding:28px;box-shadow:0 2px 8px #082a4d0d;display:grid;grid-template-columns:1fr 230px;gap:28px}h2{font-size:24px;line-height:1.3;margin:0 0 20px}.fields{display:grid;grid-template-columns:1fr 1fr;gap:20px}label{display:block;font-weight:600;margin-bottom:8px}input{width:100%;max-width:100%;min-width:0;border:1px solid #909599;border-radius:4px;font:inherit;color:inherit;padding:12px;background:white}input[aria-invalid=true]{border-color:#d61c52}button{background:#0077b3;color:white;border:0;border-radius:20rem;padding:12px 36px;font:600 16px/1.5 system-ui;cursor:pointer}button:hover{background:#004b81}button:focus-visible,input:focus-visible{outline:3px solid #082a4d;outline-offset:3px}.error{font-size:14px;color:#d61c52;min-height:24px;margin:8px 0 20px}.calendar{background:#f0f7fa;border-radius:4px;padding:20px}.calendar strong{display:block;margin-bottom:12px}.grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;font-size:12px;text-align:center}.grid span{padding:3px 0}.grid .in-range{background:#c6e1ee}.grid .endpoint{background:#0077b3;color:white;border-radius:50%}.caption{font-size:12px;margin:12px 0 0}.result{margin-top:20px;background:#e4f1f7;padding:20px;border-radius:4px}.result:empty{display:none}.boundary{font-size:12px;margin-top:28px}.hint{font-size:14px}@media(max-width:650px){main{padding:24px 16px}.hero{grid-template-columns:1fr}.art{display:none}h1{font-size:28px}.card{grid-template-columns:1fr;padding:20px}.fields{grid-template-columns:1fr;gap:16px}.calendar{max-width:300px;width:100%}button{width:100%;padding:12px 20px}}
</style><main><div class="hero"><div><div class="eyebrow">Travel period planner</div><h1>Make time for a change of scenery.</h1><p>Choose a departure and return date to explore an inclusive calendar-day count.</p></div><div class="art" aria-hidden="true"><div class="sun"></div><div class="hill"></div><div class="hill two"></div><div class="road"></div></div></div><div class="card"><section><h2>When will you travel?</h2><p class="hint" id="hint">Use dates from 1–30 June 2027. This fixed month is for demonstration.</p><form novalidate><div class="fields"><div><label for="start">Departure</label><input id="start" type="date" min="2027-06-01" max="2027-06-30" value="2027-06-10" required aria-describedby="hint error"></div><div><label for="end">Return</label><input id="end" type="date" min="2027-06-01" max="2027-06-30" value="2027-06-17" required aria-describedby="hint error"></div></div><div class="error" id="error" role="alert"></div><button type="submit">Prepare date range</button></form></section><aside class="calendar"><strong>June 2027</strong><div class="grid" id="calendar" aria-hidden="true"></div><p class="caption" id="range-caption">10–17 June selected</p></aside></div><div class="result" id="result" role="status"></div><p class="boundary">Independent HTML interpretation of Duet tokens with native date fields. The calendar image is a non-interactive range overview. No insurance quote, booking or policy is created.</p></main><script>const start=document.querySelector('#start'),end=document.querySelector('#end'),result=document.querySelector('#result'),error=document.querySelector('#error');function valid(){return start.validity.valid&&end.validity.valid&&start.value&&end.value&&end.value>=start.value}function draw(){let days=['M','T','W','T','F','S','S'].map(d=>'<span>'+d+'</span>').join('')+'<span></span>';for(let i=1;i<=30;i++){let iso='2027-06-'+String(i).padStart(2,'0'),range=valid()&&iso>=start.value&&iso<=end.value,edge=range&&(iso===start.value||iso===end.value);days+='<span class="'+(edge?'endpoint':range?'in-range':'')+'">'+i+'</span>'}document.querySelector('#calendar').innerHTML=days;document.querySelector('#range-caption').textContent=valid()?start.value+' to '+end.value:'Choose a valid range to highlight it.'}function changed(){result.textContent='';error.textContent='';start.removeAttribute('aria-invalid');end.removeAttribute('aria-invalid');draw()}[start,end].forEach(el=>el.oninput=changed);document.querySelector('form').onsubmit=e=>{e.preventDefault();let bad;if(!start.value||!start.validity.valid){error.textContent='Choose a departure date in June 2027.';bad=start}else if(!end.value||!end.validity.valid){error.textContent='Choose a return date in June 2027.';bad=end}else if(end.value<start.value){error.textContent='Return must be on or after departure.';bad=end}if(bad){bad.setAttribute('aria-invalid','true');bad.focus();result.textContent='';return}const days=(Date.parse(end.value+'T00:00:00Z')-Date.parse(start.value+'T00:00:00Z'))/86400000+1;result.textContent=days+' calendar '+(days===1?'day':'days')+', including departure and return. Local draft: '+start.value+' to '+end.value+'. No policy created.'};draw();</script></html>
Este documento utiliza controles de fecha nativos del navegador. El ejemplo de Duet independiente usa el selector del sistema principal; no debe confundirse con el paquete independiente de código abierto para seleccionar fechas.
Validar un par de selectores de fecha del sistema principal
Dos campos etiquetados, fechas de junio con límites definidos, extremos en orden, foco en el selector no válido y recuento inclusivo de días.
HTML
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Date range draft</title>
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/5.1.4/lib/duet.min.css">
<script type="module" src="https://cdn.duetds.com/api/components/10.7.0/lib/duet/duet.esm.js"></script>
<style>main{max-width:680px;margin:auto;padding:28px}.range{display:grid;grid-template-columns:1fr 1fr;gap:20px}@media(max-width:576px){.range{grid-template-columns:1fr}}</style>
<main><h1>Choose a travel period</h1><p>Demonstration only. No insurance is quoted or purchased.</p><div class="range">
<duet-date-picker id="start" label="Departure" required expand value="2027-06-10" min="2027-06-01" max="2027-06-30"></duet-date-picker>
<duet-date-picker id="end" label="Return" required expand value="2027-06-17" min="2027-06-01" max="2027-06-30"></duet-date-picker></div>
<duet-button id="prepare" variation="primary">Prepare date range</duet-button>
<p id="result" role="status"></p></main><script type="module">
await customElements.whenDefined('duet-date-picker');
const start=document.querySelector('#start'),end=document.querySelector('#end'),result=document.querySelector('#result');
function error(picker){const v=picker.validity;if(!picker.value)return 'Choose a date.';if(v&&!v.valid)return 'Choose a valid date in June 2027.';return '';}
function validate(){start.error=error(start);end.error=error(end);if(!start.error&&!end.error&&end.value<start.value)end.error='Return must be on or after departure.';return !start.error&&!end.error;}
[start,end].forEach(p=>p.addEventListener('duetChange',()=>{result.textContent='';validate()}));
document.querySelector('#prepare').addEventListener('click',async()=>{if(!validate()){await(start.error?start:end).setFocus();return;}const a=Date.parse(start.value+'T00:00:00Z'),b=Date.parse(end.value+'T00:00:00Z');result.textContent=`Local range: ${start.value} to ${end.value}, ${(b-a)/86400000+1} calendar days inclusive. No policy created.`;});
</script></html>
Este ejemplo usa @duetds/components mediante el CDN del sistema principal, no @duetds/date-picker 1.x.
Los intervalos que abarcan un mismo día contienen un día natural, incluido en el recuento.
El cálculo en UTC evita las diferencias causadas por el horario de verano.
04
Sistema de diseño Duet Configuración del agente de IA
Punto de partida para la implementación
Composición completa del sistema principal mediante CDN, con las versiones indicadas explícitamente en la página de integración inspeccionada. Las instantáneas de búsquedas públicas también muestran versiones más recientes; fija una versión compatible en lugar de dar por sentado que esta es la más reciente. Aquí no se redistribuyen las fuentes.
HTML
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Date range draft</title>
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/5.1.4/lib/duet.min.css">
<script type="module" src="https://cdn.duetds.com/api/components/10.7.0/lib/duet/duet.esm.js"></script>
<style>main{max-width:680px;margin:auto;padding:28px}.range{display:grid;grid-template-columns:1fr 1fr;gap:20px}@media(max-width:576px){.range{grid-template-columns:1fr}}</style>
<main><h1>Choose a travel period</h1><p>Demonstration only. No insurance is quoted or purchased.</p><div class="range">
<duet-date-picker id="start" label="Departure" required expand value="2027-06-10" min="2027-06-01" max="2027-06-30"></duet-date-picker>
<duet-date-picker id="end" label="Return" required expand value="2027-06-17" min="2027-06-01" max="2027-06-30"></duet-date-picker></div>
<duet-button id="prepare" variation="primary">Prepare date range</duet-button>
<p id="result" role="status"></p></main><script type="module">
await customElements.whenDefined('duet-date-picker');
const start=document.querySelector('#start'),end=document.querySelector('#end'),result=document.querySelector('#result');
function error(picker){const v=picker.validity;if(!picker.value)return 'Choose a date.';if(v&&!v.valid)return 'Choose a valid date in June 2027.';return '';}
function validate(){start.error=error(start);end.error=error(end);if(!start.error&&!end.error&&end.value<start.value)end.error='Return must be on or after departure.';return !start.error&&!end.error;}
[start,end].forEach(p=>p.addEventListener('duetChange',()=>{result.textContent='';validate()}));
document.querySelector('#prepare').addEventListener('click',async()=>{if(!validate()){await(start.error?start:end).setFocus();return;}const a=Date.parse(start.value+'T00:00:00Z'),b=Date.parse(end.value+'T00:00:00Z');result.textContent=`Local range: ${start.value} to ${end.value}, ${(b-a)/86400000+1} calendar days inclusive. No policy created.`;});
</script></html>
Una instrucción para tu proyecto
Instrucción para el agente
Crea un intervalo de fechas de Duet del sistema principal con dos selectores de fecha etiquetados, valores ISO y comprobaciones de validez. Valida por separado el orden de los extremos, llama a setFocus cuando haya errores y usa una acción local explícita para preparar el intervalo. No incluyas el paquete de selector independiente en la misma página.
05
Sistema de diseño Duet Fuentes y alcance
Referencia independiente de OpenDesign. Planificador original; no crea ninguna póliza, reserva ni cotización. Duet del sistema principal y su selector de fechas independiente de código abierto tienen contratos distintos.