@placeholderco/placeholder-ui 1.0.11 → 2.0.0
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/LICENSE +1 -1
- package/README.md +134 -130
- package/dist/app.css +178 -0
- package/dist/bootstrap.min.css +3600 -0
- package/dist/cards/GitCard.svelte +115 -0
- package/dist/cards/GitCard.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte +29 -17
- package/dist/display/Avatar.svelte.d.ts +12 -2
- package/dist/display/LinkCollection.svelte +40 -18
- package/dist/display/LinkCollection.svelte.d.ts +9 -2
- package/dist/display/Paper.svelte +31 -19
- package/dist/display/Paper.svelte.d.ts +12 -3
- package/dist/display/alert/Alert.svelte +129 -0
- package/dist/display/alert/Alert.svelte.d.ts +15 -0
- package/dist/display/alert/AlertVariant.d.ts +1 -0
- package/dist/display/alert/AlertVariant.js +1 -0
- package/dist/display/filetree/FileTree.svelte +259 -0
- package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
- package/dist/display/filetree/FileTreeItem.svelte +396 -0
- package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
- package/dist/display/filetree/FileTreeNode.d.ts +46 -0
- package/dist/display/filetree/FileTreeNode.js +115 -0
- package/dist/display/filetree/index.d.ts +5 -0
- package/dist/display/filetree/index.js +3 -0
- package/dist/editors/CodeMirror.svelte +306 -0
- package/dist/editors/CodeMirror.svelte.d.ts +31 -0
- package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
- package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
- package/dist/editors/tiptap/TipTap.svelte +856 -0
- package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
- package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
- package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
- package/dist/editors/tiptap/collaboration.d.ts +55 -0
- package/dist/editors/tiptap/collaboration.js +1 -0
- package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
- package/dist/editors/tiptap/extensions/Alert.js +72 -0
- package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
- package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
- package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
- package/dist/editors/tiptap/extensions/Div.js +89 -0
- package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
- package/dist/editors/tiptap/extensions/Span.js +56 -0
- package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
- package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
- package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
- package/dist/editors/tiptap/extensions/index.d.ts +7 -0
- package/dist/editors/tiptap/extensions/index.js +5 -0
- package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
- package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
- package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
- package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
- package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
- package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
- package/dist/form/Autocomplete.svelte +270 -137
- package/dist/form/Autocomplete.svelte.d.ts +58 -10
- package/dist/form/AutocompleteMulti.svelte +385 -227
- package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
- package/dist/form/Checkbox.svelte +124 -43
- package/dist/form/Checkbox.svelte.d.ts +26 -2
- package/dist/form/Chips.svelte +47 -17
- package/dist/form/Chips.svelte.d.ts +24 -3
- package/dist/form/ComboBox.svelte +30 -20
- package/dist/form/ComboBox.svelte.d.ts +1 -1
- package/dist/form/ComboBoxItemBuilder.svelte +161 -188
- package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
- package/dist/form/ComboBoxMulti.svelte +38 -24
- package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
- package/dist/form/CronBuilder.svelte +84 -67
- package/dist/form/CronBuilder.svelte.d.ts +16 -3
- package/dist/form/DatePicker.svelte +177 -191
- package/dist/form/DatePicker.svelte.d.ts +17 -2
- package/dist/form/DateRangePicker.svelte +775 -0
- package/dist/form/DateRangePicker.svelte.d.ts +23 -0
- package/dist/form/DateTimePicker.svelte +168 -209
- package/dist/form/DateTimePicker.svelte.d.ts +10 -2
- package/dist/form/FormGroup.svelte +33 -10
- package/dist/form/FormGroup.svelte.d.ts +12 -2
- package/dist/form/Number.svelte +71 -29
- package/dist/form/Number.svelte.d.ts +39 -6
- package/dist/form/Radio.svelte +174 -0
- package/dist/form/Radio.svelte.d.ts +21 -0
- package/dist/form/RadioGroup.svelte +52 -138
- package/dist/form/RadioGroup.svelte.d.ts +19 -2
- package/dist/form/SegmentedControl.svelte +103 -57
- package/dist/form/SegmentedControl.svelte.d.ts +12 -2
- package/dist/form/Select.svelte +160 -229
- package/dist/form/Select.svelte.d.ts +35 -6
- package/dist/form/SelectMulti.svelte +166 -277
- package/dist/form/SelectMulti.svelte.d.ts +37 -6
- package/dist/form/Slider.svelte +185 -268
- package/dist/form/Slider.svelte.d.ts +33 -16
- package/dist/form/StringArrayBuilder.svelte +249 -0
- package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
- package/dist/form/Switch.svelte +164 -106
- package/dist/form/Switch.svelte.d.ts +22 -3
- package/dist/form/TextArea.svelte +80 -45
- package/dist/form/TextArea.svelte.d.ts +35 -10
- package/dist/form/Textbox.svelte +80 -47
- package/dist/form/Textbox.svelte.d.ts +41 -8
- package/dist/form/TimePicker.svelte +42 -47
- package/dist/form/TimePicker.svelte.d.ts +12 -2
- package/dist/form/comboBoxCore.svelte.d.ts +99 -0
- package/dist/form/comboBoxCore.svelte.js +243 -0
- package/dist/icon/Icon.svelte +8 -3
- package/dist/icon/Icon.svelte.d.ts +8 -3
- package/dist/icon/cube-send.svg +1 -0
- package/dist/icon/file-type-bmp.svg +1 -0
- package/dist/icon/file-type-csv.svg +1 -0
- package/dist/icon/file-type-doc.svg +1 -0
- package/dist/icon/file-type-docx.svg +1 -0
- package/dist/icon/file-type-jpg.svg +1 -0
- package/dist/icon/file-type-pdf.svg +1 -0
- package/dist/icon/file-type-png.svg +1 -0
- package/dist/icon/file-type-ppt.svg +1 -0
- package/dist/icon/file-type-svg.svg +1 -0
- package/dist/icon/file-type-txt.svg +1 -0
- package/dist/icon/file-type-xls.svg +1 -0
- package/dist/icon/file-type-zip.svg +1 -0
- package/dist/icon/index.d.ts +166 -145
- package/dist/icon/index.js +166 -146
- package/dist/icon/layout-sidebar-left-collapse.svg +1 -0
- package/dist/icon/layout-sidebar-left-expand.svg +1 -0
- package/dist/icon/logo-placeholder.svg +6 -0
- package/dist/icon/paperclip.svg +1 -0
- package/dist/icon/source-code.svg +1 -0
- package/dist/icon/sun-moon.svg +1 -0
- package/dist/icon/table.svg +6 -0
- package/dist/icon/thumb-down.svg +1 -0
- package/dist/icon/thumb-up.svg +1 -0
- package/dist/index.d.ts +93 -22
- package/dist/index.js +28 -27
- package/dist/layout/AppShell.svelte +12 -162
- package/dist/layout/AppShell.svelte.d.ts +6 -27
- package/dist/layout/CustomNavbar.svelte +9 -7
- package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
- package/dist/layout/Navbar.svelte +158 -110
- package/dist/layout/Navbar.svelte.d.ts +26 -12
- package/dist/layout/NavbarItemDisplay.svelte +2 -2
- package/dist/layout/NavbarItemView.svelte +182 -0
- package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
- package/dist/layout/Sidenav.svelte +280 -341
- package/dist/layout/Sidenav.svelte.d.ts +36 -4
- package/dist/models/ComboBoxItem.d.ts +2 -0
- package/dist/models/Employee.d.ts +53 -0
- package/dist/models/Employee.js +23 -0
- package/dist/models/Hyperlink.d.ts +3 -1
- package/dist/models/LinkCollectionItem.d.ts +3 -1
- package/dist/models/NavbarItem.d.ts +6 -2
- package/dist/theme.svelte.d.ts +0 -1
- package/dist/theme.svelte.js +46 -58
- package/dist/ui/Accordion.svelte +81 -242
- package/dist/ui/Accordion.svelte.d.ts +37 -14
- package/dist/ui/AccordionItem.svelte +303 -0
- package/dist/ui/AccordionItem.svelte.d.ts +21 -0
- package/dist/ui/ActionIcon.svelte +25 -21
- package/dist/ui/ActionIcon.svelte.d.ts +15 -2
- package/dist/ui/Badge.svelte +170 -161
- package/dist/ui/Badge.svelte.d.ts +16 -4
- package/dist/ui/Button.svelte +178 -205
- package/dist/ui/Button.svelte.d.ts +19 -2
- package/dist/ui/ButtonVariant.d.ts +15 -1
- package/dist/ui/ContextMenu.svelte +146 -0
- package/dist/ui/ContextMenu.svelte.d.ts +37 -0
- package/dist/ui/ContextMenuList.svelte +188 -0
- package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
- package/dist/ui/Dialog.svelte +183 -104
- package/dist/ui/Dialog.svelte.d.ts +21 -2
- package/dist/ui/Drawer.svelte +237 -184
- package/dist/ui/Drawer.svelte.d.ts +20 -2
- package/dist/ui/Dropdown.svelte +24 -14
- package/dist/ui/Dropdown.svelte.d.ts +11 -2
- package/dist/ui/Dropzone.svelte +159 -57
- package/dist/ui/Dropzone.svelte.d.ts +29 -2
- package/dist/ui/Link.svelte +12 -4
- package/dist/ui/Link.svelte.d.ts +8 -2
- package/dist/ui/Loader.svelte +23 -18
- package/dist/ui/Loader.svelte.d.ts +5 -2
- package/dist/ui/Logo.svelte +37 -0
- package/dist/ui/Logo.svelte.d.ts +16 -0
- package/dist/ui/MultiSortable.svelte +287 -0
- package/dist/ui/MultiSortable.svelte.d.ts +50 -0
- package/dist/ui/Pagination.svelte +12 -6
- package/dist/ui/Pagination.svelte.d.ts +6 -2
- package/dist/ui/Popover.svelte +43 -65
- package/dist/ui/Popover.svelte.d.ts +14 -5
- package/dist/ui/ProgressBar.svelte +169 -0
- package/dist/ui/ProgressBar.svelte.d.ts +30 -0
- package/dist/ui/ProgressBarVariant.d.ts +7 -0
- package/dist/ui/ProgressBarVariant.js +1 -0
- package/dist/ui/SegmentedControl.svelte +0 -0
- package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
- package/dist/ui/Sortable.svelte +163 -0
- package/dist/ui/Sortable.svelte.d.ts +47 -0
- package/dist/ui/Table.svelte +497 -56
- package/dist/ui/Table.svelte.d.ts +64 -2
- package/dist/ui/Tabs.svelte +22 -18
- package/dist/ui/Tabs.svelte.d.ts +6 -2
- package/dist/ui/ThemeSwitcher.svelte +26 -7
- package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
- package/dist/ui/Tooltip.svelte +312 -180
- package/dist/ui/Tooltip.svelte.d.ts +4 -3
- package/dist/uiTheme.svelte.d.ts +86 -0
- package/dist/uiTheme.svelte.js +214 -0
- package/dist/util/DateFunctions.js +1 -1
- package/dist/util/DragDrop.d.ts +50 -0
- package/dist/util/DragDrop.js +154 -0
- package/dist/util/NavigateTo.js +2 -2
- package/dist/util/dayjs.d.ts +4 -0
- package/dist/util/dayjs.js +15 -0
- package/dist/util/interceptLinkClick.d.ts +13 -0
- package/dist/util/interceptLinkClick.js +33 -0
- package/package.json +66 -26
- package/dist/display/Alert.svelte +0 -179
- package/dist/display/Alert.svelte.d.ts +0 -13
- package/dist/form/FileInput.svelte +0 -235
- package/dist/form/FileInput.svelte.d.ts +0 -23
- package/dist/form/PasswordInput.svelte +0 -252
- package/dist/form/PasswordInput.svelte.d.ts +0 -33
- package/dist/form/Rating.svelte +0 -235
- package/dist/form/Rating.svelte.d.ts +0 -21
- package/dist/styles/components.css +0 -199
- package/dist/styles/dark.css +0 -146
- package/dist/styles/index.css +0 -116
- package/dist/styles/reset.css +0 -110
- package/dist/styles/semantic.css +0 -86
- package/dist/styles/tokens.css +0 -203
- package/dist/styles/utilities.css +0 -523
- package/dist/ui/Breadcrumbs.svelte +0 -131
- package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
- package/dist/ui/LoadingOverlay.svelte +0 -53
- package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
- package/dist/ui/Progress.svelte +0 -191
- package/dist/ui/Progress.svelte.d.ts +0 -15
- package/dist/ui/RingProgress.svelte +0 -141
- package/dist/ui/RingProgress.svelte.d.ts +0 -18
- package/dist/ui/Skeleton.svelte +0 -85
- package/dist/ui/Skeleton.svelte.d.ts +0 -12
- package/dist/ui/Stepper.svelte +0 -355
- package/dist/ui/Stepper.svelte.d.ts +0 -24
- package/dist/ui/Timeline.svelte +0 -225
- package/dist/ui/Timeline.svelte.d.ts +0 -23
- /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
- /package/dist/{actions → util}/ClickOutside.js +0 -0
- /package/dist/{transitions → util}/Transitions.d.ts +0 -0
- /package/dist/{transitions → util}/Transitions.js +0 -0
package/dist/ui/Table.svelte
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { type Snippet } from 'svelte';
|
|
3
3
|
import Textbox from '../form/Textbox.svelte';
|
|
4
|
+
import Checkbox from '../form/Checkbox.svelte';
|
|
4
5
|
import Icon from '../icon/Icon.svelte';
|
|
5
|
-
import
|
|
6
|
+
import Pagination from './Pagination.svelte';
|
|
7
|
+
import {
|
|
8
|
+
iconArrowsSort,
|
|
9
|
+
iconChevronDown,
|
|
10
|
+
iconChevronRight,
|
|
11
|
+
iconChevronUp,
|
|
12
|
+
iconSearch
|
|
13
|
+
} from '../icon/index.js';
|
|
14
|
+
import { navigateTo } from '../util/NavigateTo.js';
|
|
6
15
|
|
|
7
16
|
export interface Column<T = any> {
|
|
8
17
|
key: string;
|
|
@@ -10,23 +19,81 @@
|
|
|
10
19
|
sortable?: boolean;
|
|
11
20
|
width?: string;
|
|
12
21
|
align?: 'left' | 'center' | 'right';
|
|
22
|
+
/** Snippet rendered as the cell content. Takes precedence over `render`. */
|
|
23
|
+
cell?: Snippet<[{ value: any; row: T; index: number }]>;
|
|
24
|
+
/** @deprecated Returns raw HTML injected via {@html} — unsafe for untrusted
|
|
25
|
+
* data and cannot render components. Use `cell` instead. */
|
|
13
26
|
render?: (value: any, row: T) => any;
|
|
14
27
|
}
|
|
15
28
|
|
|
16
|
-
interface
|
|
29
|
+
export interface TableProps<T = any> {
|
|
30
|
+
/** Column definitions for the table */
|
|
17
31
|
columns: Column<T>[];
|
|
32
|
+
/** Data rows to display */
|
|
18
33
|
rows: T[];
|
|
34
|
+
/** Enable search/filter functionality */
|
|
19
35
|
searchable?: boolean;
|
|
36
|
+
/** Placeholder text for search input */
|
|
20
37
|
searchPlaceholder?: string;
|
|
38
|
+
/** Additional CSS classes */
|
|
21
39
|
class?: string;
|
|
40
|
+
/** Enable alternating row colors */
|
|
22
41
|
striped?: boolean;
|
|
42
|
+
/** Disable rounded corners on table container */
|
|
23
43
|
notRounded?: boolean;
|
|
44
|
+
/** Enable hover effect on rows */
|
|
24
45
|
hover?: boolean;
|
|
46
|
+
/** Message shown when no data is available */
|
|
25
47
|
emptyMessage?: string;
|
|
48
|
+
/** Show loading state */
|
|
26
49
|
loading?: boolean;
|
|
50
|
+
/** Content to render below the table */
|
|
27
51
|
children?: Snippet;
|
|
52
|
+
/** Action buttons snippet, receives row data and index */
|
|
28
53
|
buttons?: Snippet<[T, number]>;
|
|
54
|
+
/** Callback when a row is clicked */
|
|
29
55
|
onrowclick?: (row: T, index: number) => void;
|
|
56
|
+
/** Returns a URL for a row. When provided, rows act as links: a plain click
|
|
57
|
+
* navigates client-side, while middle-click or ctrl/cmd/shift-click opens the
|
|
58
|
+
* URL in a new tab. Return a falsy value to make a row non-navigable. */
|
|
59
|
+
rowHref?: (row: T, index: number) => string | undefined | null;
|
|
60
|
+
/** Enable checkbox selection */
|
|
61
|
+
selectable?: boolean;
|
|
62
|
+
/** Field name used to uniquely identify rows (required when selectable is true) */
|
|
63
|
+
rowKey?: string;
|
|
64
|
+
/** Currently selected row objects (bindable) */
|
|
65
|
+
selectedRows?: T[];
|
|
66
|
+
/** Callback when selection changes */
|
|
67
|
+
onselect?: (selectedRows: T[]) => void;
|
|
68
|
+
/** Detail content rendered in a full-width row beneath an expanded row.
|
|
69
|
+
* Providing this enables row expansion: expandable rows toggle on row click
|
|
70
|
+
* or via their chevron button. Requires rowKey. */
|
|
71
|
+
expandedContent?: Snippet<[T, number]>;
|
|
72
|
+
/** Limits which rows can expand (e.g. only group rows). Default: all rows. */
|
|
73
|
+
canExpand?: (row: T, index: number) => boolean;
|
|
74
|
+
/** Keys (via rowKey) of currently expanded rows (bindable) */
|
|
75
|
+
expandedKeys?: any[];
|
|
76
|
+
/** Callback when a row is expanded or collapsed — trigger on-demand fetches here */
|
|
77
|
+
onexpand?: (row: T, index: number, expanded: boolean) => void;
|
|
78
|
+
/** Rows per page. Setting this enables built-in client-side pagination,
|
|
79
|
+
* applied after search filtering and sorting. */
|
|
80
|
+
pageSize?: number;
|
|
81
|
+
/** Current page number, 1-based (bindable) */
|
|
82
|
+
page?: number;
|
|
83
|
+
/** Callback when the current page changes */
|
|
84
|
+
onpagechange?: (page: number) => void;
|
|
85
|
+
/** Key of the column currently sorted by, or null for unsorted (bindable).
|
|
86
|
+
* Set it to render the sort indicator for a server-supplied sort order. */
|
|
87
|
+
sortKey?: string | null;
|
|
88
|
+
/** Current sort direction (bindable) */
|
|
89
|
+
sortDirection?: 'asc' | 'desc';
|
|
90
|
+
/** Callback when the user clicks a sortable header, after `sortKey` and
|
|
91
|
+
* `sortDirection` have been updated. Use it to request sorted data from a
|
|
92
|
+
* server. Paginated tables also reset to page 1 before this fires. */
|
|
93
|
+
onsort?: (key: string, direction: 'asc' | 'desc') => void;
|
|
94
|
+
/** Skip the built-in client-side sort and render `rows` in the order given.
|
|
95
|
+
* Use with `onsort` when the server returns pre-sorted rows. */
|
|
96
|
+
manualSort?: boolean;
|
|
30
97
|
}
|
|
31
98
|
|
|
32
99
|
let {
|
|
@@ -42,22 +109,190 @@
|
|
|
42
109
|
loading = false,
|
|
43
110
|
children,
|
|
44
111
|
buttons,
|
|
45
|
-
onrowclick
|
|
46
|
-
|
|
112
|
+
onrowclick,
|
|
113
|
+
rowHref = undefined,
|
|
114
|
+
selectable = false,
|
|
115
|
+
rowKey = undefined,
|
|
116
|
+
selectedRows = $bindable([]),
|
|
117
|
+
onselect = undefined,
|
|
118
|
+
expandedContent = undefined,
|
|
119
|
+
canExpand = undefined,
|
|
120
|
+
expandedKeys = $bindable([]),
|
|
121
|
+
onexpand = undefined,
|
|
122
|
+
pageSize = undefined,
|
|
123
|
+
page = $bindable(1),
|
|
124
|
+
onpagechange = undefined,
|
|
125
|
+
sortKey = $bindable(null),
|
|
126
|
+
sortDirection = $bindable('asc'),
|
|
127
|
+
onsort = undefined,
|
|
128
|
+
manualSort = false
|
|
129
|
+
}: TableProps = $props();
|
|
47
130
|
|
|
48
131
|
let searchQuery = $state('');
|
|
49
|
-
|
|
50
|
-
let
|
|
132
|
+
|
|
133
|
+
let _selectionWarned = false;
|
|
134
|
+
$effect(() => {
|
|
135
|
+
if (selectable && !rowKey && !_selectionWarned) {
|
|
136
|
+
_selectionWarned = true;
|
|
137
|
+
console.warn('Table: rowKey is required when selectable is true');
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
let _expandWarned = false;
|
|
142
|
+
$effect(() => {
|
|
143
|
+
if (expandedContent && !rowKey && !_expandWarned) {
|
|
144
|
+
_expandWarned = true;
|
|
145
|
+
console.warn('Table: rowKey is required when expandedContent is provided');
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const expandable = $derived(!!expandedContent && !!rowKey);
|
|
150
|
+
|
|
151
|
+
// Prune expandedKeys when rows changes to remove entries no longer present
|
|
152
|
+
$effect(() => {
|
|
153
|
+
if (!expandable || expandedKeys.length === 0) return;
|
|
154
|
+
const validKeys = new Set(rows.map((r) => getValue(r, rowKey!)));
|
|
155
|
+
const pruned = expandedKeys.filter((k) => validKeys.has(k));
|
|
156
|
+
if (pruned.length !== expandedKeys.length) {
|
|
157
|
+
expandedKeys = pruned;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Set of expanded row keys for O(1) lookup
|
|
162
|
+
const expandedKeySet = $derived(new Set(expandedKeys));
|
|
163
|
+
|
|
164
|
+
function isRowExpanded(row: any): boolean {
|
|
165
|
+
if (!expandable) return false;
|
|
166
|
+
return expandedKeySet.has(getValue(row, rowKey!));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function rowCanExpand(row: any, index: number): boolean {
|
|
170
|
+
if (!expandable) return false;
|
|
171
|
+
return canExpand ? canExpand(row, index) : true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function toggleExpand(row: any, index: number) {
|
|
175
|
+
if (!rowCanExpand(row, index)) return;
|
|
176
|
+
|
|
177
|
+
const key = getValue(row, rowKey!);
|
|
178
|
+
const expanded = !expandedKeySet.has(key);
|
|
179
|
+
if (expanded) {
|
|
180
|
+
expandedKeys = [...expandedKeys, key];
|
|
181
|
+
} else {
|
|
182
|
+
expandedKeys = expandedKeys.filter((k) => k !== key);
|
|
183
|
+
}
|
|
184
|
+
onexpand?.(row, index, expanded);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Prune selectedRows when rows changes to remove entries no longer present
|
|
188
|
+
$effect(() => {
|
|
189
|
+
if (!selectable || !rowKey || selectedRows.length === 0) return;
|
|
190
|
+
const validKeys = new Set(rows.map((r) => getValue(r, rowKey)));
|
|
191
|
+
const pruned = selectedRows.filter((r) => validKeys.has(getValue(r, rowKey)));
|
|
192
|
+
if (pruned.length !== selectedRows.length) {
|
|
193
|
+
selectedRows = pruned;
|
|
194
|
+
onselect?.(selectedRows);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Set of selected row keys for O(1) lookup
|
|
199
|
+
const selectedKeys = $derived.by(() => {
|
|
200
|
+
if (!selectable || !rowKey) return new Set<any>();
|
|
201
|
+
return new Set(selectedRows.map((r) => getValue(r, rowKey)));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Check if a row is selected
|
|
205
|
+
function isRowSelected(row: any): boolean {
|
|
206
|
+
if (!selectable || !rowKey) return false;
|
|
207
|
+
return selectedKeys.has(getValue(row, rowKey));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Toggle individual row selection
|
|
211
|
+
function toggleRow(row: any) {
|
|
212
|
+
if (!selectable || !rowKey) return;
|
|
213
|
+
|
|
214
|
+
const key = getValue(row, rowKey);
|
|
215
|
+
if (selectedKeys.has(key)) {
|
|
216
|
+
// Deselect: remove from selectedRows
|
|
217
|
+
selectedRows = selectedRows.filter((r) => getValue(r, rowKey) !== key);
|
|
218
|
+
} else {
|
|
219
|
+
// Select: add to selectedRows
|
|
220
|
+
selectedRows = [...selectedRows, row];
|
|
221
|
+
}
|
|
222
|
+
onselect?.(selectedRows);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Handle a row click. Middle-click and ctrl/cmd/shift-click are treated as
|
|
226
|
+
// open-in-new-tab intent when a rowHref is provided.
|
|
227
|
+
function handleRowClick(row: any, index: number, event: MouseEvent) {
|
|
228
|
+
const href = rowHref?.(row, index);
|
|
229
|
+
const newTabIntent = event.button === 1 || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
230
|
+
|
|
231
|
+
// Expansion/selection toggling only applies to a plain primary click without
|
|
232
|
+
// nav intent. Expansion wins on rows that can expand; selection stays
|
|
233
|
+
// available via the checkbox and still handles non-expandable rows.
|
|
234
|
+
if (expandable && !href && event.button !== 1 && rowCanExpand(row, index)) {
|
|
235
|
+
toggleExpand(row, index);
|
|
236
|
+
} else if (selectable && !href && event.button !== 1) {
|
|
237
|
+
toggleRow(row);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
onrowclick?.(row, index);
|
|
241
|
+
|
|
242
|
+
if (href) {
|
|
243
|
+
event.preventDefault();
|
|
244
|
+
if (newTabIntent) window.open(href, '_blank', 'noopener');
|
|
245
|
+
else navigateTo(href);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Toggle all visible rows (the current page when paginated, else all filtered rows)
|
|
250
|
+
function toggleAll() {
|
|
251
|
+
if (!selectable || !rowKey) return;
|
|
252
|
+
|
|
253
|
+
// Check if all visible rows are selected
|
|
254
|
+
const allSelected =
|
|
255
|
+
pagedRows.length > 0 && pagedRows.every((row) => selectedKeys.has(getValue(row, rowKey!)));
|
|
256
|
+
|
|
257
|
+
if (allSelected) {
|
|
258
|
+
// Deselect all visible rows
|
|
259
|
+
const visibleKeys = new Set(pagedRows.map((r) => getValue(r, rowKey!)));
|
|
260
|
+
selectedRows = selectedRows.filter((r) => !visibleKeys.has(getValue(r, rowKey!)));
|
|
261
|
+
} else {
|
|
262
|
+
// Select all visible rows (merge with existing selections elsewhere)
|
|
263
|
+
const existingKeys = new Set(selectedRows.map((r) => getValue(r, rowKey!)));
|
|
264
|
+
const newSelections = pagedRows.filter((r) => !existingKeys.has(getValue(r, rowKey!)));
|
|
265
|
+
selectedRows = [...selectedRows, ...newSelections];
|
|
266
|
+
}
|
|
267
|
+
onselect?.(selectedRows);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Derived states for select-all checkbox
|
|
271
|
+
const isAllSelected = $derived.by(() => {
|
|
272
|
+
if (!selectable || !rowKey || pagedRows.length === 0) return false;
|
|
273
|
+
return pagedRows.every((row) => selectedKeys.has(getValue(row, rowKey)));
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const isSomeSelected = $derived.by(() => {
|
|
277
|
+
if (!selectable || !rowKey || pagedRows.length === 0) return false;
|
|
278
|
+
const selectedCount = pagedRows.filter((row) => selectedKeys.has(getValue(row, rowKey))).length;
|
|
279
|
+
return selectedCount > 0 && selectedCount < pagedRows.length;
|
|
280
|
+
});
|
|
51
281
|
|
|
52
282
|
function handleSort(column: Column) {
|
|
53
283
|
if (!column.sortable) return;
|
|
54
284
|
|
|
55
|
-
if (
|
|
285
|
+
if (sortKey === column.key) {
|
|
56
286
|
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
|
|
57
287
|
} else {
|
|
58
|
-
|
|
288
|
+
sortKey = column.key;
|
|
59
289
|
sortDirection = 'asc';
|
|
60
290
|
}
|
|
291
|
+
|
|
292
|
+
// A new sort order invalidates the current page position
|
|
293
|
+
if (paginated && page !== 1) page = 1;
|
|
294
|
+
|
|
295
|
+
onsort?.(column.key, sortDirection);
|
|
61
296
|
}
|
|
62
297
|
|
|
63
298
|
function getValue(row: any, key: string): any {
|
|
@@ -74,8 +309,8 @@
|
|
|
74
309
|
|
|
75
310
|
// Apply search filter
|
|
76
311
|
if (searchable && searchQuery) {
|
|
77
|
-
filtered = filtered.filter(row => {
|
|
78
|
-
return columns.some(column => {
|
|
312
|
+
filtered = filtered.filter((row) => {
|
|
313
|
+
return columns.some((column) => {
|
|
79
314
|
const value = getValue(row, column.key);
|
|
80
315
|
if (value === null || value === undefined) return false;
|
|
81
316
|
return String(value).toLowerCase().includes(searchQuery.toLowerCase());
|
|
@@ -83,11 +318,11 @@
|
|
|
83
318
|
});
|
|
84
319
|
}
|
|
85
320
|
|
|
86
|
-
// Apply sorting
|
|
87
|
-
if (
|
|
321
|
+
// Apply sorting — skipped when the caller sorts the rows itself (e.g. server-side)
|
|
322
|
+
if (sortKey && !manualSort) {
|
|
88
323
|
filtered.sort((a, b) => {
|
|
89
|
-
const aValue = getValue(a,
|
|
90
|
-
const bValue = getValue(b,
|
|
324
|
+
const aValue = getValue(a, sortKey!);
|
|
325
|
+
const bValue = getValue(b, sortKey!);
|
|
91
326
|
|
|
92
327
|
if (aValue === null || aValue === undefined) return 1;
|
|
93
328
|
if (bValue === null || bValue === undefined) return -1;
|
|
@@ -106,15 +341,51 @@
|
|
|
106
341
|
return filtered;
|
|
107
342
|
});
|
|
108
343
|
|
|
344
|
+
// Pagination — applied after search filtering and sorting
|
|
345
|
+
const paginated = $derived(!!pageSize && pageSize > 0);
|
|
346
|
+
const totalPages = $derived(
|
|
347
|
+
paginated ? Math.max(1, Math.ceil(filteredRows.length / pageSize!)) : 1
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// Clamp page when filtering or a rows update shrinks the page count
|
|
351
|
+
$effect(() => {
|
|
352
|
+
if (page > totalPages) page = totalPages;
|
|
353
|
+
else if (page < 1) page = 1;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// A new search invalidates the current page position — jump back to the first page
|
|
357
|
+
let _lastQuery = '';
|
|
358
|
+
$effect(() => {
|
|
359
|
+
if (searchQuery !== _lastQuery) {
|
|
360
|
+
_lastQuery = searchQuery;
|
|
361
|
+
if (page !== 1) page = 1;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const pagedRows = $derived.by(() => {
|
|
366
|
+
if (!paginated) return filteredRows;
|
|
367
|
+
const start = (page - 1) * pageSize!;
|
|
368
|
+
return filteredRows.slice(start, start + pageSize!);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const pageStart = $derived(paginated ? (page - 1) * pageSize! + 1 : 1);
|
|
372
|
+
const pageEnd = $derived(
|
|
373
|
+
paginated ? Math.min(page * pageSize!, filteredRows.length) : filteredRows.length
|
|
374
|
+
);
|
|
375
|
+
|
|
109
376
|
const getSortIcon = (column: Column) => {
|
|
110
377
|
if (!column.sortable) return '';
|
|
111
|
-
if (
|
|
378
|
+
if (sortKey !== column.key) return iconArrowsSort;
|
|
112
379
|
return sortDirection === 'asc' ? iconChevronUp : iconChevronDown;
|
|
113
380
|
};
|
|
114
381
|
|
|
115
382
|
const tableClasses = $derived(
|
|
116
383
|
`pui-table ${tableClass} ${striped ? 'striped' : ''} ${hover ? 'hover' : ''}`
|
|
117
384
|
);
|
|
385
|
+
|
|
386
|
+
const totalColumns = $derived(
|
|
387
|
+
columns.length + (expandable ? 1 : 0) + (selectable && rowKey ? 1 : 0) + (buttons ? 1 : 0)
|
|
388
|
+
);
|
|
118
389
|
</script>
|
|
119
390
|
|
|
120
391
|
<div class="table-container">
|
|
@@ -133,6 +404,20 @@
|
|
|
133
404
|
<table class={tableClasses}>
|
|
134
405
|
<thead>
|
|
135
406
|
<tr>
|
|
407
|
+
{#if expandable}
|
|
408
|
+
<th class="table-header expand-cell" style="width: 40px"></th>
|
|
409
|
+
{/if}
|
|
410
|
+
{#if selectable && rowKey}
|
|
411
|
+
<th class="table-header checkbox-cell" style="width: 40px">
|
|
412
|
+
<Checkbox
|
|
413
|
+
controlled
|
|
414
|
+
checked={isAllSelected}
|
|
415
|
+
indeterminate={isSomeSelected}
|
|
416
|
+
onchange={() => toggleAll()}
|
|
417
|
+
ariaLabel="Select all rows"
|
|
418
|
+
/>
|
|
419
|
+
</th>
|
|
420
|
+
{/if}
|
|
136
421
|
{#each columns as column}
|
|
137
422
|
<th
|
|
138
423
|
class="table-header {column.sortable ? 'sortable' : ''} {column.align || 'left'}"
|
|
@@ -143,10 +428,7 @@
|
|
|
143
428
|
<span>{column.label}</span>
|
|
144
429
|
{#if column.sortable}
|
|
145
430
|
<div class="sort-icon">
|
|
146
|
-
<Icon
|
|
147
|
-
svg={getSortIcon(column)}
|
|
148
|
-
size="14px"
|
|
149
|
-
/>
|
|
431
|
+
<Icon svg={getSortIcon(column)} size="14px" />
|
|
150
432
|
</div>
|
|
151
433
|
{/if}
|
|
152
434
|
</div>
|
|
@@ -160,26 +442,70 @@
|
|
|
160
442
|
<tbody>
|
|
161
443
|
{#if loading}
|
|
162
444
|
<tr>
|
|
163
|
-
<td colspan={
|
|
445
|
+
<td colspan={totalColumns} class="loading-cell">
|
|
164
446
|
<div class="loading-content">Loading...</div>
|
|
165
447
|
</td>
|
|
166
448
|
</tr>
|
|
167
449
|
{:else if filteredRows.length === 0}
|
|
168
450
|
<tr>
|
|
169
|
-
<td colspan={
|
|
451
|
+
<td colspan={totalColumns} class="empty-cell">
|
|
170
452
|
<div class="empty-content">{emptyMessage}</div>
|
|
171
453
|
</td>
|
|
172
454
|
</tr>
|
|
173
455
|
{:else}
|
|
174
|
-
{#each
|
|
456
|
+
{#each pagedRows as row, index}
|
|
457
|
+
{@const expanded = isRowExpanded(row)}
|
|
175
458
|
<tr
|
|
176
|
-
class={onrowclick
|
|
177
|
-
|
|
459
|
+
class={(onrowclick ||
|
|
460
|
+
selectable ||
|
|
461
|
+
rowHref ||
|
|
462
|
+
(expandable && rowCanExpand(row, index))
|
|
463
|
+
? 'clickable-row'
|
|
464
|
+
: '') +
|
|
465
|
+
(selectable && isRowSelected(row) ? ' selected' : '') +
|
|
466
|
+
(expanded ? ' expanded' : '')}
|
|
467
|
+
class:row-even={index % 2 === 1}
|
|
468
|
+
onclick={(e) => handleRowClick(row, index, e)}
|
|
469
|
+
onmousedown={(e) => {
|
|
470
|
+
// Suppress the default middle-button action (autoscroll) so auxclick fires.
|
|
471
|
+
if (e.button === 1 && rowHref?.(row, index)) e.preventDefault();
|
|
472
|
+
}}
|
|
473
|
+
onauxclick={(e) => {
|
|
474
|
+
if (e.button === 1) handleRowClick(row, index, e);
|
|
475
|
+
}}
|
|
178
476
|
>
|
|
477
|
+
{#if expandable}
|
|
478
|
+
<td class="table-cell expand-cell" onclick={(e) => e.stopPropagation()}>
|
|
479
|
+
{#if rowCanExpand(row, index)}
|
|
480
|
+
<button
|
|
481
|
+
type="button"
|
|
482
|
+
class="expand-toggle"
|
|
483
|
+
class:expanded
|
|
484
|
+
aria-expanded={expanded}
|
|
485
|
+
aria-label={expanded ? 'Collapse row' : 'Expand row'}
|
|
486
|
+
onclick={() => toggleExpand(row, index)}
|
|
487
|
+
>
|
|
488
|
+
<Icon svg={iconChevronRight} size="16px" />
|
|
489
|
+
</button>
|
|
490
|
+
{/if}
|
|
491
|
+
</td>
|
|
492
|
+
{/if}
|
|
493
|
+
{#if selectable && rowKey}
|
|
494
|
+
<td class="table-cell checkbox-cell" onclick={(e) => e.stopPropagation()}>
|
|
495
|
+
<Checkbox
|
|
496
|
+
controlled
|
|
497
|
+
checked={isRowSelected(row)}
|
|
498
|
+
onchange={() => toggleRow(row)}
|
|
499
|
+
ariaLabel="Select row"
|
|
500
|
+
/>
|
|
501
|
+
</td>
|
|
502
|
+
{/if}
|
|
179
503
|
{#each columns as column}
|
|
180
504
|
{@const value = getValue(row, column.key)}
|
|
181
505
|
<td class="table-cell {column.align || 'left'}">
|
|
182
|
-
{#if column.
|
|
506
|
+
{#if column.cell}
|
|
507
|
+
{@render column.cell({ value, row, index })}
|
|
508
|
+
{:else if column.render}
|
|
183
509
|
{@html column.render(value, row)}
|
|
184
510
|
{:else if typeof value === 'function'}
|
|
185
511
|
{@render value()}
|
|
@@ -194,12 +520,28 @@
|
|
|
194
520
|
</td>
|
|
195
521
|
{/if}
|
|
196
522
|
</tr>
|
|
523
|
+
{#if expanded && expandedContent}
|
|
524
|
+
<tr class="detail-row" class:row-even={index % 2 === 1}>
|
|
525
|
+
<td class="detail-cell" colspan={totalColumns}>
|
|
526
|
+
{@render expandedContent(row, index)}
|
|
527
|
+
</td>
|
|
528
|
+
</tr>
|
|
529
|
+
{/if}
|
|
197
530
|
{/each}
|
|
198
531
|
{/if}
|
|
199
532
|
</tbody>
|
|
200
533
|
</table>
|
|
201
534
|
</div>
|
|
202
535
|
|
|
536
|
+
{#if paginated && !loading && totalPages > 1}
|
|
537
|
+
<div class="table-pagination">
|
|
538
|
+
<span class="pagination-info">
|
|
539
|
+
Showing {pageStart}–{pageEnd} of {filteredRows.length}
|
|
540
|
+
</span>
|
|
541
|
+
<Pagination bind:selectedPage={page} {totalPages} onPageChange={(p) => onpagechange?.(p)} />
|
|
542
|
+
</div>
|
|
543
|
+
{/if}
|
|
544
|
+
|
|
203
545
|
{@render children?.()}
|
|
204
546
|
</div>
|
|
205
547
|
|
|
@@ -209,45 +551,45 @@
|
|
|
209
551
|
}
|
|
210
552
|
|
|
211
553
|
.table-search {
|
|
212
|
-
margin-bottom:
|
|
554
|
+
margin-bottom: 1rem;
|
|
213
555
|
max-width: 400px;
|
|
214
556
|
}
|
|
215
557
|
|
|
216
558
|
.table-wrapper {
|
|
217
559
|
width: 100%;
|
|
218
560
|
overflow-x: auto;
|
|
219
|
-
border: 1px solid var(--
|
|
220
|
-
background-color: var(--
|
|
561
|
+
border: 1px solid var(--border-color);
|
|
562
|
+
background-color: var(--input-bg-color);
|
|
221
563
|
}
|
|
222
564
|
|
|
223
565
|
.table-wrapper.rounded {
|
|
224
|
-
border-radius:
|
|
566
|
+
border-radius: 0.5rem;
|
|
225
567
|
}
|
|
226
568
|
|
|
227
569
|
.pui-table {
|
|
228
570
|
width: 100%;
|
|
229
571
|
border-collapse: collapse;
|
|
230
|
-
font-size:
|
|
572
|
+
font-size: 0.875rem;
|
|
231
573
|
}
|
|
232
574
|
|
|
233
575
|
.table-header {
|
|
234
|
-
padding:
|
|
576
|
+
padding: 0.5rem;
|
|
235
577
|
text-align: left;
|
|
236
|
-
font-weight:
|
|
237
|
-
color: var(--
|
|
238
|
-
background-color: var(--
|
|
239
|
-
border-bottom: 2px solid var(--
|
|
578
|
+
font-weight: 600;
|
|
579
|
+
color: var(--text-color);
|
|
580
|
+
background-color: var(--bg-color);
|
|
581
|
+
border-bottom: 2px solid var(--border-color);
|
|
240
582
|
user-select: none;
|
|
241
583
|
white-space: nowrap;
|
|
242
584
|
}
|
|
243
585
|
|
|
244
586
|
.table-header.sortable {
|
|
245
587
|
cursor: pointer;
|
|
246
|
-
transition: background-color
|
|
588
|
+
transition: background-color 0.2s;
|
|
247
589
|
}
|
|
248
590
|
|
|
249
591
|
.table-header.sortable:hover {
|
|
250
|
-
background-color: var(--
|
|
592
|
+
background-color: var(--hover-bg);
|
|
251
593
|
}
|
|
252
594
|
|
|
253
595
|
.table-header.center {
|
|
@@ -261,7 +603,7 @@
|
|
|
261
603
|
.header-content {
|
|
262
604
|
display: flex;
|
|
263
605
|
align-items: center;
|
|
264
|
-
gap:
|
|
606
|
+
gap: 0.5rem;
|
|
265
607
|
justify-content: space-between;
|
|
266
608
|
}
|
|
267
609
|
|
|
@@ -269,7 +611,7 @@
|
|
|
269
611
|
display: inline-flex;
|
|
270
612
|
align-items: center;
|
|
271
613
|
opacity: 0.5;
|
|
272
|
-
transition: opacity
|
|
614
|
+
transition: opacity 0.2s;
|
|
273
615
|
}
|
|
274
616
|
|
|
275
617
|
.table-header.sortable:hover .sort-icon {
|
|
@@ -277,10 +619,10 @@
|
|
|
277
619
|
}
|
|
278
620
|
|
|
279
621
|
.table-cell {
|
|
280
|
-
padding:
|
|
622
|
+
padding: 0.5rem;
|
|
281
623
|
text-align: left;
|
|
282
|
-
color: var(--
|
|
283
|
-
border-bottom: 1px solid var(--
|
|
624
|
+
color: var(--text-color);
|
|
625
|
+
border-bottom: 1px solid var(--border-color);
|
|
284
626
|
}
|
|
285
627
|
|
|
286
628
|
.table-cell.center {
|
|
@@ -291,13 +633,88 @@
|
|
|
291
633
|
text-align: right;
|
|
292
634
|
}
|
|
293
635
|
|
|
294
|
-
.
|
|
295
|
-
|
|
636
|
+
.checkbox-cell {
|
|
637
|
+
width: 40px;
|
|
638
|
+
text-align: center;
|
|
639
|
+
padding: 0.25rem;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.checkbox-cell :global(.checkbox-container) {
|
|
643
|
+
display: inline-flex;
|
|
644
|
+
justify-content: center;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.checkbox-cell :global(input) {
|
|
648
|
+
margin: 2px;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.expand-cell {
|
|
652
|
+
width: 40px;
|
|
653
|
+
text-align: center;
|
|
654
|
+
padding: 0.25rem;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.expand-toggle {
|
|
658
|
+
display: inline-flex;
|
|
659
|
+
align-items: center;
|
|
660
|
+
justify-content: center;
|
|
661
|
+
width: 24px;
|
|
662
|
+
height: 24px;
|
|
663
|
+
padding: 0;
|
|
664
|
+
border: none;
|
|
665
|
+
background: transparent;
|
|
666
|
+
color: var(--text-color);
|
|
667
|
+
cursor: pointer;
|
|
668
|
+
border-radius: 0.25rem;
|
|
669
|
+
transition:
|
|
670
|
+
transform 0.15s ease,
|
|
671
|
+
background-color 0.2s;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.expand-toggle:hover {
|
|
675
|
+
background-color: var(--hover-bg);
|
|
296
676
|
}
|
|
297
677
|
|
|
298
|
-
.
|
|
299
|
-
|
|
300
|
-
|
|
678
|
+
.expand-toggle.expanded {
|
|
679
|
+
transform: rotate(90deg);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/* An expanded row and its detail row read as one unit: the parent's border
|
|
683
|
+
* moves to the bottom of the detail row. */
|
|
684
|
+
tbody tr.expanded td {
|
|
685
|
+
border-bottom: none;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.detail-cell {
|
|
689
|
+
padding: 0.5rem;
|
|
690
|
+
color: var(--text-color);
|
|
691
|
+
border-bottom: 1px solid var(--border-color);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.pui-table.striped tbody tr.row-even {
|
|
695
|
+
background-color: var(--stripe-bg);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.pui-table.hover tbody tr:not(.detail-row):hover {
|
|
699
|
+
background-color: var(--hover-bg);
|
|
700
|
+
transition: background-color 0.2s;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.pui-table tbody tr.selected,
|
|
704
|
+
.pui-table.striped tbody tr.selected.row-even {
|
|
705
|
+
background-color: rgba(var(--ui-tertiary-rgbc), 0.15);
|
|
706
|
+
}
|
|
707
|
+
.pui-table tbody tr.selected:hover,
|
|
708
|
+
.pui-table.hover tbody tr.selected:hover {
|
|
709
|
+
background-color: rgba(var(--ui-tertiary-rgbc), 0.22);
|
|
710
|
+
}
|
|
711
|
+
:global(.dark) .pui-table tbody tr.selected,
|
|
712
|
+
:global(.dark) .pui-table.striped tbody tr.selected.row-even {
|
|
713
|
+
background-color: rgba(var(--ui-tertiary-rgbc), 0.12);
|
|
714
|
+
}
|
|
715
|
+
:global(.dark) .pui-table tbody tr.selected:hover,
|
|
716
|
+
:global(.dark) .pui-table.hover tbody tr.selected:hover {
|
|
717
|
+
background-color: rgba(var(--ui-tertiary-rgbc), 0.16);
|
|
301
718
|
}
|
|
302
719
|
|
|
303
720
|
.clickable-row {
|
|
@@ -305,8 +722,8 @@
|
|
|
305
722
|
}
|
|
306
723
|
|
|
307
724
|
.clickable-row:hover {
|
|
308
|
-
background-color: var(--
|
|
309
|
-
transition: background-color
|
|
725
|
+
background-color: var(--hover-bg);
|
|
726
|
+
transition: background-color 0.2s;
|
|
310
727
|
}
|
|
311
728
|
|
|
312
729
|
tbody tr:last-child td {
|
|
@@ -315,9 +732,9 @@
|
|
|
315
732
|
|
|
316
733
|
.empty-cell,
|
|
317
734
|
.loading-cell {
|
|
318
|
-
padding:
|
|
735
|
+
padding: 2rem;
|
|
319
736
|
text-align: center;
|
|
320
|
-
color: var(--
|
|
737
|
+
color: var(--text-muted);
|
|
321
738
|
border-bottom: none;
|
|
322
739
|
}
|
|
323
740
|
|
|
@@ -326,21 +743,45 @@
|
|
|
326
743
|
font-style: italic;
|
|
327
744
|
}
|
|
328
745
|
|
|
329
|
-
|
|
746
|
+
.table-pagination {
|
|
747
|
+
display: flex;
|
|
748
|
+
align-items: center;
|
|
749
|
+
justify-content: space-between;
|
|
750
|
+
gap: 1rem;
|
|
751
|
+
flex-wrap: wrap;
|
|
752
|
+
margin-top: 1rem;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.pagination-info {
|
|
756
|
+
color: var(--text-muted);
|
|
757
|
+
font-size: 0.875rem;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
:global(:root) {
|
|
761
|
+
--stripe-bg: rgba(0, 0, 0, 0.02);
|
|
762
|
+
--hover-bg: rgba(0, 0, 0, 0.04);
|
|
763
|
+
--text-muted: #6b7280;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
:global(.dark) {
|
|
767
|
+
--stripe-bg: rgba(255, 255, 255, 0.02);
|
|
768
|
+
--hover-bg: rgba(255, 255, 255, 0.04);
|
|
769
|
+
--text-muted: #9ca3af;
|
|
770
|
+
}
|
|
771
|
+
|
|
330
772
|
:global(.pui-table .sort-icon svg) {
|
|
331
773
|
width: 14px;
|
|
332
774
|
height: 14px;
|
|
333
775
|
}
|
|
334
776
|
|
|
335
|
-
/* Responsive adjustments */
|
|
336
777
|
@media (max-width: 640px) {
|
|
337
778
|
.table-header,
|
|
338
779
|
.table-cell {
|
|
339
|
-
padding:
|
|
780
|
+
padding: 0.5rem 0.75rem;
|
|
340
781
|
}
|
|
341
782
|
|
|
342
783
|
.pui-table {
|
|
343
|
-
font-size:
|
|
784
|
+
font-size: 0.75rem;
|
|
344
785
|
}
|
|
345
786
|
}
|
|
346
|
-
</style>
|
|
787
|
+
</style>
|