@svadmin/ui 0.24.1 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svadmin/ui",
3
- "version": "0.24.1",
3
+ "version": "0.25.1",
4
4
  "description": "Pre-built admin UI components — AdminApp, AutoTable, AutoForm, Sidebar, Layout",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -28,7 +28,6 @@
28
28
  import * as DropdownMenu from './ui/dropdown-menu/index.js';
29
29
  import * as PaginationUI from './ui/pagination/index.js';
30
30
  import * as ContextMenu from './ui/context-menu/index.js';
31
- import { Select } from './ui/select/index.js';
32
31
  import {
33
32
  Plus, Pencil, Trash2,
34
33
  Search, Download, Upload, ChevronDown, ChevronUp, SlidersHorizontal, Filter as FilterIcon,
@@ -60,6 +59,8 @@
60
59
  pagination?: { current: number; pageSize: number };
61
60
  /** Externally controlled sorters */
62
61
  sorters?: Sort[];
62
+ /** Custom batch actions to render when rows are selected */
63
+ batchActions?: Snippet<[{ selectedIds: string[] }]>;
63
64
  }
64
65
 
65
66
  let {
@@ -71,6 +72,7 @@
71
72
  rowActions,
72
73
  emptyState,
73
74
  expandedRowRender,
75
+ batchActions,
74
76
  pagination: externalPagination,
75
77
  sorters: externalSorters,
76
78
  }: Props = $props();
@@ -353,10 +355,20 @@
353
355
  </Button>
354
356
  {/if}
355
357
  {#if selectedCount > 0 && canDelete}
356
- <Button variant="destructive" size="sm" onclick={confirmBatchDelete}>
358
+ <Button
359
+ variant="destructive"
360
+ size="sm"
361
+ class="h-9 whitespace-nowrap"
362
+ onclick={confirmBatchDelete}
363
+ >
357
364
  <Trash2 class="h-4 w-4" data-icon="inline-start" /> {t('common.batchDelete', { count: selectedCount })}
358
365
  </Button>
359
366
  {/if}
367
+
368
+ {#if selectedCount > 0 && batchActions}
369
+ {@render batchActions({ selectedIds: Object.keys(rowSelection) })}
370
+ {/if}
371
+
360
372
  <!-- Column Visibility Picker (DropdownMenu) -->
361
373
  <DropdownMenu.Root>
362
374
  <DropdownMenu.Trigger>
@@ -423,21 +435,23 @@
423
435
  <div class="space-y-1">
424
436
  <label class="text-xs text-muted-foreground" for="filter-{field.key}">{field.label}</label>
425
437
  {#if field.type === 'select' && field.options}
426
- <Select
438
+ <select
427
439
  id="filter-{field.key}"
428
- class="h-9 text-sm w-full font-normal"
429
- bind:value={filterValues[field.key]}
440
+ class="h-9 text-sm w-full font-normal flex w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
441
+ value={filterValues[field.key] ?? ''}
442
+ onchange={(e) => filterValues[field.key] = (e.currentTarget as HTMLSelectElement).value}
430
443
  >
431
444
  <option value="">全部</option>
432
445
  {#each field.options as opt}
433
446
  <option value={opt.value}>{opt.label}</option>
434
447
  {/each}
435
- </Select>
448
+ </select>
436
449
  {:else}
437
450
  <Input
438
451
  id="filter-{field.key}"
439
452
  type="text"
440
- bind:value={filterValues[field.key]}
453
+ value={filterValues[field.key] ?? ''}
454
+ oninput={(e) => filterValues[field.key] = (e.currentTarget as HTMLInputElement).value}
441
455
  placeholder={field.label}
442
456
  class="h-9 text-sm"
443
457
  />
@@ -755,18 +769,21 @@
755
769
  <div class="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground">
756
770
  <div class="flex items-center gap-2">
757
771
  <span>{t('common.total', { total: query.data?.total ?? 0 })}</span>
758
- <Select
759
- class="hidden sm:inline-block h-8 w-auto text-xs"
772
+ <select
773
+ class="h-8 w-[70px] px-1 py-1 flex items-center justify-between rounded-md border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
760
774
  value={String(pagination.pageSize ?? 10)}
761
- onchange={(e: Event) => {
775
+ onchange={(e) => {
762
776
  const size = Number((e.target as HTMLSelectElement).value);
763
- pagination = { ...pagination, pageSize: size, current: 1 };
777
+ if (!isNaN(size)) {
778
+ pagination = { ...pagination, pageSize: size, current: 1 };
779
+ }
764
780
  }}
765
781
  >
766
- {#each [10, 20, 50, 100] as size}
767
- <option value={size}>{size} / {t('common.perPage')}</option>
768
- {/each}
769
- </Select>
782
+ <option value="10">10</option>
783
+ <option value="20">20</option>
784
+ <option value="50">50</option>
785
+ <option value="100">100</option>
786
+ </select>
770
787
  </div>
771
788
  <PaginationUI.Root>
772
789
  <PaginationUI.Content>