# Дизайн-система Kobalte

## Предварительный просмотр интерфейса дизайн-системы Kobalte

Измените количество ингредиентов, соберите нужные продукты и локально закрепите оригинальный рецепт.

## Справочник по дизайн-системе Kobalte

Kobalte 0.13.14 предоставляет бессоставные примитивы Solid, но не задаёт эталонную визуальную шкалу. Все цвета и размеры recipe-* ниже — полная конфигурация оригинального приложения. Названия API и атрибуты состояний проверены по установленному пакету и официальной документации компонентов.

### Исходные семантические цвета

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| --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 | Фон счётчика и нажатого переключателя закрепления |
### Исходная типографика и размеры

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| Body | system-ui, sans-serif | Без загрузки шрифтов |
| Page heading | 34px / 1.15; 29px narrow | Исходная иерархия |
| Recipe title | Georgia, serif; 30px / 1.2 | Оригинальный редакционный акцент |
| Ingredient copy | 13px / 1.5; 12px narrow | Удобные для чтения переносы меток |
| --recipe-space-1 / 2 / 3 | 4px / 8px / 12px | Небольшие интервалы |
| --recipe-space-4 / 6 / 8 | 16px / 24px / 32px | Отступы панелей и страницы |
| Panel radius | 16px | Исходная геометрия поверхностей |
| Checkbox control | 21 × 21px; 5px radius | Исходный видимый индикатор |
| Stepper trigger | 42px wide | Нативный триггер с исходной геометрией |
| Layout breakpoint | 760px | Две колонки переходят в одну |
| Focus ring | 3px; 3px offset | Исходное видимое оформление клавиатурного фокуса |
### Контракт состояний нативного компонента

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| NumberField.rawValue | number | Числовое состояние вместо форматированного текста |
| NumberField.onRawValueChange | (value: number) => void | Обновляет количества и сбрасывает устаревшие отметки |
| minValue / maxValue / step | 1 / 8 / 1 | Ограничения приложения, переданные нативному числовому полю |
| formatOptions.maximumFractionDigits | 0 | Отображение целого количества порций |
| validationState | valid \| invalid | Валидность приложения отражена в нативном поле |
| Checkbox.checked / onChange | boolean / callback | Управляемый выбор ингредиентов |
| Checkbox data attributes | data-checked; data-focus-visible | Стилизация нативных состояний «отмечен» и «в фокусе» |
| ToggleButton.pressed / onChange | boolean / callback | Управляемое локальное закрепление |
| ToggleButton data-pressed | present when pressed | Стиль закреплённого состояния с заливкой |
## Полное руководство по дизайн-системе Kobalte

Практическое руководство по выбору, применению и оценке этой системы для реального интерфейса.

Подробные рекомендации, отправная точка для реализации и ссылки на источники.

## Дизайн-система Kobalte — подключение компонентов Kobalte к сигналам Solid

### Подключите компоненты Kobalte к сигналам Solid

> Компонент использует сигналы Solid для количества порций, собранных ингредиентов и закрепления. createMemo вычисляет валидность на основе числового сигнала, а For отображает стабильную коллекцию ингредиентов. Управляемые свойства Kobalte напрямую считывают эти сигналы; для обновлений не нужны отдельный провайдер формы или адаптер состояния в стиле React.

NumberField, Checkbox и ToggleButton импортируются из точек входа соответствующих компонентов. У каждого своя роль: числовое поле предназначено для редактирования числового значения, каждый флажок отмечает один собранный ингредиент, а переключатель закрепляет рецепт. Арифметика и правила сброса остаются в функциях приложения, а не встраиваются в визуальные селекторы.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — храните числовое значение отдельно от форматированного текста

### Храните числовое значение отдельно от форматированного текста

В NumberField передаются rawValue={portions()} и onRawValueChange={update}. Числовой сигнал напрямую используется для умножения, а поле отвечает за форматирование и ввод данных пользователем. Если подставлять в расчёты отображаемый отформатированный текст, придётся делать допущения о разделителях и локали, тогда как нативный примитив уже решает эту задачу.

