Sistema de componentes sin estilos · Nuevo recurso

Sistema de diseño de Kobalte.

Kobalte proporciona componentes sin interfaz para Solid, incluidos campos numéricos con valores sin formato y formateados por separado, la anatomía compuesta de casillas de verificación y botones con estado de pulsación. Esta guía conecta esas primitivas con las señales de Solid mediante una herramienta para ajustar recetas, con cantidades derivadas y controles de ingredientes que se pueden restablecer.

Guía de OpenDesign9 capítulos29 entradas de referenciaGuía de aplicación original
01

Vista previa de la interfaz del sistema de diseño de Kobalte

Ajusta las cantidades de los ingredientes, reúne los elementos y guarda una receta original de forma local.

Tarjeta de receta reactivaAbrir ejemplo completo
Kobalte 0.13.14 con Solid 1.9.15; primitivas nativas sin interfaz y CSS original completa. · Referencia de implementación
02

Referencia de diseño del sistema de diseño de Kobalte

Kobalte 0.13.14 proporciona primitivas de Solid sin interfaz, pero no una escala visual canónica. Cada color y dimensión recipe-* que aparece a continuación forma parte de la configuración original completa de la aplicación. Los nombres API y los atributos de estado se verificaron con el paquete instalado y la documentación oficial de los componentes.

Colores semánticos originales

Fuente
Nombre / ReglaValor / ConfiguraciónUso
--recipe-canvas#f6f2ec Lienzo exterior
--recipe-surface#fffefa Paneles de recetas y porciones
--recipe-ink#403a30 Texto principal
--recipe-muted#807465 Texto complementario
--recipe-line#e6ded2 Separadores y bordes
--recipe-action#95612f Casilla seleccionada y texto de acción
--recipe-on-action#fffPrimer plano de la acción rellena
--recipe-focus#b88955 Indicador visible de foco del teclado
--recipe-soft#f1e4d3 Fondo del control incremental y del pin presionado

Tipografía y dimensiones originales

Fuente
Nombre / ReglaValor / ConfiguraciónUso
Bodysystem-ui, sans-serifSin descarga de fuentes
Page heading34px / 1.15; 29px narrowJerarquía original
Recipe titleGeorgia, serif; 30px / 1.2Acento editorial original
Ingredient copy13px / 1.5; 12px narrowEtiquetas con ajuste de línea legible
--recipe-space-1 / 2 / 34px / 8px / 12pxEspacios pequeños
--recipe-space-4 / 6 / 816px / 24px / 32pxEspaciado de paneles y página
Panel radius16pxGeometría original de las superficies
Checkbox control21 × 21px; 5px radiusIndicador visible original
Stepper trigger42px wideActivador nativo con geometría original
Layout breakpoint760pxDos columnas se convierten en una
Focus ring3px; 3px offsetTratamiento original visible del teclado

Contrato de estado del componente nativo

Fuente
Nombre / ReglaValor / ConfiguraciónUso
NumberField.rawValuenumberEstado aritmético en lugar de texto formateado
NumberField.onRawValueChange(value: number) => voidActualiza las cantidades y borra las selecciones obsoletas
minValue / maxValue / step1 / 8 / 1Límites de la aplicación aplicados al campo numérico nativo
formatOptions.maximumFractionDigits0Visualización de porciones enteras
validationStatevalid | invalidValidez de la aplicación reflejada en el campo nativo
Checkbox.checked / onChangeboolean / callbackSelección controlada de ingredientes
Checkbox data attributesdata-checked; data-focus-visibleAplicar estilos a los estados nativos de selección y foco del teclado
ToggleButton.pressed / onChangeboolean / callbackFijar localmente con estado controlado
ToggleButton data-pressedpresent when pressedEstilo de fijación local activada
03

Guía completa del sistema de diseño Kobalte

Una guía práctica para elegir, aplicar y revisar este sistema en una interfaz real.

DESIGN-kobalte.md

Orientación completa, un punto de partida para la implementación y enlaces al código fuente.

Descargar la guía

Conecta los componentes de sistema de diseño Kobalte con señales de Solid

Conecta los componentes de Kobalte con las señales de Solid

El componente usa señales de Solid para las porciones, los ingredientes reunidos y la fijación. createMemo deriva la validez de la señal numérica, y For representa una colección estable de ingredientes. Las propiedades controladas de Kobalte leen estas señales directamente; las actualizaciones no requieren un proveedor de formularios aparte ni un adaptador de estado al estilo de React.

De esta guía de OpenDesign

