Создавайте понятные формы для финских государственных услуг с Source Sans 3, явными токенами интервалов и восстанавливаемым сценарием выбора документов.
Исходная интерпретация HTML/CSS документированного сценария с одним файлом; резервный шрифт Arial. · Справочник по реализации
02
Дизайн-система Suomi.fi — справочник по дизайн-системе
Официальная документация, изученный репозиторий токенов и метаданные suomifi-ui-components 18.0.0. Предпросмотр — оригинальная интерпретация, а не нативная среда выполнения React.
Suomi.fi предоставляет React компонентов со стилями на основе styled-components и отдельный пакет токенов. В версии 18 ожидаемым шрифтом стал Source Sans 3. На страницах более ранней версии 17 всё ещё может использоваться Source Sans Pro; сравнение таких снимков экрана без проверки версии пакета может привести к ошибочной корректировке типографики.
Встроенный предпросмотр по-прежнему явно обозначен как интерпретация HTML/CSS документированного сценария с одним файлом. Ниже также добавлен отдельный пример нативного FileInput из React с проверенными обратным вызовом, управляемым значением, зависимостями и импортами шрифтов. Это две реализации одной и той же локальной задачи выбора файла; нативный пример не превращает задним числом встроенный предпросмотр HTML в компонент React.
Дизайн-система Suomi.fi — типографика и загрузка шрифтов
Сохраняйте читаемость основного текста
Используйте рекомендованный размер основного текста 18px на мобильных и настольных устройствах. Узкая область просмотра не является поводом уменьшать размер всех пояснений к форме. Малый текст — 16px, он предназначен для второстепенной информации. Размер вводного текста — 22px, а в компактном режиме — 20px; используйте его только во вступлении к странице.
Загрузите нужные начертания шрифта, прежде чем сравнивать переносы строк. Пакет компонентов ожидает файлы Source Sans 3, тогда как в этом независимом предпросмотре намеренно используется Arial. Эта замена отмечена в примечании к предпросмотру; его нельзя выдавать за точное отображение нативного компонента.
В источнике токенов обычные отступы отделены от внутренних. Обычный отступ l в изученном JSON равен 25px; не копируйте устаревший пример из README, где для l указано 32px. Внутренние отступы начинаются с 2px и далее идут по другой последовательности. При генерации стилей используйте фактические экспорты установленной версии.
Для FileInput документированы максимальная ширина 600px и свойство fullWidth. Это ограничение компонента, а не основание считать 600px универсальной шириной контейнера страницы. Форму для загрузки документов можно поместить в более широкую компоновку, сохранив поясняющий текст рядом с её меткой.
Видимая метка называет нужный документ. Подсказка до открытия диалога выбора объясняет поддерживаемые форматы, размер и допустимое количество файлов. Область перетаскивания предлагает быстрый способ выбора, но не должна заменять поле ввода файла. В официальных рекомендациях элемент управления выбором описан как метка скрытого нативного поля ввода файла.
В режиме выбора одного файла выбранный документ заменяет область выбора и перетаскивания. Рядом с документом оставьте понятное действие для удаления. Режим выбора нескольких файлов использует другой формат списка; не добавляйте незаметно дополнительные файлы в запрос на выбор одного файла.
labelText: назовите требуемое подтверждение или документ, а не ограничивайтесь словом «Загрузить».
removeFileText: сформулируйте действие удаления так, чтобы оно было понятно в контексте файла.
addedFileAriaText: перед объявлением имени файла предоставьте контекст выбора.
Дизайн-система Suomi.fi — выбор файла и восстановление после ошибки
Локальная машина состояний для вложения
Пример принимает один PDF размером не более 5 000 000 байт. Это правила приложения, выбранные для сценария данного практикума. Они не являются настройками пакета по умолчанию или официальной политикой Suomi.fi по загрузке файлов. Атрибут accept в браузере лишь помогает фильтровать файлы в диалоге выбора; в примере имя и размер файла дополнительно проверяются после выбора или перетаскивания.
При некорректных метаданных поле выбора остаётся доступным, а сообщение объясняет, как исправить ситуацию. После выбора подходящего файла его имя выводится через textContent, отображается размер в байтах, а фокус перемещается на кнопку удаления. При удалении очищается значение исходного поля, восстанавливается область выбора и возвращается фокус — тот же файл можно выбрать повторно.
Выберите или перетащите ровно один файл; при выборе нескольких файлов покажите соответствующее сообщение.
Проверьте локальные правила примера и объявите либо сообщение об ошибке, либо имя выбранного файла.
Удалите вложение и восстановите исходный элемент выбора.
В опубликованной версии 18.0.0 реализация FileInput вызывает onChange с FileList, а не с событием изменения React. Управляемое значение — это массив объектов файлов; в примере каждый принятый File преобразуется в { file }. Тот же обратный вызов выполняется при изменении списка встроенным действием удаления, поэтому пустой FileList очищает управляемый массив. Эти контракты проверены в опубликованном модуле dist/esm/core/Form/FileInput/FileInput.js.
Управляйте value с первого рендера, начав с пустого массива. Проверяйте входящий FileList, прежде чем преобразовывать его в этот массив. В примере отклоняются файлы, имена которых не оканчиваются на .pdf или размер которых превышает 5 000 000 байт; при отклонении выбор очищается. Это локальные правила примера, а не проверка безопасности и не политика Suomi.fi. Перед приёмом реальной загрузки необходимо проверять содержимое файлов на сервере.
Приведённый ниже нативный пример загружает Source Sans 3 начертаниями 400 и 600, монтирует React в явно заданный корневой элемент и использует styled-components через библиотеку. Явно укажите tslib: ESM-модули версии 18.0.0 импортируют её вспомогательные функции, и чистая сборка без этой зависимости завершилась ошибкой. В закреплённой ниже конфигурации указаны недостающая среда выполнения и файлы шрифтов. Для этого примера с темой по умолчанию дополнительный провайдер темы не нужен.
В официальном руководстве по стилям показаны suomifiDesignTokens.spacing и suomifiDesignTokens.colors. В примере ниже эти экспортированные пути используются для пользовательской обёртки; это не альтернативная реализация внутренних механизмов FileInput.
tsx
import { suomifiDesignTokens } from 'suomifi-design-tokens';
// Real exported token paths. Use values instead of copying README example numbers.
const attachmentStyle = {
maxWidth: 600,
padding: suomifiDesignTokens.spacing.m,
borderColor: suomifiDesignTokens.colors.highlightBase
};
Дизайн-система Suomi.fi Доступность и адаптивное использование
Доступ к полю без перетаскивания
Сохраняйте возможность работы с нативным полем выбора файлов с клавиатуры, даже если область перетаскивания заметно выделена. Свяжите подсказку и сообщение об ошибке с помощью aria-describedby. Объявляйте изменения выбора и удаление, не зачитывая страницу заново. Если в форме может быть несколько таких элементов управления, кнопка удаления должна указывать, к какому выбранному файлу она относится.
Официальный проп smallScreen обеспечивает компактное отображение. Он не задаёт глобальную контрольную точку. В этом независимом примере для отступов используется специфичное для приложения изменение при ширине 480px, а размер основного текста остаётся равным 18px. Проверяйте длинные имена файлов, масштабирование и переведённые подписи; переносите имена файлов по строкам, не позволяя всей странице стать шире.
Дизайн-система Suomi.fi Ответственность в производственной среде
Выбранный файл — ещё не загруженный файл
Демонстрационный пример не читает содержимое документов и не отправляет запросы. Имя выбранного файла и его размер в байтах не подтверждают, что документ действителен, сохранён или принят. Для реальных сервисов необходимы проверка на сервере, отображение хода загрузки, возможность восстановиться после ошибки, правила хранения и подтверждение, основанное на фактическом ответе.
Код компонента распространяется по лицензии MIT. Эта лицензия на код не даёт независимому проекту права представлять себя как финскую государственную службу или использовать защищённую институциональную айдентику. Для экспериментов используйте нейтральное название проекта, а для официальной реализации получите соответствующие рекомендации по брендингу.
Полная самостоятельная реализация. Ограничения по формату PDF и размеру выбраны для примера; загрузка не выполняется.
html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Attachment example</title><style>*{box-sizing:border-box}body{margin:0;padding:30px 20px;font:18px/1.5 Arial,sans-serif;color:#202020;background:#fff}main{max-width:600px;margin:auto}h1{font-size:32px;line-height:1.2;font-weight:400;margin:0 0 20px}p{margin:0 0 20px}label{font-weight:600;display:block}small{display:block;font-size:16px}.drop{margin-top:15px;border:2px dashed hsl(212,63%,45%);padding:30px;text-align:center;background:hsl(212,63%,90%)}button,input::file-selector-button{font:600 18px Arial;padding:12px 20px;border:1px solid hsl(212,63%,37%);border-radius:2px;background:hsl(212,63%,45%);color:white;cursor:pointer}button:focus-visible,input:focus-visible{outline:3px solid #202020;outline-offset:3px}input{width:100%;font-size:16px;margin:15px 0}input::file-selector-button{margin-right:10px}.file{border:1px solid #777;padding:20px;margin:20px 0;overflow-wrap:anywhere}.file button{margin-top:15px;background:white;color:hsl(212,63%,37%)}#error{color:#a32020;font-weight:bold}footer{font-size:14px;margin-top:30px;border-top:1px solid #ccc;padding-top:15px}[hidden]{display:none!important}@media(max-width:480px){body{padding:20px 15px}.drop{padding:20px}h1{font-size:28px}}</style><main><small>COMMUNITY WORKSHOP · ATTACHMENT</small><h1>Add your project outline</h1><p>Choose one PDF up to 5 MB. This local example checks file metadata; it does not read or send the document.</p><div id="picker"><label for="file">Project outline</label><small id="hint">One PDF file. Maximum 5 MB (5,000,000 bytes).</small><input id="file" type="file" accept=".pdf,application/pdf" aria-describedby="hint error"><div class="drop" id="drop">Or drop one PDF here</div></div><p id="error" role="alert" hidden></p><section id="selected" class="file" hidden aria-label="Selected attachment"><strong id="name"></strong><small id="size"></small><button id="remove" type="button">Remove file</button></section><p id="status" role="status">No file selected.</p><footer>OpenDesign interpretation of the Suomi.fi attachment pattern. Arial fallback; no official identity or React component runtime. PDF and 5 MB are example rules.</footer></main><script>const input=document.querySelector('#file'),picker=document.querySelector('#picker'),selected=document.querySelector('#selected'),error=document.querySelector('#error'),status=document.querySelector('#status');function choose(files){error.hidden=true;if(files.length!==1){error.textContent='Choose exactly one file.';error.hidden=false;input.value='';return}const file=files[0];if(!/\.pdf$/i.test(file.name)||file.size>5000000){error.textContent='Choose a PDF no larger than 5 MB.';error.hidden=false;input.setAttribute('aria-invalid','true');input.value='';return}input.removeAttribute('aria-invalid');document.querySelector('#name').textContent=file.name;document.querySelector('#size').textContent=file.size.toLocaleString('en')+' bytes · selected locally';document.querySelector('#remove').setAttribute('aria-label','Remove '+file.name);picker.hidden=true;selected.hidden=false;status.textContent='Selected file: '+file.name;document.querySelector('#remove').focus()}input.addEventListener('change',()=>{if(input.files.length)choose(input.files)});document.querySelector('#drop').addEventListener('dragover',e=>e.preventDefault());document.querySelector('#drop').addEventListener('drop',e=>{e.preventDefault();choose(e.dataTransfer.files)});document.querySelector('#remove').onclick=()=>{input.value='';picker.hidden=false;selected.hidden=true;error.hidden=true;input.removeAttribute('aria-invalid');status.textContent='File removed. Choose another file.';input.focus()};</script></html>
Проверку выполняет приложение; нативный компонент обеспечивает выбор и удаление файлов, а также доступные элементы управления файлами.
Макет страницы нативного примера
Сохраните как app.css. Вместе эти три файла воспроизводят нативный пример React с помощью команд настройки.
css
body{margin:0;font:18px/1.5 'Source Sans 3',sans-serif;color:#292929;background:#fff}main{max-width:600px;margin:0 auto;padding:24px}h1{font-size:32px;line-height:1.2}*{box-sizing:border-box}
Проверку выполняет приложение; нативный компонент обеспечивает выбор и удаление файлов, а также доступные элементы управления файлами.
04
Дизайн-система Suomi.fi Настройка ИИ-агента
Отправная точка для реализации
Эта настройка собирает приведённый ниже нативный пример React, включая локальные файлы шрифта Source Sans 3. Проверено с недопустимым форматом, корректным выбором, встроенным удалением и PDF-файлом слишком большого размера при ширине 390px и 1440px. Существующий архив ZIP со скачиваемым предпросмотром — это отдельная интерпретация HTML/CSS; его README остаётся актуальным.
Используйте предоставленный нативный пример Suomi.fi FileInput 18.0.0 React со шрифтом Source Sans 3 и закреплёнными зависимостями среды выполнения, включая tslib. Управляйте value как массивом объектов { file }; onChange получает FileList напрямую, поэтому не обращайтесь в этом обратном вызове к event.target. Проверяйте формат и размер до принятия локально выбранного файла, обрабатывайте пустой список, возвращаемый при удалении, и оставляйте подсказки и сообщения об ошибках видимыми. Встроенный предпросмотр HTML следует считать отдельно обозначенной интерпретацией. Ни одна из реализаций не загружает файл; проверка на сервере, отображение хода загрузки и подтверждение сохранения требуют фактического контракта с серверной частью.
05
Дизайн-система Suomi.fi Источники и область применения
Встроенный предпросмотр и скачиваемый ZIP — это интерпретация OpenDesign HTML/CSS. Отдельный полный пример React использует suomifi-ui-components 18.0.0 и проверенные контракты value и onChange компонента FileInput. В обоих примерах можно локально выбрать файл; ни один из них не загружает и не сохраняет документ на сервере.