В этом примере допускается от одной до восьми целых порций, шаг равен единице, а maximumFractionDigits задан равным нулю. Отдельный вычисляемый предикат по-прежнему проверяет конечность, целочисленность и допустимые границы: при редактировании поле может временно содержать неполное или недопустимое значение. Пока значение недопустимо, вместо суммы отображается длинное тире, а флажки ингредиентов отключены. Интерфейс не выдаёт правдоподобное, но неверное количество за корректный ввод пользователя.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — составьте поле из нативной метки и сообщений

### Составьте поле из нативной метки и сообщений

Числовое поле включает Label, DecrementTrigger, Input, IncrementTrigger, Description и ErrorMessage. Видимое описание поясняет диапазон и последствия изменения количества порций. Триггерам даны понятные названия — «Меньше порций» и «Больше порций», поэтому их условным знакам минуса и плюса не нужно самостоятельно обеспечивать полное доступное имя.

validationState переключается между valid и invalid в зависимости от предиката приложения. ErrorMessage относится к этому нативному полю, а не к отдельному абзацу в другой части страницы. Для отправляемой формы Kobalte также предоставляет HiddenInput для сериализации исходного значения; в этом примере его нет, поскольку здесь не предусмотрены ни конечная точка отправки, ни данные формы.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — храните выбор ингредиентов в неизменяемом множестве

### Храните выбор ингредиентов в неизменяемом множестве

Для каждого ингредиента используется полная структура Checkbox: Input, Control, Indicator и Label. Настоящий элемент ввода сохраняет семантику и управление с клавиатуры, а видимый элемент управления получает галочку и оригинальные стили состояний. Метка включает и название ингредиента, и его количество, поэтому пользователь видит, сколько именно продукта нужно собрать.

mark создаёт новое Set на основе предыдущего выбора, прежде чем добавить или удалить ID. Простое изменение существующего Set не обеспечило бы столь же надёжного обновления сигнала. Отображаемый счётчик считывает размер Set, а каждый Checkbox проверяет наличие стабильного ID ингредиента. При изменении количества порций весь выбор сбрасывается: отметка о сборе 320 граммов не подтверждает, что выполнено новое требование в 400 граммов.

- Связывайте каждое видимое название ингредиента с Checkbox.Label.

- Сохраняйте Checkbox.Input, даже если видимый квадрат оформлен пользовательскими стилями.

- Используйте стабильные ID для выбора и создавайте новое Set при каждом обновлении.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — используйте переключатель для сохранения локального выбора

### Используйте переключатель для сохранения локального выбора

Для закрепления используется ToggleButton со свойствами pressed и onChange, а не обычная кнопка, которая только меняет подпись. Состояние нажатия отражается в нативной семантике и селекторе data-pressed. Метка меняется на «Закреплено» с галочкой, а расположенный рядом статус поясняет, что это влияет только на локальный предпросмотр.

Закрепление не меняет количество ингредиентов или их выбор. При изменении количества порций отметки ингредиентов сбрасываются, но закрепление сохраняется: рецепт остаётся тем же. Команда сброса рецепта по умолчанию одновременно восстанавливает все три части модели: четыре порции, пустое множество ингредиентов и ненажатый переключатель. Эти границы сброса определяются смыслом состояния, а не правилом сбрасывать всё при каждом взаимодействии.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — задайте воспроизводимую визуальную конфигурацию для бессоставных элементов управления

### Задайте воспроизводимую визуальную конфигурацию для бессоставных элементов управления

Таблица стилей рецепта отдельно задаёт поверхность редактирования числового поля, триггеры счётчика и стили выбранных флажков. Приглушённый цвет текста ингредиента применяется только после выбора; количества остаются хорошо различимыми, чтобы пользователь мог сопоставить собранное количество с текущим числом порций.

В отступах используются значения 4, 8, 12, 16, 24 и 32 пикселя. В оригинальной иерархии шрифтов для элементов управления используется системный шрифт без засечек, а для заголовка рецепта — Georgia. Рядом с полной связанной меткой расположен визуальный флажок размером 21 пиксель; метка остаётся удобной областью для нажатия. Все эти точные значения указаны в полном CSS, чтобы воссоздать образец без догадок по скриншоту.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — адаптируйте композицию, не скрывая информацию