NumberField, Checkbox y ToggleButton se importan desde sus puntos de entrada de componentes. Sus funciones son distintas: el campo numérico gestiona la entrada de valores numéricos editables, cada casilla representa un ingrediente reunido y el botón de alternancia mantiene la fijación de la receta. Las reglas aritméticas y de invalidación permanecen en las funciones de la aplicación, en lugar de quedar integradas en los selectores visuales.

Consulta la especificación complementaria

Mantén el estado numérico separado del texto formateado en sistema de diseño Kobalte

Mantén el estado numérico separado del texto formateado

NumberField recibe rawValue={portions()} y onRawValueChange={update}. La señal numérica impulsa directamente la multiplicación, mientras que el campo gestiona el formato y la edición del usuario. Devolver el texto de visualización formateado a la operación aritmética introduciría suposiciones de análisis sobre los separadores o la configuración regional que la primitiva nativa ya resuelve.

El ejemplo permite de una a ocho porciones enteras, con un incremento de uno y maximumFractionDigits establecido en cero. Un predicado calculado independiente comprueba que el valor sea finito, entero y esté dentro de los límites, ya que un campo editable puede contener temporalmente un valor incompleto o no válido. Mientras el valor no sea válido, los totales muestran una raya y las casillas de ingredientes están desactivadas. La interfaz no presenta una cantidad verosímil pero incorrecta como si el usuario hubiera introducido un valor válido.

Consulta la especificación complementaria

Compón el campo con su etiqueta y sus mensajes nativos en sistema de diseño Kobalte

Compón el campo con su etiqueta y sus mensajes nativos

El campo numérico contiene Label, DecrementTrigger, Input, IncrementTrigger, Description y ErrorMessage. La descripción visible explica tanto el intervalo como la consecuencia de cambiar el número de porciones. Los activadores tienen etiquetas claras, Menos porciones y Más porciones, así que los signos menos y más no tienen que aportar por sí solos todo el nombre accesible.

validationState alterna entre válido y no válido mediante el predicado de la aplicación. ErrorMessage pertenece a ese campo nativo, no es un párrafo ajeno colocado en otra parte de la página. Para un formulario enviado, Kobalte también proporciona un HiddenInput para serializar el valor sin procesar; este ejemplo local no incluye uno porque no tiene un endpoint de envío ni una carga útil de formulario.

Consulta la especificación complementaria

Mantén la selección de ingredientes en un Set inmutable en sistema de diseño Kobalte

Mantén la selección de ingredientes en un conjunto inmutable

Cada ingrediente usa la estructura completa de Checkbox: Input, Control, Indicator y Label. El elemento de entrada real conserva la semántica y la interacción con el teclado, mientras que el control visible recibe la marca de verificación y los estilos originales de estado. La etiqueta incluye tanto el nombre del ingrediente como la cantidad, de modo que la cantidad forma parte del elemento que se está reuniendo.

mark crea un nuevo Set a partir de la selección anterior antes de añadir o quitar un ID. Modificar únicamente el Set existente no proporcionaría la misma actualización fiable de la señal. El recuento mostrado lee el tamaño del Set y cada Checkbox consulta la pertenencia mediante un ID de ingrediente estable. Un cambio en la cantidad de porciones borra toda la selección, porque reunir 320 gramos no demuestra que se cumpla el nuevo requisito de 400 gramos.

  • Asocia cada nombre de ingrediente visible con Checkbox.Label.
  • Conserva Checkbox.Input aunque el cuadrado visible tenga estilos personalizados.
  • Usa ID estables para la selección y crea un Set nuevo en cada actualización.

Consulta la especificación complementaria

Usa un botón de alternancia para una elección local persistente en sistema de diseño Kobalte

Usa un interruptor para una opción local persistente

La fijación usa ToggleButton con pressed y onChange, no un botón normal que solo cambia su texto. El estado pressed se refleja en la semántica nativa y en el selector data-pressed. La etiqueta cambia a Fijada, con una marca de verificación, y el estado cercano explica que esto solo afecta a la vista previa local.

Fijar la receta no cambia las cantidades ni la selección de ingredientes. Cambiar el número de porciones borra las marcas de los ingredientes, pero conserva la fijación porque la identidad de la receta no ha cambiado. Restablecer la receta predeterminada reinicia a la vez los tres aspectos del modelo: cuatro porciones, un Set de ingredientes vacío y una fijación desactivada. Estos distintos límites de restablecimiento responden al significado de cada estado, en lugar de borrarlo todo con cada interacción.

