Komponen
Di halaman ini
sitelo-ui adalah pustaka komponen untuk sitelo. Setiap komponen adalah fungsi yang mengembalikan string HTML, jadi ia langsung bersarang ke dalam pohon javascript-to-html tanpa apa pun di antaranya — tanpa kompiler, tanpa runtime, tanpa hidrasi. Apa yang Anda bangun itulah yang mendarat di dist/.
Ia disertakan bersama sitelo, di bawah titik masuk sitelo/ui.
Mulai cepat
npm install sitelo javascript-to-htmlTaruh styles() di head dan panggil komponen di body. Itu seluruh penyiapannya:
import { body, head, html, meta, title } from 'javascript-to-html'
import { styles, container, stack, heading, text, button } from 'sitelo/ui'
export default () => html({ lang: 'id' },
head(
meta({ charset: 'utf-8' }),
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1' }),
title('Situs saya'),
styles(),
),
body(
container({ size: 'md' },
stack({ gap: 'md' },
heading({ level: 1 }, 'Halo'),
text({ variant: 'lead' }, 'Halaman yang dibangun dari komponen.'),
button({ href: '/docs' }, 'Baca dokumentasi'),
),
),
),
)Nama komponen sengaja cocok dengan apa yang direndernya, yang berarti beberapa di antaranya — button, input, table, link, code, select, progress — berbenturan dengan fungsi elemen javascript-to-html. Impor pustakanya sebagai namespace bila Anda butuh keduanya:
import * as ui from 'sitelo/ui'
ui.card(
ui.cardHeader({ title: 'Perutean', subtitle: 'Berbasis berkas' }),
ui.cardBody(ui.text('src/about.ht.js menjadi /about.')),
ui.cardFooter({ divided: true }, ui.button({ size: 'sm' }, 'Baca selengkapnya')),
)Konvensi pemanggilan
Setiap komponen menerima objek props opsional lalu anak-anaknya, persis seperti elemen javascript-to-html. Props yang dipahami komponen dikonsumsi berdasarkan namanya; selebihnya jatuh ke elemen hasil render sebagai atribut, sehingga id, data-*, aria-*, dan atribut peristiwa bekerja tanpa pustakanya perlu mendaftarkannya:
button({ id: 'save', 'data-analytics': 'save-click', onclick: 'save()' }, 'Simpan')
// <button type="button" id="save" data-analytics="save-click" onclick="save()" class="su-btn …">Props yang nilainya tidak dikenali komponen — variant: 'nonsense' — mundur ke nilai bawaan alih-alih melempar galat. Salah ketik yang sifatnya kosmetik seharusnya tidak menggagalkan build.
Penataan
styles() mengembalikan <link> ke satu berkas, yang disinggahkan peramban lintas halaman; plugin sitelo menyajikannya saat pengembangan dan menulisnya ke dalam build, dengan nama ber-hash konten yang bisa Anda sajikan sebagai immutable. { inline: true } justru mengembalikan <style> berisi seluruh lembarnya — sekitar 11 kB di jaringan, tanpa permintaan tambahan, dan tidak ada yang bisa hilang dari dist/:
import { styles } from 'sitelo/ui'
head(
// seluruh lembar gaya di dalam halaman — tanpa permintaan sama sekali
styles({ inline: true }),
)Lembar itu mencakup setiap komponen di pustaka, sementara sebuah situs hanya memakai segelintir. pruneCss: true di sitelo.config.js hanya menulis aturan yang bisa dicocokkan build: plugin membaca kelas su- dari halaman yang baru saja ditulisnya — dan dari skrip di sebelahnya, untuk kelas yang ditambahkan toast atau step belakangan — lalu membuang setiap aturan yang pemilihnya menyebut kelas yang tidak dibawa apa pun. Diputuskan dari keluarannya, bukan dari impornya, jadi button({ variant: 'soft' }) mempertahankan .su-btn--soft sedangkan button() biasa tidak. Lembar tertaut dipangkas terhadap seluruh situs dan mendapat hash baru, dengan setiap <link> ditulis ulang agar cocok; yang disisipkan dipangkas terhadap halamannya sendiri. Selusin komponen menjadi 2–3 kB ter-gzip. Pengembangan menyajikan seluruh lembarnya; markup yang tidak pernah dilihat build, seperti milik island server, perlu kelasnya disebutkan di keep:
export default {
pruneCss: true,
// atau sebutkan kelas yang tak pernah dilihat build; `*` untuk awalan
// pruneCss: { keep: ['su-card', 'su-btn*'] },
}Tema
Semuanya digerakkan properti kustom CSS pada :root — lima palet, skala jarak, radius, tipografi, dan bayangan. theme() menulis penimpanya, dan menerima nama camelCase (radiusMd → --su-radius-md), objek palet, atau properti kustom harfiah:
import { styles, theme } from 'sitelo/ui'
head(
styles(),
// Setelah styles(), jadi yang ini menang.
theme({
primary: { base: '#5b5bd6', hover: '#4a4ac4', fg: '#ffffff' },
radiusMd: '2px',
fontSans: '"Inter", system-ui, sans-serif',
}, {
dark: { primary: { base: '#8f8ff0' } },
}),
)Mode gelap diselesaikan sendiri dari prefers-color-scheme. Menyetel data-theme atau data-su-theme menjadi light atau dark pada leluhur mana pun akan menimpanya — dan itulah yang dilakukan themeToggle():
import { styles, themeScript, themeToggle } from 'sitelo/ui'
head(
themeScript(), // menerapkan pilihan tersimpan sebelum cat pertama
styles(),
)
// …di mana saja dalam body
themeToggle()Atau ubah seluruh tampilan sekaligus: styles({ preset: 'neumorphism' }) menautkan lembar sebuah preset tepat setelah lembar inti, setiap komponen mengikutinya, dan theme() tetap bekerja di atasnya. Lihat langsung di halaman Neumorfisme.
JavaScript, dan betapa sedikitnya
Sebagian besar komponen tidak membutuhkannya. Modal dan laci adalah elemen popover, jadi peramban menangani pembukaan, latar, klik di luar, dan Escape. Akordeon adalah <details name>. Menu adalah <details>. Tooltip adalah CSS. Tab yang panelnya bertukar di tempat adalah grup radio: tiap tab adalah <label>, dan panel yang mengikuti radio tercentang itulah yang ditampilkan CSS.
Tiga hal memang butuh skrip, dan masing-masing mengambil skripnya sendiri:
- tombol tutup pada peringatan yang bisa ditutup
- menutup menu lewat klik di luar atau Escape
- pengalih tema
Tidak ada yang perlu ditambahkan ke berkas entri Anda — impornya adalah atribut peristiwa itu sendiri:
<!-- rendered by alert({ dismissible: true }) -->
<button class="su-alert-dismiss"
onclick="import('/su/alert.js').then(m=>m.dismiss(this))">
×
</button>sitelo menyajikan modul-modul itu dari /su/ selagi Anda mengembangkan, dan menyalin yang benar-benar dirujuk halaman Anda ke dalam build. Masing-masing jauh di bawah satu kilobita, tidak ada yang diambil sebelum interaksi pertama, dan setiap komponen dirender dengan benar sampai saat itu tiba: menu membuka dan menutup sendiri, tombol tutupnya tidak melakukan apa-apa.
Pengecualiannya adalah toast(), karena tidak ada yang memicunya untuk Anda di halaman:
// src/main.js
import { toast } from 'sitelo/ui/client'Contoh
Formulir menyambungkan sendiri label, id, teks bantuan, dan pesan galatnya:
import { card, cardBody, cardFooter, button, stack, textField, selectField } from 'sitelo/ui'
card(
cardBody(
stack({ gap: 'md' },
textField({ label: 'Email', name: 'email', type: 'email', help: 'Tidak pernah dibagikan.' }),
textField({ label: 'Situs', name: 'site', startAdornment: 'https://', error: 'Bukan URL.' }),
selectField({ label: 'Paket', name: 'plan', options: ['Gratis', 'Pro'], value: 'Pro' }),
),
),
cardFooter({ divided: true }, button({ type: 'submit' }, 'Simpan')),
)Modal adalah popover dan pemicunya adalah tombol mana pun yang menunjuk id-nya:
import { button, modal } from 'sitelo/ui'
button({ popovertarget: 'confirm' }, 'Hapus…')
modal({
id: 'confirm',
title: 'Hapus halaman ini?',
footer: button({ color: 'danger' }, 'Hapus'),
}, 'Ini tidak bisa dibatalkan.')Tab hadir dalam dua bentuk — tautan, atau panel:
// Tab tautan: satu halaman per tab, tanpa skrip sama sekali.
tabs({ items: [
{ label: 'Dokumentasi', href: '/docs', active: true },
{ label: 'API', href: '/api' },
] })
// Tab panel: bertukar di tempat, dengan grup radio dan CSS.
tabs({ value: 'use', items: [
{ id: 'install', label: 'Pasang', panel: code('npm install sitelo') },
{ id: 'use', label: 'Pakai', panel: code("import * as ui from 'sitelo/ui'") },
] })Tabel menerima columns dan rows, dengan fungsi render di mana pun sebuah sel butuh lebih dari sekadar nilai:
table({
striped: true,
columns: [
{ key: 'page', header: 'Halaman' },
{ key: 'size', header: 'Ukuran', align: 'end' },
{ header: 'Status', render: (row) => chip({ color: row.ok ? 'success' : 'danger' }, row.ok ? 'ok' : 'gagal') },
],
rows: pages,
})Direktori examples/ui di repositori merender setiap komponen dalam satu halaman — itu cara tercepat melihat keseluruhan kumpulannya.
Rujukan komponen
Setiap ekspor, menurut grup. Props-nya bertipe: sitelo/ui menyertakan berkas .d.ts, jadi editor melengkapi variant, color, dan size untuk Anda di JavaScript maupun TypeScript.
| Grup | Komponen |
|---|---|
| Tata letak | container, stack, grid, divider, card, cardHeader, cardTitle, cardSubtitle, cardMedia, cardBody, cardFooter, aspectRatio |
| Tipografi | text, heading, link, code, inlineCode, kbd, visuallyHidden, prose |
| Masukan | button, iconButton, buttonGroup, field, input, textarea, select, textField, textareaField, selectField, checkbox, radio, toggle, choiceGroup, slider, sliderField, toggleButton, toggleGroup |
| Tampilan data | avatar, avatarGroup, badge, chip, tooltip, table, list, listItem, figure |
| Umpan balik | alert, progress, skeleton, toasts, empty |
| Navigasi | breadcrumbs, pagination, tabs, appBar, appBarNav, appBarSpacer, appBarActions, navLink, themeToggle |
| Lapisan | modal, drawer, closeButton, menu, menuItem, menuSeparator, accordion, accordionItem, collapsible |
| Bagian | hero, footer, siteFooter, footerColumn, footerBottom, stat, statGroup, steps, timeline, timelineItem, mockup |
| Penataan | styles, stylesheet, stylesUrl, theme, themeScript |
Dua nama berbeda dari dugaan Anda: sakelarnya adalah toggle, karena switch adalah kata kunci dan tidak bisa menjadi pengikat impor; dan tautan bergaya diekspor sebagai link sekaligus textLink, agar bisa berdampingan dengan link milik javascript-to-html. table, input, select, dan progress punya jalan keluar yang sama: dataTable, textInput, selectField, progressBar.
Tambahan
Titik masuk kedua, sitelo/ui-extras, memuat komponen yang tidak untuk semua orang — tekstur dan efek, dimulai dari butiran film. Masing-masing membawa lembar gayanya sendiri, grainStyles() di samping styles(), sehingga sebuah halaman hanya menautkan apa yang dipakainya, dan sitelo/ui-extras/client membawa pemanggilan sisi halamannya. Semuanya didaftar di sitelo UI extras.