### Адаптируйте композицию, не скрывая информацию

В широкой версии гибкая карточка рецепта расположена рядом с панелью порций шириной 280 пикселей. При ширине 760 пикселей блоки выстраиваются в одну колонку. Заголовок карточки и метки ингредиентов могут переноситься, а количество остаётся компактным значением без переноса. На самой узкой контрольной точке отступы панели и размер шрифта меток немного уменьшаются, а не скрывают количества.

Иллюстрация салата — оригинальная работа CSS, помеченная как декоративная. Смысл передают название рецепта, число порций и количества ингредиентов, независимо от изображения. При замене иллюстрации или сужении карточки сохраняйте полные названия ингредиентов и их количества: именно по ним пользователь собирает нужные продукты.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte — обрабатывайте изменение количества как обновление зависимого состояния

### Обрабатывайте изменение количества как обновление зависимого состояния

На каждую порцию приходится по 250 граммов каждого из пяти ингредиентов. При увеличении числа порций с четырёх до пяти общий вес меняется с 1 000 до 1 250 граммов, а количество апельсинов — с 320 до 400 граммов. Ранее собранные ингредиенты больше не отмечены, поскольку их количество соответствовало прежним значениям; закрепление рецепта сохраняется, так как сам рецепт не изменился.

Функция обновления сначала сравнивает входящее значение с текущим сигналом с помощью Object.is. Если значение не изменилось, обратный вызов не должен очищать список отметок или сообщать об изменении количества. Для недопустимых значений количества не отображаются, а сбор отключается; сообщение об ошибке объясняет допустимый диапазон. Эти правила позволяют отслеживать промежуточные изменения, не допуская, чтобы недопустимое число приводило к неверному итогу.

1. Выберите 4 порции апельсиновых долек.

2. Увеличьте количество до пяти и убедитесь, что апельсина нужно 400 г, всего ингредиентов — 1 250 г, а собрано 0 позиций.

3. Закрепите рецепт, затем восстановите значения по умолчанию и убедитесь, что всё локальное состояние сброшено.

Прочитать вспомогательную спецификацию

## Дизайн-система Kobalte: используйте Solid Build и подключайте таблицу стилей целиком

### Используйте сборку Solid и подключайте таблицу стилей целиком

Настройка использует шаблон Vite Solid, фиксирует проверенные версии Solid и Kobalte и монтирует приложение в явно заданный корневой элемент. Приведённые выше компонент и таблица стилей — полные файлы. Для этого примера не нужны провайдер темы, пакет иконок, внешний шрифт или серверная часть.

При интеграции в другое приложение согласуйте компилятор фреймворка и генерацию компонентов. Трансформация React не преобразует JSX Solid в корректное приложение Kobalte. Аналогично, перед заменой закреплённой зависимости на будущую мажорную версию Kobalte API следует свериться с её документацией. Количества ингредиентов и палитра — примеры данных приложения, поэтому их адаптация не требует изменения контракта нативных примитивов.

Прочитать вспомогательную спецификацию

## Kobalte Примеры компонентов дизайн-системы

### Полный реактивный компонент рецепта

Нативное числовое поле, структура флажка и кнопка-переключатель с явной логикой ошибок и сброса.

```
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>
}
```

Справочник по коду

- Используйте шаблон Solid Vite, а не компилятор JSX для React.

- rawValue хранит числовое состояние; все количества ингредиентов рассчитываются на основе этого сигнала.

- При изменении количества порций очищается Set с отметками, поскольку прежние количества больше не актуальны.

### Полная оригинальная визуальная конфигурация