Consulta la especificación complementaria

Configura los controles sin estilos predefinidos de forma reproducible en sistema de diseño Kobalte

Configura controles sin interfaz con un estilo visual reproducible

La hoja de estilos de la receta separa la superficie de edición de la entrada numérica, sus activadores de incremento y decremento y la función de selección de las casillas. El texto atenuado de los ingredientes solo se aplica después de marcarlos; las cantidades siguen siendo legibles para que el usuario pueda compararlas con el número actual de porciones.

El espaciado usa cuatro, ocho, doce, dieciséis, veinticuatro y treinta y dos píxeles. La jerarquía tipográfica original combina una fuente sans serif del sistema para los controles con Georgia para el título de la receta. Una casilla visual de veintiún píxeles aparece junto a una etiqueta asociada completa; la etiqueta sigue siendo el área de activación práctica. Estos valores exactos se incluyen en CSS completo para que el lector pueda reproducir el ejemplo sin tener que calcularlos a partir de una captura de pantalla.

Consulta la especificación complementaria

Permite que la composición se reduzca sin ocultar información en sistema de diseño Kobalte

Permite que la composición se reduzca sin ocultar información

La disposición amplia combina una tarjeta de receta flexible con un panel de porciones de 280 píxeles. A los 760 píxeles, se apilan en una sola columna. El encabezado de la tarjeta puede ocupar varias líneas, las etiquetas de ingredientes pueden partirse en otra línea y la cantidad mantiene un formato compacto sin saltos de línea. En el punto de ruptura más pequeño, se reduce ligeramente el relleno del panel y el tamaño de letra de las etiquetas, en lugar de ocultar las cantidades.

La ilustración de la ensalada es original de CSS y está marcada como decorativa. El nombre de la receta, el número de porciones y las cantidades de los ingredientes transmiten el significado independientemente de esa ilustración. Si cambias la ilustración o estrechas la tarjeta, conserva las etiquetas completas de los ingredientes y sus cantidades: son los datos que se utilizan realmente para reunirlos.

Consulta la especificación complementaria

Sistema de diseño Kobalte: gestionar los cambios de cantidad como una actualización de estado dependiente

Gestiona los cambios de cantidad como una actualización de estado dependiente

Cada porción aporta 250 gramos entre los cinco ingredientes. Al pasar de cuatro a cinco porciones, el total mostrado cambia de 1.000 a 1.250 gramos y la cantidad de naranja necesaria, de 320 a 400 gramos. Se borran las casillas marcadas anteriormente porque correspondían a las cantidades anteriores, mientras que la receta sigue fijada porque su identidad no ha cambiado.

La función de actualización compara primero el valor recibido con la señal actual mediante Object.is. Una llamada de retorno con un valor sin cambios no debería borrar la lista ni anunciar un cambio de cantidad. Los valores no válidos ocultan las cantidades e impiden marcar ingredientes; el mensaje de error explica entonces el intervalo aceptado. Estas reglas permiten observar las ediciones intermedias sin que un número no válido genere un total engañoso.

  1. Selecciona Gajos de naranja con cuatro porciones.
  2. Aumenta a cinco y confirma que hay 400 g de naranja, 1.250 g en total y cero ingredientes marcados.
  3. Fija la receta y, después, restablece los valores predeterminados para confirmar que se restablece todo el estado local.

Consulta la especificación complementaria

Sistema de diseño Kobalte: usar una compilación sólida e incluir la hoja de estilos completa

Usa una compilación de Solid e incluye la hoja de estilos completa

La configuración utiliza la plantilla de Vite para Solid, fija las versiones verificadas de Solid y Kobalte y se monta en una raíz app explícita. El componente y la hoja de estilos anteriores son archivos completos. Este ejemplo no necesita un proveedor de temas, un paquete de iconos, una fuente externa ni un backend.

Al integrarlo en otra aplicación, mantén alineados el compilador del framework y la generación de componentes. Una transformación de React no convertirá JSX de Solid en una aplicación Kobalte correcta. Asimismo, antes de sustituir la dependencia fijada por una futura versión principal de Kobalte API, consulta la documentación correspondiente. Las cantidades de la receta y la paleta son datos de ejemplo de la aplicación; adaptarlos no requiere cambiar el contrato de las primitivas nativas.

Consulta la especificación complementaria

Kobalte Ejemplos de componentes del sistema de diseño

Componente reactivo de receta completo

