İçeriğe geç
BigBang

Sık açılanlar

    ↑↓Gezin↵AçEscKapat
    EN

    Kalıplar

    Toplu işlemler

    Birden çok satırı seçip tek eylemle işlemek; çubuğun ne zaman görüneceği, sayının nasıl bildirileceği ve silmenin nasıl onaylanacağı.

    Toplu işlem, kullanıcının birçok satıra aynı eylemi tek adımda uygulamasını sağlar. Bu kalıp seçimi, eylem çubuğunu ve sonucun bildirilmesini sabitler.

    • Kullanıcının tablo ya da listede aynı eylemi çok sayıda satıra uygulaması gerektiğinde.
    • Eylemler seçili öğelerin tümü için anlamlıysa: arşivleme, dışa aktarma, silme.
    • Tek satırlık eylemler için satır eylemlerini kullanın; çubuk gerekmez.

    Satırları seçin. Çubuk ilk seçimle belirir ve sayıyı gösterir. “Arşivle” seçimi temizler ve sonucu “Geri al” eylemli bir bildirimle söyler. “Sil” önce bir onay penceresi açar. Çubukta Escape seçimi temizler.

    Canlı örnek, StorybookStorybook'ta aç
    Öğe listesi
    Durum
    Öğe 1Etkin50
    Öğe 2Beklemede100
    Öğe 3Taslak150
    Öğe 4Etkin200
    Öğe 5Beklemede250
    Öğe 6Taslak300
    Öğe 7Etkin350
    Öğe 8Beklemede400
    Silme, sayıyı düğmede gösteren bir onay ister: “3 öğeyi sil”. Onay kalıbı
    import { ActionBar, AlertDialog, createDataTableColumnHelper, DataTable, Link, Stack, StatusBadge, Text, ToolbarButton, useToast, type DataTableRowSelection } from '@bigbang/ui';
    import { useMemo, useState } from 'react';
    import { type Lang, LangProvider } from '../lang';
    const copy = {
    tr: {
    caption: 'Öğe listesi',
    name: 'Ad',
    status: 'Durum',
    count: 'Adet',
    item: 'Öğe',
    archive: 'Arşivle',
    export: 'Dışa aktar',
    delete: 'Sil',
    selected: (count: number) => `${count} öğe seçildi`,
    archived: (count: number) => `${count} öğe arşivlendi`,
    exported: (count: number) => `${count} öğe dışa aktarıldı`,
    deleted: (count: number) => `${count} öğe silindi`,
    undo: 'Geri al',
    confirmTitle: (count: number) => `${count} öğe silinsin mi?`,
    confirmText: 'Seçili öğeler listeden kaldırılır. Bu işlem geri alınamaz.',
    confirmLabel: (count: number) => `${count} öğeyi sil`,
    cancel: 'Vazgeç',
    rule: (count: number) => `Silme, sayıyı düğmede gösteren bir onay ister: “${count} öğeyi sil”.`,
    ruleLink: 'Onay kalıbı',
    confirmHref: '/patterns/confirmation/',
    },
    en: {
    caption: 'Item list',
    name: 'Name',
    status: 'Status',
    count: 'Count',
    item: 'Item',
    archive: 'Archive',
    export: 'Export',
    delete: 'Delete',
    selected: (count: number) => `${count} selected`,
    archived: (count: number) => `${count} ${count === 1 ? 'item' : 'items'} archived`,
    exported: (count: number) => `${count} ${count === 1 ? 'item' : 'items'} exported`,
    deleted: (count: number) => `${count} ${count === 1 ? 'item' : 'items'} deleted`,
    undo: 'Undo',
    confirmTitle: (count: number) => `Delete ${count} ${count === 1 ? 'item' : 'items'}?`,
    confirmText: 'The selected items are removed from the list. This cannot be undone.',
    confirmLabel: (count: number) => `Delete ${count} ${count === 1 ? 'item' : 'items'}`,
    cancel: 'Cancel',
    rule: (count: number) => `Deleting asks for a confirmation that shows the count on the button: “Delete ${count} ${count === 1 ? 'item' : 'items'}”.`,
    ruleLink: 'Confirmation pattern',
    confirmHref: '/en/patterns/confirmation/',
    },
    };
    type Row = { id: string; name: string; status: 'active' | 'pending' | 'draft' | 'archived'; count: number };
    const statusOrder = ['active', 'pending', 'draft'] as const;
    const helper = createDataTableColumnHelper<Row>();
    /**
    * A table with row selection and an action bar. The bar appears with the first selected row and says how many are selected.
    * An action runs on all selected rows, clears the selection and reports the result in a toast; archive offers Undo.
    * Delete asks for confirmation first, with the count in the dialog title and on its button.
    */
    export function BulkActionsDemo({ lang = 'tr' }: { lang?: Lang }) {
    return (
    <LangProvider lang={lang}>
    <BulkTable lang={lang} />
    </LangProvider>
    );
    }
    function BulkTable({ lang }: { lang: Lang }) {
    const t = copy[lang];
    const toast = useToast();
    const [rows, setRows] = useState<Row[]>(() =>
    Array.from({ length: 8 }, (_, index) => ({ id: `row-${index + 1}`, name: `${t.item} ${index + 1}`, status: statusOrder[index % statusOrder.length] ?? 'draft', count: (index + 1) * 50 })),
    );
    const [selection, setSelection] = useState<DataTableRowSelection>({});
    const [confirmOpen, setConfirmOpen] = useState(false);
    const count = Object.keys(selection).length;
    const columns = useMemo(
    () => [
    helper.accessor('name', { header: t.name, meta: { rowHeader: true } }),
    helper.accessor('status', { header: t.status, enableSorting: false, cell: (context) => <StatusBadge status={context.getValue()} /> }),
    helper.accessor('count', { header: t.count, meta: { numeric: true } }),
    ],
    [t],
    );
    const archive = () => {
    const previous = new Map(rows.filter((row) => selection[row.id]).map((row) => [row.id, row.status]));
    setRows((current) => current.map((row) => (previous.has(row.id) ? { ...row, status: 'archived' } : row)));
    toast.show({
    title: t.archived(count),
    tone: 'success',
    action: { label: t.undo, onClick: () => setRows((current) => current.map((row) => (previous.has(row.id) ? { ...row, status: previous.get(row.id) ?? row.status } : row))) },
    });
    setSelection({});
    };
    const exportRows = () => {
    toast.show({ title: t.exported(count), tone: 'success' });
    setSelection({});
    };
    const deleteRows = () => {
    setRows((current) => current.filter((row) => !selection[row.id]));
    toast.show({ title: t.deleted(count), tone: 'success' });
    setSelection({});
    };
    return (
    <>
    <Stack gap="md">
    <ActionBar placement="inline" count={count} countLabel={t.selected} onClear={() => setSelection({})}>
    <ToolbarButton label={t.archive} icon="file" onClick={archive} />
    <ToolbarButton label={t.export} icon="download" onClick={exportRows} />
    <ToolbarButton label={t.delete} icon="trash" onClick={() => setConfirmOpen(true)} />
    </ActionBar>
    <DataTable<Row>
    columns={columns}
    data={rows}
    getRowId={(row) => row.id}
    getRowLabel={(row) => row.name}
    caption={t.caption}
    captionHidden
    selectionMode="multiple"
    rowSelection={selection}
    onRowSelectionChange={setSelection}
    // The action bar announces the count; the table stays quiet so it is read once.
    messages={{ 'selected-count': '' }}
    />
    <Text size="sm" tone="subtle">
    {t.rule(Math.max(count, 3))} <Link href={t.confirmHref}>{t.ruleLink}</Link>
    </Text>
    </Stack>
    <AlertDialog
    open={confirmOpen}
    onOpenChange={setConfirmOpen}
    title={t.confirmTitle(count)}
    description={t.confirmText}
    confirmLabel={t.confirmLabel(count)}
    cancelLabel={t.cancel}
    tone="danger"
    onConfirm={deleteRows}
    />
    </>
    );
    }
    Kural Değer
    Çubuk Yalnızca en az 1 seçim varken görünür.
    Yerleşim Sayfa uzunsa placement="floating" (görünüm alanının altına sabit); tablonun üstünde sabit alan varsa placement="inline". Örnekte inline.
    Eylem sayısı 3 ile 5 arası. Sık kullanılan eylem solda, yıkıcı eylem en sonda.
    Sayı Çubukta “3 öğe seçildi”; ekran okuyucuya bir kez duyurulur.
    Escape Çubuk içinde seçimi temizler.
    Başlık onay kutusu Görünen sayfadaki satırları seçer.
    Tüm sayfalar “Tüm 1.000 öğeyi seç” bağlantısı sunulur; sayfaya özgü seçimle karışmaz.
    Eylem sonrası Seçim temizlenir; sonuç bir Toast ile bildirilir: “3 öğe arşivlendi”. Geri alınabilen eylemde bildirim “Geri al” sunar.
    Yıkıcı eylem AlertDialog ile onay ister; sayı başlıkta ve düğmede yer alır: “3 öğe silinsin mi?”, “3 öğeyi sil”. Bkz. Onay.
    YapınYıkıcı onay düğmesi sayıyı söyler.
    YapmayınSayısız düğme kullanıcıyı neyi sildiğinden emin bırakmaz.
    3 öğe arşivlendi
    YapınSonuç, ne kadar öğenin etkilendiğini söyler.
    İşlem tamamlandı
    YapmayınGenel bir metin etkiyi belirsiz bırakır.
    1. Kullanıcı bir satır ya da başlık onay kutusunu seçer. Başlık onay kutusu yalnızca görünen sayfayı seçer.
    2. Çubuk belirir ve seçili sayıyı gösterir. Birden çok sayfa varsa “Tüm N öğeyi seç” bağlantısı sunulur.
    3. Kullanıcı bir eylem seçer. Eylem tüm seçili satırlara uygulanır.
    4. Eylem bitince seçim temizlenir, çubuk kapanır ve bir bildirim sonucu söyler. Arşivleme gibi geri alınabilir eylemde bildirim “Geri al” sunar.
    5. Silme önce onay ister: sayıyı başlıkta ve düğmede taşıyan, tehlike tonlu bir AlertDialog açılır. Odak “Vazgeç”te başlar; vazgeçilirse satırlar ve seçim yerinde kalır. Onay iletişim kutusunun ayrıntıları Onay kalıbında tanımlıdır.
    • Çubuk, “Toplu eylemler” adlı bir araç çubuğudur; oklar eylemler arasında gezdirir.
    • Seçili sayı bir durum bölgesinde nazikçe ve bir kez okunur. Tablonun kendi seçim duyurusu, örnekte kapatılır; böylece sayı iki kez okunmaz.
    • “Seçimi temizle” ilk düğmedir; Escape ile aynı işi yapar.
    • Her satır onay kutusu satırı adıyla söyler: “Öğe 1 satırını seç”.
    • Eylem sonucu, odak değişmeden “Bildirimler” bölgesinde nazikçe duyurulur (WCAG 4.1.3). Geri al eylemi bildirimin içinde bir düğmedir.
    • Onay penceresi alertdialog rolündedir; dışarı tıklamayla kapanmaz.
    • Eylem adları fiildir: “Arşivle”, “Dışa aktar”, “Sil”.
    • Sonuç sayıyı ve fiili verir: “3 öğe arşivlendi”.
    • Yıkıcı onay düğmesi sayıyı taşır: “3 öğeyi sil”.
    • Tüm sayfalar bağlantısı toplamı söyler: “Tüm 1.000 öğeyi seç”.
    Öğe Hareket Preset
    Çubuğun belirmesi 240 ms, 8 px yukarı kayma ve solma motion.toast
    Sayı değişimi 110 ms çapraz solma; sayaç animasyonu yok motion.reveal
    Eylem düğmeleri Basınca 0,97 ölçek motion.press

    Hareketi azaltma tercihinde kayma kalkar, yalnızca solma kalır.

    DataTable, ActionBar, Toolbar, Toast, AlertDialog, StatusBadge, Link, Button. İlgili kalıplar: Onay, Filtreleme, Veri dışa aktarma.