Семантические пользовательские свойства, иерархия типографики, отступы, оформление состояний и оригинальная иллюстрация 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}}
```

Справочник по коду

- Эти значения recipe-* — оригинальные решения приложения, а не официальные токены Kobalte.

- Полная таблица стилей включает адаптивную компоновку и заметное оформление фокуса.

## Kobalte Настройка агента дизайн-системы

### Отправная точка для реализации

Шаблон Solid Vite предоставляет необходимый компилятор JSX для Solid. Примеры App.jsx и style.css выше содержат весь код приложения и стили; провайдер или внешний сервис не требуются.

```
// npm create vite@latest kobalte-recipe -- --template solid
// cd kobalte-recipe && npm install
// npm install solid-js@1.9.15 @kobalte/core@0.13.14
// 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
```

### Запрос для вашего проекта

```
Используйте Kobalte 0.13.14 с Solid 1.9.15, чтобы воспроизвести реактивную карточку рецепта. Сохраните NumberField rawValue/onRawValueChange, диапазон от одного до восьми, проверку целого числа порций и полную структуру Label/Description/ErrorMessage. Рассчитывайте граммы ингредиентов и итоговые значения на основе сигнала количества порций; при фактическом изменении количества очищайте неизменяемый Set идентификаторов отмеченных позиций, но сохраняйте закрепление рецепта. Используйте нативные части Checkbox и ToggleButton с pressed/onChange, отключайте сбор при недопустимом количестве и при сбросе возвращайте четыре порции, отсутствие отметок и отсутствие закрепления. Добавьте полный оригинальный рецепт CSS; всё состояние остаётся локальным.
```

## Kobalte Источники и область применения дизайн-системы

Проверено с Kobalte 0.13.14 и Solid 1.9.15. Все токены recipe-*, иллюстрация CSS и количества ингредиентов — оригинальные данные примера. Закрепление и сбор хранятся в локальном состоянии; приложение не подключено к учётной записи, сервису покупок или постоянному хранилищу рецептов.

- Начало работы Настройка Solid и импорты компонентов.

- Оформление Стили без предустановленного оформления и селекторы состояний.

- Числовое поле Числовые значения, ограничения, структура поля и необработанный ввод формы.

- Checkbox Input, Control, Indicator и Label.

- Кнопка-переключатель Состояние нажатия, обратный вызов и поведение клавиатуры.

## Kobalte Связанные материалы по дизайн-системе

### Mantine

Справочник по Mantine 9 с нативной таблицей участников и боковой панелью планирования. Изучите настоящие шкалы темы, подключите useForm к TextInput, Select, Checkbox и DatePickerInput и проверьте валидацию перед добавлением локальной записи.

### Melt UI

Конструкторы хранилищ и действий Melt UI добавляют доступное поведение к разметке Svelte, которой вы управляете. В руководстве @melt-ui/svelte 0.86.6 связывает конструкторы radio, slider и switch через их атрибуты, действия и доступные для записи хранилища; это решение отличается от более нового варианта на runes API.

### Naive UI

Рабочая среда для таблиц на основе Naive UI: проверенные значения объектов темы, выбор строк, раскрытие, сортировка, пагинация и локальное действие для пакетной проверки.


- [Справочник по реализации](https://kobalte.dev/docs/core/components/number-field)
- [Источник](https://kobalte.dev/docs/core/overview/styling)
- [Источник](https://kobalte.dev/docs/core/components/number-field)
- [Прочитать вспомогательную спецификацию](https://kobalte.dev/docs/core/overview/getting-started)
- [Прочитать вспомогательную спецификацию](https://kobalte.dev/docs/core/components/number-field)
- [Прочитать вспомогательную спецификацию](https://kobalte.dev/docs/core/components/checkbox)
- [Прочитать вспомогательную спецификацию](https://kobalte.dev/docs/core/components/toggle-button)
- [Прочитать вспомогательную спецификацию](https://kobalte.dev/docs/core/overview/styling)
- [Справочник по коду](https://kobalte.dev/docs/core/components/number-field)
- [Справочник по коду](https://kobalte.dev/docs/core/overview/styling)
- [Начало работы Настройка Solid и импорты компонентов.](https://kobalte.dev/docs/core/overview/getting-started)
- [Оформление Стили без предустановленного оформления и селекторы состояний.](https://kobalte.dev/docs/core/overview/styling)
- [Числовое поле Числовые значения, ограничения, структура поля и необработанный ввод формы.](https://kobalte.dev/docs/core/components/number-field)
- [Checkbox Input, Control, Indicator и Label.](https://kobalte.dev/docs/core/components/checkbox)
- [Кнопка-переключатель Состояние нажатия, обратный вызов и поведение клавиатуры.](https://kobalte.dev/docs/core/components/toggle-button)