Estructura de un campo numérico nativo, una casilla de verificación y un botón de alternancia, con comportamientos explícitos para los estados no válidos y el restablecimiento.

jsx
import {createSignal,createMemo,For} from 'solid-js';
import {NumberField} from '@kobalte/core/number-field';
import {Checkbox} from '@kobalte/core/checkbox';
import {ToggleButton} from '@kobalte/core/toggle-button';
export default function App(){
 const[portions,setPortions]=createSignal(4),[checked,setChecked]=createSignal(new Set()),[pinned,setPinned]=createSignal(false),[notice,setNotice]=createSignal('');
 const ingredients=[{id:'orange',name:'Orange segments',grams:80},{id:'beans',name:'Cooked white beans',grams:90},{id:'leaves',name:'Salad leaves',grams:25},{id:'fennel',name:'Thinly sliced fennel',grams:40},{id:'dressing',name:'Citrus dressing',grams:15}];
 const valid=createMemo(()=>Number.isFinite(portions())&&Number.isInteger(portions())&&portions()>=1&&portions()<=8);
 function update(value){if(Object.is(value,portions()))return;setPortions(value);setChecked(new Set());setNotice('Portions changed. Ingredient checks were cleared for the new quantities.')}
 function mark(id,value){setChecked(previous=>{const next=new Set(previous);value?next.add(id):next.delete(id);return next})}
 function reset(){setPortions(4);setChecked(new Set());setPinned(false);setNotice('Restored four portions and an unchecked ingredient list.')}
 return <main class="recipe-shell"><header><p class="eyebrow">KITCHEN NOTEBOOK · REACTIVE RECIPE CARD</p><h1>A brighter bowl, sized for your table.</h1><p>Change the portions, check the scaled ingredients and pin the recipe locally. The quantities are original sample data for this interface.</p></header><div class="recipe-layout"><section class="recipe-card"><div class="salad-art" aria-hidden="true"><div class="plate"><i/><b/><em/><span/><strong/></div></div><div class="recipe-heading"><div><p class="eyebrow">CITRUS & WHITE BEAN SALAD</p><h2>Fresh, crisp, generous.</h2></div><ToggleButton class="pin" pressed={pinned()} onChange={value=>{setPinned(value);setNotice(value?'Recipe pinned in this local preview.':'Recipe unpinned in this local preview.')}} aria-label="Pin recipe">{pinned()?'Pinned ✓':'Pin recipe'}</ToggleButton></div><p class="recipe-description">Sweet citrus, tender beans and crisp fennel. Use the checklist to gather the amounts for your chosen portion count.</p><div class="ingredient-title"><h3>Ingredients</h3><span>{checked().size} / 5 gathered</span></div><div class="ingredients"><For each={ingredients}>{ingredient=><Checkbox class="ingredient" checked={checked().has(ingredient.id)} onChange={value=>mark(ingredient.id,value)} disabled={!valid()}><Checkbox.Input/><Checkbox.Control class="check-control"><Checkbox.Indicator>✓</Checkbox.Indicator></Checkbox.Control><Checkbox.Label class="ingredient-label"><span>{ingredient.name}</span><strong>{valid()?ingredient.grams*portions()+' g':'—'}</strong></Checkbox.Label></Checkbox>}</For></div></section><aside class="portion-panel"><h2>Make it yours</h2><NumberField rawValue={portions()} onRawValueChange={update} minValue={1} maxValue={8} step={1} formatOptions={{maximumFractionDigits:0}} validationState={valid()?'valid':'invalid'} class="portion-field"><NumberField.Label class="field-label">Portions</NumberField.Label><div class="stepper"><NumberField.DecrementTrigger aria-label="Fewer portions">−</NumberField.DecrementTrigger><NumberField.Input/><NumberField.IncrementTrigger aria-label="More portions">+</NumberField.IncrementTrigger></div><NumberField.Description class="field-description">Choose 1–8 whole portions. Changing the quantity clears ingredient checks.</NumberField.Description><NumberField.ErrorMessage class="field-error">Enter a whole number from 1 to 8.</NumberField.ErrorMessage></NumberField><div class="portion-total"><span>Total ingredients</span><strong>{valid()?ingredients.reduce((s,x)=>s+x.grams,0)*portions()+' g':'—'}</strong></div><h3>A simple preparation order</h3><ol><li>Gather the scaled amounts and drain the cooked beans.</li><li>Combine the orange, fennel and leaves in a bowl.</li><li>Add the beans and dressing, then toss gently.</li></ol><button class="reset" onClick={reset}>Restore default recipe</button><p role="status" class="notice">{notice()||(pinned()?'Recipe pinned in this local preview.':'No shopping order or account update is created.')}</p></aside></div></main>
}

Referencia de código

  • Usa la plantilla de Vite para Solid, no un compilador JSX de React.
  • rawValue contiene el estado numérico; todas las cantidades de los ingredientes se derivan de esa señal.
  • Al cambiar las porciones, se borra el Set de elementos marcados porque las cantidades anteriores ya no son las actuales.

Configuración visual original completa

Propiedades personalizadas semánticas, jerarquía tipográfica, espaciado, estilos de estado e ilustración original de CSS.

css
:root{--recipe-canvas:#f6f2ec;--recipe-surface:#fffefa;--recipe-ink:#403a30;--recipe-muted:#807465;--recipe-line:#e6ded2;--recipe-action:#95612f;--recipe-on-action:#fff;--recipe-focus:#b88955;--recipe-soft:#f1e4d3;--recipe-space-1:4px;--recipe-space-2:8px;--recipe-space-3:12px;--recipe-space-4:16px;--recipe-space-6:24px;--recipe-space-8:32px}html,body,#app{height:auto;min-height:0;margin:0}*{box-sizing:border-box}body{font-family:system-ui,sans-serif;color:var(--recipe-ink);background:var(--recipe-canvas)}button,input{font:inherit}button{cursor:pointer}button:disabled{opacity:.4;cursor:default}button:focus-visible,input:focus-visible{outline:3px solid var(--recipe-focus);outline-offset:3px}.recipe-shell{max-width:1090px;margin:auto;padding:32px}.eyebrow{font-size:10px;font-weight:700;letter-spacing:.13em;color:var(--recipe-muted)}h1{font-size:34px;line-height:1.15;max-width:700px;margin:12px 0}header>p:last-child{font-size:14px;line-height:1.7;color:var(--recipe-muted);max-width:630px}.recipe-layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:24px;margin-top:28px}.recipe-card,.portion-panel{background:var(--recipe-surface);border:1px solid var(--recipe-line);border-radius:16px;padding:24px;min-width:0}.portion-panel{align-self:start}.salad-art{height:180px;background:#e8e4d5;border-radius:10px;position:relative;overflow:hidden;margin-bottom:24px}.plate{position:absolute;width:210px;height:210px;left:50%;top:18px;transform:translateX(-50%);border:18px solid #faf8f0;border-radius:50%;background:#dedcbf;box-shadow:0 10px 25px #5e584b1c}.plate i,.plate b,.plate em,.plate span,.plate strong{position:absolute;display:block}.plate i{width:85px;height:42px;border-radius:0 0 85px 85px;background:#dc9658;border:6px solid #f7c888;left:14px;top:18px;transform:rotate(-23deg)}.plate b{width:72px;height:36px;border-radius:0 0 72px 72px;background:#dc9658;border:6px solid #f7c888;left:75px;top:83px;transform:rotate(28deg)}.plate em{width:50px;height:77px;background:#83976a;border-radius:80% 0 80% 0;left:108px;top:4px;transform:rotate(20deg)}.plate span{width:30px;height:50px;background:#667f56;border-radius:80% 0 80% 0;left:25px;top:88px;transform:rotate(-23deg)}.plate strong{width:24px;height:34px;background:#fff3d7;border-radius:50%;left:80px;top:46px;box-shadow:-34px 14px 0 #fff3d7,25px 28px 0 #fff3d7}.recipe-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.recipe-heading h2{font:400 30px/1.2 Georgia,serif;margin:8px 0}.pin{border:1px solid var(--recipe-line);background:white;border-radius:999px;padding:9px 13px;font-size:11px;color:var(--recipe-action)}.pin[data-pressed]{background:var(--recipe-soft);border-color:var(--recipe-action)}.recipe-description{font-size:13px;line-height:1.7;color:var(--recipe-muted)}.ingredient-title{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:24px}.ingredient-title h3{font-size:16px;margin:0}.ingredient-title span{font-size:11px;color:var(--recipe-muted)}.ingredients{margin-top:14px}.ingredient{display:flex;gap:12px;align-items:center;border-top:1px solid var(--recipe-line);padding:16px 0;cursor:pointer}.check-control{height:21px;width:21px;border:1px solid #b9ab98;border-radius:5px;flex-shrink:0;display:flex;justify-content:center;align-items:center;font-size:13px}.check-control[data-checked]{background:var(--recipe-action);color:white;border-color:var(--recipe-action)}.check-control[data-focus-visible]{outline:3px solid var(--recipe-focus);outline-offset:3px}.ingredient-label{display:flex;justify-content:space-between;gap:12px;width:100%;font-size:13px;line-height:1.5;cursor:pointer}.ingredient-label strong{white-space:nowrap;font-size:12px}.ingredient[data-checked] .ingredient-label>span{text-decoration:line-through;color:var(--recipe-muted)}.portion-panel>h2{font-size:20px;margin:0 0 24px}.field-label{font-size:13px;font-weight:600}.stepper{display:flex;margin-top:10px;border:1px solid var(--recipe-line);border-radius:8px;overflow:hidden}.stepper button{width:42px;flex-shrink:0;background:var(--recipe-soft);border:0;font-size:21px}.stepper input{width:100%;min-width:0;text-align:center;border:0;padding:12px 0;background:white;color:var(--recipe-ink)}.field-description{font-size:11px;line-height:1.7;color:var(--recipe-muted);margin:10px 0 0}.field-error{font-size:12px;color:#a73324}.portion-total{display:flex;justify-content:space-between;gap:12px;margin:24px 0;padding:18px 0;border-top:1px solid var(--recipe-line);border-bottom:1px solid var(--recipe-line);font-size:12px}.portion-total strong{font-size:19px;white-space:nowrap}.portion-panel h3{font-size:13px;line-height:1.6}.portion-panel ol{padding-left:18px;font-size:12px;line-height:1.7;color:var(--recipe-muted)}.portion-panel li{margin-bottom:12px}.reset{width:100%;padding:12px;border:1px solid var(--recipe-line);border-radius:8px;background:white;color:var(--recipe-action);font-size:12px;margin-top:16px}.notice{font-size:11px;line-height:1.7;color:var(--recipe-muted)}@media(max-width:760px){.recipe-layout{grid-template-columns:minmax(0,1fr)}.recipe-shell{padding:20px}h1{font-size:29px}}@media(max-width:360px){.recipe-shell{padding:14px}.recipe-card,.portion-panel{padding:16px}.ingredient-label{gap:8px;font-size:12px}.ingredient{gap:8px}.ingredient-label strong{font-size:11px}.recipe-heading h2{font-size:27px}}

Referencia de código

  • Estos valores recipe-* son opciones originales de la aplicación, no tokens oficiales de Kobalte.
  • La hoja de estilos completa incluye una composición adaptable y un indicador de foco visible.
04

Kobalte Configuración del agente del sistema de diseño

Punto de partida para la implementación

La plantilla de Vite para Solid proporciona el compilador JSX necesario para Solid. Los ejemplos completos de App.jsx y style.css anteriores incluyen todo el código y los estilos de la aplicación; no hace falta ningún proveedor ni servicio externo.

javascript
// npm create vite@latest kobalte-recipe -- --template solid
// cd kobalte-recipe && npm install
// npm install [email protected] @kobalte/[email protected]
// Save the complete examples as src/App.jsx and src/style.css.
// src/index.jsx:
import {render} from 'solid-js/web';
import App from './App.jsx';
import './style.css';
render(() => <App />, document.getElementById('app'));
// index.html: <div id="app"></div><script type="module" src="/src/index.jsx"></script>
// npm run dev

Una instrucción para tu proyecto

Instrucción para el agente
Usa Kobalte 0.13.14 con Solid 1.9.15 para reproducir la tarjeta de receta reactiva. Mantén NumberField rawValue/onRawValueChange, los límites de uno a ocho, la validación de números enteros de porciones y la estructura completa Label/Description/ErrorMessage. Deriva los gramos de cada ingrediente y los totales de la señal de porciones; un cambio real en la cantidad borra el Set inmutable de ID marcados, pero conserva la receta fijada. Mantén las partes nativas de Checkbox y ToggleButton pressed/onChange, impide marcar ingredientes cuando la cantidad no sea válida y restablece cuatro porciones, ninguna casilla marcada y ninguna receta fijada. Incluye la receta original completa de CSS; todo el estado permanece local.
05

Kobalte Fuentes y alcance del sistema de diseño

Verificado con Kobalte 0.13.14 y Solid 1.9.15. Todos los tokens recipe-*, la ilustración de CSS y las cantidades de los ingredientes son datos originales del ejemplo. Fijar la receta y marcar ingredientes son acciones de estado local; no hay conexión con ninguna cuenta, servicio de compras ni almacenamiento persistente de recetas.