@malva-ui/core 0.1.13 → 0.1.14
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/AGENTS.md +4 -1
- package/README.md +15 -0
- package/docs/ai/avatar.md +2 -0
- package/docs/ai/breadcrumb.md +67 -7
- package/docs/ai/button.md +74 -19
- package/docs/ai/card.md +8 -6
- package/docs/ai/chat.md +59 -45
- package/docs/ai/checkbox.md +12 -0
- package/docs/ai/combobox.md +18 -2
- package/docs/ai/copy-to-clipboard.md +1 -1
- package/docs/ai/core.md +15 -0
- package/docs/ai/data-table.md +89 -54
- package/docs/ai/dialog.md +76 -67
- package/docs/ai/drawer.md +15 -12
- package/docs/ai/dropdown.md +24 -19
- package/docs/ai/empty-state.md +3 -3
- package/docs/ai/filter.md +24 -5
- package/docs/ai/form-utils.md +160 -5
- package/docs/ai/icon-toggle.md +160 -0
- package/docs/ai/input.md +30 -0
- package/docs/ai/layout.md +23 -0
- package/docs/ai/list.md +10 -6
- package/docs/ai/menu.md +75 -1
- package/docs/ai/page.md +220 -60
- package/docs/ai/radio.md +9 -0
- package/docs/ai/scrollbar.md +30 -8
- package/docs/ai/segmented.md +35 -35
- package/docs/ai/select.md +30 -5
- package/docs/ai/sidebar.md +45 -27
- package/docs/ai/switch.md +114 -19
- package/docs/ai/table.md +69 -0
- package/docs/ai/tabs.md +2 -1
- package/docs/ai/tile.md +311 -85
- package/docs/ai/timeline.md +63 -39
- package/docs/ai/tokenizer.md +21 -5
- package/docs/ai/tooltip.md +5 -5
- package/docs/ai/view-variant.md +75 -0
- package/fesm2022/malva-ui-core-accordion.mjs +167 -0
- package/fesm2022/malva-ui-core-accordion.mjs.map +1 -0
- package/fesm2022/malva-ui-core-action-bar.mjs +111 -0
- package/fesm2022/malva-ui-core-action-bar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-alert.mjs +173 -0
- package/fesm2022/malva-ui-core-alert.mjs.map +1 -0
- package/fesm2022/malva-ui-core-autocomplete.mjs +775 -0
- package/fesm2022/malva-ui-core-autocomplete.mjs.map +1 -0
- package/fesm2022/malva-ui-core-avatar-group.mjs +224 -0
- package/fesm2022/malva-ui-core-avatar-group.mjs.map +1 -0
- package/fesm2022/malva-ui-core-avatar.mjs +247 -0
- package/fesm2022/malva-ui-core-avatar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-badge.mjs +122 -0
- package/fesm2022/malva-ui-core-badge.mjs.map +1 -0
- package/fesm2022/malva-ui-core-bottom-nav.mjs +161 -0
- package/fesm2022/malva-ui-core-bottom-nav.mjs.map +1 -0
- package/fesm2022/malva-ui-core-breadcrumb.mjs +494 -0
- package/fesm2022/malva-ui-core-breadcrumb.mjs.map +1 -0
- package/fesm2022/malva-ui-core-button.mjs +406 -0
- package/fesm2022/malva-ui-core-button.mjs.map +1 -0
- package/fesm2022/malva-ui-core-calendar.mjs +938 -0
- package/fesm2022/malva-ui-core-calendar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-card.mjs +164 -0
- package/fesm2022/malva-ui-core-card.mjs.map +1 -0
- package/fesm2022/malva-ui-core-chat.mjs +825 -0
- package/fesm2022/malva-ui-core-chat.mjs.map +1 -0
- package/fesm2022/malva-ui-core-checkbox.mjs +272 -0
- package/fesm2022/malva-ui-core-checkbox.mjs.map +1 -0
- package/fesm2022/malva-ui-core-chip.mjs +176 -0
- package/fesm2022/malva-ui-core-chip.mjs.map +1 -0
- package/fesm2022/malva-ui-core-color-picker.mjs +1204 -0
- package/fesm2022/malva-ui-core-color-picker.mjs.map +1 -0
- package/fesm2022/malva-ui-core-combobox.mjs +945 -0
- package/fesm2022/malva-ui-core-combobox.mjs.map +1 -0
- package/fesm2022/malva-ui-core-copy-to-clipboard.mjs +255 -0
- package/fesm2022/malva-ui-core-copy-to-clipboard.mjs.map +1 -0
- package/fesm2022/malva-ui-core-data-table.mjs +2696 -0
- package/fesm2022/malva-ui-core-data-table.mjs.map +1 -0
- package/fesm2022/malva-ui-core-date-range-picker.mjs +276 -0
- package/fesm2022/malva-ui-core-date-range-picker.mjs.map +1 -0
- package/fesm2022/malva-ui-core-day-picker.mjs +131 -0
- package/fesm2022/malva-ui-core-day-picker.mjs.map +1 -0
- package/fesm2022/malva-ui-core-dialog-routable-dialog-CvjXMtlD.mjs +94 -0
- package/fesm2022/malva-ui-core-dialog-routable-dialog-CvjXMtlD.mjs.map +1 -0
- package/fesm2022/malva-ui-core-dialog.mjs +1223 -0
- package/fesm2022/malva-ui-core-dialog.mjs.map +1 -0
- package/fesm2022/malva-ui-core-divider.mjs +80 -0
- package/fesm2022/malva-ui-core-divider.mjs.map +1 -0
- package/fesm2022/malva-ui-core-drawer-routable-drawer-qUk6Etnx.mjs +94 -0
- package/fesm2022/malva-ui-core-drawer-routable-drawer-qUk6Etnx.mjs.map +1 -0
- package/fesm2022/malva-ui-core-drawer.mjs +814 -0
- package/fesm2022/malva-ui-core-drawer.mjs.map +1 -0
- package/fesm2022/malva-ui-core-dropdown.mjs +994 -0
- package/fesm2022/malva-ui-core-dropdown.mjs.map +1 -0
- package/fesm2022/malva-ui-core-empty-state.mjs +50 -0
- package/fesm2022/malva-ui-core-empty-state.mjs.map +1 -0
- package/fesm2022/malva-ui-core-expand.mjs +130 -0
- package/fesm2022/malva-ui-core-expand.mjs.map +1 -0
- package/fesm2022/malva-ui-core-file-upload.mjs +451 -0
- package/fesm2022/malva-ui-core-file-upload.mjs.map +1 -0
- package/fesm2022/malva-ui-core-filter.mjs +1627 -0
- package/fesm2022/malva-ui-core-filter.mjs.map +1 -0
- package/fesm2022/malva-ui-core-form-utils-testing.mjs +39 -0
- package/fesm2022/malva-ui-core-form-utils-testing.mjs.map +1 -0
- package/fesm2022/malva-ui-core-form-utils.mjs +977 -0
- package/fesm2022/malva-ui-core-form-utils.mjs.map +1 -0
- package/fesm2022/malva-ui-core-form.mjs +283 -0
- package/fesm2022/malva-ui-core-form.mjs.map +1 -0
- package/fesm2022/malva-ui-core-icon-toggle.mjs +120 -0
- package/fesm2022/malva-ui-core-icon-toggle.mjs.map +1 -0
- package/fesm2022/malva-ui-core-input.mjs +375 -0
- package/fesm2022/malva-ui-core-input.mjs.map +1 -0
- package/fesm2022/malva-ui-core-kbd.mjs +131 -0
- package/fesm2022/malva-ui-core-kbd.mjs.map +1 -0
- package/fesm2022/malva-ui-core-layout.mjs +212 -0
- package/fesm2022/malva-ui-core-layout.mjs.map +1 -0
- package/fesm2022/malva-ui-core-link.mjs +89 -0
- package/fesm2022/malva-ui-core-link.mjs.map +1 -0
- package/fesm2022/malva-ui-core-list.mjs +413 -0
- package/fesm2022/malva-ui-core-list.mjs.map +1 -0
- package/fesm2022/malva-ui-core-loader.mjs +141 -0
- package/fesm2022/malva-ui-core-loader.mjs.map +1 -0
- package/fesm2022/malva-ui-core-menu.mjs +2540 -0
- package/fesm2022/malva-ui-core-menu.mjs.map +1 -0
- package/fesm2022/malva-ui-core-notification.mjs +201 -0
- package/fesm2022/malva-ui-core-notification.mjs.map +1 -0
- package/fesm2022/malva-ui-core-number-input.mjs +404 -0
- package/fesm2022/malva-ui-core-number-input.mjs.map +1 -0
- package/fesm2022/malva-ui-core-page.mjs +1898 -0
- package/fesm2022/malva-ui-core-page.mjs.map +1 -0
- package/fesm2022/malva-ui-core-pagination.mjs +458 -0
- package/fesm2022/malva-ui-core-pagination.mjs.map +1 -0
- package/fesm2022/malva-ui-core-pin-input.mjs +405 -0
- package/fesm2022/malva-ui-core-pin-input.mjs.map +1 -0
- package/fesm2022/malva-ui-core-popup.mjs +1488 -0
- package/fesm2022/malva-ui-core-popup.mjs.map +1 -0
- package/fesm2022/malva-ui-core-progress.mjs +109 -0
- package/fesm2022/malva-ui-core-progress.mjs.map +1 -0
- package/fesm2022/malva-ui-core-radio.mjs +317 -0
- package/fesm2022/malva-ui-core-radio.mjs.map +1 -0
- package/fesm2022/malva-ui-core-rating.mjs +236 -0
- package/fesm2022/malva-ui-core-rating.mjs.map +1 -0
- package/fesm2022/malva-ui-core-scrollbar.mjs +430 -0
- package/fesm2022/malva-ui-core-scrollbar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-search-field.mjs +578 -0
- package/fesm2022/malva-ui-core-search-field.mjs.map +1 -0
- package/fesm2022/malva-ui-core-segmented.mjs +458 -0
- package/fesm2022/malva-ui-core-segmented.mjs.map +1 -0
- package/fesm2022/malva-ui-core-select.mjs +855 -0
- package/fesm2022/malva-ui-core-select.mjs.map +1 -0
- package/fesm2022/malva-ui-core-sidebar.mjs +1504 -0
- package/fesm2022/malva-ui-core-sidebar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-skeleton.mjs +85 -0
- package/fesm2022/malva-ui-core-skeleton.mjs.map +1 -0
- package/fesm2022/malva-ui-core-slider.mjs +514 -0
- package/fesm2022/malva-ui-core-slider.mjs.map +1 -0
- package/fesm2022/malva-ui-core-split-pane.mjs +359 -0
- package/fesm2022/malva-ui-core-split-pane.mjs.map +1 -0
- package/fesm2022/malva-ui-core-status-indicator.mjs +78 -0
- package/fesm2022/malva-ui-core-status-indicator.mjs.map +1 -0
- package/fesm2022/malva-ui-core-stepper.mjs +332 -0
- package/fesm2022/malva-ui-core-stepper.mjs.map +1 -0
- package/fesm2022/malva-ui-core-switch.mjs +272 -0
- package/fesm2022/malva-ui-core-switch.mjs.map +1 -0
- package/fesm2022/malva-ui-core-table.mjs +79 -0
- package/fesm2022/malva-ui-core-table.mjs.map +1 -0
- package/fesm2022/malva-ui-core-tabs.mjs +794 -0
- package/fesm2022/malva-ui-core-tabs.mjs.map +1 -0
- package/fesm2022/malva-ui-core-textarea.mjs +201 -0
- package/fesm2022/malva-ui-core-textarea.mjs.map +1 -0
- package/fesm2022/malva-ui-core-tile.mjs +1404 -0
- package/fesm2022/malva-ui-core-tile.mjs.map +1 -0
- package/fesm2022/malva-ui-core-time-picker.mjs +533 -0
- package/fesm2022/malva-ui-core-time-picker.mjs.map +1 -0
- package/fesm2022/malva-ui-core-timeline.mjs +216 -0
- package/fesm2022/malva-ui-core-timeline.mjs.map +1 -0
- package/fesm2022/malva-ui-core-title.mjs +178 -0
- package/fesm2022/malva-ui-core-title.mjs.map +1 -0
- package/fesm2022/malva-ui-core-toast.mjs +749 -0
- package/fesm2022/malva-ui-core-toast.mjs.map +1 -0
- package/fesm2022/malva-ui-core-tokenizer.mjs +502 -0
- package/fesm2022/malva-ui-core-tokenizer.mjs.map +1 -0
- package/fesm2022/malva-ui-core-toolbar.mjs +141 -0
- package/fesm2022/malva-ui-core-toolbar.mjs.map +1 -0
- package/fesm2022/malva-ui-core-tooltip.mjs +432 -0
- package/fesm2022/malva-ui-core-tooltip.mjs.map +1 -0
- package/fesm2022/malva-ui-core-tree.mjs +505 -0
- package/fesm2022/malva-ui-core-tree.mjs.map +1 -0
- package/fesm2022/malva-ui-core-view-variant.mjs +292 -0
- package/fesm2022/malva-ui-core-view-variant.mjs.map +1 -0
- package/fesm2022/malva-ui-core.mjs +77 -0
- package/fesm2022/malva-ui-core.mjs.map +1 -0
- package/package.json +179 -156
- package/styles/malva-ui.css +253 -220
- package/styles/tokens.md +174 -173
- package/table/README.md +46 -0
- package/types/malva-ui-core-accordion.d.ts +121 -0
- package/types/malva-ui-core-action-bar.d.ts +82 -0
- package/types/malva-ui-core-alert.d.ts +131 -0
- package/types/malva-ui-core-autocomplete.d.ts +301 -0
- package/types/malva-ui-core-avatar-group.d.ts +119 -0
- package/types/malva-ui-core-avatar.d.ts +156 -0
- package/types/malva-ui-core-badge.d.ts +97 -0
- package/types/malva-ui-core-bottom-nav.d.ts +104 -0
- package/types/malva-ui-core-breadcrumb.d.ts +308 -0
- package/types/malva-ui-core-button.d.ts +194 -0
- package/types/malva-ui-core-calendar.d.ts +339 -0
- package/types/malva-ui-core-card.d.ts +88 -0
- package/types/malva-ui-core-chat.d.ts +375 -0
- package/types/malva-ui-core-checkbox.d.ts +158 -0
- package/types/malva-ui-core-chip.d.ts +128 -0
- package/types/malva-ui-core-color-picker.d.ts +442 -0
- package/types/malva-ui-core-combobox.d.ts +419 -0
- package/types/malva-ui-core-copy-to-clipboard.d.ts +148 -0
- package/types/malva-ui-core-data-table.d.ts +1074 -0
- package/types/malva-ui-core-date-range-picker.d.ts +149 -0
- package/types/malva-ui-core-day-picker.d.ts +55 -0
- package/types/malva-ui-core-dialog.d.ts +597 -0
- package/types/malva-ui-core-divider.d.ts +68 -0
- package/types/malva-ui-core-drawer.d.ts +333 -0
- package/types/malva-ui-core-dropdown.d.ts +592 -0
- package/types/malva-ui-core-empty-state.d.ts +37 -0
- package/types/malva-ui-core-expand.d.ts +102 -0
- package/types/malva-ui-core-file-upload.d.ts +267 -0
- package/types/malva-ui-core-filter.d.ts +552 -0
- package/types/malva-ui-core-form-utils-testing.d.ts +50 -0
- package/types/malva-ui-core-form-utils.d.ts +579 -0
- package/types/malva-ui-core-form.d.ts +176 -0
- package/types/malva-ui-core-icon-toggle.d.ts +80 -0
- package/types/malva-ui-core-input.d.ts +262 -0
- package/types/malva-ui-core-kbd.d.ts +56 -0
- package/types/malva-ui-core-layout.d.ts +70 -0
- package/types/malva-ui-core-link.d.ts +28 -0
- package/types/malva-ui-core-list.d.ts +252 -0
- package/types/malva-ui-core-loader.d.ts +89 -0
- package/types/malva-ui-core-menu.d.ts +954 -0
- package/types/malva-ui-core-notification.d.ts +122 -0
- package/types/malva-ui-core-number-input.d.ts +167 -0
- package/types/malva-ui-core-page.d.ts +799 -0
- package/types/malva-ui-core-pagination.d.ts +261 -0
- package/types/malva-ui-core-pin-input.d.ts +203 -0
- package/types/malva-ui-core-popup.d.ts +834 -0
- package/types/malva-ui-core-progress.d.ts +73 -0
- package/types/malva-ui-core-radio.d.ts +130 -0
- package/types/malva-ui-core-rating.d.ts +115 -0
- package/types/malva-ui-core-scrollbar.d.ts +203 -0
- package/types/malva-ui-core-search-field.d.ts +408 -0
- package/types/malva-ui-core-segmented.d.ts +206 -0
- package/types/malva-ui-core-select.d.ts +456 -0
- package/types/malva-ui-core-sidebar.d.ts +698 -0
- package/types/malva-ui-core-skeleton.d.ts +64 -0
- package/types/malva-ui-core-slider.d.ts +219 -0
- package/types/malva-ui-core-split-pane.d.ts +149 -0
- package/types/malva-ui-core-status-indicator.d.ts +65 -0
- package/types/malva-ui-core-stepper.d.ts +168 -0
- package/types/malva-ui-core-switch.d.ts +146 -0
- package/types/malva-ui-core-table.d.ts +37 -0
- package/types/malva-ui-core-tabs.d.ts +339 -0
- package/types/malva-ui-core-textarea.d.ts +79 -0
- package/types/malva-ui-core-tile.d.ts +373 -0
- package/types/malva-ui-core-time-picker.d.ts +141 -0
- package/types/malva-ui-core-timeline.d.ts +188 -0
- package/types/malva-ui-core-title.d.ts +66 -0
- package/types/malva-ui-core-toast.d.ts +432 -0
- package/types/malva-ui-core-tokenizer.d.ts +217 -0
- package/types/malva-ui-core-toolbar.d.ts +91 -0
- package/types/malva-ui-core-tooltip.d.ts +200 -0
- package/types/malva-ui-core-tree.d.ts +289 -0
- package/types/malva-ui-core-view-variant.d.ts +207 -0
- package/types/malva-ui-core.d.ts +72 -0
- package/view-variant/README.md +3 -0
- package/accordion/index.d.ts +0 -3
- package/accordion/lib/accordion/accordion.d.ts +0 -47
- package/accordion/lib/accordion-item/accordion-header.d.ts +0 -22
- package/accordion/lib/accordion-item/accordion-item.d.ts +0 -49
- package/accordion/malva-ui-core-accordion.d.ts +0 -5
- package/action-bar/index.d.ts +0 -4
- package/action-bar/lib/action-bar/action-bar.d.ts +0 -59
- package/action-bar/lib/action-bar/components/action-bar-actions.d.ts +0 -9
- package/action-bar/lib/action-bar/components/action-bar-logo.d.ts +0 -5
- package/action-bar/lib/action-bar/components/action-bar-spacer.d.ts +0 -5
- package/action-bar/malva-ui-core-action-bar.d.ts +0 -5
- package/alert/index.d.ts +0 -2
- package/alert/lib/alert/alert.d.ts +0 -84
- package/alert/lib/alert/alert.directives.d.ts +0 -44
- package/alert/malva-ui-core-alert.d.ts +0 -5
- package/autocomplete/index.d.ts +0 -1
- package/autocomplete/lib/autocomplete/autocomplete.d.ts +0 -296
- package/autocomplete/malva-ui-core-autocomplete.d.ts +0 -5
- package/avatar/index.d.ts +0 -2
- package/avatar/lib/avatar/avatar.d.ts +0 -125
- package/avatar/lib/color-from-text.pipe.d.ts +0 -21
- package/avatar/malva-ui-core-avatar.d.ts +0 -5
- package/avatar-group/index.d.ts +0 -1
- package/avatar-group/lib/avatar-group/avatar-group.d.ts +0 -115
- package/avatar-group/malva-ui-core-avatar-group.d.ts +0 -5
- package/badge/index.d.ts +0 -2
- package/badge/lib/badge/badge.d.ts +0 -59
- package/badge/lib/badge-icon.d.ts +0 -35
- package/badge/malva-ui-core-badge.d.ts +0 -5
- package/bottom-nav/index.d.ts +0 -1
- package/bottom-nav/lib/bottom-nav/bottom-nav.d.ts +0 -99
- package/bottom-nav/malva-ui-core-bottom-nav.d.ts +0 -5
- package/breadcrumb/index.d.ts +0 -5
- package/breadcrumb/lib/breadcrumb/breadcrumb-item-host.d.ts +0 -32
- package/breadcrumb/lib/breadcrumb/breadcrumb-item.d.ts +0 -41
- package/breadcrumb/lib/breadcrumb/breadcrumb-separator.d.ts +0 -31
- package/breadcrumb/lib/breadcrumb/breadcrumb.d.ts +0 -151
- package/breadcrumb/lib/breadcrumb/breadcrumb.types.d.ts +0 -26
- package/breadcrumb/malva-ui-core-breadcrumb.d.ts +0 -5
- package/button/index.d.ts +0 -7
- package/button/lib/button/button.d.ts +0 -61
- package/button/lib/button-close/button-close.d.ts +0 -24
- package/button/lib/button-group/button-group.d.ts +0 -21
- package/button/lib/button-split/button-split.d.ts +0 -21
- package/button/lib/button-toggle/button-toggle.d.ts +0 -33
- package/button/lib/button-variant.token.d.ts +0 -13
- package/button/lib/button.directives.d.ts +0 -14
- package/button/lib/button.types.d.ts +0 -8
- package/button/malva-ui-core-button.d.ts +0 -5
- package/calendar/index.d.ts +0 -3
- package/calendar/lib/calendar/calendar.d.ts +0 -182
- package/calendar/lib/date-provider/date-adapter.d.ts +0 -92
- package/calendar/lib/date-provider/native-date-adapter.d.ts +0 -60
- package/calendar/malva-ui-core-calendar.d.ts +0 -5
- package/card/index.d.ts +0 -5
- package/card/lib/card/card.d.ts +0 -43
- package/card/lib/card-actions-def.d.ts +0 -10
- package/card/lib/card-footer-def.d.ts +0 -13
- package/card/lib/card-header-def.d.ts +0 -10
- package/card/lib/card-subheader-def.d.ts +0 -16
- package/card/malva-ui-core-card.d.ts +0 -5
- package/chat/index.d.ts +0 -9
- package/chat/lib/chat/chat.d.ts +0 -133
- package/chat/lib/chat-audio/chat-audio.d.ts +0 -51
- package/chat/lib/chat-audio/chat-audio.service.d.ts +0 -21
- package/chat/lib/chat-date/chat-date.d.ts +0 -16
- package/chat/lib/chat-format.d.ts +0 -5
- package/chat/lib/chat-media-grid/chat-media-grid.d.ts +0 -32
- package/chat/lib/chat-message/chat-message.d.ts +0 -45
- package/chat/lib/chat-render-list.d.ts +0 -16
- package/chat/lib/chat-tokens.d.ts +0 -25
- package/chat/lib/chat-typing/chat-typing.d.ts +0 -16
- package/chat/lib/chat.types.d.ts +0 -80
- package/chat/lib/defs/chat-author-def.d.ts +0 -30
- package/chat/lib/defs/chat-date-def.d.ts +0 -22
- package/chat/lib/defs/chat-message-def.d.ts +0 -23
- package/chat/malva-ui-core-chat.d.ts +0 -5
- package/checkbox/index.d.ts +0 -3
- package/checkbox/lib/checkbox/checkbox.d.ts +0 -129
- package/checkbox/lib/checkbox-group/checkbox-group.d.ts +0 -24
- package/checkbox/lib/checkbox-group-token.d.ts +0 -6
- package/checkbox/malva-ui-core-checkbox.d.ts +0 -5
- package/chip/index.d.ts +0 -2
- package/chip/lib/chip/chip.d.ts +0 -107
- package/chip/lib/chip/chip.directives.d.ts +0 -18
- package/chip/malva-ui-core-chip.d.ts +0 -5
- package/color-picker/index.d.ts +0 -3
- package/color-picker/lib/color-picker/color-picker.d.ts +0 -188
- package/color-picker/lib/color-picker-popup/color-picker-popup.d.ts +0 -151
- package/color-picker/lib/color-utils/color-utils.d.ts +0 -102
- package/color-picker/malva-ui-core-color-picker.d.ts +0 -5
- package/combobox/index.d.ts +0 -2
- package/combobox/lib/combobox/combobox.d.ts +0 -400
- package/combobox/lib/combobox-template.directives.d.ts +0 -10
- package/combobox/malva-ui-core-combobox.d.ts +0 -5
- package/copy-to-clipboard/index.d.ts +0 -1
- package/copy-to-clipboard/lib/copy-to-clipboard/copy-to-clipboard.d.ts +0 -130
- package/copy-to-clipboard/malva-ui-core-copy-to-clipboard.d.ts +0 -5
- package/data-table/index.d.ts +0 -8
- package/data-table/lib/data-source.d.ts +0 -5
- package/data-table/lib/data-table/data-table-layout.d.ts +0 -31
- package/data-table/lib/data-table/data-table.d.ts +0 -699
- package/data-table/lib/data-table/services/data-table-column-visibility.service.d.ts +0 -19
- package/data-table/lib/data-table/services/data-table-editing.service.d.ts +0 -37
- package/data-table/lib/data-table/services/data-table-pinning.service.d.ts +0 -37
- package/data-table/lib/data-table-cell.d.ts +0 -44
- package/data-table/lib/data-table-edit-cell.d.ts +0 -44
- package/data-table/lib/data-table-error.d.ts +0 -37
- package/data-table/lib/data-table-footer.d.ts +0 -26
- package/data-table/lib/data-table-no-data.d.ts +0 -19
- package/data-table/lib/filter-dropdown/filter-dropdown.d.ts +0 -54
- package/data-table/lib/types.d.ts +0 -134
- package/data-table/malva-ui-core-data-table.d.ts +0 -5
- package/date-range-picker/index.d.ts +0 -1
- package/date-range-picker/lib/date-range-picker/date-range-picker.d.ts +0 -145
- package/date-range-picker/malva-ui-core-date-range-picker.d.ts +0 -5
- package/day-picker/index.d.ts +0 -1
- package/day-picker/lib/day-picker/day-picker.d.ts +0 -51
- package/day-picker/malva-ui-core-day-picker.d.ts +0 -5
- package/dialog/index.d.ts +0 -11
- package/dialog/lib/confirm-dialog-options.d.ts +0 -41
- package/dialog/lib/confirm-dialog.d.ts +0 -52
- package/dialog/lib/dialog/dialog.d.ts +0 -22
- package/dialog/lib/dialog-body.d.ts +0 -9
- package/dialog/lib/dialog-close.d.ts +0 -27
- package/dialog/lib/dialog-config.d.ts +0 -112
- package/dialog/lib/dialog-container.d.ts +0 -40
- package/dialog/lib/dialog-footer.d.ts +0 -13
- package/dialog/lib/dialog-header.d.ts +0 -74
- package/dialog/lib/dialog-ref.d.ts +0 -95
- package/dialog/lib/dialog-template.d.ts +0 -65
- package/dialog/lib/dialog-text-content.d.ts +0 -24
- package/dialog/lib/dialog.service.d.ts +0 -63
- package/dialog/lib/generate-routable-dialog-route.d.ts +0 -49
- package/dialog/lib/inject-dialog-ref.d.ts +0 -8
- package/dialog/lib/routable-dialog.d.ts +0 -30
- package/dialog/malva-ui-core-dialog.d.ts +0 -5
- package/divider/index.d.ts +0 -1
- package/divider/lib/divider/divider.d.ts +0 -64
- package/divider/malva-ui-core-divider.d.ts +0 -5
- package/drawer/index.d.ts +0 -11
- package/drawer/lib/drawer/drawer.d.ts +0 -106
- package/drawer/lib/drawer-body.d.ts +0 -8
- package/drawer/lib/drawer-content.d.ts +0 -6
- package/drawer/lib/drawer-footer.d.ts +0 -5
- package/drawer/lib/drawer-header.d.ts +0 -5
- package/drawer/lib/drawer-ref.d.ts +0 -29
- package/drawer/lib/drawer-resize.d.ts +0 -65
- package/drawer/lib/drawer-section/drawer-section.d.ts +0 -15
- package/drawer/lib/drawer-sections/drawer-sections.d.ts +0 -22
- package/drawer/lib/drawer-sections.service.d.ts +0 -42
- package/drawer/lib/drawer.service.d.ts +0 -66
- package/drawer/lib/generate-routable-drawer-route.d.ts +0 -42
- package/drawer/lib/routable-drawer.d.ts +0 -30
- package/drawer/malva-ui-core-drawer.d.ts +0 -5
- package/dropdown/index.d.ts +0 -9
- package/dropdown/lib/active-descendant.d.ts +0 -64
- package/dropdown/lib/dropdown-panel/dropdown-panel.d.ts +0 -178
- package/dropdown/lib/highlight-match.pipe.d.ts +0 -27
- package/dropdown/lib/option-matcher.d.ts +0 -87
- package/dropdown/lib/options-adapter.d.ts +0 -142
- package/dropdown/lib/options-result.d.ts +0 -6
- package/dropdown/lib/reconciliation.d.ts +0 -19
- package/dropdown/lib/select-data-source.d.ts +0 -18
- package/dropdown/lib/select-option.d.ts +0 -37
- package/dropdown/malva-ui-core-dropdown.d.ts +0 -5
- package/empty-state/index.d.ts +0 -1
- package/empty-state/lib/empty-state/empty-state.d.ts +0 -34
- package/empty-state/malva-ui-core-empty-state.d.ts +0 -5
- package/esm2022/accordion/index.js +0 -4
- package/esm2022/accordion/index.js.map +0 -1
- package/esm2022/accordion/lib/accordion/accordion.js +0 -65
- package/esm2022/accordion/lib/accordion/accordion.js.map +0 -1
- package/esm2022/accordion/lib/accordion-item/accordion-header.js +0 -30
- package/esm2022/accordion/lib/accordion-item/accordion-header.js.map +0 -1
- package/esm2022/accordion/lib/accordion-item/accordion-item.js +0 -70
- package/esm2022/accordion/lib/accordion-item/accordion-item.js.map +0 -1
- package/esm2022/accordion/malva-ui-core-accordion.js +0 -5
- package/esm2022/accordion/malva-ui-core-accordion.js.map +0 -1
- package/esm2022/action-bar/index.js +0 -5
- package/esm2022/action-bar/index.js.map +0 -1
- package/esm2022/action-bar/lib/action-bar/action-bar.js +0 -64
- package/esm2022/action-bar/lib/action-bar/action-bar.js.map +0 -1
- package/esm2022/action-bar/lib/action-bar/components/action-bar-actions.js +0 -20
- package/esm2022/action-bar/lib/action-bar/components/action-bar-actions.js.map +0 -1
- package/esm2022/action-bar/lib/action-bar/components/action-bar-logo.js +0 -13
- package/esm2022/action-bar/lib/action-bar/components/action-bar-logo.js.map +0 -1
- package/esm2022/action-bar/lib/action-bar/components/action-bar-spacer.js +0 -13
- package/esm2022/action-bar/lib/action-bar/components/action-bar-spacer.js.map +0 -1
- package/esm2022/action-bar/malva-ui-core-action-bar.js +0 -5
- package/esm2022/action-bar/malva-ui-core-action-bar.js.map +0 -1
- package/esm2022/alert/index.js +0 -3
- package/esm2022/alert/index.js.map +0 -1
- package/esm2022/alert/lib/alert/alert.directives.js +0 -53
- package/esm2022/alert/lib/alert/alert.directives.js.map +0 -1
- package/esm2022/alert/lib/alert/alert.js +0 -118
- package/esm2022/alert/lib/alert/alert.js.map +0 -1
- package/esm2022/alert/malva-ui-core-alert.js +0 -5
- package/esm2022/alert/malva-ui-core-alert.js.map +0 -1
- package/esm2022/autocomplete/index.js +0 -2
- package/esm2022/autocomplete/index.js.map +0 -1
- package/esm2022/autocomplete/lib/autocomplete/autocomplete.js +0 -765
- package/esm2022/autocomplete/lib/autocomplete/autocomplete.js.map +0 -1
- package/esm2022/autocomplete/malva-ui-core-autocomplete.js +0 -5
- package/esm2022/autocomplete/malva-ui-core-autocomplete.js.map +0 -1
- package/esm2022/avatar/index.js +0 -3
- package/esm2022/avatar/index.js.map +0 -1
- package/esm2022/avatar/lib/avatar/avatar.js +0 -192
- package/esm2022/avatar/lib/avatar/avatar.js.map +0 -1
- package/esm2022/avatar/lib/color-from-text.pipe.js +0 -39
- package/esm2022/avatar/lib/color-from-text.pipe.js.map +0 -1
- package/esm2022/avatar/malva-ui-core-avatar.js +0 -5
- package/esm2022/avatar/malva-ui-core-avatar.js.map +0 -1
- package/esm2022/avatar-group/index.js +0 -2
- package/esm2022/avatar-group/index.js.map +0 -1
- package/esm2022/avatar-group/lib/avatar-group/avatar-group.js +0 -217
- package/esm2022/avatar-group/lib/avatar-group/avatar-group.js.map +0 -1
- package/esm2022/avatar-group/malva-ui-core-avatar-group.js +0 -5
- package/esm2022/avatar-group/malva-ui-core-avatar-group.js.map +0 -1
- package/esm2022/badge/index.js +0 -3
- package/esm2022/badge/index.js.map +0 -1
- package/esm2022/badge/lib/badge/badge.js +0 -71
- package/esm2022/badge/lib/badge/badge.js.map +0 -1
- package/esm2022/badge/lib/badge-icon.js +0 -47
- package/esm2022/badge/lib/badge-icon.js.map +0 -1
- package/esm2022/badge/malva-ui-core-badge.js +0 -5
- package/esm2022/badge/malva-ui-core-badge.js.map +0 -1
- package/esm2022/bottom-nav/index.js +0 -2
- package/esm2022/bottom-nav/index.js.map +0 -1
- package/esm2022/bottom-nav/lib/bottom-nav/bottom-nav.js +0 -155
- package/esm2022/bottom-nav/lib/bottom-nav/bottom-nav.js.map +0 -1
- package/esm2022/bottom-nav/malva-ui-core-bottom-nav.js +0 -5
- package/esm2022/bottom-nav/malva-ui-core-bottom-nav.js.map +0 -1
- package/esm2022/breadcrumb/index.js +0 -6
- package/esm2022/breadcrumb/index.js.map +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-item-host.js +0 -43
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-item-host.js.map +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-item.js +0 -110
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-item.js.map +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-separator.js +0 -38
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb-separator.js.map +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.js +0 -284
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.js.map +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.types.js +0 -1
- package/esm2022/breadcrumb/lib/breadcrumb/breadcrumb.types.js.map +0 -1
- package/esm2022/breadcrumb/malva-ui-core-breadcrumb.js +0 -5
- package/esm2022/breadcrumb/malva-ui-core-breadcrumb.js.map +0 -1
- package/esm2022/button/index.js +0 -8
- package/esm2022/button/index.js.map +0 -1
- package/esm2022/button/lib/button/button.js +0 -137
- package/esm2022/button/lib/button/button.js.map +0 -1
- package/esm2022/button/lib/button-close/button-close.js +0 -52
- package/esm2022/button/lib/button-close/button-close.js.map +0 -1
- package/esm2022/button/lib/button-group/button-group.js +0 -44
- package/esm2022/button/lib/button-group/button-group.js.map +0 -1
- package/esm2022/button/lib/button-split/button-split.js +0 -44
- package/esm2022/button/lib/button-split/button-split.js.map +0 -1
- package/esm2022/button/lib/button-toggle/button-toggle.js +0 -94
- package/esm2022/button/lib/button-toggle/button-toggle.js.map +0 -1
- package/esm2022/button/lib/button-variant.token.js +0 -4
- package/esm2022/button/lib/button-variant.token.js.map +0 -1
- package/esm2022/button/lib/button.directives.js +0 -37
- package/esm2022/button/lib/button.directives.js.map +0 -1
- package/esm2022/button/lib/button.types.js +0 -1
- package/esm2022/button/lib/button.types.js.map +0 -1
- package/esm2022/button/malva-ui-core-button.js +0 -5
- package/esm2022/button/malva-ui-core-button.js.map +0 -1
- package/esm2022/calendar/index.js +0 -4
- package/esm2022/calendar/index.js.map +0 -1
- package/esm2022/calendar/lib/calendar/calendar.js +0 -672
- package/esm2022/calendar/lib/calendar/calendar.js.map +0 -1
- package/esm2022/calendar/lib/date-provider/date-adapter.js +0 -111
- package/esm2022/calendar/lib/date-provider/date-adapter.js.map +0 -1
- package/esm2022/calendar/lib/date-provider/native-date-adapter.js +0 -151
- package/esm2022/calendar/lib/date-provider/native-date-adapter.js.map +0 -1
- package/esm2022/calendar/malva-ui-core-calendar.js +0 -5
- package/esm2022/calendar/malva-ui-core-calendar.js.map +0 -1
- package/esm2022/card/index.js +0 -6
- package/esm2022/card/index.js.map +0 -1
- package/esm2022/card/lib/card/card.js +0 -54
- package/esm2022/card/lib/card/card.js.map +0 -1
- package/esm2022/card/lib/card-actions-def.js +0 -27
- package/esm2022/card/lib/card-actions-def.js.map +0 -1
- package/esm2022/card/lib/card-footer-def.js +0 -32
- package/esm2022/card/lib/card-footer-def.js.map +0 -1
- package/esm2022/card/lib/card-header-def.js +0 -27
- package/esm2022/card/lib/card-header-def.js.map +0 -1
- package/esm2022/card/lib/card-subheader-def.js +0 -33
- package/esm2022/card/lib/card-subheader-def.js.map +0 -1
- package/esm2022/card/malva-ui-core-card.js +0 -5
- package/esm2022/card/malva-ui-core-card.js.map +0 -1
- package/esm2022/chat/index.js +0 -10
- package/esm2022/chat/index.js.map +0 -1
- package/esm2022/chat/lib/chat/chat.js +0 -326
- package/esm2022/chat/lib/chat/chat.js.map +0 -1
- package/esm2022/chat/lib/chat-audio/chat-audio.js +0 -110
- package/esm2022/chat/lib/chat-audio/chat-audio.js.map +0 -1
- package/esm2022/chat/lib/chat-audio/chat-audio.service.js +0 -28
- package/esm2022/chat/lib/chat-audio/chat-audio.service.js.map +0 -1
- package/esm2022/chat/lib/chat-date/chat-date.js +0 -46
- package/esm2022/chat/lib/chat-date/chat-date.js.map +0 -1
- package/esm2022/chat/lib/chat-format.js +0 -11
- package/esm2022/chat/lib/chat-format.js.map +0 -1
- package/esm2022/chat/lib/chat-media-grid/chat-media-grid.js +0 -53
- package/esm2022/chat/lib/chat-media-grid/chat-media-grid.js.map +0 -1
- package/esm2022/chat/lib/chat-message/chat-message.js +0 -86
- package/esm2022/chat/lib/chat-message/chat-message.js.map +0 -1
- package/esm2022/chat/lib/chat-render-list.js +0 -55
- package/esm2022/chat/lib/chat-render-list.js.map +0 -1
- package/esm2022/chat/lib/chat-tokens.js +0 -9
- package/esm2022/chat/lib/chat-tokens.js.map +0 -1
- package/esm2022/chat/lib/chat-typing/chat-typing.js +0 -50
- package/esm2022/chat/lib/chat-typing/chat-typing.js.map +0 -1
- package/esm2022/chat/lib/chat.types.js +0 -1
- package/esm2022/chat/lib/chat.types.js.map +0 -1
- package/esm2022/chat/lib/defs/chat-author-def.js +0 -27
- package/esm2022/chat/lib/defs/chat-author-def.js.map +0 -1
- package/esm2022/chat/lib/defs/chat-date-def.js +0 -24
- package/esm2022/chat/lib/defs/chat-date-def.js.map +0 -1
- package/esm2022/chat/lib/defs/chat-message-def.js +0 -30
- package/esm2022/chat/lib/defs/chat-message-def.js.map +0 -1
- package/esm2022/chat/malva-ui-core-chat.js +0 -5
- package/esm2022/chat/malva-ui-core-chat.js.map +0 -1
- package/esm2022/checkbox/index.js +0 -4
- package/esm2022/checkbox/index.js.map +0 -1
- package/esm2022/checkbox/lib/checkbox/checkbox.js +0 -201
- package/esm2022/checkbox/lib/checkbox/checkbox.js.map +0 -1
- package/esm2022/checkbox/lib/checkbox-group/checkbox-group.js +0 -68
- package/esm2022/checkbox/lib/checkbox-group/checkbox-group.js.map +0 -1
- package/esm2022/checkbox/lib/checkbox-group-token.js +0 -3
- package/esm2022/checkbox/lib/checkbox-group-token.js.map +0 -1
- package/esm2022/checkbox/malva-ui-core-checkbox.js +0 -5
- package/esm2022/checkbox/malva-ui-core-checkbox.js.map +0 -1
- package/esm2022/chip/index.js +0 -3
- package/esm2022/chip/index.js.map +0 -1
- package/esm2022/chip/lib/chip/chip.directives.js +0 -32
- package/esm2022/chip/lib/chip/chip.directives.js.map +0 -1
- package/esm2022/chip/lib/chip/chip.js +0 -140
- package/esm2022/chip/lib/chip/chip.js.map +0 -1
- package/esm2022/chip/malva-ui-core-chip.js +0 -5
- package/esm2022/chip/malva-ui-core-chip.js.map +0 -1
- package/esm2022/color-picker/index.js +0 -4
- package/esm2022/color-picker/index.js.map +0 -1
- package/esm2022/color-picker/lib/color-picker/color-picker.js +0 -530
- package/esm2022/color-picker/lib/color-picker/color-picker.js.map +0 -1
- package/esm2022/color-picker/lib/color-picker-popup/color-picker-popup.js +0 -419
- package/esm2022/color-picker/lib/color-picker-popup/color-picker-popup.js.map +0 -1
- package/esm2022/color-picker/lib/color-utils/color-utils.js +0 -256
- package/esm2022/color-picker/lib/color-utils/color-utils.js.map +0 -1
- package/esm2022/color-picker/malva-ui-core-color-picker.js +0 -5
- package/esm2022/color-picker/malva-ui-core-color-picker.js.map +0 -1
- package/esm2022/combobox/index.js +0 -3
- package/esm2022/combobox/index.js.map +0 -1
- package/esm2022/combobox/lib/combobox/combobox.js +0 -911
- package/esm2022/combobox/lib/combobox/combobox.js.map +0 -1
- package/esm2022/combobox/lib/combobox-template.directives.js +0 -24
- package/esm2022/combobox/lib/combobox-template.directives.js.map +0 -1
- package/esm2022/combobox/malva-ui-core-combobox.js +0 -5
- package/esm2022/combobox/malva-ui-core-combobox.js.map +0 -1
- package/esm2022/copy-to-clipboard/index.js +0 -2
- package/esm2022/copy-to-clipboard/index.js.map +0 -1
- package/esm2022/copy-to-clipboard/lib/copy-to-clipboard/copy-to-clipboard.js +0 -201
- package/esm2022/copy-to-clipboard/lib/copy-to-clipboard/copy-to-clipboard.js.map +0 -1
- package/esm2022/copy-to-clipboard/malva-ui-core-copy-to-clipboard.js +0 -5
- package/esm2022/copy-to-clipboard/malva-ui-core-copy-to-clipboard.js.map +0 -1
- package/esm2022/data-table/index.js +0 -9
- package/esm2022/data-table/index.js.map +0 -1
- package/esm2022/data-table/lib/data-source.js +0 -6
- package/esm2022/data-table/lib/data-source.js.map +0 -1
- package/esm2022/data-table/lib/data-table/data-table-layout.js +0 -84
- package/esm2022/data-table/lib/data-table/data-table-layout.js.map +0 -1
- package/esm2022/data-table/lib/data-table/data-table.js +0 -1846
- package/esm2022/data-table/lib/data-table/data-table.js.map +0 -1
- package/esm2022/data-table/lib/data-table/services/data-table-column-visibility.service.js +0 -37
- package/esm2022/data-table/lib/data-table/services/data-table-column-visibility.service.js.map +0 -1
- package/esm2022/data-table/lib/data-table/services/data-table-editing.service.js +0 -63
- package/esm2022/data-table/lib/data-table/services/data-table-editing.service.js.map +0 -1
- package/esm2022/data-table/lib/data-table/services/data-table-pinning.service.js +0 -68
- package/esm2022/data-table/lib/data-table/services/data-table-pinning.service.js.map +0 -1
- package/esm2022/data-table/lib/data-table-cell.js +0 -46
- package/esm2022/data-table/lib/data-table-cell.js.map +0 -1
- package/esm2022/data-table/lib/data-table-edit-cell.js +0 -46
- package/esm2022/data-table/lib/data-table-edit-cell.js.map +0 -1
- package/esm2022/data-table/lib/data-table-error.js +0 -37
- package/esm2022/data-table/lib/data-table-error.js.map +0 -1
- package/esm2022/data-table/lib/data-table-footer.js +0 -33
- package/esm2022/data-table/lib/data-table-footer.js.map +0 -1
- package/esm2022/data-table/lib/data-table-no-data.js +0 -26
- package/esm2022/data-table/lib/data-table-no-data.js.map +0 -1
- package/esm2022/data-table/lib/filter-dropdown/filter-dropdown.js +0 -224
- package/esm2022/data-table/lib/filter-dropdown/filter-dropdown.js.map +0 -1
- package/esm2022/data-table/lib/types.js +0 -1
- package/esm2022/data-table/lib/types.js.map +0 -1
- package/esm2022/data-table/malva-ui-core-data-table.js +0 -5
- package/esm2022/data-table/malva-ui-core-data-table.js.map +0 -1
- package/esm2022/date-range-picker/index.js +0 -2
- package/esm2022/date-range-picker/index.js.map +0 -1
- package/esm2022/date-range-picker/lib/date-range-picker/date-range-picker.js +0 -269
- package/esm2022/date-range-picker/lib/date-range-picker/date-range-picker.js.map +0 -1
- package/esm2022/date-range-picker/malva-ui-core-date-range-picker.js +0 -5
- package/esm2022/date-range-picker/malva-ui-core-date-range-picker.js.map +0 -1
- package/esm2022/day-picker/index.js +0 -2
- package/esm2022/day-picker/index.js.map +0 -1
- package/esm2022/day-picker/lib/day-picker/day-picker.js +0 -124
- package/esm2022/day-picker/lib/day-picker/day-picker.js.map +0 -1
- package/esm2022/day-picker/malva-ui-core-day-picker.js +0 -5
- package/esm2022/day-picker/malva-ui-core-day-picker.js.map +0 -1
- package/esm2022/dialog/index.js +0 -12
- package/esm2022/dialog/index.js.map +0 -1
- package/esm2022/dialog/lib/confirm-dialog-options.js +0 -1
- package/esm2022/dialog/lib/confirm-dialog-options.js.map +0 -1
- package/esm2022/dialog/lib/confirm-dialog.js +0 -155
- package/esm2022/dialog/lib/confirm-dialog.js.map +0 -1
- package/esm2022/dialog/lib/dialog/dialog.js +0 -40
- package/esm2022/dialog/lib/dialog/dialog.js.map +0 -1
- package/esm2022/dialog/lib/dialog-body.js +0 -33
- package/esm2022/dialog/lib/dialog-body.js.map +0 -1
- package/esm2022/dialog/lib/dialog-close.js +0 -45
- package/esm2022/dialog/lib/dialog-close.js.map +0 -1
- package/esm2022/dialog/lib/dialog-config.js +0 -23
- package/esm2022/dialog/lib/dialog-config.js.map +0 -1
- package/esm2022/dialog/lib/dialog-container.js +0 -69
- package/esm2022/dialog/lib/dialog-container.js.map +0 -1
- package/esm2022/dialog/lib/dialog-footer.js +0 -29
- package/esm2022/dialog/lib/dialog-footer.js.map +0 -1
- package/esm2022/dialog/lib/dialog-header.js +0 -181
- package/esm2022/dialog/lib/dialog-header.js.map +0 -1
- package/esm2022/dialog/lib/dialog-ref.js +0 -167
- package/esm2022/dialog/lib/dialog-ref.js.map +0 -1
- package/esm2022/dialog/lib/dialog-template.js +0 -136
- package/esm2022/dialog/lib/dialog-template.js.map +0 -1
- package/esm2022/dialog/lib/dialog-text-content.js +0 -59
- package/esm2022/dialog/lib/dialog-text-content.js.map +0 -1
- package/esm2022/dialog/lib/dialog.service.js +0 -205
- package/esm2022/dialog/lib/dialog.service.js.map +0 -1
- package/esm2022/dialog/lib/generate-routable-dialog-route.js +0 -59
- package/esm2022/dialog/lib/generate-routable-dialog-route.js.map +0 -1
- package/esm2022/dialog/lib/inject-dialog-ref.js +0 -16
- package/esm2022/dialog/lib/inject-dialog-ref.js.map +0 -1
- package/esm2022/dialog/lib/routable-dialog.js +0 -91
- package/esm2022/dialog/lib/routable-dialog.js.map +0 -1
- package/esm2022/dialog/malva-ui-core-dialog.js +0 -5
- package/esm2022/dialog/malva-ui-core-dialog.js.map +0 -1
- package/esm2022/divider/index.js +0 -2
- package/esm2022/divider/index.js.map +0 -1
- package/esm2022/divider/lib/divider/divider.js +0 -73
- package/esm2022/divider/lib/divider/divider.js.map +0 -1
- package/esm2022/divider/malva-ui-core-divider.js +0 -5
- package/esm2022/divider/malva-ui-core-divider.js.map +0 -1
- package/esm2022/drawer/index.js +0 -12
- package/esm2022/drawer/index.js.map +0 -1
- package/esm2022/drawer/lib/drawer/drawer.js +0 -180
- package/esm2022/drawer/lib/drawer/drawer.js.map +0 -1
- package/esm2022/drawer/lib/drawer-body.js +0 -32
- package/esm2022/drawer/lib/drawer-body.js.map +0 -1
- package/esm2022/drawer/lib/drawer-content.js +0 -14
- package/esm2022/drawer/lib/drawer-content.js.map +0 -1
- package/esm2022/drawer/lib/drawer-footer.js +0 -14
- package/esm2022/drawer/lib/drawer-footer.js.map +0 -1
- package/esm2022/drawer/lib/drawer-header.js +0 -14
- package/esm2022/drawer/lib/drawer-header.js.map +0 -1
- package/esm2022/drawer/lib/drawer-ref.js +0 -31
- package/esm2022/drawer/lib/drawer-ref.js.map +0 -1
- package/esm2022/drawer/lib/drawer-resize.js +0 -243
- package/esm2022/drawer/lib/drawer-resize.js.map +0 -1
- package/esm2022/drawer/lib/drawer-section/drawer-section.js +0 -26
- package/esm2022/drawer/lib/drawer-section/drawer-section.js.map +0 -1
- package/esm2022/drawer/lib/drawer-sections/drawer-sections.js +0 -58
- package/esm2022/drawer/lib/drawer-sections/drawer-sections.js.map +0 -1
- package/esm2022/drawer/lib/drawer-sections.service.js +0 -83
- package/esm2022/drawer/lib/drawer-sections.service.js.map +0 -1
- package/esm2022/drawer/lib/drawer.service.js +0 -86
- package/esm2022/drawer/lib/drawer.service.js.map +0 -1
- package/esm2022/drawer/lib/generate-routable-drawer-route.js +0 -52
- package/esm2022/drawer/lib/generate-routable-drawer-route.js.map +0 -1
- package/esm2022/drawer/lib/routable-drawer.js +0 -91
- package/esm2022/drawer/lib/routable-drawer.js.map +0 -1
- package/esm2022/drawer/malva-ui-core-drawer.js +0 -5
- package/esm2022/drawer/malva-ui-core-drawer.js.map +0 -1
- package/esm2022/dropdown/index.js +0 -10
- package/esm2022/dropdown/index.js.map +0 -1
- package/esm2022/dropdown/lib/active-descendant.js +0 -92
- package/esm2022/dropdown/lib/active-descendant.js.map +0 -1
- package/esm2022/dropdown/lib/dropdown-panel/dropdown-panel.js +0 -295
- package/esm2022/dropdown/lib/dropdown-panel/dropdown-panel.js.map +0 -1
- package/esm2022/dropdown/lib/highlight-match.pipe.js +0 -36
- package/esm2022/dropdown/lib/highlight-match.pipe.js.map +0 -1
- package/esm2022/dropdown/lib/option-matcher.js +0 -124
- package/esm2022/dropdown/lib/option-matcher.js.map +0 -1
- package/esm2022/dropdown/lib/options-adapter.js +0 -356
- package/esm2022/dropdown/lib/options-adapter.js.map +0 -1
- package/esm2022/dropdown/lib/options-result.js +0 -11
- package/esm2022/dropdown/lib/options-result.js.map +0 -1
- package/esm2022/dropdown/lib/reconciliation.js +0 -32
- package/esm2022/dropdown/lib/reconciliation.js.map +0 -1
- package/esm2022/dropdown/lib/select-data-source.js +0 -21
- package/esm2022/dropdown/lib/select-data-source.js.map +0 -1
- package/esm2022/dropdown/lib/select-option.js +0 -25
- package/esm2022/dropdown/lib/select-option.js.map +0 -1
- package/esm2022/dropdown/malva-ui-core-dropdown.js +0 -5
- package/esm2022/dropdown/malva-ui-core-dropdown.js.map +0 -1
- package/esm2022/empty-state/index.js +0 -2
- package/esm2022/empty-state/index.js.map +0 -1
- package/esm2022/empty-state/lib/empty-state/empty-state.js +0 -43
- package/esm2022/empty-state/lib/empty-state/empty-state.js.map +0 -1
- package/esm2022/empty-state/malva-ui-core-empty-state.js +0 -5
- package/esm2022/empty-state/malva-ui-core-empty-state.js.map +0 -1
- package/esm2022/expand/index.js +0 -3
- package/esm2022/expand/index.js.map +0 -1
- package/esm2022/expand/lib/expand/expand-content.js +0 -33
- package/esm2022/expand/lib/expand/expand-content.js.map +0 -1
- package/esm2022/expand/lib/expand/expand.js +0 -93
- package/esm2022/expand/lib/expand/expand.js.map +0 -1
- package/esm2022/expand/malva-ui-core-expand.js +0 -5
- package/esm2022/expand/malva-ui-core-expand.js.map +0 -1
- package/esm2022/file-upload/index.js +0 -5
- package/esm2022/file-upload/index.js.map +0 -1
- package/esm2022/file-upload/lib/file-upload/file-upload.js +0 -324
- package/esm2022/file-upload/lib/file-upload/file-upload.js.map +0 -1
- package/esm2022/file-upload/lib/file-upload/file-upload.types.js +0 -1
- package/esm2022/file-upload/lib/file-upload/file-upload.types.js.map +0 -1
- package/esm2022/file-upload/lib/file-upload-action.js +0 -65
- package/esm2022/file-upload/lib/file-upload-action.js.map +0 -1
- package/esm2022/file-upload/lib/file-upload-item/file-upload-item.js +0 -55
- package/esm2022/file-upload/lib/file-upload-item/file-upload-item.js.map +0 -1
- package/esm2022/file-upload/malva-ui-core-file-upload.js +0 -5
- package/esm2022/file-upload/malva-ui-core-file-upload.js.map +0 -1
- package/esm2022/filter/index.js +0 -4
- package/esm2022/filter/index.js.map +0 -1
- package/esm2022/filter/lib/filter/filter.js +0 -552
- package/esm2022/filter/lib/filter/filter.js.map +0 -1
- package/esm2022/filter/lib/filter.types.js +0 -1
- package/esm2022/filter/lib/filter.types.js.map +0 -1
- package/esm2022/filter/lib/smart-filter-bar/smart-filter-bar.js +0 -518
- package/esm2022/filter/lib/smart-filter-bar/smart-filter-bar.js.map +0 -1
- package/esm2022/filter/malva-ui-core-filter.js +0 -5
- package/esm2022/filter/malva-ui-core-filter.js.map +0 -1
- package/esm2022/form/index.js +0 -7
- package/esm2022/form/index.js.map +0 -1
- package/esm2022/form/lib/fieldset/fieldset.js +0 -101
- package/esm2022/form/lib/fieldset/fieldset.js.map +0 -1
- package/esm2022/form/lib/fieldset-span.js +0 -49
- package/esm2022/form/lib/fieldset-span.js.map +0 -1
- package/esm2022/form/lib/form/form.js +0 -60
- package/esm2022/form/lib/form/form.js.map +0 -1
- package/esm2022/form/lib/form-actions.js +0 -34
- package/esm2022/form/lib/form-actions.js.map +0 -1
- package/esm2022/form/lib/form-gap.js +0 -15
- package/esm2022/form/lib/form-gap.js.map +0 -1
- package/esm2022/form/lib/form-header.js +0 -27
- package/esm2022/form/lib/form-header.js.map +0 -1
- package/esm2022/form/lib/form.types.js +0 -1
- package/esm2022/form/lib/form.types.js.map +0 -1
- package/esm2022/form/malva-ui-core-form.js +0 -5
- package/esm2022/form/malva-ui-core-form.js.map +0 -1
- package/esm2022/form-utils/index.js +0 -16
- package/esm2022/form-utils/index.js.map +0 -1
- package/esm2022/form-utils/lib/aria-value-bridge.js +0 -57
- package/esm2022/form-utils/lib/aria-value-bridge.js.map +0 -1
- package/esm2022/form-utils/lib/description/description.js +0 -24
- package/esm2022/form-utils/lib/description/description.js.map +0 -1
- package/esm2022/form-utils/lib/focusable-group-base.js +0 -87
- package/esm2022/form-utils/lib/focusable-group-base.js.map +0 -1
- package/esm2022/form-utils/lib/form-control-base/signal-form-control-base.js +0 -192
- package/esm2022/form-utils/lib/form-control-base/signal-form-control-base.js.map +0 -1
- package/esm2022/form-utils/lib/form-control-sides.js +0 -34
- package/esm2022/form-utils/lib/form-control-sides.js.map +0 -1
- package/esm2022/form-utils/lib/form-control-wrapper/form-control-wrapper-control.js +0 -14
- package/esm2022/form-utils/lib/form-control-wrapper/form-control-wrapper-control.js.map +0 -1
- package/esm2022/form-utils/lib/form-control-wrapper/form-control-wrapper.js +0 -47
- package/esm2022/form-utils/lib/form-control-wrapper/form-control-wrapper.js.map +0 -1
- package/esm2022/form-utils/lib/form-field/form-field.js +0 -245
- package/esm2022/form-utils/lib/form-field/form-field.js.map +0 -1
- package/esm2022/form-utils/lib/hint/hint.js +0 -11
- package/esm2022/form-utils/lib/hint/hint.js.map +0 -1
- package/esm2022/form-utils/lib/label/label.js +0 -55
- package/esm2022/form-utils/lib/label/label.js.map +0 -1
- package/esm2022/form-utils/lib/message/message.js +0 -20
- package/esm2022/form-utils/lib/message/message.js.map +0 -1
- package/esm2022/form-utils/lib/models/error-display-strategy.js +0 -1
- package/esm2022/form-utils/lib/models/error-display-strategy.js.map +0 -1
- package/esm2022/form-utils/lib/models/form-control-connector.js +0 -3
- package/esm2022/form-utils/lib/models/form-control-connector.js.map +0 -1
- package/esm2022/form-utils/lib/models/form-state.js +0 -1
- package/esm2022/form-utils/lib/models/form-state.js.map +0 -1
- package/esm2022/form-utils/lib/selection.service.js +0 -81
- package/esm2022/form-utils/lib/selection.service.js.map +0 -1
- package/esm2022/form-utils/malva-ui-core-form-utils.js +0 -5
- package/esm2022/form-utils/malva-ui-core-form-utils.js.map +0 -1
- package/esm2022/form-utils/testing/index.js +0 -2
- package/esm2022/form-utils/testing/index.js.map +0 -1
- package/esm2022/form-utils/testing/lib/forms-binding-matrix.js +0 -32
- package/esm2022/form-utils/testing/lib/forms-binding-matrix.js.map +0 -1
- package/esm2022/form-utils/testing/malva-ui-core-form-utils-testing.js +0 -5
- package/esm2022/form-utils/testing/malva-ui-core-form-utils-testing.js.map +0 -1
- package/esm2022/index.js +0 -70
- package/esm2022/index.js.map +0 -1
- package/esm2022/input/index.js +0 -4
- package/esm2022/input/index.js.map +0 -1
- package/esm2022/input/lib/input/input-native.js +0 -49
- package/esm2022/input/lib/input/input-native.js.map +0 -1
- package/esm2022/input/lib/input/input-value-accessor.js +0 -4
- package/esm2022/input/lib/input/input-value-accessor.js.map +0 -1
- package/esm2022/input/lib/input/input.js +0 -277
- package/esm2022/input/lib/input/input.js.map +0 -1
- package/esm2022/input/lib/input/password-strength.js +0 -46
- package/esm2022/input/lib/input/password-strength.js.map +0 -1
- package/esm2022/input/malva-ui-core-input.js +0 -5
- package/esm2022/input/malva-ui-core-input.js.map +0 -1
- package/esm2022/kbd/index.js +0 -2
- package/esm2022/kbd/index.js.map +0 -1
- package/esm2022/kbd/lib/kbd/kbd.js +0 -124
- package/esm2022/kbd/lib/kbd/kbd.js.map +0 -1
- package/esm2022/kbd/malva-ui-core-kbd.js +0 -5
- package/esm2022/kbd/malva-ui-core-kbd.js.map +0 -1
- package/esm2022/layout/index.js +0 -5
- package/esm2022/layout/index.js.map +0 -1
- package/esm2022/layout/lib/layout/directives/MlvLayoutSide.js +0 -14
- package/esm2022/layout/lib/layout/directives/MlvLayoutSide.js.map +0 -1
- package/esm2022/layout/lib/layout/directives/MlvLayoutTop.js +0 -14
- package/esm2022/layout/lib/layout/directives/MlvLayoutTop.js.map +0 -1
- package/esm2022/layout/lib/layout/layout.js +0 -43
- package/esm2022/layout/lib/layout/layout.js.map +0 -1
- package/esm2022/layout/lib/layout/services/theme.service.js +0 -121
- package/esm2022/layout/lib/layout/services/theme.service.js.map +0 -1
- package/esm2022/layout/malva-ui-core-layout.js +0 -5
- package/esm2022/layout/malva-ui-core-layout.js.map +0 -1
- package/esm2022/link/index.js +0 -3
- package/esm2022/link/index.js.map +0 -1
- package/esm2022/link/lib/link/link.directives.js +0 -24
- package/esm2022/link/lib/link/link.directives.js.map +0 -1
- package/esm2022/link/lib/link/link.js +0 -61
- package/esm2022/link/lib/link/link.js.map +0 -1
- package/esm2022/link/malva-ui-core-link.js +0 -5
- package/esm2022/link/malva-ui-core-link.js.map +0 -1
- package/esm2022/list/index.js +0 -14
- package/esm2022/list/index.js.map +0 -1
- package/esm2022/list/lib/list/list.js +0 -28
- package/esm2022/list/lib/list/list.js.map +0 -1
- package/esm2022/list/lib/list-item/list-item.js +0 -125
- package/esm2022/list/lib/list-item/list-item.js.map +0 -1
- package/esm2022/list/lib/list-item-actions.js +0 -23
- package/esm2022/list/lib/list-item-actions.js.map +0 -1
- package/esm2022/list/lib/list-item-byline.js +0 -13
- package/esm2022/list/lib/list-item-byline.js.map +0 -1
- package/esm2022/list/lib/list-item-group/list-item-group.js +0 -25
- package/esm2022/list/lib/list-item-group/list-item-group.js.map +0 -1
- package/esm2022/list/lib/list-item-link/list-item-link.js +0 -20
- package/esm2022/list/lib/list-item-link/list-item-link.js.map +0 -1
- package/esm2022/list/lib/list-item-media.js +0 -13
- package/esm2022/list/lib/list-item-media.js.map +0 -1
- package/esm2022/list/lib/list-item-meta.js +0 -13
- package/esm2022/list/lib/list-item-meta.js.map +0 -1
- package/esm2022/list/lib/list-item-prefix.js +0 -13
- package/esm2022/list/lib/list-item-prefix.js.map +0 -1
- package/esm2022/list/lib/list-item-suffix.js +0 -13
- package/esm2022/list/lib/list-item-suffix.js.map +0 -1
- package/esm2022/list/lib/list-item-template.js +0 -14
- package/esm2022/list/lib/list-item-template.js.map +0 -1
- package/esm2022/list/lib/list-item-title.js +0 -13
- package/esm2022/list/lib/list-item-title.js.map +0 -1
- package/esm2022/list/lib/list-selectable.js +0 -116
- package/esm2022/list/lib/list-selectable.js.map +0 -1
- package/esm2022/list/malva-ui-core-list.js +0 -5
- package/esm2022/list/malva-ui-core-list.js.map +0 -1
- package/esm2022/loader/index.js +0 -2
- package/esm2022/loader/index.js.map +0 -1
- package/esm2022/loader/lib/loader/loader.js +0 -134
- package/esm2022/loader/lib/loader/loader.js.map +0 -1
- package/esm2022/loader/malva-ui-core-loader.js +0 -5
- package/esm2022/loader/malva-ui-core-loader.js.map +0 -1
- package/esm2022/malva-ui-core.js +0 -5
- package/esm2022/malva-ui-core.js.map +0 -1
- package/esm2022/menu/index.js +0 -10
- package/esm2022/menu/index.js.map +0 -1
- package/esm2022/menu/lib/menu/menu-group-label.js +0 -35
- package/esm2022/menu/lib/menu/menu-group-label.js.map +0 -1
- package/esm2022/menu/lib/menu/menu-group.js +0 -44
- package/esm2022/menu/lib/menu/menu-group.js.map +0 -1
- package/esm2022/menu/lib/menu/menu-item.js +0 -117
- package/esm2022/menu/lib/menu/menu-item.js.map +0 -1
- package/esm2022/menu/lib/menu/menu-separator.js +0 -41
- package/esm2022/menu/lib/menu/menu-separator.js.map +0 -1
- package/esm2022/menu/lib/menu/menu-trigger.js +0 -653
- package/esm2022/menu/lib/menu/menu-trigger.js.map +0 -1
- package/esm2022/menu/lib/menu/menu.js +0 -308
- package/esm2022/menu/lib/menu/menu.js.map +0 -1
- package/esm2022/menu/lib/menu/menu.types.js +0 -4
- package/esm2022/menu/lib/menu/menu.types.js.map +0 -1
- package/esm2022/menu/lib/menu/menubar.js +0 -257
- package/esm2022/menu/lib/menu/menubar.js.map +0 -1
- package/esm2022/menu/lib/menu/menubar.types.js +0 -4
- package/esm2022/menu/lib/menu/menubar.types.js.map +0 -1
- package/esm2022/menu/lib/menu/submenu-aim.js +0 -30
- package/esm2022/menu/lib/menu/submenu-aim.js.map +0 -1
- package/esm2022/menu/malva-ui-core-menu.js +0 -5
- package/esm2022/menu/malva-ui-core-menu.js.map +0 -1
- package/esm2022/notification/index.js +0 -5
- package/esm2022/notification/index.js.map +0 -1
- package/esm2022/notification/lib/notification-item/notification-item.js +0 -65
- package/esm2022/notification/lib/notification-item/notification-item.js.map +0 -1
- package/esm2022/notification/lib/notification-ref.js +0 -13
- package/esm2022/notification/lib/notification-ref.js.map +0 -1
- package/esm2022/notification/lib/notification.service.js +0 -118
- package/esm2022/notification/lib/notification.service.js.map +0 -1
- package/esm2022/notification/lib/notification.types.js +0 -6
- package/esm2022/notification/lib/notification.types.js.map +0 -1
- package/esm2022/notification/malva-ui-core-notification.js +0 -5
- package/esm2022/notification/malva-ui-core-notification.js.map +0 -1
- package/esm2022/number-input/index.js +0 -2
- package/esm2022/number-input/index.js.map +0 -1
- package/esm2022/number-input/lib/number-input/number-input.js +0 -395
- package/esm2022/number-input/lib/number-input/number-input.js.map +0 -1
- package/esm2022/number-input/malva-ui-core-number-input.js +0 -5
- package/esm2022/number-input/malva-ui-core-number-input.js.map +0 -1
- package/esm2022/page/index.js +0 -15
- package/esm2022/page/index.js.map +0 -1
- package/esm2022/page/lib/page/page-scroll.token.js +0 -9
- package/esm2022/page/lib/page/page-scroll.token.js.map +0 -1
- package/esm2022/page/lib/page/page-snap-controller.js +0 -170
- package/esm2022/page/lib/page/page-snap-controller.js.map +0 -1
- package/esm2022/page/lib/page/page-snap.directive.js +0 -65
- package/esm2022/page/lib/page/page-snap.directive.js.map +0 -1
- package/esm2022/page/lib/page/page.js +0 -173
- package/esm2022/page/lib/page/page.js.map +0 -1
- package/esm2022/page/lib/page-content/page-aside.js +0 -13
- package/esm2022/page/lib/page-content/page-aside.js.map +0 -1
- package/esm2022/page/lib/page-content/page-content.js +0 -72
- package/esm2022/page/lib/page-content/page-content.js.map +0 -1
- package/esm2022/page/lib/page-dock/page-dock.js +0 -128
- package/esm2022/page/lib/page-dock/page-dock.js.map +0 -1
- package/esm2022/page/lib/page-dock/page-dock.slots.js +0 -39
- package/esm2022/page/lib/page-dock/page-dock.slots.js.map +0 -1
- package/esm2022/page/lib/page-header/page-header.directives.js +0 -88
- package/esm2022/page/lib/page-header/page-header.directives.js.map +0 -1
- package/esm2022/page/lib/page-header/page-header.js +0 -124
- package/esm2022/page/lib/page-header/page-header.js.map +0 -1
- package/esm2022/page/lib/page-shell/page-shell-color.js +0 -193
- package/esm2022/page/lib/page-shell/page-shell-color.js.map +0 -1
- package/esm2022/page/lib/page-shell/page-shell-css-color.js +0 -207
- package/esm2022/page/lib/page-shell/page-shell-css-color.js.map +0 -1
- package/esm2022/page/lib/page-shell/page-shell.js +0 -131
- package/esm2022/page/lib/page-shell/page-shell.js.map +0 -1
- package/esm2022/page/lib/page-shell/page-shell.slots.js +0 -41
- package/esm2022/page/lib/page-shell/page-shell.slots.js.map +0 -1
- package/esm2022/page/lib/page-summary/page-summary-item.js +0 -26
- package/esm2022/page/lib/page-summary/page-summary-item.js.map +0 -1
- package/esm2022/page/lib/page-summary/page-summary.js +0 -87
- package/esm2022/page/lib/page-summary/page-summary.js.map +0 -1
- package/esm2022/page/malva-ui-core-page.js +0 -5
- package/esm2022/page/malva-ui-core-page.js.map +0 -1
- package/esm2022/pagination/index.js +0 -5
- package/esm2022/pagination/index.js.map +0 -1
- package/esm2022/pagination/lib/pagination/pagination.directives.js +0 -58
- package/esm2022/pagination/lib/pagination/pagination.directives.js.map +0 -1
- package/esm2022/pagination/lib/pagination/pagination.js +0 -293
- package/esm2022/pagination/lib/pagination/pagination.js.map +0 -1
- package/esm2022/pagination/lib/pagination/pagination.model.js +0 -1
- package/esm2022/pagination/lib/pagination/pagination.model.js.map +0 -1
- package/esm2022/pagination/lib/pagination/pagination.service.js +0 -108
- package/esm2022/pagination/lib/pagination/pagination.service.js.map +0 -1
- package/esm2022/pagination/malva-ui-core-pagination.js +0 -5
- package/esm2022/pagination/malva-ui-core-pagination.js.map +0 -1
- package/esm2022/pin-input/index.js +0 -3
- package/esm2022/pin-input/index.js.map +0 -1
- package/esm2022/pin-input/lib/pin-input/pin-input-separator.js +0 -31
- package/esm2022/pin-input/lib/pin-input/pin-input-separator.js.map +0 -1
- package/esm2022/pin-input/lib/pin-input/pin-input.js +0 -365
- package/esm2022/pin-input/lib/pin-input/pin-input.js.map +0 -1
- package/esm2022/pin-input/malva-ui-core-pin-input.js +0 -5
- package/esm2022/pin-input/malva-ui-core-pin-input.js.map +0 -1
- package/esm2022/popup/index.js +0 -10
- package/esm2022/popup/index.js.map +0 -1
- package/esm2022/popup/lib/popup/popup.js +0 -500
- package/esm2022/popup/lib/popup/popup.js.map +0 -1
- package/esm2022/popup/lib/popup-container/popup-container.js +0 -169
- package/esm2022/popup/lib/popup-container/popup-container.js.map +0 -1
- package/esm2022/popup/lib/popup-container/popup-container.token.js +0 -9
- package/esm2022/popup/lib/popup-container/popup-container.token.js.map +0 -1
- package/esm2022/popup/lib/popup-content.js +0 -14
- package/esm2022/popup/lib/popup-content.js.map +0 -1
- package/esm2022/popup/lib/popup-header-content.js +0 -26
- package/esm2022/popup/lib/popup-header-content.js.map +0 -1
- package/esm2022/popup/lib/popup-pinned-content.js +0 -25
- package/esm2022/popup/lib/popup-pinned-content.js.map +0 -1
- package/esm2022/popup/lib/popup-positions.js +0 -252
- package/esm2022/popup/lib/popup-positions.js.map +0 -1
- package/esm2022/popup/lib/popup-trigger/popup-trigger.js +0 -308
- package/esm2022/popup/lib/popup-trigger/popup-trigger.js.map +0 -1
- package/esm2022/popup/lib/popup.service.js +0 -188
- package/esm2022/popup/lib/popup.service.js.map +0 -1
- package/esm2022/popup/malva-ui-core-popup.js +0 -5
- package/esm2022/popup/malva-ui-core-popup.js.map +0 -1
- package/esm2022/progress/index.js +0 -2
- package/esm2022/progress/index.js.map +0 -1
- package/esm2022/progress/lib/progress/progress.js +0 -102
- package/esm2022/progress/lib/progress/progress.js.map +0 -1
- package/esm2022/progress/malva-ui-core-progress.js +0 -5
- package/esm2022/progress/malva-ui-core-progress.js.map +0 -1
- package/esm2022/radio/index.js +0 -3
- package/esm2022/radio/index.js.map +0 -1
- package/esm2022/radio/lib/radio/radio.js +0 -134
- package/esm2022/radio/lib/radio/radio.js.map +0 -1
- package/esm2022/radio/lib/radio-group/radio-group.js +0 -176
- package/esm2022/radio/lib/radio-group/radio-group.js.map +0 -1
- package/esm2022/radio/lib/radio-group-token.js +0 -3
- package/esm2022/radio/lib/radio-group-token.js.map +0 -1
- package/esm2022/radio/malva-ui-core-radio.js +0 -5
- package/esm2022/radio/malva-ui-core-radio.js.map +0 -1
- package/esm2022/rating/index.js +0 -2
- package/esm2022/rating/index.js.map +0 -1
- package/esm2022/rating/lib/rating/rating.js +0 -208
- package/esm2022/rating/lib/rating/rating.js.map +0 -1
- package/esm2022/rating/malva-ui-core-rating.js +0 -5
- package/esm2022/rating/malva-ui-core-rating.js.map +0 -1
- package/esm2022/scrollbar/index.js +0 -2
- package/esm2022/scrollbar/index.js.map +0 -1
- package/esm2022/scrollbar/lib/scrollbar/scrollbar.js +0 -388
- package/esm2022/scrollbar/lib/scrollbar/scrollbar.js.map +0 -1
- package/esm2022/scrollbar/malva-ui-core-scrollbar.js +0 -5
- package/esm2022/scrollbar/malva-ui-core-scrollbar.js.map +0 -1
- package/esm2022/search-field/index.js +0 -3
- package/esm2022/search-field/index.js.map +0 -1
- package/esm2022/search-field/lib/search-field/search-field.js +0 -535
- package/esm2022/search-field/lib/search-field/search-field.js.map +0 -1
- package/esm2022/search-field/lib/search-field/search-overlay-content.js +0 -35
- package/esm2022/search-field/lib/search-field/search-overlay-content.js.map +0 -1
- package/esm2022/search-field/malva-ui-core-search-field.js +0 -5
- package/esm2022/search-field/malva-ui-core-search-field.js.map +0 -1
- package/esm2022/segmented/index.js +0 -5
- package/esm2022/segmented/index.js.map +0 -1
- package/esm2022/segmented/lib/segmented/segmented.js +0 -248
- package/esm2022/segmented/lib/segmented/segmented.js.map +0 -1
- package/esm2022/segmented/lib/segmented-item/segmented-item.js +0 -194
- package/esm2022/segmented/lib/segmented-item/segmented-item.js.map +0 -1
- package/esm2022/segmented/lib/segmented-token.js +0 -4
- package/esm2022/segmented/lib/segmented-token.js.map +0 -1
- package/esm2022/segmented/lib/segmented.types.js +0 -1
- package/esm2022/segmented/lib/segmented.types.js.map +0 -1
- package/esm2022/segmented/malva-ui-core-segmented.js +0 -5
- package/esm2022/segmented/malva-ui-core-segmented.js.map +0 -1
- package/esm2022/select/index.js +0 -4
- package/esm2022/select/index.js.map +0 -1
- package/esm2022/select/lib/select/select.js +0 -685
- package/esm2022/select/lib/select/select.js.map +0 -1
- package/esm2022/select/lib/select-option.js +0 -2
- package/esm2022/select/lib/select-option.js.map +0 -1
- package/esm2022/select/lib/select-template.directives.js +0 -34
- package/esm2022/select/lib/select-template.directives.js.map +0 -1
- package/esm2022/select/malva-ui-core-select.js +0 -5
- package/esm2022/select/malva-ui-core-select.js.map +0 -1
- package/esm2022/sidebar/index.js +0 -16
- package/esm2022/sidebar/index.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar/sidebar.js +0 -251
- package/esm2022/sidebar/lib/sidebar/sidebar.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-content.js +0 -37
- package/esm2022/sidebar/lib/sidebar-content.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-context.js +0 -3
- package/esm2022/sidebar/lib/sidebar-context.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-footer.js +0 -20
- package/esm2022/sidebar/lib/sidebar-footer.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-group/sidebar-group.js +0 -341
- package/esm2022/sidebar/lib/sidebar-group/sidebar-group.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-header.js +0 -20
- package/esm2022/sidebar/lib/sidebar-header.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-item/sidebar-item.js +0 -216
- package/esm2022/sidebar/lib/sidebar-item/sidebar-item.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-item-host.js +0 -39
- package/esm2022/sidebar/lib/sidebar-item-host.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-item-icon.js +0 -14
- package/esm2022/sidebar/lib/sidebar-item-icon.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-mode.js +0 -1
- package/esm2022/sidebar/lib/sidebar-mode.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-rail/sidebar-rail.js +0 -202
- package/esm2022/sidebar/lib/sidebar-rail/sidebar-rail.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-trigger/sidebar-trigger.js +0 -159
- package/esm2022/sidebar/lib/sidebar-trigger/sidebar-trigger.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.directives.js +0 -35
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.directives.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.js +0 -107
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.js.map +0 -1
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.types.js +0 -1
- package/esm2022/sidebar/lib/sidebar-workspace/sidebar-workspace.types.js.map +0 -1
- package/esm2022/sidebar/malva-ui-core-sidebar.js +0 -5
- package/esm2022/sidebar/malva-ui-core-sidebar.js.map +0 -1
- package/esm2022/skeleton/index.js +0 -2
- package/esm2022/skeleton/index.js.map +0 -1
- package/esm2022/skeleton/lib/skeleton/skeleton.js +0 -78
- package/esm2022/skeleton/lib/skeleton/skeleton.js.map +0 -1
- package/esm2022/skeleton/malva-ui-core-skeleton.js +0 -5
- package/esm2022/skeleton/malva-ui-core-skeleton.js.map +0 -1
- package/esm2022/slider/index.js +0 -3
- package/esm2022/slider/index.js.map +0 -1
- package/esm2022/slider/lib/slider/slider-tooltip-def.js +0 -31
- package/esm2022/slider/lib/slider/slider-tooltip-def.js.map +0 -1
- package/esm2022/slider/lib/slider/slider.js +0 -468
- package/esm2022/slider/lib/slider/slider.js.map +0 -1
- package/esm2022/slider/malva-ui-core-slider.js +0 -5
- package/esm2022/slider/malva-ui-core-slider.js.map +0 -1
- package/esm2022/split-pane/index.js +0 -4
- package/esm2022/split-pane/index.js.map +0 -1
- package/esm2022/split-pane/lib/split-pane/split-pane-panel.js +0 -49
- package/esm2022/split-pane/lib/split-pane/split-pane-panel.js.map +0 -1
- package/esm2022/split-pane/lib/split-pane/split-pane.js +0 -290
- package/esm2022/split-pane/lib/split-pane/split-pane.js.map +0 -1
- package/esm2022/split-pane/lib/split-pane/split-pane.types.js +0 -1
- package/esm2022/split-pane/lib/split-pane/split-pane.types.js.map +0 -1
- package/esm2022/split-pane/malva-ui-core-split-pane.js +0 -5
- package/esm2022/split-pane/malva-ui-core-split-pane.js.map +0 -1
- package/esm2022/status-indicator/index.js +0 -2
- package/esm2022/status-indicator/index.js.map +0 -1
- package/esm2022/status-indicator/lib/status-indicator/status-indicator.js +0 -71
- package/esm2022/status-indicator/lib/status-indicator/status-indicator.js.map +0 -1
- package/esm2022/status-indicator/malva-ui-core-status-indicator.js +0 -5
- package/esm2022/status-indicator/malva-ui-core-status-indicator.js.map +0 -1
- package/esm2022/stepper/index.js +0 -5
- package/esm2022/stepper/index.js.map +0 -1
- package/esm2022/stepper/lib/stepper/step-header.js +0 -46
- package/esm2022/stepper/lib/stepper/step-header.js.map +0 -1
- package/esm2022/stepper/lib/stepper/step.js +0 -65
- package/esm2022/stepper/lib/stepper/step.js.map +0 -1
- package/esm2022/stepper/lib/stepper/stepper-token.js +0 -4
- package/esm2022/stepper/lib/stepper/stepper-token.js.map +0 -1
- package/esm2022/stepper/lib/stepper/stepper.js +0 -216
- package/esm2022/stepper/lib/stepper/stepper.js.map +0 -1
- package/esm2022/stepper/lib/stepper/stepper.types.js +0 -1
- package/esm2022/stepper/lib/stepper/stepper.types.js.map +0 -1
- package/esm2022/stepper/malva-ui-core-stepper.js +0 -5
- package/esm2022/stepper/malva-ui-core-stepper.js.map +0 -1
- package/esm2022/switch/index.js +0 -3
- package/esm2022/switch/index.js.map +0 -1
- package/esm2022/switch/lib/switch/switch.js +0 -190
- package/esm2022/switch/lib/switch/switch.js.map +0 -1
- package/esm2022/switch/lib/switch-group/switch-group.js +0 -68
- package/esm2022/switch/lib/switch-group/switch-group.js.map +0 -1
- package/esm2022/switch/lib/switch-group-token.js +0 -3
- package/esm2022/switch/lib/switch-group-token.js.map +0 -1
- package/esm2022/switch/malva-ui-core-switch.js +0 -5
- package/esm2022/switch/malva-ui-core-switch.js.map +0 -1
- package/esm2022/tabs/index.js +0 -9
- package/esm2022/tabs/index.js.map +0 -1
- package/esm2022/tabs/lib/tab/tab.js +0 -72
- package/esm2022/tabs/lib/tab/tab.js.map +0 -1
- package/esm2022/tabs/lib/tab-content/tab-content.js +0 -19
- package/esm2022/tabs/lib/tab-content/tab-content.js.map +0 -1
- package/esm2022/tabs/lib/tab-content-def.js +0 -14
- package/esm2022/tabs/lib/tab-content-def.js.map +0 -1
- package/esm2022/tabs/lib/tab-def.js +0 -17
- package/esm2022/tabs/lib/tab-def.js.map +0 -1
- package/esm2022/tabs/lib/tab-group-token.js +0 -3
- package/esm2022/tabs/lib/tab-group-token.js.map +0 -1
- package/esm2022/tabs/lib/tab-item/tab-item.js +0 -44
- package/esm2022/tabs/lib/tab-item/tab-item.js.map +0 -1
- package/esm2022/tabs/lib/tabs/tabs.js +0 -542
- package/esm2022/tabs/lib/tabs/tabs.js.map +0 -1
- package/esm2022/tabs/lib/tabs.service.js +0 -83
- package/esm2022/tabs/lib/tabs.service.js.map +0 -1
- package/esm2022/tabs/malva-ui-core-tabs.js +0 -5
- package/esm2022/tabs/malva-ui-core-tabs.js.map +0 -1
- package/esm2022/textarea/index.js +0 -2
- package/esm2022/textarea/index.js.map +0 -1
- package/esm2022/textarea/lib/textarea/textarea.js +0 -194
- package/esm2022/textarea/lib/textarea/textarea.js.map +0 -1
- package/esm2022/textarea/malva-ui-core-textarea.js +0 -5
- package/esm2022/textarea/malva-ui-core-textarea.js.map +0 -1
- package/esm2022/tile/index.js +0 -3
- package/esm2022/tile/index.js.map +0 -1
- package/esm2022/tile/lib/tile/tile.js +0 -39
- package/esm2022/tile/lib/tile/tile.js.map +0 -1
- package/esm2022/tile/lib/tile-header.js +0 -14
- package/esm2022/tile/lib/tile-header.js.map +0 -1
- package/esm2022/tile/malva-ui-core-tile.js +0 -5
- package/esm2022/tile/malva-ui-core-tile.js.map +0 -1
- package/esm2022/time-picker/index.js +0 -2
- package/esm2022/time-picker/index.js.map +0 -1
- package/esm2022/time-picker/lib/time-picker/time-picker.js +0 -310
- package/esm2022/time-picker/lib/time-picker/time-picker.js.map +0 -1
- package/esm2022/time-picker/lib/time-picker-column/time-picker-column.js +0 -216
- package/esm2022/time-picker/lib/time-picker-column/time-picker-column.js.map +0 -1
- package/esm2022/time-picker/malva-ui-core-time-picker.js +0 -5
- package/esm2022/time-picker/malva-ui-core-time-picker.js.map +0 -1
- package/esm2022/timeline/index.js +0 -6
- package/esm2022/timeline/index.js.map +0 -1
- package/esm2022/timeline/lib/timeline/timeline-item-icon.js +0 -31
- package/esm2022/timeline/lib/timeline/timeline-item-icon.js.map +0 -1
- package/esm2022/timeline/lib/timeline/timeline-item-meta.js +0 -31
- package/esm2022/timeline/lib/timeline/timeline-item-meta.js.map +0 -1
- package/esm2022/timeline/lib/timeline/timeline-item.js +0 -69
- package/esm2022/timeline/lib/timeline/timeline-item.js.map +0 -1
- package/esm2022/timeline/lib/timeline/timeline.js +0 -36
- package/esm2022/timeline/lib/timeline/timeline.js.map +0 -1
- package/esm2022/timeline/lib/timeline/timeline.types.js +0 -1
- package/esm2022/timeline/lib/timeline/timeline.types.js.map +0 -1
- package/esm2022/timeline/malva-ui-core-timeline.js +0 -5
- package/esm2022/timeline/malva-ui-core-timeline.js.map +0 -1
- package/esm2022/title/index.js +0 -2
- package/esm2022/title/index.js.map +0 -1
- package/esm2022/title/lib/title/title.js +0 -171
- package/esm2022/title/lib/title/title.js.map +0 -1
- package/esm2022/title/malva-ui-core-title.js +0 -5
- package/esm2022/title/malva-ui-core-title.js.map +0 -1
- package/esm2022/toast/index.js +0 -13
- package/esm2022/toast/index.js.map +0 -1
- package/esm2022/toast/lib/abstract-toast-container.js +0 -50
- package/esm2022/toast/lib/abstract-toast-container.js.map +0 -1
- package/esm2022/toast/lib/abstract-toast-item.js +0 -75
- package/esm2022/toast/lib/abstract-toast-item.js.map +0 -1
- package/esm2022/toast/lib/abstract-toast.service.js +0 -176
- package/esm2022/toast/lib/abstract-toast.service.js.map +0 -1
- package/esm2022/toast/lib/toast-container/toast-container.js +0 -61
- package/esm2022/toast/lib/toast-container/toast-container.js.map +0 -1
- package/esm2022/toast/lib/toast-item/toast-item.js +0 -62
- package/esm2022/toast/lib/toast-item/toast-item.js.map +0 -1
- package/esm2022/toast/lib/toast-ref.js +0 -54
- package/esm2022/toast/lib/toast-ref.js.map +0 -1
- package/esm2022/toast/lib/toast-timer.js +0 -37
- package/esm2022/toast/lib/toast-timer.js.map +0 -1
- package/esm2022/toast/lib/toast.directives.js +0 -76
- package/esm2022/toast/lib/toast.directives.js.map +0 -1
- package/esm2022/toast/lib/toast.service.js +0 -127
- package/esm2022/toast/lib/toast.service.js.map +0 -1
- package/esm2022/toast/lib/toast.types.js +0 -39
- package/esm2022/toast/lib/toast.types.js.map +0 -1
- package/esm2022/toast/malva-ui-core-toast.js +0 -5
- package/esm2022/toast/malva-ui-core-toast.js.map +0 -1
- package/esm2022/tokenizer/index.js +0 -4
- package/esm2022/tokenizer/index.js.map +0 -1
- package/esm2022/tokenizer/lib/token/token.js +0 -123
- package/esm2022/tokenizer/lib/token/token.js.map +0 -1
- package/esm2022/tokenizer/lib/token-template.js +0 -23
- package/esm2022/tokenizer/lib/token-template.js.map +0 -1
- package/esm2022/tokenizer/lib/tokenizer/tokenizer.js +0 -324
- package/esm2022/tokenizer/lib/tokenizer/tokenizer.js.map +0 -1
- package/esm2022/tokenizer/malva-ui-core-tokenizer.js +0 -5
- package/esm2022/tokenizer/malva-ui-core-tokenizer.js.map +0 -1
- package/esm2022/toolbar/index.js +0 -4
- package/esm2022/toolbar/index.js.map +0 -1
- package/esm2022/toolbar/lib/toolbar/toolbar-spacer.js +0 -13
- package/esm2022/toolbar/lib/toolbar/toolbar-spacer.js.map +0 -1
- package/esm2022/toolbar/lib/toolbar/toolbar-widget.js +0 -106
- package/esm2022/toolbar/lib/toolbar/toolbar-widget.js.map +0 -1
- package/esm2022/toolbar/lib/toolbar/toolbar.js +0 -19
- package/esm2022/toolbar/lib/toolbar/toolbar.js.map +0 -1
- package/esm2022/toolbar/malva-ui-core-toolbar.js +0 -5
- package/esm2022/toolbar/malva-ui-core-toolbar.js.map +0 -1
- package/esm2022/tooltip/index.js +0 -4
- package/esm2022/tooltip/index.js.map +0 -1
- package/esm2022/tooltip/lib/tooltip/tooltip-panel.js +0 -69
- package/esm2022/tooltip/lib/tooltip/tooltip-panel.js.map +0 -1
- package/esm2022/tooltip/lib/tooltip/tooltip.js +0 -352
- package/esm2022/tooltip/lib/tooltip/tooltip.js.map +0 -1
- package/esm2022/tooltip/lib/tooltip/tooltip.types.js +0 -1
- package/esm2022/tooltip/lib/tooltip/tooltip.types.js.map +0 -1
- package/esm2022/tooltip/malva-ui-core-tooltip.js +0 -5
- package/esm2022/tooltip/malva-ui-core-tooltip.js.map +0 -1
- package/esm2022/tree/index.js +0 -5
- package/esm2022/tree/index.js.map +0 -1
- package/esm2022/tree/lib/tree/tree-context.js +0 -7
- package/esm2022/tree/lib/tree/tree-context.js.map +0 -1
- package/esm2022/tree/lib/tree/tree-node-def.js +0 -34
- package/esm2022/tree/lib/tree/tree-node-def.js.map +0 -1
- package/esm2022/tree/lib/tree/tree-node.js +0 -1
- package/esm2022/tree/lib/tree/tree-node.js.map +0 -1
- package/esm2022/tree/lib/tree/tree-subtree.js +0 -107
- package/esm2022/tree/lib/tree/tree-subtree.js.map +0 -1
- package/esm2022/tree/lib/tree/tree.js +0 -362
- package/esm2022/tree/lib/tree/tree.js.map +0 -1
- package/esm2022/tree/malva-ui-core-tree.js +0 -5
- package/esm2022/tree/malva-ui-core-tree.js.map +0 -1
- package/expand/index.d.ts +0 -2
- package/expand/lib/expand/expand-content.d.ts +0 -26
- package/expand/lib/expand/expand.d.ts +0 -74
- package/expand/malva-ui-core-expand.d.ts +0 -5
- package/file-upload/index.d.ts +0 -4
- package/file-upload/lib/file-upload/file-upload.d.ts +0 -138
- package/file-upload/lib/file-upload/file-upload.types.d.ts +0 -42
- package/file-upload/lib/file-upload-action.d.ts +0 -53
- package/file-upload/lib/file-upload-item/file-upload-item.d.ts +0 -30
- package/file-upload/malva-ui-core-file-upload.d.ts +0 -5
- package/filter/index.d.ts +0 -3
- package/filter/lib/filter/filter.d.ts +0 -156
- package/filter/lib/filter.types.d.ts +0 -75
- package/filter/lib/smart-filter-bar/smart-filter-bar.d.ts +0 -153
- package/filter/malva-ui-core-filter.d.ts +0 -5
- package/form/index.d.ts +0 -6
- package/form/lib/fieldset/fieldset.d.ts +0 -58
- package/form/lib/fieldset-span.d.ts +0 -28
- package/form/lib/form/form.d.ts +0 -37
- package/form/lib/form-actions.d.ts +0 -20
- package/form/lib/form-gap.d.ts +0 -5
- package/form/lib/form-header.d.ts +0 -18
- package/form/lib/form.types.d.ts +0 -13
- package/form/malva-ui-core-form.d.ts +0 -5
- package/form-utils/index.d.ts +0 -15
- package/form-utils/lib/aria-value-bridge.d.ts +0 -45
- package/form-utils/lib/description/description.d.ts +0 -16
- package/form-utils/lib/focusable-group-base.d.ts +0 -76
- package/form-utils/lib/form-control-base/signal-form-control-base.d.ts +0 -159
- package/form-utils/lib/form-control-sides.d.ts +0 -20
- package/form-utils/lib/form-control-wrapper/form-control-wrapper-control.d.ts +0 -6
- package/form-utils/lib/form-control-wrapper/form-control-wrapper.d.ts +0 -20
- package/form-utils/lib/form-field/form-field.d.ts +0 -68
- package/form-utils/lib/hint/hint.d.ts +0 -5
- package/form-utils/lib/label/label.d.ts +0 -22
- package/form-utils/lib/message/message.d.ts +0 -7
- package/form-utils/lib/models/error-display-strategy.d.ts +0 -1
- package/form-utils/lib/models/form-control-connector.d.ts +0 -41
- package/form-utils/lib/models/form-state.d.ts +0 -1
- package/form-utils/lib/selection.service.d.ts +0 -27
- package/form-utils/malva-ui-core-form-utils.d.ts +0 -5
- package/form-utils/testing/index.d.ts +0 -1
- package/form-utils/testing/lib/forms-binding-matrix.d.ts +0 -47
- package/form-utils/testing/malva-ui-core-form-utils-testing.d.ts +0 -5
- package/index.d.ts +0 -69
- package/input/index.d.ts +0 -3
- package/input/lib/input/input-native.d.ts +0 -36
- package/input/lib/input/input-value-accessor.d.ts +0 -11
- package/input/lib/input/input.d.ts +0 -189
- package/input/lib/input/password-strength.d.ts +0 -34
- package/input/malva-ui-core-input.d.ts +0 -5
- package/kbd/index.d.ts +0 -1
- package/kbd/lib/kbd/kbd.d.ts +0 -52
- package/kbd/malva-ui-core-kbd.d.ts +0 -5
- package/layout/index.d.ts +0 -4
- package/layout/lib/layout/directives/MlvLayoutSide.d.ts +0 -6
- package/layout/lib/layout/directives/MlvLayoutTop.d.ts +0 -6
- package/layout/lib/layout/layout.d.ts +0 -20
- package/layout/lib/layout/services/theme.service.d.ts +0 -33
- package/layout/malva-ui-core-layout.d.ts +0 -5
- package/link/index.d.ts +0 -2
- package/link/lib/link/link.d.ts +0 -15
- package/link/lib/link/link.directives.d.ts +0 -10
- package/link/malva-ui-core-link.d.ts +0 -5
- package/list/index.d.ts +0 -13
- package/list/lib/list/list.d.ts +0 -25
- package/list/lib/list-item/list-item.d.ts +0 -67
- package/list/lib/list-item-actions.d.ts +0 -12
- package/list/lib/list-item-byline.d.ts +0 -5
- package/list/lib/list-item-group/list-item-group.d.ts +0 -11
- package/list/lib/list-item-link/list-item-link.d.ts +0 -8
- package/list/lib/list-item-media.d.ts +0 -5
- package/list/lib/list-item-meta.d.ts +0 -5
- package/list/lib/list-item-prefix.d.ts +0 -5
- package/list/lib/list-item-suffix.d.ts +0 -5
- package/list/lib/list-item-template.d.ts +0 -10
- package/list/lib/list-item-title.d.ts +0 -5
- package/list/lib/list-selectable.d.ts +0 -73
- package/list/malva-ui-core-list.d.ts +0 -5
- package/loader/index.d.ts +0 -1
- package/loader/lib/loader/loader.d.ts +0 -84
- package/loader/malva-ui-core-loader.d.ts +0 -5
- package/malva-ui-core.d.ts +0 -5
- package/menu/index.d.ts +0 -9
- package/menu/lib/menu/menu-group-label.d.ts +0 -22
- package/menu/lib/menu/menu-group.d.ts +0 -27
- package/menu/lib/menu/menu-item.d.ts +0 -76
- package/menu/lib/menu/menu-separator.d.ts +0 -18
- package/menu/lib/menu/menu-trigger.d.ts +0 -255
- package/menu/lib/menu/menu.d.ts +0 -149
- package/menu/lib/menu/menu.types.d.ts +0 -13
- package/menu/lib/menu/menubar.d.ts +0 -131
- package/menu/lib/menu/menubar.types.d.ts +0 -82
- package/menu/lib/menu/submenu-aim.d.ts +0 -10
- package/menu/malva-ui-core-menu.d.ts +0 -5
- package/notification/index.d.ts +0 -4
- package/notification/lib/notification-item/notification-item.d.ts +0 -20
- package/notification/lib/notification-ref.d.ts +0 -12
- package/notification/lib/notification.service.d.ts +0 -43
- package/notification/lib/notification.types.d.ts +0 -52
- package/notification/malva-ui-core-notification.d.ts +0 -5
- package/number-input/index.d.ts +0 -1
- package/number-input/lib/number-input/number-input.d.ts +0 -162
- package/number-input/malva-ui-core-number-input.d.ts +0 -5
- package/page/index.d.ts +0 -14
- package/page/lib/page/page-scroll.token.d.ts +0 -19
- package/page/lib/page/page-snap-controller.d.ts +0 -87
- package/page/lib/page/page-snap.directive.d.ts +0 -40
- package/page/lib/page/page.d.ts +0 -74
- package/page/lib/page-content/page-aside.d.ts +0 -7
- package/page/lib/page-content/page-content.d.ts +0 -37
- package/page/lib/page-dock/page-dock.d.ts +0 -50
- package/page/lib/page-dock/page-dock.slots.d.ts +0 -16
- package/page/lib/page-header/page-header.d.ts +0 -77
- package/page/lib/page-header/page-header.directives.d.ts +0 -50
- package/page/lib/page-shell/page-shell-color.d.ts +0 -48
- package/page/lib/page-shell/page-shell-css-color.d.ts +0 -20
- package/page/lib/page-shell/page-shell.d.ts +0 -44
- package/page/lib/page-shell/page-shell.slots.d.ts +0 -16
- package/page/lib/page-summary/page-summary-item.d.ts +0 -11
- package/page/lib/page-summary/page-summary.d.ts +0 -36
- package/page/malva-ui-core-page.d.ts +0 -5
- package/pagination/index.d.ts +0 -4
- package/pagination/lib/pagination/pagination.d.ts +0 -182
- package/pagination/lib/pagination/pagination.directives.d.ts +0 -44
- package/pagination/lib/pagination/pagination.model.d.ts +0 -6
- package/pagination/lib/pagination/pagination.service.d.ts +0 -26
- package/pagination/malva-ui-core-pagination.d.ts +0 -5
- package/pin-input/index.d.ts +0 -2
- package/pin-input/lib/pin-input/pin-input-separator.d.ts +0 -24
- package/pin-input/lib/pin-input/pin-input.d.ts +0 -176
- package/pin-input/malva-ui-core-pin-input.d.ts +0 -5
- package/popup/index.d.ts +0 -9
- package/popup/lib/popup/popup.d.ts +0 -343
- package/popup/lib/popup-container/popup-container.d.ts +0 -61
- package/popup/lib/popup-container/popup-container.token.d.ts +0 -34
- package/popup/lib/popup-content.d.ts +0 -6
- package/popup/lib/popup-header-content.d.ts +0 -18
- package/popup/lib/popup-pinned-content.d.ts +0 -17
- package/popup/lib/popup-positions.d.ts +0 -105
- package/popup/lib/popup-trigger/popup-trigger.d.ts +0 -102
- package/popup/lib/popup.service.d.ts +0 -159
- package/popup/malva-ui-core-popup.d.ts +0 -5
- package/progress/index.d.ts +0 -1
- package/progress/lib/progress/progress.d.ts +0 -69
- package/progress/malva-ui-core-progress.d.ts +0 -5
- package/radio/index.d.ts +0 -2
- package/radio/lib/radio/radio.d.ts +0 -87
- package/radio/lib/radio-group/radio-group.d.ts +0 -35
- package/radio/lib/radio-group-token.d.ts +0 -7
- package/radio/malva-ui-core-radio.d.ts +0 -5
- package/rating/index.d.ts +0 -1
- package/rating/lib/rating/rating.d.ts +0 -100
- package/rating/malva-ui-core-rating.d.ts +0 -5
- package/scrollbar/index.d.ts +0 -1
- package/scrollbar/lib/scrollbar/scrollbar.d.ts +0 -166
- package/scrollbar/malva-ui-core-scrollbar.d.ts +0 -5
- package/search-field/index.d.ts +0 -2
- package/search-field/lib/search-field/search-field.d.ts +0 -347
- package/search-field/lib/search-field/search-overlay-content.d.ts +0 -59
- package/search-field/malva-ui-core-search-field.d.ts +0 -5
- package/segmented/index.d.ts +0 -4
- package/segmented/lib/segmented/segmented.d.ts +0 -80
- package/segmented/lib/segmented-item/segmented-item.d.ts +0 -89
- package/segmented/lib/segmented-token.d.ts +0 -22
- package/segmented/lib/segmented.types.d.ts +0 -9
- package/segmented/malva-ui-core-segmented.d.ts +0 -5
- package/select/index.d.ts +0 -3
- package/select/lib/select/select.d.ts +0 -379
- package/select/lib/select-option.d.ts +0 -1
- package/select/lib/select-template.directives.d.ts +0 -14
- package/select/malva-ui-core-select.d.ts +0 -5
- package/sidebar/index.d.ts +0 -15
- package/sidebar/lib/sidebar/sidebar.d.ts +0 -134
- package/sidebar/lib/sidebar-content.d.ts +0 -11
- package/sidebar/lib/sidebar-context.d.ts +0 -23
- package/sidebar/lib/sidebar-footer.d.ts +0 -9
- package/sidebar/lib/sidebar-group/sidebar-group.d.ts +0 -127
- package/sidebar/lib/sidebar-header.d.ts +0 -9
- package/sidebar/lib/sidebar-item/sidebar-item.d.ts +0 -104
- package/sidebar/lib/sidebar-item-host.d.ts +0 -18
- package/sidebar/lib/sidebar-item-icon.d.ts +0 -6
- package/sidebar/lib/sidebar-mode.d.ts +0 -2
- package/sidebar/lib/sidebar-rail/sidebar-rail.d.ts +0 -54
- package/sidebar/lib/sidebar-trigger/sidebar-trigger.d.ts +0 -67
- package/sidebar/lib/sidebar-workspace/sidebar-workspace.d.ts +0 -54
- package/sidebar/lib/sidebar-workspace/sidebar-workspace.directives.d.ts +0 -19
- package/sidebar/lib/sidebar-workspace/sidebar-workspace.types.d.ts +0 -20
- package/sidebar/malva-ui-core-sidebar.d.ts +0 -5
- package/skeleton/index.d.ts +0 -1
- package/skeleton/lib/skeleton/skeleton.d.ts +0 -60
- package/skeleton/malva-ui-core-skeleton.d.ts +0 -5
- package/slider/index.d.ts +0 -2
- package/slider/lib/slider/slider-tooltip-def.d.ts +0 -39
- package/slider/lib/slider/slider.d.ts +0 -171
- package/slider/malva-ui-core-slider.d.ts +0 -5
- package/split-pane/index.d.ts +0 -3
- package/split-pane/lib/split-pane/split-pane-panel.d.ts +0 -34
- package/split-pane/lib/split-pane/split-pane.d.ts +0 -98
- package/split-pane/lib/split-pane/split-pane.types.d.ts +0 -7
- package/split-pane/malva-ui-core-split-pane.d.ts +0 -5
- package/status-indicator/index.d.ts +0 -1
- package/status-indicator/lib/status-indicator/status-indicator.d.ts +0 -61
- package/status-indicator/malva-ui-core-status-indicator.d.ts +0 -5
- package/stepper/index.d.ts +0 -4
- package/stepper/lib/stepper/step-header.d.ts +0 -34
- package/stepper/lib/stepper/step.d.ts +0 -51
- package/stepper/lib/stepper/stepper-token.d.ts +0 -13
- package/stepper/lib/stepper/stepper.d.ts +0 -98
- package/stepper/lib/stepper/stepper.types.d.ts +0 -4
- package/stepper/malva-ui-core-stepper.d.ts +0 -5
- package/switch/index.d.ts +0 -2
- package/switch/lib/switch/switch.d.ts +0 -118
- package/switch/lib/switch-group/switch-group.d.ts +0 -24
- package/switch/lib/switch-group-token.d.ts +0 -6
- package/switch/malva-ui-core-switch.d.ts +0 -5
- package/tabs/index.d.ts +0 -8
- package/tabs/lib/tab/tab.d.ts +0 -46
- package/tabs/lib/tab-content/tab-content.d.ts +0 -11
- package/tabs/lib/tab-content-def.d.ts +0 -6
- package/tabs/lib/tab-def.d.ts +0 -11
- package/tabs/lib/tab-group-token.d.ts +0 -10
- package/tabs/lib/tab-item/tab-item.d.ts +0 -28
- package/tabs/lib/tabs/tabs.d.ts +0 -202
- package/tabs/lib/tabs.service.d.ts +0 -24
- package/tabs/malva-ui-core-tabs.d.ts +0 -5
- package/textarea/index.d.ts +0 -1
- package/textarea/lib/textarea/textarea.d.ts +0 -77
- package/textarea/malva-ui-core-textarea.d.ts +0 -5
- package/tile/index.d.ts +0 -2
- package/tile/lib/tile/tile.d.ts +0 -20
- package/tile/lib/tile-header.d.ts +0 -6
- package/tile/malva-ui-core-tile.d.ts +0 -5
- package/time-picker/index.d.ts +0 -1
- package/time-picker/lib/time-picker/time-picker.d.ts +0 -135
- package/time-picker/lib/time-picker-column/time-picker-column.d.ts +0 -111
- package/time-picker/malva-ui-core-time-picker.d.ts +0 -5
- package/timeline/index.d.ts +0 -5
- package/timeline/lib/timeline/timeline-item-icon.d.ts +0 -24
- package/timeline/lib/timeline/timeline-item-meta.d.ts +0 -24
- package/timeline/lib/timeline/timeline-item.d.ts +0 -52
- package/timeline/lib/timeline/timeline.d.ts +0 -27
- package/timeline/lib/timeline/timeline.types.d.ts +0 -18
- package/timeline/malva-ui-core-timeline.d.ts +0 -5
- package/title/index.d.ts +0 -1
- package/title/lib/title/title.d.ts +0 -63
- package/title/malva-ui-core-title.d.ts +0 -5
- package/toast/index.d.ts +0 -10
- package/toast/lib/abstract-toast-container.d.ts +0 -29
- package/toast/lib/abstract-toast-item.d.ts +0 -44
- package/toast/lib/abstract-toast.service.d.ts +0 -75
- package/toast/lib/toast-container/toast-container.d.ts +0 -23
- package/toast/lib/toast-item/toast-item.d.ts +0 -25
- package/toast/lib/toast-ref.d.ts +0 -33
- package/toast/lib/toast-timer.d.ts +0 -24
- package/toast/lib/toast.directives.d.ts +0 -13
- package/toast/lib/toast.service.d.ts +0 -41
- package/toast/lib/toast.types.d.ts +0 -139
- package/toast/malva-ui-core-toast.d.ts +0 -5
- package/tokenizer/index.d.ts +0 -3
- package/tokenizer/lib/token/token.d.ts +0 -60
- package/tokenizer/lib/token-template.d.ts +0 -29
- package/tokenizer/lib/tokenizer/tokenizer.d.ts +0 -109
- package/tokenizer/malva-ui-core-tokenizer.d.ts +0 -5
- package/toolbar/index.d.ts +0 -3
- package/toolbar/lib/toolbar/toolbar-spacer.d.ts +0 -5
- package/toolbar/lib/toolbar/toolbar-widget.d.ts +0 -75
- package/toolbar/lib/toolbar/toolbar.d.ts +0 -8
- package/toolbar/malva-ui-core-toolbar.d.ts +0 -5
- package/tooltip/index.d.ts +0 -3
- package/tooltip/lib/tooltip/tooltip-panel.d.ts +0 -26
- package/tooltip/lib/tooltip/tooltip.d.ts +0 -148
- package/tooltip/lib/tooltip/tooltip.types.d.ts +0 -17
- package/tooltip/malva-ui-core-tooltip.d.ts +0 -5
- package/tree/index.d.ts +0 -4
- package/tree/lib/tree/tree-context.d.ts +0 -62
- package/tree/lib/tree/tree-node-def.d.ts +0 -33
- package/tree/lib/tree/tree-node.d.ts +0 -45
- package/tree/lib/tree/tree-subtree.d.ts +0 -63
- package/tree/lib/tree/tree.d.ts +0 -156
- package/tree/malva-ui-core-tree.d.ts +0 -5
|
@@ -0,0 +1,2696 @@
|
|
|
1
|
+
import { MlvDataSource, MlvArrayDataSource } from '@malva-ui/cdk/data-source';
|
|
2
|
+
export * from '@malva-ui/cdk/data-source';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { input, inject, TemplateRef, Directive, signal, Injectable, model, output, ElementRef, computed, effect, untracked, afterNextRender, ChangeDetectionStrategy, ViewEncapsulation, Component, numberAttribute, contentChildren, contentChild, viewChild, viewChildren, DestroyRef, Injector, NgZone } from '@angular/core';
|
|
5
|
+
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
6
|
+
import { Grid, GridRow, GridCell, GridCellWidget } from '@angular/aria/grid';
|
|
7
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
|
+
import * as i2 from '@angular/cdk/scrolling';
|
|
9
|
+
import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
|
|
10
|
+
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
11
|
+
import { UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
|
|
12
|
+
import { LucideX, LucideArrowUp, LucideArrowDown, LucideChevronsUpDown, LucideChevronRight, LucideFilter, LucideTable2, LucidePencil, LucideCheck, LucidePlus, LucidePin, LucidePinOff, LucideEye, LucideTriangleAlert, LucideArrowUpDown, LucideFunnel } from '@lucide/angular';
|
|
13
|
+
import { MlvLoader } from '@malva-ui/core/loader';
|
|
14
|
+
import { MlvCheckbox } from '@malva-ui/core/checkbox';
|
|
15
|
+
import { MlvPagination } from '@malva-ui/core/pagination';
|
|
16
|
+
import { MlvSearchField } from '@malva-ui/core/search-field';
|
|
17
|
+
import { MlvResizeObserverService, MlvRtlService } from '@malva-ui/cdk/utils';
|
|
18
|
+
import { MlvInfiniteScroll } from '@malva-ui/cdk/infinite-scroll';
|
|
19
|
+
import { MlvButton, MlvButtonIcon } from '@malva-ui/core/button';
|
|
20
|
+
import { MlvListItem } from '@malva-ui/core/list';
|
|
21
|
+
import { MlvMenu, MlvMenuItem, MlvMenuTrigger } from '@malva-ui/core/menu';
|
|
22
|
+
import { MlvBadge } from '@malva-ui/core/badge';
|
|
23
|
+
import { MlvEmptyState } from '@malva-ui/core/empty-state';
|
|
24
|
+
import * as i1$1 from '@malva-ui/cdk/density';
|
|
25
|
+
import { MLV_DENSITY_ELEMENT, MlvDensityDirective } from '@malva-ui/cdk/density';
|
|
26
|
+
import { MLV_DATA_TABLE_I18N, MLV_FILTER_I18N, MlvI18nResolverService } from '@malva-ui/i18n';
|
|
27
|
+
import * as i1 from '@angular/forms';
|
|
28
|
+
import { FormsModule } from '@angular/forms';
|
|
29
|
+
import { MlvInput } from '@malva-ui/core/input';
|
|
30
|
+
import { MlvSelect } from '@malva-ui/core/select';
|
|
31
|
+
import { MlvPopupTrigger, MlvPopup, MlvPopupContent } from '@malva-ui/core/popup';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Compat re-export — the data source primitives now live in
|
|
35
|
+
* `@malva-ui/cdk/data-source` so option controls can share them.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Structural directive for providing custom cell templates with full type inference.
|
|
40
|
+
*
|
|
41
|
+
* Usage (asterisk shorthand — preferred):
|
|
42
|
+
* ```html
|
|
43
|
+
* <mlv-data-table [data]="employees" [columns]="columns">
|
|
44
|
+
* <span *mlvDataTableCell="'salary'; let row from employees">
|
|
45
|
+
* {{ row.salary.toLocaleString() }}
|
|
46
|
+
* </span>
|
|
47
|
+
* </mlv-data-table>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Usage (explicit ng-template):
|
|
51
|
+
* ```html
|
|
52
|
+
* <ng-template mlvDataTableCell="salary" [mlvDataTableCellFrom]="employees" let-row>
|
|
53
|
+
* <span>{{ row.salary.toLocaleString() }}</span>
|
|
54
|
+
* </ng-template>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
class MlvDataTableCell {
|
|
58
|
+
/** Column key this template applies to — typed as `keyof T` when `from` is provided. */
|
|
59
|
+
columnKey = input.required({ ...(ngDevMode ? { debugName: "columnKey" } : /* istanbul ignore next */ {}), alias: 'mlvDataTableCell' });
|
|
60
|
+
/**
|
|
61
|
+
* Pass the same value as `[data]` on the parent `mlv-data-table`.
|
|
62
|
+
* Angular uses this to infer `T` and type `let-row` in the template.
|
|
63
|
+
*/
|
|
64
|
+
from = input(undefined, { ...(ngDevMode ? { debugName: "from" } : /* istanbul ignore next */ {}), alias: 'mlvDataTableCellFrom' });
|
|
65
|
+
templateRef = inject(TemplateRef);
|
|
66
|
+
/** Narrows the template context to `MlvDataTableCellContext<T>` for type-safe `let-row`. */
|
|
67
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
/** Enables `*mlvDataTableCell="'key'; let row from data"` microsyntax. */
|
|
71
|
+
static ngTemplateGuard_mlvDataTableCellFrom;
|
|
72
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
73
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: MlvDataTableCell, isStandalone: true, selector: "[mlvDataTableCell]", inputs: { columnKey: { classPropertyName: "columnKey", publicName: "mlvDataTableCell", isSignal: true, isRequired: true, transformFunction: null }, from: { classPropertyName: "from", publicName: "mlvDataTableCellFrom", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
74
|
+
}
|
|
75
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableCell, decorators: [{
|
|
76
|
+
type: Directive,
|
|
77
|
+
args: [{
|
|
78
|
+
selector: '[mlvDataTableCell]',
|
|
79
|
+
}]
|
|
80
|
+
}], propDecorators: { columnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "mlvDataTableCell", required: true }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "mlvDataTableCellFrom", required: false }] }] } });
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Structural directive for providing custom edit-mode cell templates.
|
|
84
|
+
*
|
|
85
|
+
* When the table is in editable mode and a row enters editing, this template
|
|
86
|
+
* replaces the display template for the given column key.
|
|
87
|
+
*
|
|
88
|
+
* Usage (asterisk shorthand):
|
|
89
|
+
* ```html
|
|
90
|
+
* <mlv-input *mlvDataTableEditCell="'name'; let row from employees"
|
|
91
|
+
* [ngModel]="row.name" (ngModelChange)="row.name = $event" />
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* Usage (explicit ng-template):
|
|
95
|
+
* ```html
|
|
96
|
+
* <ng-template mlvDataTableEditCell="name" [mlvDataTableEditCellFrom]="employees" let-row>
|
|
97
|
+
* <mlv-input [ngModel]="row.name" (ngModelChange)="row.name = $event" />
|
|
98
|
+
* </ng-template>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
class MlvDataTableEditCell {
|
|
102
|
+
/** Column key this edit template applies to. */
|
|
103
|
+
columnKey = input.required({ ...(ngDevMode ? { debugName: "columnKey" } : /* istanbul ignore next */ {}), alias: 'mlvDataTableEditCell' });
|
|
104
|
+
/**
|
|
105
|
+
* Pass the same value as `[data]` on the parent `mlv-data-table`.
|
|
106
|
+
* Angular uses this to infer `T` and type `let-row` in the template.
|
|
107
|
+
*/
|
|
108
|
+
from = input(undefined, { ...(ngDevMode ? { debugName: "from" } : /* istanbul ignore next */ {}), alias: 'mlvDataTableEditCellFrom' });
|
|
109
|
+
templateRef = inject(TemplateRef);
|
|
110
|
+
/** Narrows the template context to `MlvDataTableEditCellContext<T>` for type-safe `let-row`. */
|
|
111
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
/** Enables `*mlvDataTableEditCell="'key'; let row from data"` microsyntax. */
|
|
115
|
+
static ngTemplateGuard_mlvDataTableEditCellFrom;
|
|
116
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableEditCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
117
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: MlvDataTableEditCell, isStandalone: true, selector: "[mlvDataTableEditCell]", inputs: { columnKey: { classPropertyName: "columnKey", publicName: "mlvDataTableEditCell", isSignal: true, isRequired: true, transformFunction: null }, from: { classPropertyName: "from", publicName: "mlvDataTableEditCellFrom", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
118
|
+
}
|
|
119
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableEditCell, decorators: [{
|
|
120
|
+
type: Directive,
|
|
121
|
+
args: [{
|
|
122
|
+
selector: '[mlvDataTableEditCell]',
|
|
123
|
+
}]
|
|
124
|
+
}], propDecorators: { columnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "mlvDataTableEditCell", required: true }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "mlvDataTableEditCellFrom", required: false }] }] } });
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Directive for the "no data" slot.
|
|
128
|
+
*
|
|
129
|
+
* Usage:
|
|
130
|
+
* ```html
|
|
131
|
+
* <mlv-data-table ...>
|
|
132
|
+
* <ng-template mlvDataTableNoData>
|
|
133
|
+
* <p>No records found.</p>
|
|
134
|
+
* </ng-template>
|
|
135
|
+
* </mlv-data-table>
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
class MlvDataTableNoData {
|
|
139
|
+
templateRef = inject(TemplateRef);
|
|
140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableNoData, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
141
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MlvDataTableNoData, isStandalone: true, selector: "[mlvDataTableNoData]", ngImport: i0 });
|
|
142
|
+
}
|
|
143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableNoData, decorators: [{
|
|
144
|
+
type: Directive,
|
|
145
|
+
args: [{
|
|
146
|
+
selector: '[mlvDataTableNoData]',
|
|
147
|
+
}]
|
|
148
|
+
}] });
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Directive for the "request failed" slot. Rendered in place of the table body
|
|
152
|
+
* whenever `[error]` is truthy and the table is not loading, so a failed request
|
|
153
|
+
* is never mistaken for an empty result set.
|
|
154
|
+
*
|
|
155
|
+
* Usage:
|
|
156
|
+
* ```html
|
|
157
|
+
* <mlv-data-table [data]="rows()" [columns]="columns" [error]="error()" (retry)="reload()">
|
|
158
|
+
* <ng-template mlvDataTableError let-message let-retry="retry">
|
|
159
|
+
* <p>{{ message }}</p>
|
|
160
|
+
* <button mlvButton variant="secondary" type="button" (click)="retry()">Try again</button>
|
|
161
|
+
* </ng-template>
|
|
162
|
+
* </mlv-data-table>
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
class MlvDataTableError {
|
|
166
|
+
/** The projected template rendered instead of the default error block. */
|
|
167
|
+
templateRef = inject((TemplateRef));
|
|
168
|
+
/**
|
|
169
|
+
* Type guard so Angular narrows `let-message` / `let-retry="retry"` to
|
|
170
|
+
* {@link MlvDataTableErrorContext} in strict templates.
|
|
171
|
+
*/
|
|
172
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableError, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
176
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MlvDataTableError, isStandalone: true, selector: "[mlvDataTableError]", ngImport: i0 });
|
|
177
|
+
}
|
|
178
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableError, decorators: [{
|
|
179
|
+
type: Directive,
|
|
180
|
+
args: [{
|
|
181
|
+
selector: '[mlvDataTableError]',
|
|
182
|
+
}]
|
|
183
|
+
}] });
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Directive for the footer summary row slot.
|
|
187
|
+
*
|
|
188
|
+
* The template context provides `{ $implicit: columns }` where `columns`
|
|
189
|
+
* is the current visible column list.
|
|
190
|
+
*
|
|
191
|
+
* Usage:
|
|
192
|
+
* ```html
|
|
193
|
+
* <mlv-data-table ...>
|
|
194
|
+
* <ng-template mlvDataTableFooter let-cols>
|
|
195
|
+
* <th scope="row" [attr.colspan]="cols.length - 1">Total</th>
|
|
196
|
+
* <td>...</td>
|
|
197
|
+
* </ng-template>
|
|
198
|
+
* </mlv-data-table>
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* Direct `th` and `td` children receive the table's density, divider, sticky
|
|
202
|
+
* surface, and bordered-cell styling without private component classes.
|
|
203
|
+
*/
|
|
204
|
+
class MlvDataTableFooter {
|
|
205
|
+
templateRef = inject(TemplateRef);
|
|
206
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
207
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MlvDataTableFooter, isStandalone: true, selector: "[mlvDataTableFooter]", ngImport: i0 });
|
|
208
|
+
}
|
|
209
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableFooter, decorators: [{
|
|
210
|
+
type: Directive,
|
|
211
|
+
args: [{
|
|
212
|
+
selector: '[mlvDataTableFooter]',
|
|
213
|
+
}]
|
|
214
|
+
}] });
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Optional host-owned actions projected into the Data Table's single toolbar.
|
|
218
|
+
* The template renders after all table-owned controls.
|
|
219
|
+
*/
|
|
220
|
+
class MlvDataTableToolbarActions {
|
|
221
|
+
/** Projected toolbar-actions template rendered by the owning Data Table. */
|
|
222
|
+
templateRef = inject(TemplateRef);
|
|
223
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableToolbarActions, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
224
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MlvDataTableToolbarActions, isStandalone: true, selector: "ng-template[mlvDataTableToolbarActions]", ngImport: i0 });
|
|
225
|
+
}
|
|
226
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableToolbarActions, decorators: [{
|
|
227
|
+
type: Directive,
|
|
228
|
+
args: [{ selector: 'ng-template[mlvDataTableToolbarActions]' }]
|
|
229
|
+
}] });
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Component-scoped editing state for `mlv-data-table`. Holds the per-row
|
|
233
|
+
* snapshot map used for rollback on cancel and tracks whether a given row
|
|
234
|
+
* index is currently in edit mode. The component delegates `startEdit` /
|
|
235
|
+
* `saveEdit` / `cancelEdit` to this service and emits the matching outputs
|
|
236
|
+
* itself.
|
|
237
|
+
*
|
|
238
|
+
* Provided per-component via `providers: [MlvDataTableEditingService]` so each
|
|
239
|
+
* `mlv-data-table` instance has its own isolated editing state.
|
|
240
|
+
*/
|
|
241
|
+
class MlvDataTableEditingService {
|
|
242
|
+
/** @private Map of row-index → original row snapshot (for rollback). */
|
|
243
|
+
_editingRows = signal(new Map(), /* @ts-ignore */
|
|
244
|
+
...(ngDevMode ? [{ debugName: "_editingRows" }] : /* istanbul ignore next */ []));
|
|
245
|
+
/** Whether any row is currently being edited. */
|
|
246
|
+
isEditing(index) {
|
|
247
|
+
return this._editingRows().has(index);
|
|
248
|
+
}
|
|
249
|
+
/** Whether at least one row is currently being edited. */
|
|
250
|
+
hasActiveEdit() {
|
|
251
|
+
return this._editingRows().size > 0;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Begin editing the given row. Stores a shallow clone in the rollback map.
|
|
255
|
+
* Returns the cloned snapshot for the caller to emit on `rowEditStart`.
|
|
256
|
+
*/
|
|
257
|
+
start(row, index) {
|
|
258
|
+
const snapshot = { ...row };
|
|
259
|
+
const map = new Map(this._editingRows());
|
|
260
|
+
map.set(index, snapshot);
|
|
261
|
+
this._editingRows.set(map);
|
|
262
|
+
return snapshot;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Confirm edits for the given row. Returns the original snapshot (or the
|
|
266
|
+
* row itself if no snapshot was stored) so the caller can include it on
|
|
267
|
+
* the `rowEditSave` payload.
|
|
268
|
+
*/
|
|
269
|
+
save(row, index) {
|
|
270
|
+
const original = this._editingRows().get(index) ?? row;
|
|
271
|
+
const map = new Map(this._editingRows());
|
|
272
|
+
map.delete(index);
|
|
273
|
+
this._editingRows.set(map);
|
|
274
|
+
return original;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Cancel editing the given row. Drops the snapshot. The caller is
|
|
278
|
+
* responsible for restoring the row data if it wants rollback semantics.
|
|
279
|
+
*/
|
|
280
|
+
cancel(index) {
|
|
281
|
+
const map = new Map(this._editingRows());
|
|
282
|
+
map.delete(index);
|
|
283
|
+
this._editingRows.set(map);
|
|
284
|
+
}
|
|
285
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableEditingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
286
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableEditingService });
|
|
287
|
+
}
|
|
288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableEditingService, decorators: [{
|
|
289
|
+
type: Injectable
|
|
290
|
+
}] });
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Tracks the user-toggled column hidden set for `mlv-data-table`.
|
|
294
|
+
* The component reads `isHidden(key)` while building `visibleColumns`
|
|
295
|
+
* and calls `toggle(key)` when the user clicks the column-visibility
|
|
296
|
+
* popup checkbox.
|
|
297
|
+
*/
|
|
298
|
+
class MlvDataTableColumnVisibilityService {
|
|
299
|
+
/** @private Set of currently-hidden column keys. */
|
|
300
|
+
_hiddenColumns = signal(new Set(), /* @ts-ignore */
|
|
301
|
+
...(ngDevMode ? [{ debugName: "_hiddenColumns" }] : /* istanbul ignore next */ []));
|
|
302
|
+
/** Read-only signal exposing the hidden-set for `effect()` consumers. */
|
|
303
|
+
hiddenColumns = this._hiddenColumns.asReadonly();
|
|
304
|
+
/** Whether a column is currently hidden by the user. */
|
|
305
|
+
isHidden(key) {
|
|
306
|
+
return this._hiddenColumns().has(key);
|
|
307
|
+
}
|
|
308
|
+
/** Toggle visibility of a hideable column. */
|
|
309
|
+
toggle(key) {
|
|
310
|
+
const current = this._hiddenColumns();
|
|
311
|
+
const next = new Set(current);
|
|
312
|
+
if (next.has(key)) {
|
|
313
|
+
next.delete(key);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
next.add(key);
|
|
317
|
+
}
|
|
318
|
+
this._hiddenColumns.set(next);
|
|
319
|
+
}
|
|
320
|
+
/** Replaces the hidden set with a cloned, pre-normalized key collection. */
|
|
321
|
+
replaceHiddenColumns(keys) {
|
|
322
|
+
this._hiddenColumns.set(new Set(keys));
|
|
323
|
+
}
|
|
324
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableColumnVisibilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
325
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableColumnVisibilityService });
|
|
326
|
+
}
|
|
327
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTableColumnVisibilityService, decorators: [{
|
|
328
|
+
type: Injectable
|
|
329
|
+
}] });
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Component-scoped pin-state service for `mlv-data-table`. Holds the
|
|
333
|
+
* user-driven pin/unpin overrides keyed by column key. The component
|
|
334
|
+
* delegates `togglePin`/`pinTo`/`unpin` and the read-side queries to
|
|
335
|
+
* this service while continuing to compute layout offsets internally.
|
|
336
|
+
*/
|
|
337
|
+
class MlvDataTablePinningService {
|
|
338
|
+
/** @private Map of column key → user-applied pin override. */
|
|
339
|
+
_overrides = signal(new Map(), /* @ts-ignore */
|
|
340
|
+
...(ngDevMode ? [{ debugName: "_overrides" }] : /* istanbul ignore next */ []));
|
|
341
|
+
/** Read-only signal exposing the override map for `effect()` consumers. */
|
|
342
|
+
overrides = this._overrides.asReadonly();
|
|
343
|
+
/**
|
|
344
|
+
* Returns the list of sides the user may pin a column to, based on
|
|
345
|
+
* `col.pinnable`.
|
|
346
|
+
*/
|
|
347
|
+
getPinnableSides(col) {
|
|
348
|
+
const p = col.pinnable;
|
|
349
|
+
if (!p)
|
|
350
|
+
return [];
|
|
351
|
+
if (p === true)
|
|
352
|
+
return ['left', 'right'];
|
|
353
|
+
if (typeof p === 'string')
|
|
354
|
+
return [p];
|
|
355
|
+
return p.slice();
|
|
356
|
+
}
|
|
357
|
+
/** Pin a column to the given side, or unpin if it is already pinned. */
|
|
358
|
+
togglePin(col, side = 'left') {
|
|
359
|
+
const map = new Map(this._overrides());
|
|
360
|
+
const current = map.get(col.key);
|
|
361
|
+
const effectivePinned = current ? current.pinned : !!col.pinned;
|
|
362
|
+
map.set(col.key, { pinned: !effectivePinned, pinSide: side });
|
|
363
|
+
this._overrides.set(map);
|
|
364
|
+
}
|
|
365
|
+
/** Pin a column to a specific side. */
|
|
366
|
+
pinTo(col, side) {
|
|
367
|
+
const map = new Map(this._overrides());
|
|
368
|
+
map.set(col.key, { pinned: true, pinSide: side });
|
|
369
|
+
this._overrides.set(map);
|
|
370
|
+
}
|
|
371
|
+
/** Explicitly unpin a column. */
|
|
372
|
+
unpin(col) {
|
|
373
|
+
const map = new Map(this._overrides());
|
|
374
|
+
map.set(col.key, { pinned: false, pinSide: col.pinSide ?? 'left' });
|
|
375
|
+
this._overrides.set(map);
|
|
376
|
+
}
|
|
377
|
+
/** Replaces component-scoped overrides with cloned, normalized entries. */
|
|
378
|
+
replaceOverrides(entries) {
|
|
379
|
+
this._overrides.set(new Map(entries.map(({ key, pinned, pinSide }) => [key, { pinned, pinSide }])));
|
|
380
|
+
}
|
|
381
|
+
/** Whether a column is currently pinned (accounting for overrides). */
|
|
382
|
+
isPinned(col) {
|
|
383
|
+
const override = this._overrides().get(col.key);
|
|
384
|
+
return override ? override.pinned : !!col.pinned;
|
|
385
|
+
}
|
|
386
|
+
/** Pin side for a column (considering overrides) or null. */
|
|
387
|
+
getPinSide(col) {
|
|
388
|
+
const override = this._overrides().get(col.key);
|
|
389
|
+
const pinned = override ? override.pinned : !!col.pinned;
|
|
390
|
+
if (!pinned)
|
|
391
|
+
return null;
|
|
392
|
+
return override ? override.pinSide : (col.pinSide ?? 'left');
|
|
393
|
+
}
|
|
394
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTablePinningService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
395
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTablePinningService });
|
|
396
|
+
}
|
|
397
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTablePinningService, decorators: [{
|
|
398
|
+
type: Injectable
|
|
399
|
+
}] });
|
|
400
|
+
|
|
401
|
+
const DEFAULT_TEXT_OPERATORS = [
|
|
402
|
+
'contains',
|
|
403
|
+
'not-contains',
|
|
404
|
+
'equals',
|
|
405
|
+
'not-equals',
|
|
406
|
+
];
|
|
407
|
+
/** Operators whose operand is the checkbox editor's selected-value array. */
|
|
408
|
+
const DEFAULT_OPTION_OPERATORS = [
|
|
409
|
+
'in',
|
|
410
|
+
'not-in',
|
|
411
|
+
];
|
|
412
|
+
/** Returns whether an operator consumes an array of option values. */
|
|
413
|
+
function isOptionOperator(operator) {
|
|
414
|
+
return operator === 'in' || operator === 'not-in';
|
|
415
|
+
}
|
|
416
|
+
/** Copies a filter deeply enough that draft arrays never alias committed state. */
|
|
417
|
+
function cloneFilter(filter) {
|
|
418
|
+
return {
|
|
419
|
+
...filter,
|
|
420
|
+
value: Array.isArray(filter.value) ? [...filter.value] : filter.value,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
class MlvFilterDropdown {
|
|
424
|
+
columns = input.required(/* @ts-ignore */
|
|
425
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
426
|
+
activeFilters = model([], /* @ts-ignore */
|
|
427
|
+
...(ngDevMode ? [{ debugName: "activeFilters" }] : /* istanbul ignore next */ []));
|
|
428
|
+
closed = output();
|
|
429
|
+
/** @protected Injected i18n translations for the data table. */
|
|
430
|
+
_i18n = inject(MLV_DATA_TABLE_I18N);
|
|
431
|
+
/** @protected Shared operator and filter-action translations. */
|
|
432
|
+
_filterI18n = inject(MLV_FILTER_I18N);
|
|
433
|
+
/** @private Resolver for ICU parameterized i18n strings. */
|
|
434
|
+
_resolver = inject(MlvI18nResolverService);
|
|
435
|
+
/** @private Host used to place focus in the first editor after overlay creation. */
|
|
436
|
+
_host = inject(ElementRef);
|
|
437
|
+
/** @protected Transform mapping a `MlvDataSourceFilterOperator` to a `MlvSelectOption` for the operator dropdown. */
|
|
438
|
+
operatorTransform = (op) => ({
|
|
439
|
+
label: this._operatorLabel(op),
|
|
440
|
+
value: op,
|
|
441
|
+
});
|
|
442
|
+
/** @protected The subset of columns that are marked filterable. */
|
|
443
|
+
filterableColumns = computed(() => this.columns().filter((c) => c.filterable), /* @ts-ignore */
|
|
444
|
+
...(ngDevMode ? [{ debugName: "filterableColumns" }] : /* istanbul ignore next */ []));
|
|
445
|
+
/** @private Working copy of in-progress filter edits, keyed by column key. */
|
|
446
|
+
_localFilters = signal(new Map(), /* @ts-ignore */
|
|
447
|
+
...(ngDevMode ? [{ debugName: "_localFilters" }] : /* istanbul ignore next */ []));
|
|
448
|
+
constructor() {
|
|
449
|
+
effect(() => {
|
|
450
|
+
const allowedKeys = new Set(this.filterableColumns().map((column) => column.key));
|
|
451
|
+
const committed = this.activeFilters();
|
|
452
|
+
const next = new Map();
|
|
453
|
+
for (const filter of committed) {
|
|
454
|
+
if (allowedKeys.has(filter.key)) {
|
|
455
|
+
next.set(filter.key, cloneFilter(filter));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
untracked(() => this._localFilters.set(next));
|
|
459
|
+
});
|
|
460
|
+
// The popup service stamps this component into a detached overlay portal.
|
|
461
|
+
// Move focus directly into its first field so keyboard users do not have to
|
|
462
|
+
// tab through the underlying page to reach the non-modal dialog.
|
|
463
|
+
afterNextRender(() => {
|
|
464
|
+
const editor = this._host.nativeElement.querySelector('.mlv-dt-filter-dropdown__body [role="combobox"], .mlv-dt-filter-dropdown__body input:not([disabled])');
|
|
465
|
+
editor?.focus();
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
/** @protected Returns the allowed operators for a column, falling back to the defaults. */
|
|
469
|
+
operators(col) {
|
|
470
|
+
const configured = col.filterConfig?.operators;
|
|
471
|
+
if (this.options(col).length > 0) {
|
|
472
|
+
const compatible = configured?.filter(isOptionOperator) ?? [];
|
|
473
|
+
return compatible.length > 0 ? compatible : DEFAULT_OPTION_OPERATORS;
|
|
474
|
+
}
|
|
475
|
+
return configured?.length ? configured : DEFAULT_TEXT_OPERATORS;
|
|
476
|
+
}
|
|
477
|
+
/** @protected Returns the configured filter options for a column, or an empty list. */
|
|
478
|
+
options(col) {
|
|
479
|
+
return col.filterConfig?.options ?? [];
|
|
480
|
+
}
|
|
481
|
+
/** @protected Returns the working filter state for a column key, creating a default if absent. */
|
|
482
|
+
getFilter(key) {
|
|
483
|
+
return (this._localFilters().get(key) ?? {
|
|
484
|
+
key,
|
|
485
|
+
operator: this._defaultOperator(key),
|
|
486
|
+
value: '',
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
/** @protected Updates the operator of the working filter for a column key. */
|
|
490
|
+
setOperator(key, operator) {
|
|
491
|
+
const current = this.getFilter(key);
|
|
492
|
+
let value = current.value;
|
|
493
|
+
if (isOptionOperator(operator) && !Array.isArray(value)) {
|
|
494
|
+
value =
|
|
495
|
+
value === '' || value === null || value === undefined ? [] : [value];
|
|
496
|
+
}
|
|
497
|
+
else if (!isOptionOperator(operator) && Array.isArray(value)) {
|
|
498
|
+
value = value[0] ?? '';
|
|
499
|
+
}
|
|
500
|
+
const updated = new Map(this._localFilters());
|
|
501
|
+
updated.set(key, { ...current, operator, value });
|
|
502
|
+
this._localFilters.set(updated);
|
|
503
|
+
}
|
|
504
|
+
/** @protected Updates the value of the working filter for a column key. */
|
|
505
|
+
setValue(key, value) {
|
|
506
|
+
const current = this.getFilter(key);
|
|
507
|
+
const updated = new Map(this._localFilters());
|
|
508
|
+
updated.set(key, { ...current, value });
|
|
509
|
+
this._localFilters.set(updated);
|
|
510
|
+
}
|
|
511
|
+
/** @protected Commits non-empty working filters to `activeFilters` and closes the dropdown. */
|
|
512
|
+
apply() {
|
|
513
|
+
const editedKeys = new Set(this.filterableColumns().map((column) => column.key));
|
|
514
|
+
const filters = this.activeFilters().filter((filter) => !editedKeys.has(filter.key));
|
|
515
|
+
this._localFilters().forEach((f) => {
|
|
516
|
+
if (f.value !== '' &&
|
|
517
|
+
f.value !== null &&
|
|
518
|
+
f.value !== undefined &&
|
|
519
|
+
!(Array.isArray(f.value) && f.value.length === 0)) {
|
|
520
|
+
filters.push(cloneFilter(f));
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
this.activeFilters.set(filters);
|
|
524
|
+
this.closed.emit();
|
|
525
|
+
}
|
|
526
|
+
/** @protected Clears all working and active filters, then closes the dropdown. */
|
|
527
|
+
clear() {
|
|
528
|
+
this._localFilters.set(new Map());
|
|
529
|
+
const editedKeys = new Set(this.filterableColumns().map((column) => column.key));
|
|
530
|
+
this.activeFilters.set(this.activeFilters().filter((filter) => !editedKeys.has(filter.key)));
|
|
531
|
+
this.closed.emit();
|
|
532
|
+
}
|
|
533
|
+
/** @protected Discards draft edits and asks the owning popup to close. */
|
|
534
|
+
cancel() {
|
|
535
|
+
const allowedKeys = new Set(this.filterableColumns().map((column) => column.key));
|
|
536
|
+
const restored = new Map();
|
|
537
|
+
for (const filter of this.activeFilters()) {
|
|
538
|
+
if (allowedKeys.has(filter.key))
|
|
539
|
+
restored.set(filter.key, cloneFilter(filter));
|
|
540
|
+
}
|
|
541
|
+
this._localFilters.set(restored);
|
|
542
|
+
this.closed.emit();
|
|
543
|
+
}
|
|
544
|
+
/** @protected Toggles a value in a multi-select (array) filter for a column key. */
|
|
545
|
+
toggleInArray(key, value) {
|
|
546
|
+
const current = this.getFilter(key);
|
|
547
|
+
const arr = Array.isArray(current.value) ? [...current.value] : [];
|
|
548
|
+
const idx = arr.indexOf(value);
|
|
549
|
+
if (idx >= 0)
|
|
550
|
+
arr.splice(idx, 1);
|
|
551
|
+
else
|
|
552
|
+
arr.push(value);
|
|
553
|
+
const updated = new Map(this._localFilters());
|
|
554
|
+
updated.set(key, {
|
|
555
|
+
key,
|
|
556
|
+
operator: isOptionOperator(current.operator)
|
|
557
|
+
? current.operator
|
|
558
|
+
: this._defaultOperator(key),
|
|
559
|
+
value: arr,
|
|
560
|
+
});
|
|
561
|
+
this._localFilters.set(updated);
|
|
562
|
+
}
|
|
563
|
+
/** @protected Returns whether a value is currently selected in a column's array filter. */
|
|
564
|
+
isInArray(key, value) {
|
|
565
|
+
const current = this.getFilter(key);
|
|
566
|
+
return Array.isArray(current.value) && current.value.includes(value);
|
|
567
|
+
}
|
|
568
|
+
/** @protected Resolves the filterByColumn ICU string for a given column name. */
|
|
569
|
+
resolveFilterPlaceholder(columnName) {
|
|
570
|
+
return this._resolver.resolve(this._i18n(), 'filterByColumn', { column: columnName });
|
|
571
|
+
}
|
|
572
|
+
/** @protected Localized accessible name for one column's operator selector. */
|
|
573
|
+
resolveOperatorLabel(col) {
|
|
574
|
+
return `${this._operatorLabel(this.getFilter(col.key).operator)}: ${col.title ?? col.key}`;
|
|
575
|
+
}
|
|
576
|
+
/** @private Operator used when a field has no committed or draft value. */
|
|
577
|
+
_defaultOperator(key) {
|
|
578
|
+
const column = this.filterableColumns().find((item) => item.key === key);
|
|
579
|
+
return column ? (this.operators(column)[0] ?? 'contains') : 'contains';
|
|
580
|
+
}
|
|
581
|
+
/** @private Resolves one operator key through the shared filter translations. */
|
|
582
|
+
_operatorLabel(operator) {
|
|
583
|
+
const labels = this._filterI18n();
|
|
584
|
+
switch (operator) {
|
|
585
|
+
case 'contains':
|
|
586
|
+
return labels.contains;
|
|
587
|
+
case 'not-contains':
|
|
588
|
+
return labels.notContains;
|
|
589
|
+
case 'equals':
|
|
590
|
+
return labels.equals;
|
|
591
|
+
case 'not-equals':
|
|
592
|
+
return labels.notEquals;
|
|
593
|
+
case 'in':
|
|
594
|
+
return labels.in;
|
|
595
|
+
case 'not-in':
|
|
596
|
+
return labels.notIn;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvFilterDropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
600
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MlvFilterDropdown, isStandalone: true, selector: "mlv-dt-filter-dropdown", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, activeFilters: { classPropertyName: "activeFilters", publicName: "activeFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeFilters: "activeFiltersChange", closed: "closed" }, host: { classAttribute: "mlv-dt-filter-dropdown" }, ngImport: i0, template: "<div class=\"mlv-dt-filter-dropdown__panel\">\n <div class=\"mlv-dt-filter-dropdown__header\">\n <span class=\"mlv-dt-filter-dropdown__title\">{{ _i18n().filters }}</span>\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"cancel()\"\n [attr.aria-label]=\"_i18n().closeFilters\"\n >\n <svg lucideX mlvButtonIcon [size]=\"16\" />\n </button>\n </div>\n\n <div class=\"mlv-dt-filter-dropdown__body\">\n @for (col of filterableColumns(); track col.key) {\n <div class=\"mlv-dt-filter-dropdown__group\">\n <span class=\"mlv-dt-filter-dropdown__label\"\n >{{ col.title ?? col.key }}</span\n >\n\n @if (options(col).length > 0) {\n <mlv-select\n class=\"mlv-dt-filter-dropdown__option-operator\"\n [options]=\"operators(col)\"\n [toOption]=\"operatorTransform\"\n [ariaLabel]=\"resolveOperatorLabel(col)\"\n [ngModel]=\"getFilter(col.key).operator\"\n (ngModelChange)=\"setOperator(col.key, $event)\"\n />\n <div class=\"mlv-dt-filter-dropdown__options\">\n @for (opt of options(col); track opt.value) {\n <div class=\"mlv-dt-filter-dropdown__option\">\n <mlv-checkbox\n [checked]=\"isInArray(col.key, opt.value)\"\n [ariaLabel]=\"opt.label\"\n (checkedChange)=\"toggleInArray(col.key, opt.value)\"\n >{{ opt.label }}</mlv-checkbox\n >\n </div>\n }\n </div>\n } @else {\n <div class=\"mlv-dt-filter-dropdown__row\">\n <mlv-select\n class=\"mlv-dt-filter-dropdown__operator\"\n [options]=\"operators(col)\"\n [toOption]=\"operatorTransform\"\n [ariaLabel]=\"resolveOperatorLabel(col)\"\n [ngModel]=\"getFilter(col.key).operator\"\n (ngModelChange)=\"setOperator(col.key, $event)\"\n />\n <mlv-input\n class=\"mlv-dt-filter-dropdown__text-input\"\n [placeholder]=\"resolveFilterPlaceholder(col.title ?? col.key)\"\n [ariaLabel]=\"resolveFilterPlaceholder(col.title ?? col.key)\"\n [ngModel]=\"$any(getFilter(col.key).value)\"\n (ngModelChange)=\"setValue(col.key, $event)\"\n />\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"mlv-dt-filter-dropdown__footer\">\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n (click)=\"clear()\"\n >\n {{ _i18n().clearAll }}\n </button>\n <button mlvButton mlvDensity=\"compact\" type=\"button\" (click)=\"apply()\">\n {{ _i18n().apply }}\n </button>\n </div>\n</div>\n", styles: ["@layer mlv.components{.mlv-dt-filter-dropdown{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-dt-filter-dropdown *{box-sizing:border-box}.mlv-dt-filter-dropdown{position:relative}.mlv-dt-filter-dropdown__panel{width:20rem;display:flex;flex-direction:column;border-radius:var(--mlv-radius-l)}.mlv-dt-filter-dropdown__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:.0625rem solid var(--mlv-border-subtle)}.mlv-dt-filter-dropdown__title{font-size:var(--mlv-font-size-m);font-weight:var(--mlv-font-weight-medium);color:var(--mlv-text-primary)}.mlv-dt-filter-dropdown__body{padding:.75rem 1rem;display:flex;flex-direction:column;gap:1rem;max-height:20rem;overflow-y:auto}.mlv-dt-filter-dropdown__group{display:flex;flex-direction:column;gap:.375rem}.mlv-dt-filter-dropdown__label{font-size:var(--mlv-font-size-xs);font-weight:var(--mlv-font-weight-medium);color:var(--mlv-text-secondary);letter-spacing:.01em}.mlv-dt-filter-dropdown__row{display:flex;gap:.5rem;align-items:flex-start}.mlv-dt-filter-dropdown__operator{flex:0 0 auto;min-width:8rem}.mlv-dt-filter-dropdown__option-operator{width:100%}.mlv-dt-filter-dropdown__text-input{flex:1;min-width:0}.mlv-dt-filter-dropdown__options{display:flex;flex-direction:column;gap:.25rem}.mlv-dt-filter-dropdown__option{display:flex;align-items:center;gap:.5rem;font-size:var(--mlv-font-size-m);color:var(--mlv-text-primary);cursor:pointer;transition:color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-dt-filter-dropdown__option:hover{color:var(--mlv-text-action)}.mlv-dt-filter-dropdown__footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:.0625rem solid var(--mlv-border-subtle)}@media(prefers-reduced-motion:reduce){.mlv-dt-filter-dropdown,.mlv-dt-filter-dropdown *,.mlv-dt-filter-dropdown:before,.mlv-dt-filter-dropdown:after,[class^=mlv-dt-filter-dropdown__],[class*=\" mlv-dt-filter-dropdown__\"],[class^=mlv-dt-filter-dropdown--],[class*=\" mlv-dt-filter-dropdown--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "component", type: MlvCheckbox, selector: "mlv-checkbox", inputs: ["ariaLabelledBy", "checked", "indeterminate", "tabbable"], outputs: ["checkedChange"] }, { kind: "component", type: MlvInput, selector: "mlv-input", inputs: ["type", "placeholder", "autocomplete", "inputMode", "maxLength", "minLength", "pattern", "name", "autofocus", "min", "max", "step", "bare", "projectControl", "role", "ariaExpanded", "ariaHasPopup", "ariaAutocomplete", "ariaControls", "ariaActiveDescendant", "ariaDescribedBy", "value"], outputs: ["valueChange", "inputFocus", "inputBlur"] }, { kind: "component", type: MlvSelect, selector: "mlv-select", inputs: ["value", "options", "searchFn", "searchDebounce", "multiple", "native", "placeholder", "toOption", "compareWith", "searchable", "searchPlaceholder", "matcher", "mobileMode", "mlvDensity", "mobileTitle"], outputs: ["valueChange"] }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
601
|
+
}
|
|
602
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvFilterDropdown, decorators: [{
|
|
603
|
+
type: Component,
|
|
604
|
+
args: [{ selector: 'mlv-dt-filter-dropdown', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
605
|
+
FormsModule,
|
|
606
|
+
MlvButton,
|
|
607
|
+
MlvButtonIcon,
|
|
608
|
+
MlvCheckbox,
|
|
609
|
+
MlvInput,
|
|
610
|
+
MlvSelect,
|
|
611
|
+
LucideX,
|
|
612
|
+
], host: { class: 'mlv-dt-filter-dropdown' }, template: "<div class=\"mlv-dt-filter-dropdown__panel\">\n <div class=\"mlv-dt-filter-dropdown__header\">\n <span class=\"mlv-dt-filter-dropdown__title\">{{ _i18n().filters }}</span>\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"cancel()\"\n [attr.aria-label]=\"_i18n().closeFilters\"\n >\n <svg lucideX mlvButtonIcon [size]=\"16\" />\n </button>\n </div>\n\n <div class=\"mlv-dt-filter-dropdown__body\">\n @for (col of filterableColumns(); track col.key) {\n <div class=\"mlv-dt-filter-dropdown__group\">\n <span class=\"mlv-dt-filter-dropdown__label\"\n >{{ col.title ?? col.key }}</span\n >\n\n @if (options(col).length > 0) {\n <mlv-select\n class=\"mlv-dt-filter-dropdown__option-operator\"\n [options]=\"operators(col)\"\n [toOption]=\"operatorTransform\"\n [ariaLabel]=\"resolveOperatorLabel(col)\"\n [ngModel]=\"getFilter(col.key).operator\"\n (ngModelChange)=\"setOperator(col.key, $event)\"\n />\n <div class=\"mlv-dt-filter-dropdown__options\">\n @for (opt of options(col); track opt.value) {\n <div class=\"mlv-dt-filter-dropdown__option\">\n <mlv-checkbox\n [checked]=\"isInArray(col.key, opt.value)\"\n [ariaLabel]=\"opt.label\"\n (checkedChange)=\"toggleInArray(col.key, opt.value)\"\n >{{ opt.label }}</mlv-checkbox\n >\n </div>\n }\n </div>\n } @else {\n <div class=\"mlv-dt-filter-dropdown__row\">\n <mlv-select\n class=\"mlv-dt-filter-dropdown__operator\"\n [options]=\"operators(col)\"\n [toOption]=\"operatorTransform\"\n [ariaLabel]=\"resolveOperatorLabel(col)\"\n [ngModel]=\"getFilter(col.key).operator\"\n (ngModelChange)=\"setOperator(col.key, $event)\"\n />\n <mlv-input\n class=\"mlv-dt-filter-dropdown__text-input\"\n [placeholder]=\"resolveFilterPlaceholder(col.title ?? col.key)\"\n [ariaLabel]=\"resolveFilterPlaceholder(col.title ?? col.key)\"\n [ngModel]=\"$any(getFilter(col.key).value)\"\n (ngModelChange)=\"setValue(col.key, $event)\"\n />\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"mlv-dt-filter-dropdown__footer\">\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n (click)=\"clear()\"\n >\n {{ _i18n().clearAll }}\n </button>\n <button mlvButton mlvDensity=\"compact\" type=\"button\" (click)=\"apply()\">\n {{ _i18n().apply }}\n </button>\n </div>\n</div>\n", styles: ["@layer mlv.components{.mlv-dt-filter-dropdown{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-dt-filter-dropdown *{box-sizing:border-box}.mlv-dt-filter-dropdown{position:relative}.mlv-dt-filter-dropdown__panel{width:20rem;display:flex;flex-direction:column;border-radius:var(--mlv-radius-l)}.mlv-dt-filter-dropdown__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:.0625rem solid var(--mlv-border-subtle)}.mlv-dt-filter-dropdown__title{font-size:var(--mlv-font-size-m);font-weight:var(--mlv-font-weight-medium);color:var(--mlv-text-primary)}.mlv-dt-filter-dropdown__body{padding:.75rem 1rem;display:flex;flex-direction:column;gap:1rem;max-height:20rem;overflow-y:auto}.mlv-dt-filter-dropdown__group{display:flex;flex-direction:column;gap:.375rem}.mlv-dt-filter-dropdown__label{font-size:var(--mlv-font-size-xs);font-weight:var(--mlv-font-weight-medium);color:var(--mlv-text-secondary);letter-spacing:.01em}.mlv-dt-filter-dropdown__row{display:flex;gap:.5rem;align-items:flex-start}.mlv-dt-filter-dropdown__operator{flex:0 0 auto;min-width:8rem}.mlv-dt-filter-dropdown__option-operator{width:100%}.mlv-dt-filter-dropdown__text-input{flex:1;min-width:0}.mlv-dt-filter-dropdown__options{display:flex;flex-direction:column;gap:.25rem}.mlv-dt-filter-dropdown__option{display:flex;align-items:center;gap:.5rem;font-size:var(--mlv-font-size-m);color:var(--mlv-text-primary);cursor:pointer;transition:color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-dt-filter-dropdown__option:hover{color:var(--mlv-text-action)}.mlv-dt-filter-dropdown__footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:.0625rem solid var(--mlv-border-subtle)}@media(prefers-reduced-motion:reduce){.mlv-dt-filter-dropdown,.mlv-dt-filter-dropdown *,.mlv-dt-filter-dropdown:before,.mlv-dt-filter-dropdown:after,[class^=mlv-dt-filter-dropdown__],[class*=\" mlv-dt-filter-dropdown__\"],[class^=mlv-dt-filter-dropdown--],[class*=\" mlv-dt-filter-dropdown--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"] }]
|
|
613
|
+
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], activeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilters", required: false }] }, { type: i0.Output, args: ["activeFiltersChange"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
614
|
+
|
|
615
|
+
/** Returns the original row reference used for expansion identity. */
|
|
616
|
+
function originalRow(row) {
|
|
617
|
+
return row['_mlvRef'] ?? row;
|
|
618
|
+
}
|
|
619
|
+
/** Recursively flattens expanded tree rows into render order. */
|
|
620
|
+
function flattenRows(rows, expanded, depth = 0) {
|
|
621
|
+
const result = [];
|
|
622
|
+
for (const row of rows) {
|
|
623
|
+
const original = originalRow(row);
|
|
624
|
+
result.push({ ...row, _mlvDepth: depth, _mlvRef: original });
|
|
625
|
+
const children = original['_mlvChildren'];
|
|
626
|
+
if (expanded.has(original) && children?.length) {
|
|
627
|
+
result.push(...flattenRows(children, expanded, depth + 1));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return result;
|
|
631
|
+
}
|
|
632
|
+
/** Resolves responsive column visibility at the supplied container width. */
|
|
633
|
+
function isColumnVisible(column, containerWidth) {
|
|
634
|
+
if (!column.responsive || containerWidth === 0)
|
|
635
|
+
return true;
|
|
636
|
+
const breakpoints = Object.keys(column.responsive)
|
|
637
|
+
.map(Number)
|
|
638
|
+
.filter(Number.isFinite)
|
|
639
|
+
.sort((a, b) => a - b);
|
|
640
|
+
let visibility = null;
|
|
641
|
+
for (const breakpoint of breakpoints) {
|
|
642
|
+
if (containerWidth >= breakpoint) {
|
|
643
|
+
visibility = column.responsive[breakpoint];
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (visibility === null) {
|
|
647
|
+
const fallback = Object.keys(column.responsive).find((key) => !Number.isFinite(Number(key)));
|
|
648
|
+
if (fallback)
|
|
649
|
+
visibility = column.responsive[fallback];
|
|
650
|
+
}
|
|
651
|
+
return visibility !== 'hidden';
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Parses a complete, non-negative CSS pixel width.
|
|
655
|
+
*
|
|
656
|
+
* Other CSS units deliberately return `undefined`; treating `12rem` or `50%`
|
|
657
|
+
* as `12px`/`50px` would corrupt resize bounds and pinned-column offsets.
|
|
658
|
+
*/
|
|
659
|
+
function parsePixelWidth(width) {
|
|
660
|
+
if (!width)
|
|
661
|
+
return undefined;
|
|
662
|
+
const match = width.trim().match(/^(?:\d+(?:\.\d+)?|\.\d+)px$/i);
|
|
663
|
+
if (!match)
|
|
664
|
+
return undefined;
|
|
665
|
+
const parsed = Number.parseFloat(match[0]);
|
|
666
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
667
|
+
}
|
|
668
|
+
/** Builds stable width styles for a table column. */
|
|
669
|
+
function columnWidthStyles(column) {
|
|
670
|
+
const styles = {};
|
|
671
|
+
if (column._currentWidth !== undefined) {
|
|
672
|
+
styles['width'] = `${column._currentWidth}px`;
|
|
673
|
+
styles['min-width'] = `${column._currentWidth}px`;
|
|
674
|
+
styles['max-width'] = `${column._currentWidth}px`;
|
|
675
|
+
return styles;
|
|
676
|
+
}
|
|
677
|
+
if (column.width)
|
|
678
|
+
styles['width'] = column.width;
|
|
679
|
+
if (column.minWidth)
|
|
680
|
+
styles['min-width'] = column.minWidth;
|
|
681
|
+
if (column.maxWidth)
|
|
682
|
+
styles['max-width'] = column.maxWidth;
|
|
683
|
+
return styles;
|
|
684
|
+
}
|
|
685
|
+
/** Adds sticky pin offsets to the base column width styles. */
|
|
686
|
+
function columnCellStyles(column, offsets) {
|
|
687
|
+
const styles = columnWidthStyles(column);
|
|
688
|
+
if (!column.pinned)
|
|
689
|
+
return styles;
|
|
690
|
+
styles['position'] = 'sticky';
|
|
691
|
+
styles['z-index'] = '2';
|
|
692
|
+
const side = column.pinSide === 'right' ? 'right' : 'left';
|
|
693
|
+
const offset = offsets.get(`${column.key}_${side}`) ?? '0px';
|
|
694
|
+
styles[side] =
|
|
695
|
+
`calc(${offset} + var(--mlv-dt-pinned-${side}-correction, 0px))`;
|
|
696
|
+
return styles;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
const DEFAULT_COLUMN_WIDTH = 150;
|
|
700
|
+
const DEFAULT_COLUMN_MIN_WIDTH = 60;
|
|
701
|
+
const DEFAULT_COLUMN_MAX_WIDTH = 2000;
|
|
702
|
+
const DEFAULT_SELECTION_COLUMN_WIDTH = 40;
|
|
703
|
+
const DEFAULT_ACTIONS_COLUMN_WIDTH = 80;
|
|
704
|
+
const COLUMN_RESIZE_KEYBOARD_STEP = 8;
|
|
705
|
+
const COLUMN_RESIZE_KEYBOARD_LARGE_STEP = 32;
|
|
706
|
+
class MlvDataTable {
|
|
707
|
+
/** @protected Injected i18n translations for the data table. */
|
|
708
|
+
_i18n = inject(MLV_DATA_TABLE_I18N);
|
|
709
|
+
// ---- Inputs ----------------------------------------------------------------
|
|
710
|
+
columns = input.required(/* @ts-ignore */
|
|
711
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
712
|
+
data = input(undefined, /* @ts-ignore */
|
|
713
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
714
|
+
rowHeight = input(40, /* @ts-ignore */
|
|
715
|
+
...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
|
|
716
|
+
/** Enable CDK virtual scroll for large datasets. */
|
|
717
|
+
virtualScroll = input(false, { ...(ngDevMode ? { debugName: "virtualScroll" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
718
|
+
/** Alternating row shading. */
|
|
719
|
+
striped = input(false, { ...(ngDevMode ? { debugName: "striped" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
720
|
+
/** Cell border lines. */
|
|
721
|
+
bordered = input(false, { ...(ngDevMode ? { debugName: "bordered" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
722
|
+
/** Sticky table header on scroll. */
|
|
723
|
+
stickyHeader = input(true, { ...(ngDevMode ? { debugName: "stickyHeader" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
724
|
+
/** Maximum height of the scrollable table area (e.g. `'28rem'`, `'400px'`). Enables vertical scroll. */
|
|
725
|
+
maxHeight = input(undefined, /* @ts-ignore */
|
|
726
|
+
...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
727
|
+
/** Column group definitions for multi-row headers. */
|
|
728
|
+
columnGroups = input([], /* @ts-ignore */
|
|
729
|
+
...(ngDevMode ? [{ debugName: "columnGroups" }] : /* istanbul ignore next */ []));
|
|
730
|
+
/** Enable editable mode on the table. */
|
|
731
|
+
editable = input(false, { ...(ngDevMode ? { debugName: "editable" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
732
|
+
/** Edit granularity: `'row'` edits entire rows, `'cell'` edits individual cells. */
|
|
733
|
+
editMode = input('row', /* @ts-ignore */
|
|
734
|
+
...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
|
|
735
|
+
/** Show an "Add row" button in the toolbar when editable. */
|
|
736
|
+
addRow = input(false, { ...(ngDevMode ? { debugName: "addRow" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
737
|
+
/** Show a loading overlay on top of the table. */
|
|
738
|
+
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
739
|
+
/**
|
|
740
|
+
* Failed-request state. `false` (default) renders normally; `true` renders the
|
|
741
|
+
* error block with the localized default message; a non-empty string renders
|
|
742
|
+
* that string as the message.
|
|
743
|
+
*
|
|
744
|
+
* While set — and while {@link loading} is falsy — the error block replaces the
|
|
745
|
+
* table body, taking precedence over both the rows and the `mlvDataTableNoData`
|
|
746
|
+
* template so a failed request is never mistaken for an empty result set.
|
|
747
|
+
* Project `<ng-template mlvDataTableError>` to replace the default block.
|
|
748
|
+
*/
|
|
749
|
+
error = input(false, /* @ts-ignore */
|
|
750
|
+
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
751
|
+
/** Row selection mode: `'single'`, `'multi'`, or `false` to disable. */
|
|
752
|
+
selectable = input(false, /* @ts-ignore */
|
|
753
|
+
...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
|
|
754
|
+
/**
|
|
755
|
+
* Accessible name for the trailing actions column header (rendered when
|
|
756
|
+
* {@link editable} is on). The actions `<th>` has no visible label, so this
|
|
757
|
+
* string is exposed to assistive tech via visually-hidden text to satisfy the
|
|
758
|
+
* `empty-table-header` requirement. Defaults to `'Actions'`.
|
|
759
|
+
*
|
|
760
|
+
* NB: this is a plain English default input rather than a `MLV_DATA_TABLE_I18N`
|
|
761
|
+
* token entry — adding an i18n string is a follow-up (see `libs-data-table.md`).
|
|
762
|
+
*/
|
|
763
|
+
actionsHeaderLabel = input('Actions', /* @ts-ignore */
|
|
764
|
+
...(ngDevMode ? [{ debugName: "actionsHeaderLabel" }] : /* istanbul ignore next */ []));
|
|
765
|
+
/**
|
|
766
|
+
* **Experimental.** Opt into full cell-level keyboard navigation backed by the
|
|
767
|
+
* `@angular/aria` grid pattern (`ngGrid`/`ngGridRow`/`ngGridCell`/`ngGridCellWidget`).
|
|
768
|
+
*
|
|
769
|
+
* When `false` (default), the table keeps its stable **row-level** roving
|
|
770
|
+
* navigation (ArrowUp/Down move between rows, Home/End jump, Space/Enter toggle
|
|
771
|
+
* row selection). When `true`, arrow keys move focus between individual **cells**
|
|
772
|
+
* (Arrow keys in both axes, Home/End within a row), interactive cells expose an
|
|
773
|
+
* `ngGridCellWidget` so Enter pauses grid navigation to interact (edit inputs,
|
|
774
|
+
* action buttons), and Escape returns to grid navigation.
|
|
775
|
+
*
|
|
776
|
+
* Limitations of the current prototype (see `libs-data-table.md`):
|
|
777
|
+
* - **Requires non-virtual mode.** Cell navigation is inert while
|
|
778
|
+
* {@link virtualScroll} is `true` — CDK row recycling and the split
|
|
779
|
+
* header/body/footer tables are incompatible with the grid's DOM-registered
|
|
780
|
+
* cell/row collection. `virtualScroll` wins; the table falls back to
|
|
781
|
+
* row-level roving.
|
|
782
|
+
* - Row selection stays row-level (via the checkbox widget); the aria grid's
|
|
783
|
+
* own cell-selection model is intentionally not wired.
|
|
784
|
+
*/
|
|
785
|
+
cellNavigation = input(false, { ...(ngDevMode ? { debugName: "cellNavigation" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
786
|
+
/**
|
|
787
|
+
* Pagination strategy.
|
|
788
|
+
* - `'paged'` (default) — renders the classic paginator footer and swaps rows per page.
|
|
789
|
+
* - `'infinite'` — hides the paginator and emits `loadMore` when the user scrolls near the bottom of the scroll container. Consumers should append the new page's rows to the existing data source.
|
|
790
|
+
*/
|
|
791
|
+
paginationMode = input('paged', /* @ts-ignore */
|
|
792
|
+
...(ngDevMode ? [{ debugName: "paginationMode" }] : /* istanbul ignore next */ []));
|
|
793
|
+
/**
|
|
794
|
+
* Whether more data is available to load. Only consulted in `paginationMode: 'infinite'`.
|
|
795
|
+
* Bind this to the consumer's own "has more pages" flag to stop the directive from
|
|
796
|
+
* firing once the backing data source has been exhausted.
|
|
797
|
+
*/
|
|
798
|
+
hasMore = input(true, { ...(ngDevMode ? { debugName: "hasMore" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
799
|
+
/**
|
|
800
|
+
* Distance in px from the bottom of the scrollable area at which `loadMore` fires.
|
|
801
|
+
* Only consulted in `paginationMode: 'infinite'`. Defaults to `200`.
|
|
802
|
+
*/
|
|
803
|
+
infiniteScrollThreshold = input(200, /* @ts-ignore */
|
|
804
|
+
...(ngDevMode ? [{ debugName: "infiniteScrollThreshold" }] : /* istanbul ignore next */ []));
|
|
805
|
+
/** Where table-owned filter controls are displayed. */
|
|
806
|
+
filterDisplay = input('toolbar', /* @ts-ignore */
|
|
807
|
+
...(ngDevMode ? [{ debugName: "filterDisplay" }] : /* istanbul ignore next */ []));
|
|
808
|
+
/** Whether the built-in global-search field is rendered in the toolbar. */
|
|
809
|
+
showSearch = input(true, { ...(ngDevMode ? { debugName: "showSearch" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
810
|
+
/** Whether the generic Sort menu is rendered when sortable columns exist. */
|
|
811
|
+
showSortMenu = input(false, { ...(ngDevMode ? { debugName: "showSortMenu" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
812
|
+
/** Whether global search executes as the user types or only on submit. */
|
|
813
|
+
searchTrigger = input('live', /* @ts-ignore */
|
|
814
|
+
...(ngDevMode ? [{ debugName: "searchTrigger" }] : /* istanbul ignore next */ []));
|
|
815
|
+
/** Delay in milliseconds used by live global search. */
|
|
816
|
+
searchDebounce = input(200, { ...(ngDevMode ? { debugName: "searchDebounce" } : /* istanbul ignore next */ {}), transform: (value) => Math.max(0, numberAttribute(value, 200)) });
|
|
817
|
+
// ---- Outputs ----------------------------------------------------------------
|
|
818
|
+
/** Emits when a row enters edit mode. */
|
|
819
|
+
rowEditStart = output();
|
|
820
|
+
/** Emits when the user confirms edits on a row. */
|
|
821
|
+
rowEditSave = output();
|
|
822
|
+
/** Emits when the user cancels editing a row. */
|
|
823
|
+
rowEditCancel = output();
|
|
824
|
+
/** Emits when the user clicks "Add row". Consumer is responsible for adding the row. */
|
|
825
|
+
rowAdd = output();
|
|
826
|
+
/** Emits when the user clicks a data row. */
|
|
827
|
+
rowClick = output();
|
|
828
|
+
/** Emits when the row selection changes. */
|
|
829
|
+
selectionChange = output();
|
|
830
|
+
/**
|
|
831
|
+
* Emits when the user activates the error block's retry control (the default
|
|
832
|
+
* "Retry" button, or `retry()` from a custom `mlvDataTableError` template).
|
|
833
|
+
* The consumer owns the refetch and is responsible for clearing {@link error}.
|
|
834
|
+
*/
|
|
835
|
+
retry = output();
|
|
836
|
+
/**
|
|
837
|
+
* Emits after a pointer or keyboard interaction commits a column width, or
|
|
838
|
+
* after a reset removes a user width override.
|
|
839
|
+
*/
|
|
840
|
+
columnResize = output();
|
|
841
|
+
/**
|
|
842
|
+
* Emits a complete normalized durable presentation snapshot after a user
|
|
843
|
+
* changes sorting, column visibility, pinning, committed widths, or page size.
|
|
844
|
+
* Programmatic {@link applyPresentationState} calls deliberately do not emit.
|
|
845
|
+
*/
|
|
846
|
+
presentationStateChange = output();
|
|
847
|
+
/**
|
|
848
|
+
* Emits in `paginationMode: 'infinite'` when the user scrolls near the bottom
|
|
849
|
+
* of the scroll container. The payload carries the next page number,
|
|
850
|
+
* current per-page size, and remaining scroll distance.
|
|
851
|
+
*/
|
|
852
|
+
loadMore = output();
|
|
853
|
+
/** Two-way bindable set of selected rows. */
|
|
854
|
+
selectedRows = model(new Set(), /* @ts-ignore */
|
|
855
|
+
...(ngDevMode ? [{ debugName: "selectedRows" }] : /* istanbul ignore next */ []));
|
|
856
|
+
/** Applied global-search query. Submit-mode drafts are committed here on search. */
|
|
857
|
+
searchQuery = model('', /* @ts-ignore */
|
|
858
|
+
...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
859
|
+
// ---- Content children -------------------------------------------------------
|
|
860
|
+
cellTemplates = contentChildren(MlvDataTableCell, { ...(ngDevMode ? { debugName: "cellTemplates" } : /* istanbul ignore next */ {}), descendants: true });
|
|
861
|
+
editCellTemplates = contentChildren(MlvDataTableEditCell, { ...(ngDevMode ? { debugName: "editCellTemplates" } : /* istanbul ignore next */ {}), descendants: true });
|
|
862
|
+
noDataTemplate = contentChildren(MlvDataTableNoData, { ...(ngDevMode ? { debugName: "noDataTemplate" } : /* istanbul ignore next */ {}), descendants: true });
|
|
863
|
+
errorTemplate = contentChildren(MlvDataTableError, { ...(ngDevMode ? { debugName: "errorTemplate" } : /* istanbul ignore next */ {}), descendants: true });
|
|
864
|
+
footerTemplate = contentChildren(MlvDataTableFooter, { ...(ngDevMode ? { debugName: "footerTemplate" } : /* istanbul ignore next */ {}), descendants: true });
|
|
865
|
+
/** @protected Optional host-owned actions rendered last in the table toolbar. */
|
|
866
|
+
_toolbarActions = contentChild(MlvDataTableToolbarActions, /* @ts-ignore */
|
|
867
|
+
...(ngDevMode ? [{ debugName: "_toolbarActions" }] : /* istanbul ignore next */ []));
|
|
868
|
+
// ---- View children ----------------------------------------------------------
|
|
869
|
+
tableWrapperRef = viewChild('tableWrapper', /* @ts-ignore */
|
|
870
|
+
...(ngDevMode ? [{ debugName: "tableWrapperRef" }] : /* istanbul ignore next */ []));
|
|
871
|
+
tableRef = viewChild('tableEl', /* @ts-ignore */
|
|
872
|
+
...(ngDevMode ? [{ debugName: "tableRef" }] : /* istanbul ignore next */ []));
|
|
873
|
+
/**
|
|
874
|
+
* @private Rendered resize separators. Used after rendering to measure
|
|
875
|
+
* non-pixel CSS widths for accurate initial ARIA values.
|
|
876
|
+
*/
|
|
877
|
+
_resizeHandleRefs = viewChildren('resizeHandle', /* @ts-ignore */
|
|
878
|
+
...(ngDevMode ? [{ debugName: "_resizeHandleRefs" }] : /* istanbul ignore next */ []));
|
|
879
|
+
/**
|
|
880
|
+
* @private Toolbar "Filters" trigger button. Focus is returned here when the
|
|
881
|
+
* filter dialog popup closes, matching the overlay focus-restore pattern.
|
|
882
|
+
*/
|
|
883
|
+
_filterTriggerRef = viewChild('filterBtn', { ...(ngDevMode ? { debugName: "_filterTriggerRef" } : /* istanbul ignore next */ {}), read: ElementRef });
|
|
884
|
+
/** @private CDK virtual-scroll viewport (only present in virtual-scroll mode). */
|
|
885
|
+
_virtualViewportRef = viewChild(CdkVirtualScrollViewport, /* @ts-ignore */
|
|
886
|
+
...(ngDevMode ? [{ debugName: "_virtualViewportRef" }] : /* istanbul ignore next */ []));
|
|
887
|
+
// ---- Services ---------------------------------------------------------------
|
|
888
|
+
/** @private DestroyRef used for observable cleanup. */
|
|
889
|
+
_destroyRef = inject(DestroyRef);
|
|
890
|
+
/** @private Shared resize-observer service used to track the host width. */
|
|
891
|
+
_resizeService = inject(MlvResizeObserverService);
|
|
892
|
+
_rtlService = inject(MlvRtlService);
|
|
893
|
+
/** @private Owning document for pointer fallback listeners and DOM queries. */
|
|
894
|
+
_document = inject(DOCUMENT);
|
|
895
|
+
/** @private Host element ref, observed for width and used for row focus queries. */
|
|
896
|
+
_el = inject(ElementRef);
|
|
897
|
+
/** @private Injector used to schedule `afterNextRender` from imperative handlers. */
|
|
898
|
+
_injector = inject(Injector);
|
|
899
|
+
/** @private Angular zone — column-resize drag listeners run outside it so pointer moves don't trigger a full CD tick per event (see {@link onResizeStart}). */
|
|
900
|
+
_ngZone = inject(NgZone);
|
|
901
|
+
/** @private Resolver for ICU parameterized i18n strings. */
|
|
902
|
+
_resolver = inject(MlvI18nResolverService);
|
|
903
|
+
/**
|
|
904
|
+
* @protected Flat-rows index of the data row that currently owns the roving
|
|
905
|
+
* `tabindex="0"`. All other data rows are `tabindex="-1"`, giving the row grid
|
|
906
|
+
* a single tab stop. Clamped in a constructor effect when `flatRows` changes.
|
|
907
|
+
*/
|
|
908
|
+
_focusedRowIndex = signal(0, /* @ts-ignore */
|
|
909
|
+
...(ngDevMode ? [{ debugName: "_focusedRowIndex" }] : /* istanbul ignore next */ []));
|
|
910
|
+
// ---- Internal state ---------------------------------------------------------
|
|
911
|
+
containerWidth = signal(0, /* @ts-ignore */
|
|
912
|
+
...(ngDevMode ? [{ debugName: "containerWidth" }] : /* istanbul ignore next */ []));
|
|
913
|
+
activeFilters = model([], /* @ts-ignore */
|
|
914
|
+
...(ngDevMode ? [{ debugName: "activeFilters" }] : /* istanbul ignore next */ []));
|
|
915
|
+
/** @protected Search text currently shown in the toolbar, including submit-mode drafts. */
|
|
916
|
+
_searchDraft = signal('', /* @ts-ignore */
|
|
917
|
+
...(ngDevMode ? [{ debugName: "_searchDraft" }] : /* istanbul ignore next */ []));
|
|
918
|
+
currentSort = signal(null, /* @ts-ignore */
|
|
919
|
+
...(ngDevMode ? [{ debugName: "currentSort" }] : /* istanbul ignore next */ []));
|
|
920
|
+
currentPage = signal(1, /* @ts-ignore */
|
|
921
|
+
...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
922
|
+
currentPerPage = signal(10, /* @ts-ignore */
|
|
923
|
+
...(ngDevMode ? [{ debugName: "currentPerPage" }] : /* istanbul ignore next */ []));
|
|
924
|
+
/**
|
|
925
|
+
* Captures durable user-controlled table presentation in declaration order.
|
|
926
|
+
* The returned object is safe to persist and excludes transient page state.
|
|
927
|
+
*/
|
|
928
|
+
getPresentationState() {
|
|
929
|
+
const columns = this.columns();
|
|
930
|
+
const sort = this.currentSort();
|
|
931
|
+
const widths = this._columnWidths();
|
|
932
|
+
const columnWidths = {};
|
|
933
|
+
const visibleColumnKeys = [];
|
|
934
|
+
const pinnedStartColumnKeys = [];
|
|
935
|
+
const pinnedEndColumnKeys = [];
|
|
936
|
+
for (const column of columns) {
|
|
937
|
+
if (!this._visibility.isHidden(column.key)) {
|
|
938
|
+
visibleColumnKeys.push(column.key);
|
|
939
|
+
}
|
|
940
|
+
const pinSide = this._pinning.getPinSide(column);
|
|
941
|
+
if (pinSide === 'left')
|
|
942
|
+
pinnedStartColumnKeys.push(column.key);
|
|
943
|
+
if (pinSide === 'right')
|
|
944
|
+
pinnedEndColumnKeys.push(column.key);
|
|
945
|
+
const width = widths.get(column.key);
|
|
946
|
+
if (width !== undefined)
|
|
947
|
+
columnWidths[column.key] = width;
|
|
948
|
+
}
|
|
949
|
+
return {
|
|
950
|
+
sort: sort ? { ...sort } : null,
|
|
951
|
+
visibleColumnKeys,
|
|
952
|
+
pinnedStartColumnKeys,
|
|
953
|
+
pinnedEndColumnKeys,
|
|
954
|
+
columnWidths,
|
|
955
|
+
perPage: this._normalizePerPage(this.currentPerPage()),
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Applies only the supplied durable presentation fields after filtering stale
|
|
960
|
+
* keys and normalizing widths and page size. Applying a snapshot always
|
|
961
|
+
* returns the transient current page to one and never emits an echo event.
|
|
962
|
+
*/
|
|
963
|
+
applyPresentationState(state) {
|
|
964
|
+
const columns = this.columns();
|
|
965
|
+
const columnKeys = new Set(columns.map((column) => column.key));
|
|
966
|
+
if (state.sort !== undefined) {
|
|
967
|
+
this.currentSort.set(this._normalizePresentationSort(state.sort, columns));
|
|
968
|
+
}
|
|
969
|
+
if (state.visibleColumnKeys !== undefined) {
|
|
970
|
+
const visible = this._knownPresentationKeys(state.visibleColumnKeys, columnKeys);
|
|
971
|
+
for (const column of columns) {
|
|
972
|
+
if (!column.hideable)
|
|
973
|
+
visible.add(column.key);
|
|
974
|
+
}
|
|
975
|
+
this._visibility.replaceHiddenColumns(new Set(columns
|
|
976
|
+
.filter((column) => column.hideable && !visible.has(column.key))
|
|
977
|
+
.map((column) => column.key)));
|
|
978
|
+
}
|
|
979
|
+
if (state.pinnedStartColumnKeys !== undefined ||
|
|
980
|
+
state.pinnedEndColumnKeys !== undefined) {
|
|
981
|
+
const start = state.pinnedStartColumnKeys === undefined
|
|
982
|
+
? undefined
|
|
983
|
+
: this._knownPresentationKeys(state.pinnedStartColumnKeys, columnKeys);
|
|
984
|
+
const end = state.pinnedEndColumnKeys === undefined
|
|
985
|
+
? undefined
|
|
986
|
+
: this._knownPresentationKeys(state.pinnedEndColumnKeys, columnKeys);
|
|
987
|
+
this._pinning.replaceOverrides(columns.map((column) => {
|
|
988
|
+
let pinSide = this._pinning.getPinSide(column);
|
|
989
|
+
if (start !== undefined) {
|
|
990
|
+
pinSide = start.has(column.key)
|
|
991
|
+
? 'left'
|
|
992
|
+
: pinSide === 'left'
|
|
993
|
+
? null
|
|
994
|
+
: pinSide;
|
|
995
|
+
}
|
|
996
|
+
if (end !== undefined) {
|
|
997
|
+
pinSide = end.has(column.key)
|
|
998
|
+
? 'right'
|
|
999
|
+
: pinSide === 'right'
|
|
1000
|
+
? null
|
|
1001
|
+
: pinSide;
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
key: column.key,
|
|
1005
|
+
pinned: pinSide !== null,
|
|
1006
|
+
pinSide: pinSide ?? column.pinSide ?? 'left',
|
|
1007
|
+
};
|
|
1008
|
+
}));
|
|
1009
|
+
}
|
|
1010
|
+
if (state.columnWidths !== undefined) {
|
|
1011
|
+
const widths = new Map();
|
|
1012
|
+
for (const column of columns) {
|
|
1013
|
+
const width = state.columnWidths[column.key];
|
|
1014
|
+
if (typeof width !== 'number')
|
|
1015
|
+
continue;
|
|
1016
|
+
widths.set(column.key, this._normalizeColumnWidth(width, this._columnResizeBounds(column)));
|
|
1017
|
+
}
|
|
1018
|
+
this._columnWidths.set(widths);
|
|
1019
|
+
}
|
|
1020
|
+
if (state.perPage !== undefined) {
|
|
1021
|
+
this.currentPerPage.set(this._normalizePerPage(state.perPage));
|
|
1022
|
+
}
|
|
1023
|
+
this.currentPage.set(1);
|
|
1024
|
+
afterNextRender(() => this._measureHeaderWidths(), {
|
|
1025
|
+
injector: this._injector,
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
/** @private Set of currently expanded tree rows (by original row reference). */
|
|
1029
|
+
_expanded = signal(new Set(), /* @ts-ignore */
|
|
1030
|
+
...(ngDevMode ? [{ debugName: "_expanded" }] : /* istanbul ignore next */ []));
|
|
1031
|
+
/** @private User-resized column widths keyed by column key (px). Committed once per completed pointer drag. */
|
|
1032
|
+
_columnWidths = signal(new Map(), /* @ts-ignore */
|
|
1033
|
+
...(ngDevMode ? [{ debugName: "_columnWidths" }] : /* istanbul ignore next */ []));
|
|
1034
|
+
/**
|
|
1035
|
+
* @private Live width (px) of the column currently being drag-resized, applied
|
|
1036
|
+
* optimistically during the drag before the committed {@link _columnWidths} map is
|
|
1037
|
+
* updated on pointer release. `null` when no resize is in progress. Kept separate from
|
|
1038
|
+
* {@link _columnWidths} so a move updates a single lightweight signal instead of
|
|
1039
|
+
* cloning the whole widths map every frame.
|
|
1040
|
+
*/
|
|
1041
|
+
_liveResize = signal(null, /* @ts-ignore */
|
|
1042
|
+
...(ngDevMode ? [{ debugName: "_liveResize" }] : /* istanbul ignore next */ []));
|
|
1043
|
+
/**
|
|
1044
|
+
* @private Last DOM-resolved bounds for each resize handle. CSS lengths such
|
|
1045
|
+
* as `rem` can be resolved to pixels from the rendered header during an
|
|
1046
|
+
* interaction and then reused by the separator's ARIA attributes.
|
|
1047
|
+
*/
|
|
1048
|
+
_resolvedResizeBounds = signal(new Map(), /* @ts-ignore */
|
|
1049
|
+
...(ngDevMode ? [{ debugName: "_resolvedResizeBounds" }] : /* istanbul ignore next */ []));
|
|
1050
|
+
/**
|
|
1051
|
+
* @private Rendered header widths keyed by column. This supplies accurate
|
|
1052
|
+
* separator values when a column's declared width uses `rem`, `%`, or layout.
|
|
1053
|
+
*/
|
|
1054
|
+
_measuredColumnWidths = signal(new Map(), /* @ts-ignore */
|
|
1055
|
+
...(ngDevMode ? [{ debugName: "_measuredColumnWidths" }] : /* istanbul ignore next */ []));
|
|
1056
|
+
/** @private Rendered widths of the optional selection and actions columns. */
|
|
1057
|
+
_measuredAuxiliaryWidths = signal({}, /* @ts-ignore */
|
|
1058
|
+
...(ngDevMode ? [{ debugName: "_measuredAuxiliaryWidths" }] : /* istanbul ignore next */ []));
|
|
1059
|
+
/** @protected Native vertical-scrollbar width inside the virtual viewport. */
|
|
1060
|
+
_virtualScrollbarGutter = signal(0, /* @ts-ignore */
|
|
1061
|
+
...(ngDevMode ? [{ debugName: "_virtualScrollbarGutter" }] : /* istanbul ignore next */ []));
|
|
1062
|
+
/**
|
|
1063
|
+
* @protected Inert outer scroll width that reproduces the virtual viewport's
|
|
1064
|
+
* native horizontal range without changing any split table's layout.
|
|
1065
|
+
*/
|
|
1066
|
+
_virtualHorizontalScrollExtent = signal(0, /* @ts-ignore */
|
|
1067
|
+
...(ngDevMode ? [{ debugName: "_virtualHorizontalScrollExtent" }] : /* istanbul ignore next */ []));
|
|
1068
|
+
/** @private Whether table geometry is currently frozen to explicit pixel widths. */
|
|
1069
|
+
_columnLayoutFrozen = computed(() => this._liveResize() !== null || this._columnWidths().size > 0, /* @ts-ignore */
|
|
1070
|
+
...(ngDevMode ? [{ debugName: "_columnLayoutFrozen" }] : /* istanbul ignore next */ []));
|
|
1071
|
+
/**
|
|
1072
|
+
* @private Exact measured utility-column styles used once data columns are
|
|
1073
|
+
* frozen. Keeping selection/actions cells and their `<col>` elements on the
|
|
1074
|
+
* same widths prevents fixed table layout from redistributing data columns.
|
|
1075
|
+
*/
|
|
1076
|
+
_auxiliaryColumnStyles = computed(() => {
|
|
1077
|
+
const measured = this._measuredAuxiliaryWidths();
|
|
1078
|
+
if (!this._columnLayoutFrozen()) {
|
|
1079
|
+
return { selection: null, actions: null };
|
|
1080
|
+
}
|
|
1081
|
+
return {
|
|
1082
|
+
selection: this._fixedColumnWidthStyles(measured.selection),
|
|
1083
|
+
actions: this._fixedColumnWidthStyles(measured.actions),
|
|
1084
|
+
};
|
|
1085
|
+
}, /* @ts-ignore */
|
|
1086
|
+
...(ngDevMode ? [{ debugName: "_auxiliaryColumnStyles" }] : /* istanbul ignore next */ []));
|
|
1087
|
+
/**
|
|
1088
|
+
* @private Per-row cache of the cell-template `ngTemplateOutletContext`, keyed by the
|
|
1089
|
+
* flattened row object identity (see {@link getCellContext}). A `WeakMap` so entries
|
|
1090
|
+
* for rows dropped by a `flatRows()` recompute are reclaimed automatically.
|
|
1091
|
+
*/
|
|
1092
|
+
_cellContextCache = new WeakMap();
|
|
1093
|
+
/** @private Stable one-column arrays used by repeated header filter editors. */
|
|
1094
|
+
_columnFilterLists = new Map();
|
|
1095
|
+
/** @private Editing state moved to MlvDataTableEditingService. */
|
|
1096
|
+
_editing = inject((MlvDataTableEditingService));
|
|
1097
|
+
/** @private Column visibility state moved to MlvDataTableColumnVisibilityService. */
|
|
1098
|
+
_visibility = inject(MlvDataTableColumnVisibilityService);
|
|
1099
|
+
/** @private Pin override state moved to MlvDataTablePinningService. */
|
|
1100
|
+
_pinning = inject(MlvDataTablePinningService);
|
|
1101
|
+
// ---- Derived state ----------------------------------------------------------
|
|
1102
|
+
effectiveDataSource = computed(() => {
|
|
1103
|
+
const d = this.data();
|
|
1104
|
+
if (d instanceof MlvDataSource) {
|
|
1105
|
+
return d;
|
|
1106
|
+
}
|
|
1107
|
+
const rows = Array.isArray(d) ? d : [];
|
|
1108
|
+
return new MlvArrayDataSource(rows);
|
|
1109
|
+
}, /* @ts-ignore */
|
|
1110
|
+
...(ngDevMode ? [{ debugName: "effectiveDataSource" }] : /* istanbul ignore next */ []));
|
|
1111
|
+
displayRows = computed(() => {
|
|
1112
|
+
const ds = this.effectiveDataSource();
|
|
1113
|
+
return ds.connect()();
|
|
1114
|
+
}, /* @ts-ignore */
|
|
1115
|
+
...(ngDevMode ? [{ debugName: "displayRows" }] : /* istanbul ignore next */ []));
|
|
1116
|
+
flatRows = computed(() => {
|
|
1117
|
+
const rows = this.displayRows();
|
|
1118
|
+
const expanded = this._expanded();
|
|
1119
|
+
return flattenRows(rows, expanded);
|
|
1120
|
+
}, /* @ts-ignore */
|
|
1121
|
+
...(ngDevMode ? [{ debugName: "flatRows" }] : /* istanbul ignore next */ []));
|
|
1122
|
+
totalItems = computed(() => this.effectiveDataSource().totalItems(), /* @ts-ignore */
|
|
1123
|
+
...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
|
|
1124
|
+
shownItems = computed(() => this.flatRows().length, /* @ts-ignore */
|
|
1125
|
+
...(ngDevMode ? [{ debugName: "shownItems" }] : /* istanbul ignore next */ []));
|
|
1126
|
+
visibleColumns = computed(() => {
|
|
1127
|
+
const cols = this.columns();
|
|
1128
|
+
const containerW = this.containerWidth();
|
|
1129
|
+
const widths = this._columnWidths();
|
|
1130
|
+
const live = this._liveResize();
|
|
1131
|
+
const measured = this._measuredColumnWidths();
|
|
1132
|
+
const freezeLayout = this._columnLayoutFrozen();
|
|
1133
|
+
const pinOverrides = this._pinning.overrides();
|
|
1134
|
+
const hidden = this._visibility.hiddenColumns();
|
|
1135
|
+
return cols
|
|
1136
|
+
.map((col) => {
|
|
1137
|
+
const visible = isColumnVisible(col, containerW);
|
|
1138
|
+
// During a drag the live width wins over the committed map value so the
|
|
1139
|
+
// column tracks the pointer before the map is updated on pointer release.
|
|
1140
|
+
const w = live && live.key === col.key ? live.width : widths.get(col.key);
|
|
1141
|
+
const override = pinOverrides.get(col.key);
|
|
1142
|
+
return {
|
|
1143
|
+
...col,
|
|
1144
|
+
pinned: override ? override.pinned : col.pinned,
|
|
1145
|
+
pinSide: override ? override.pinSide : col.pinSide,
|
|
1146
|
+
_currentWidth: w ??
|
|
1147
|
+
(freezeLayout
|
|
1148
|
+
? (measured.get(col.key) ?? parsePixelWidth(col.width))
|
|
1149
|
+
: undefined),
|
|
1150
|
+
_visible: visible,
|
|
1151
|
+
};
|
|
1152
|
+
})
|
|
1153
|
+
.filter((c) => c._visible !== false && !hidden.has(c.key))
|
|
1154
|
+
.sort((a, b) => {
|
|
1155
|
+
const order = (col) => {
|
|
1156
|
+
if (col.pinned && col.pinSide !== 'right')
|
|
1157
|
+
return 0;
|
|
1158
|
+
if (!col.pinned)
|
|
1159
|
+
return 1;
|
|
1160
|
+
return 2; // pinned right
|
|
1161
|
+
};
|
|
1162
|
+
return order(a) - order(b);
|
|
1163
|
+
});
|
|
1164
|
+
}, /* @ts-ignore */
|
|
1165
|
+
...(ngDevMode ? [{ debugName: "visibleColumns" }] : /* istanbul ignore next */ []));
|
|
1166
|
+
pinnedLeftColumns = computed(() => this.visibleColumns().filter((c) => c.pinned && c.pinSide !== 'right'), /* @ts-ignore */
|
|
1167
|
+
...(ngDevMode ? [{ debugName: "pinnedLeftColumns" }] : /* istanbul ignore next */ []));
|
|
1168
|
+
pinnedRightColumns = computed(() => this.visibleColumns().filter((c) => c.pinned && c.pinSide === 'right'), /* @ts-ignore */
|
|
1169
|
+
...(ngDevMode ? [{ debugName: "pinnedRightColumns" }] : /* istanbul ignore next */ []));
|
|
1170
|
+
columnOffsets = computed(() => {
|
|
1171
|
+
const map = new Map();
|
|
1172
|
+
const leftWidths = [];
|
|
1173
|
+
for (const col of this.pinnedLeftColumns()) {
|
|
1174
|
+
map.set(col.key + '_left', this._sumCssLengths(leftWidths));
|
|
1175
|
+
leftWidths.push(this._columnOffsetWidth(col));
|
|
1176
|
+
}
|
|
1177
|
+
const rightWidths = [];
|
|
1178
|
+
const rightCols = [...this.pinnedRightColumns()].reverse();
|
|
1179
|
+
for (const col of rightCols) {
|
|
1180
|
+
map.set(col.key + '_right', this._sumCssLengths(rightWidths));
|
|
1181
|
+
rightWidths.push(this._columnOffsetWidth(col));
|
|
1182
|
+
}
|
|
1183
|
+
return map;
|
|
1184
|
+
}, /* @ts-ignore */
|
|
1185
|
+
...(ngDevMode ? [{ debugName: "columnOffsets" }] : /* istanbul ignore next */ []));
|
|
1186
|
+
/**
|
|
1187
|
+
* Exact table width used while at least one column has a live or committed
|
|
1188
|
+
* user override. Freezing every measured column and the table to the same
|
|
1189
|
+
* pixel sum prevents `width: 100%` table layout from redistributing the
|
|
1190
|
+
* committed width. All virtual split tables and their viewport consume this
|
|
1191
|
+
* same value.
|
|
1192
|
+
*/
|
|
1193
|
+
resizedTableWidth = computed(() => {
|
|
1194
|
+
if (!this._columnLayoutFrozen())
|
|
1195
|
+
return null;
|
|
1196
|
+
const measured = this._measuredColumnWidths();
|
|
1197
|
+
const auxiliary = this._measuredAuxiliaryWidths();
|
|
1198
|
+
let total = 0;
|
|
1199
|
+
for (const col of this.visibleColumns()) {
|
|
1200
|
+
total +=
|
|
1201
|
+
col._currentWidth ??
|
|
1202
|
+
measured.get(col.key) ??
|
|
1203
|
+
parsePixelWidth(col.width) ??
|
|
1204
|
+
DEFAULT_COLUMN_WIDTH;
|
|
1205
|
+
}
|
|
1206
|
+
if (this.selectable()) {
|
|
1207
|
+
total += auxiliary.selection ?? DEFAULT_SELECTION_COLUMN_WIDTH;
|
|
1208
|
+
}
|
|
1209
|
+
if (this.editable()) {
|
|
1210
|
+
total += auxiliary.actions ?? DEFAULT_ACTIONS_COLUMN_WIDTH;
|
|
1211
|
+
}
|
|
1212
|
+
return this._roundColumnWidth(total);
|
|
1213
|
+
}, /* @ts-ignore */
|
|
1214
|
+
...(ngDevMode ? [{ debugName: "resizedTableWidth" }] : /* istanbul ignore next */ []));
|
|
1215
|
+
/**
|
|
1216
|
+
* @private Memoized inline `[style]` object per visible column, keyed by column key.
|
|
1217
|
+
* Rebuilt only when {@link visibleColumns} or {@link columnOffsets} change (width /
|
|
1218
|
+
* pin / visibility / responsive / live-resize changes). Cell `[style]` bindings read
|
|
1219
|
+
* this map through {@link getCellStyle} so they receive a *stable* object reference
|
|
1220
|
+
* across change-detection cycles instead of a freshly allocated `Record` per cell per
|
|
1221
|
+
* CD; the header and body cells of a column share one object.
|
|
1222
|
+
*/
|
|
1223
|
+
_columnStyles = computed(() => {
|
|
1224
|
+
const offsets = this.columnOffsets();
|
|
1225
|
+
const map = new Map();
|
|
1226
|
+
for (const col of this.visibleColumns()) {
|
|
1227
|
+
map.set(col.key, columnCellStyles(col, offsets));
|
|
1228
|
+
}
|
|
1229
|
+
return map;
|
|
1230
|
+
}, /* @ts-ignore */
|
|
1231
|
+
...(ngDevMode ? [{ debugName: "_columnStyles" }] : /* istanbul ignore next */ []));
|
|
1232
|
+
/**
|
|
1233
|
+
* @private Display cell templates resolved to a `Map<columnKey, TemplateRef>`, rebuilt
|
|
1234
|
+
* only when the projected {@link cellTemplates} set changes. Replaces a per-cell
|
|
1235
|
+
* `Array.find()` on every CD ({@link getTemplate}). First registration wins for
|
|
1236
|
+
* duplicate keys, preserving the previous `find()` (first-match) semantics.
|
|
1237
|
+
*/
|
|
1238
|
+
_cellTemplateMap = computed(() => {
|
|
1239
|
+
const map = new Map();
|
|
1240
|
+
for (const t of this.cellTemplates()) {
|
|
1241
|
+
const key = t.columnKey();
|
|
1242
|
+
if (!map.has(key))
|
|
1243
|
+
map.set(key, t.templateRef);
|
|
1244
|
+
}
|
|
1245
|
+
return map;
|
|
1246
|
+
}, /* @ts-ignore */
|
|
1247
|
+
...(ngDevMode ? [{ debugName: "_cellTemplateMap" }] : /* istanbul ignore next */ []));
|
|
1248
|
+
/**
|
|
1249
|
+
* @private Edit-mode cell templates resolved to a `Map<columnKey, TemplateRef>`,
|
|
1250
|
+
* rebuilt only when the projected {@link editCellTemplates} set changes. Replaces a
|
|
1251
|
+
* per-cell `Array.find()` on every CD ({@link getEditTemplate}). First registration
|
|
1252
|
+
* wins for duplicate keys.
|
|
1253
|
+
*/
|
|
1254
|
+
_editCellTemplateMap = computed(() => {
|
|
1255
|
+
const map = new Map();
|
|
1256
|
+
for (const t of this.editCellTemplates()) {
|
|
1257
|
+
const key = t.columnKey();
|
|
1258
|
+
if (!map.has(key))
|
|
1259
|
+
map.set(key, t.templateRef);
|
|
1260
|
+
}
|
|
1261
|
+
return map;
|
|
1262
|
+
}, /* @ts-ignore */
|
|
1263
|
+
...(ngDevMode ? [{ debugName: "_editCellTemplateMap" }] : /* istanbul ignore next */ []));
|
|
1264
|
+
/**
|
|
1265
|
+
* @protected Whether the experimental aria cell-level grid navigation is
|
|
1266
|
+
* active. Gated to non-virtual mode: `virtualScroll` recycles rows out of the
|
|
1267
|
+
* DOM, which the aria grid's DOM-registered row/cell collection cannot track,
|
|
1268
|
+
* so cell navigation yields to the stable row-roving path when virtual scroll
|
|
1269
|
+
* is on.
|
|
1270
|
+
*/
|
|
1271
|
+
_cellNav = computed(() => this.cellNavigation() && !this.virtualScroll(), /* @ts-ignore */
|
|
1272
|
+
...(ngDevMode ? [{ debugName: "_cellNav" }] : /* istanbul ignore next */ []));
|
|
1273
|
+
/**
|
|
1274
|
+
* Whether the error block replaces the table body. An in-flight refetch wins:
|
|
1275
|
+
* while `loading` is truthy the previous error is suppressed so the loader is
|
|
1276
|
+
* not competing with a stale failure message.
|
|
1277
|
+
*/
|
|
1278
|
+
showError = computed(() => {
|
|
1279
|
+
const error = this.error();
|
|
1280
|
+
if (this.loading())
|
|
1281
|
+
return false;
|
|
1282
|
+
return typeof error === 'string' ? error.trim().length > 0 : error === true;
|
|
1283
|
+
}, /* @ts-ignore */
|
|
1284
|
+
...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
|
|
1285
|
+
/**
|
|
1286
|
+
* Message rendered by the error block: the `error` string when one was
|
|
1287
|
+
* supplied, otherwise the localized `errorMessage` default.
|
|
1288
|
+
*/
|
|
1289
|
+
errorMessage = computed(() => {
|
|
1290
|
+
const error = this.error();
|
|
1291
|
+
return typeof error === 'string' && error.trim().length > 0
|
|
1292
|
+
? error
|
|
1293
|
+
: this._i18n().errorMessage;
|
|
1294
|
+
}, /* @ts-ignore */
|
|
1295
|
+
...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
1296
|
+
/**
|
|
1297
|
+
* @private Stable `retry()` callback handed to the `mlvDataTableError`
|
|
1298
|
+
* template context, so the context object identity only changes with the
|
|
1299
|
+
* message.
|
|
1300
|
+
*/
|
|
1301
|
+
_emitRetry = () => this.onRetry();
|
|
1302
|
+
/**
|
|
1303
|
+
* @protected `ngTemplateOutletContext` for a projected `mlvDataTableError`
|
|
1304
|
+
* template.
|
|
1305
|
+
*/
|
|
1306
|
+
_errorContext = computed(() => ({
|
|
1307
|
+
$implicit: this.errorMessage(),
|
|
1308
|
+
retry: this._emitRetry,
|
|
1309
|
+
}), /* @ts-ignore */
|
|
1310
|
+
...(ngDevMode ? [{ debugName: "_errorContext" }] : /* istanbul ignore next */ []));
|
|
1311
|
+
/**
|
|
1312
|
+
* @private Per-column raw-value → label lookup, memoized from
|
|
1313
|
+
* `visibleColumns()`. Falls back to `filterConfig.options` when a column
|
|
1314
|
+
* declares no explicit `valueLabels`. Keys are stringified raw values.
|
|
1315
|
+
*/
|
|
1316
|
+
_columnValueLabels = computed(() => {
|
|
1317
|
+
const map = new Map();
|
|
1318
|
+
for (const col of this.visibleColumns()) {
|
|
1319
|
+
const source = col.valueLabels ?? col.filterConfig?.options;
|
|
1320
|
+
if (!source)
|
|
1321
|
+
continue;
|
|
1322
|
+
const labels = new Map();
|
|
1323
|
+
if (Array.isArray(source)) {
|
|
1324
|
+
for (const option of source) {
|
|
1325
|
+
labels.set(String(option.value), option.label);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
for (const [value, label] of Object.entries(source)) {
|
|
1330
|
+
labels.set(value, label);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
if (labels.size > 0)
|
|
1334
|
+
map.set(col.key, labels);
|
|
1335
|
+
}
|
|
1336
|
+
return map;
|
|
1337
|
+
}, /* @ts-ignore */
|
|
1338
|
+
...(ngDevMode ? [{ debugName: "_columnValueLabels" }] : /* istanbul ignore next */ []));
|
|
1339
|
+
hasFilters = computed(() => this.activeFilters().length > 0, /* @ts-ignore */
|
|
1340
|
+
...(ngDevMode ? [{ debugName: "hasFilters" }] : /* istanbul ignore next */ []));
|
|
1341
|
+
/** Columns included in the global query, independent of responsive visibility. */
|
|
1342
|
+
searchableColumns = computed(() => this.columns().filter((column) => column.searchable), /* @ts-ignore */
|
|
1343
|
+
...(ngDevMode ? [{ debugName: "searchableColumns" }] : /* istanbul ignore next */ []));
|
|
1344
|
+
/** Stable key list passed to the data source for OR-across-columns search. */
|
|
1345
|
+
searchableColumnKeys = computed(() => this.searchableColumns().map((column) => column.key), /* @ts-ignore */
|
|
1346
|
+
...(ngDevMode ? [{ debugName: "searchableColumnKeys" }] : /* istanbul ignore next */ []));
|
|
1347
|
+
/** Whether a global search field belongs in the toolbar. */
|
|
1348
|
+
hasSearchableColumns = computed(() => this.searchableColumns().length > 0, /* @ts-ignore */
|
|
1349
|
+
...(ngDevMode ? [{ debugName: "hasSearchableColumns" }] : /* istanbul ignore next */ []));
|
|
1350
|
+
/** Whether any configured column supports filtering. */
|
|
1351
|
+
hasFilterableColumns = computed(() => this.columns().some((column) => column.filterable), /* @ts-ignore */
|
|
1352
|
+
...(ngDevMode ? [{ debugName: "hasFilterableColumns" }] : /* istanbul ignore next */ []));
|
|
1353
|
+
/** Whether any configured column supports sorting. */
|
|
1354
|
+
hasSortableColumns = computed(() => this.columns().some((column) => column.sortable), /* @ts-ignore */
|
|
1355
|
+
...(ngDevMode ? [{ debugName: "hasSortableColumns" }] : /* istanbul ignore next */ []));
|
|
1356
|
+
/** Localized active-filter summary announced when the committed set changes. */
|
|
1357
|
+
activeFilterLabel = computed(() => this._resolver.resolve(this._i18n(), 'activeFilterCount', { count: this.activeFilters().length }), /* @ts-ignore */
|
|
1358
|
+
...(ngDevMode ? [{ debugName: "activeFilterLabel" }] : /* istanbul ignore next */ []));
|
|
1359
|
+
/** Total number of rendered columns (visible + selection checkbox + actions). */
|
|
1360
|
+
totalColumnCount = computed(() => {
|
|
1361
|
+
let count = this.visibleColumns().length;
|
|
1362
|
+
if (this.selectable())
|
|
1363
|
+
count++;
|
|
1364
|
+
if (this.editable())
|
|
1365
|
+
count++;
|
|
1366
|
+
return count;
|
|
1367
|
+
}, /* @ts-ignore */
|
|
1368
|
+
...(ngDevMode ? [{ debugName: "totalColumnCount" }] : /* istanbul ignore next */ []));
|
|
1369
|
+
/**
|
|
1370
|
+
* Pixel/CSS height applied to the `cdk-virtual-scroll-viewport` when `virtualScroll` is on.
|
|
1371
|
+
* Falls back to `'24rem'` if `maxHeight` is not provided. The viewport requires an explicit
|
|
1372
|
+
* height because `cdk-virtual-scroll-viewport` does not derive its size from its content.
|
|
1373
|
+
*/
|
|
1374
|
+
virtualViewportHeight = computed(() => this.maxHeight() ?? '24rem', /* @ts-ignore */
|
|
1375
|
+
...(ngDevMode ? [{ debugName: "virtualViewportHeight" }] : /* istanbul ignore next */ []));
|
|
1376
|
+
/** Whether any column has `hideable: true`. */
|
|
1377
|
+
hasHideableColumns = computed(() => this.columns().some((c) => c.hideable), /* @ts-ignore */
|
|
1378
|
+
...(ngDevMode ? [{ debugName: "hasHideableColumns" }] : /* istanbul ignore next */ []));
|
|
1379
|
+
/** Whether the toolbar has a visible control or table-owned status to render. */
|
|
1380
|
+
hasToolbarContent = computed(() => (this.showSearch() && this.hasSearchableColumns()) ||
|
|
1381
|
+
(this.filterDisplay() !== 'none' && this.hasFilters()) ||
|
|
1382
|
+
(this.editable() && this.addRow()) ||
|
|
1383
|
+
(this.showSortMenu() && this.hasSortableColumns()) ||
|
|
1384
|
+
this.hasHideableColumns() ||
|
|
1385
|
+
(this.filterDisplay() === 'toolbar' && this.hasFilterableColumns()) ||
|
|
1386
|
+
!!this._toolbarActions(), /* @ts-ignore */
|
|
1387
|
+
...(ngDevMode ? [{ debugName: "hasToolbarContent" }] : /* istanbul ignore next */ []));
|
|
1388
|
+
/** All columns (for column visibility popup). */
|
|
1389
|
+
allColumns = computed(() => this.columns(), /* @ts-ignore */
|
|
1390
|
+
...(ngDevMode ? [{ debugName: "allColumns" }] : /* istanbul ignore next */ []));
|
|
1391
|
+
/** Whether all visible rows are selected. */
|
|
1392
|
+
allRowsSelected = computed(() => {
|
|
1393
|
+
const rows = this.flatRows();
|
|
1394
|
+
const selected = this.selectedRows();
|
|
1395
|
+
return rows.length > 0 && rows.every((r) => selected.has(this._ref(r)));
|
|
1396
|
+
}, /* @ts-ignore */
|
|
1397
|
+
...(ngDevMode ? [{ debugName: "allRowsSelected" }] : /* istanbul ignore next */ []));
|
|
1398
|
+
/** Whether some (but not all) rows are selected. */
|
|
1399
|
+
someRowsSelected = computed(() => {
|
|
1400
|
+
const rows = this.flatRows();
|
|
1401
|
+
const selected = this.selectedRows();
|
|
1402
|
+
const count = rows.filter((r) => selected.has(this._ref(r))).length;
|
|
1403
|
+
return count > 0 && count < rows.length;
|
|
1404
|
+
}, /* @ts-ignore */
|
|
1405
|
+
...(ngDevMode ? [{ debugName: "someRowsSelected" }] : /* istanbul ignore next */ []));
|
|
1406
|
+
/** Whether the table has multi-row column groups defined. */
|
|
1407
|
+
hasColumnGroups = computed(() => this.columnGroups().length > 0, /* @ts-ignore */
|
|
1408
|
+
...(ngDevMode ? [{ debugName: "hasColumnGroups" }] : /* istanbul ignore next */ []));
|
|
1409
|
+
/**
|
|
1410
|
+
* Computes the group header row layout.
|
|
1411
|
+
* Columns covered by a group get colspan in the group row.
|
|
1412
|
+
* Standalone columns (not in any group) get rowspan="2" in the main header row.
|
|
1413
|
+
*/
|
|
1414
|
+
headerLayout = computed(() => {
|
|
1415
|
+
const groups = this.columnGroups();
|
|
1416
|
+
const visible = this.visibleColumns();
|
|
1417
|
+
if (groups.length === 0)
|
|
1418
|
+
return null;
|
|
1419
|
+
const groupedKeys = new Set(groups.flatMap((g) => g.columns));
|
|
1420
|
+
// Build group header cells
|
|
1421
|
+
const groupCells = [];
|
|
1422
|
+
const standaloneKeys = new Set();
|
|
1423
|
+
// Track which visible columns belong to which group
|
|
1424
|
+
let colIndex = 0;
|
|
1425
|
+
while (colIndex < visible.length) {
|
|
1426
|
+
const col = visible[colIndex];
|
|
1427
|
+
const group = groups.find((g) => g.columns.includes(col.key));
|
|
1428
|
+
if (group) {
|
|
1429
|
+
// Count how many consecutive visible columns belong to this group
|
|
1430
|
+
const span = visible.filter((c) => group.columns.includes(c.key)).length;
|
|
1431
|
+
groupCells.push({ type: 'group', group, colspan: span });
|
|
1432
|
+
// Skip all columns in this group
|
|
1433
|
+
colIndex += span;
|
|
1434
|
+
}
|
|
1435
|
+
else {
|
|
1436
|
+
standaloneKeys.add(col.key);
|
|
1437
|
+
colIndex++;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return { groupCells, standaloneKeys, groupedKeys };
|
|
1441
|
+
}, /* @ts-ignore */
|
|
1442
|
+
...(ngDevMode ? [{ debugName: "headerLayout" }] : /* istanbul ignore next */ []));
|
|
1443
|
+
// ---- Lifecycle --------------------------------------------------------------
|
|
1444
|
+
constructor() {
|
|
1445
|
+
// Detach any in-flight column-resize drag listeners if the table is destroyed
|
|
1446
|
+
// mid-drag (e.g. a route change while the user is resizing a column) so the dead
|
|
1447
|
+
// component's document listeners can't keep firing.
|
|
1448
|
+
this._destroyRef.onDestroy(() => this._cleanupResize());
|
|
1449
|
+
effect(() => {
|
|
1450
|
+
const ds = this.effectiveDataSource();
|
|
1451
|
+
ds.setSort(this.currentSort());
|
|
1452
|
+
});
|
|
1453
|
+
effect(() => {
|
|
1454
|
+
const ds = this.effectiveDataSource();
|
|
1455
|
+
const filters = this.activeFilters();
|
|
1456
|
+
ds.setFilters(filters);
|
|
1457
|
+
untracked(() => {
|
|
1458
|
+
if (this.currentPage() !== 1)
|
|
1459
|
+
this.currentPage.set(1);
|
|
1460
|
+
});
|
|
1461
|
+
});
|
|
1462
|
+
effect(() => {
|
|
1463
|
+
const ds = this.effectiveDataSource();
|
|
1464
|
+
const query = this.searchQuery();
|
|
1465
|
+
const keys = this.searchableColumnKeys();
|
|
1466
|
+
ds.setSearch(query.trim() && keys.length ? { query, keys } : null);
|
|
1467
|
+
untracked(() => {
|
|
1468
|
+
if (this._searchDraft() !== query)
|
|
1469
|
+
this._searchDraft.set(query);
|
|
1470
|
+
if (this.currentPage() !== 1)
|
|
1471
|
+
this.currentPage.set(1);
|
|
1472
|
+
});
|
|
1473
|
+
});
|
|
1474
|
+
effect(() => {
|
|
1475
|
+
const ds = this.effectiveDataSource();
|
|
1476
|
+
// In infinite or virtual-scroll mode the consumer hands over the entire
|
|
1477
|
+
// row set up front, so the internal data source must stay on page 1 at
|
|
1478
|
+
// all times — pagination is disabled in both modes.
|
|
1479
|
+
const unpaged = this.paginationMode() === 'infinite' || this.virtualScroll();
|
|
1480
|
+
ds.setPage(unpaged ? 1 : this.currentPage());
|
|
1481
|
+
});
|
|
1482
|
+
effect(() => {
|
|
1483
|
+
const ds = this.effectiveDataSource();
|
|
1484
|
+
// In infinite or virtual-scroll mode disable internal per-page slicing
|
|
1485
|
+
// so every row the consumer has provided gets rendered. Virtual scroll
|
|
1486
|
+
// then renders only the visible slice of that full list via CDK.
|
|
1487
|
+
const unpaged = this.paginationMode() === 'infinite' || this.virtualScroll();
|
|
1488
|
+
ds.setPerPage(unpaged ? Number.MAX_SAFE_INTEGER : this.currentPerPage());
|
|
1489
|
+
});
|
|
1490
|
+
// Keep the roving row index in range as the visible rows change
|
|
1491
|
+
// (filtering, sorting, paging, tree expand/collapse, data replacement).
|
|
1492
|
+
effect(() => {
|
|
1493
|
+
const count = this.flatRows().length;
|
|
1494
|
+
const current = untracked(this._focusedRowIndex);
|
|
1495
|
+
if (count === 0) {
|
|
1496
|
+
if (current !== 0)
|
|
1497
|
+
this._focusedRowIndex.set(0);
|
|
1498
|
+
}
|
|
1499
|
+
else if (current > count - 1) {
|
|
1500
|
+
this._focusedRowIndex.set(count - 1);
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
effect(() => {
|
|
1504
|
+
const handles = this._resizeHandleRefs();
|
|
1505
|
+
if (!handles.length)
|
|
1506
|
+
return;
|
|
1507
|
+
afterNextRender(() => this._measureHeaderWidths(), {
|
|
1508
|
+
injector: this._injector,
|
|
1509
|
+
});
|
|
1510
|
+
});
|
|
1511
|
+
effect((onCleanup) => {
|
|
1512
|
+
if (!this.virtualScroll())
|
|
1513
|
+
return;
|
|
1514
|
+
const wrapper = this.tableWrapperRef()?.nativeElement;
|
|
1515
|
+
const viewport = this._virtualViewportRef()?.elementRef.nativeElement;
|
|
1516
|
+
if (!wrapper || !viewport)
|
|
1517
|
+
return;
|
|
1518
|
+
let synchronizing = false;
|
|
1519
|
+
const measureVirtualGeometry = () => {
|
|
1520
|
+
this._updateVirtualScrollGeometry(wrapper, viewport);
|
|
1521
|
+
};
|
|
1522
|
+
const syncFromWrapper = () => {
|
|
1523
|
+
if (synchronizing || viewport.scrollLeft === wrapper.scrollLeft)
|
|
1524
|
+
return;
|
|
1525
|
+
synchronizing = true;
|
|
1526
|
+
try {
|
|
1527
|
+
viewport.scrollLeft = wrapper.scrollLeft;
|
|
1528
|
+
}
|
|
1529
|
+
finally {
|
|
1530
|
+
synchronizing = false;
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1533
|
+
const syncFromViewport = () => {
|
|
1534
|
+
if (synchronizing || wrapper.scrollLeft === viewport.scrollLeft)
|
|
1535
|
+
return;
|
|
1536
|
+
synchronizing = true;
|
|
1537
|
+
try {
|
|
1538
|
+
wrapper.scrollLeft = viewport.scrollLeft;
|
|
1539
|
+
const acceptedScrollLeft = wrapper.scrollLeft;
|
|
1540
|
+
if (viewport.scrollLeft !== acceptedScrollLeft) {
|
|
1541
|
+
viewport.scrollLeft = acceptedScrollLeft;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
finally {
|
|
1545
|
+
synchronizing = false;
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
this._ngZone.runOutsideAngular(() => {
|
|
1549
|
+
wrapper.addEventListener('scroll', syncFromWrapper, {
|
|
1550
|
+
passive: true,
|
|
1551
|
+
});
|
|
1552
|
+
viewport.addEventListener('scroll', syncFromViewport, {
|
|
1553
|
+
passive: true,
|
|
1554
|
+
});
|
|
1555
|
+
measureVirtualGeometry();
|
|
1556
|
+
syncFromWrapper();
|
|
1557
|
+
});
|
|
1558
|
+
const viewportResize = this._resizeService
|
|
1559
|
+
.observe(viewport)
|
|
1560
|
+
.subscribe(() => {
|
|
1561
|
+
measureVirtualGeometry();
|
|
1562
|
+
syncFromWrapper();
|
|
1563
|
+
});
|
|
1564
|
+
onCleanup(() => {
|
|
1565
|
+
wrapper.removeEventListener('scroll', syncFromWrapper);
|
|
1566
|
+
viewport.removeEventListener('scroll', syncFromViewport);
|
|
1567
|
+
viewportResize.unsubscribe();
|
|
1568
|
+
});
|
|
1569
|
+
});
|
|
1570
|
+
effect(() => {
|
|
1571
|
+
if (!this.virtualScroll())
|
|
1572
|
+
return;
|
|
1573
|
+
this.resizedTableWidth();
|
|
1574
|
+
this.visibleColumns();
|
|
1575
|
+
this._virtualScrollbarGutter();
|
|
1576
|
+
afterNextRender(() => this._syncVirtualHorizontalScroll(), {
|
|
1577
|
+
injector: this._injector,
|
|
1578
|
+
});
|
|
1579
|
+
});
|
|
1580
|
+
afterNextRender(() => {
|
|
1581
|
+
const el = this._el.nativeElement;
|
|
1582
|
+
this._resizeService
|
|
1583
|
+
.observe(el)
|
|
1584
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
1585
|
+
.subscribe((entries) => {
|
|
1586
|
+
const width = entries[0]?.contentRect?.width ?? el.offsetWidth;
|
|
1587
|
+
this.containerWidth.set(width);
|
|
1588
|
+
afterNextRender(() => this._measureHeaderWidths(), {
|
|
1589
|
+
injector: this._injector,
|
|
1590
|
+
});
|
|
1591
|
+
});
|
|
1592
|
+
this.containerWidth.set(el.offsetWidth);
|
|
1593
|
+
this._measureHeaderWidths();
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
// ---- Template helpers -------------------------------------------------------
|
|
1597
|
+
/** Resolves the custom display template for a column key (if any). */
|
|
1598
|
+
getTemplate(key) {
|
|
1599
|
+
return this._cellTemplateMap().get(key) ?? null;
|
|
1600
|
+
}
|
|
1601
|
+
getNoDataTemplate() {
|
|
1602
|
+
const list = this.noDataTemplate();
|
|
1603
|
+
return list.length > 0 ? list[0].templateRef : null;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* `ngTemplateOutletContext` for a data cell's custom/edit template. Returns a
|
|
1607
|
+
* *stable* per-row object so the outlet's context does not churn (fresh object +
|
|
1608
|
+
* `NgTemplateOutlet.ngOnChanges`) every change-detection cycle. `flatRows()` rebuilds
|
|
1609
|
+
* its row objects on every data / sort / filter / expand change, so a cached entry's
|
|
1610
|
+
* `index` always matches that row's current position and stale entries (whose row
|
|
1611
|
+
* objects are no longer referenced) are garbage-collected.
|
|
1612
|
+
*/
|
|
1613
|
+
getCellContext(row, index) {
|
|
1614
|
+
let ctx = this._cellContextCache.get(row);
|
|
1615
|
+
if (!ctx) {
|
|
1616
|
+
ctx = { $implicit: row, row, index };
|
|
1617
|
+
this._cellContextCache.set(row, ctx);
|
|
1618
|
+
}
|
|
1619
|
+
return ctx;
|
|
1620
|
+
}
|
|
1621
|
+
getCellValue(row, key) {
|
|
1622
|
+
return row[key];
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Value rendered by the **default** cell renderer. Maps the raw value through
|
|
1626
|
+
* the column's `valueLabels` (or its `filterConfig.options` fallback) when a
|
|
1627
|
+
* label exists; otherwise returns the raw value unchanged. Custom
|
|
1628
|
+
* `mlvDataTableCell` templates bypass this entirely.
|
|
1629
|
+
*/
|
|
1630
|
+
getCellDisplayValue(row, col) {
|
|
1631
|
+
const raw = this.getCellValue(row, col.key);
|
|
1632
|
+
if (raw === null || raw === undefined)
|
|
1633
|
+
return raw;
|
|
1634
|
+
const labels = this._columnValueLabels().get(col.key);
|
|
1635
|
+
if (!labels)
|
|
1636
|
+
return raw;
|
|
1637
|
+
return labels.get(String(raw)) ?? raw;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Resolves the semantic tone for one default-rendered cell. Returns `null`
|
|
1641
|
+
* when the column declares no `tone` (or its resolver opted this row out), in
|
|
1642
|
+
* which case the cell renders as plain text instead of a badge.
|
|
1643
|
+
*/
|
|
1644
|
+
getCellTone(row, col) {
|
|
1645
|
+
const tone = col.tone;
|
|
1646
|
+
if (!tone)
|
|
1647
|
+
return null;
|
|
1648
|
+
if (typeof tone === 'function') {
|
|
1649
|
+
return tone(row) ?? null;
|
|
1650
|
+
}
|
|
1651
|
+
return tone;
|
|
1652
|
+
}
|
|
1653
|
+
/** Retrieves the projected error template, if the consumer supplied one. */
|
|
1654
|
+
getErrorTemplate() {
|
|
1655
|
+
const list = this.errorTemplate();
|
|
1656
|
+
return list.length > 0 ? list[0].templateRef : null;
|
|
1657
|
+
}
|
|
1658
|
+
/** Emits `retry` so the consumer can refetch the failed request. */
|
|
1659
|
+
onRetry() {
|
|
1660
|
+
this.retry.emit();
|
|
1661
|
+
}
|
|
1662
|
+
/** Resolves the edit-mode template for a column key (if any). */
|
|
1663
|
+
getEditTemplate(key) {
|
|
1664
|
+
return this._editCellTemplateMap().get(key) ?? null;
|
|
1665
|
+
}
|
|
1666
|
+
/** Whether a given row index is currently being edited. */
|
|
1667
|
+
isEditing(index) {
|
|
1668
|
+
return this._editing.isEditing(index);
|
|
1669
|
+
}
|
|
1670
|
+
/** Enter edit mode for a row. Clones the row for rollback. */
|
|
1671
|
+
startEdit(row, index) {
|
|
1672
|
+
this._editing.start(row, index);
|
|
1673
|
+
this.rowEditStart.emit({ row, index });
|
|
1674
|
+
}
|
|
1675
|
+
/** Confirm edits for a row. Emits save event with original and modified row. */
|
|
1676
|
+
saveEdit(row, index) {
|
|
1677
|
+
const originalRow = this._editing.save(row, index);
|
|
1678
|
+
this.rowEditSave.emit({ row, index, originalRow });
|
|
1679
|
+
}
|
|
1680
|
+
/** Cancel editing. Emits cancel event. */
|
|
1681
|
+
cancelEdit(row, index) {
|
|
1682
|
+
this._editing.cancel(index);
|
|
1683
|
+
this.rowEditCancel.emit({ row, index });
|
|
1684
|
+
}
|
|
1685
|
+
/** Emit add-row event. Consumer is responsible for appending the new row. */
|
|
1686
|
+
onAddRow() {
|
|
1687
|
+
this.rowAdd.emit();
|
|
1688
|
+
}
|
|
1689
|
+
// ---- Row click ---------------------------------------------------------------
|
|
1690
|
+
/** Handle click on a data row. */
|
|
1691
|
+
onRowClick(row, index, event) {
|
|
1692
|
+
this._focusedRowIndex.set(index);
|
|
1693
|
+
this.rowClick.emit({ row, index, event });
|
|
1694
|
+
}
|
|
1695
|
+
// ---- Row keyboard navigation (grid row-focus model) --------------------------
|
|
1696
|
+
/**
|
|
1697
|
+
* @protected Roving tabindex for a data row: `0` for the focused row, `-1`
|
|
1698
|
+
* otherwise, so the row grid exposes a single tab stop.
|
|
1699
|
+
*/
|
|
1700
|
+
_rowTabIndex(index) {
|
|
1701
|
+
return index === this._focusedRowIndex() ? 0 : -1;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* @protected Sync the roving row index when a row receives focus (via Tab or
|
|
1705
|
+
* a click that focuses the `<tr>`).
|
|
1706
|
+
*/
|
|
1707
|
+
_onRowFocus(index) {
|
|
1708
|
+
this._focusedRowIndex.set(index);
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* @protected Row-level keyboard navigation for the `role="grid"` table.
|
|
1712
|
+
* Active only when the `<tr>` itself holds focus — keys originating from an
|
|
1713
|
+
* interactive cell widget (checkbox, button, edit input) are left alone.
|
|
1714
|
+
*
|
|
1715
|
+
* - `ArrowUp` / `ArrowDown` — move row focus by one (clamped)
|
|
1716
|
+
* - `Home` / `End` — jump to the first / last row
|
|
1717
|
+
* - `Space` / `Enter` — toggle selection of the focused row when selectable
|
|
1718
|
+
*/
|
|
1719
|
+
_onRowKeydown(index, row, event) {
|
|
1720
|
+
if (event.target !== event.currentTarget)
|
|
1721
|
+
return;
|
|
1722
|
+
const lastIndex = this.flatRows().length - 1;
|
|
1723
|
+
switch (this._rtlService.normalizeArrowKey(event) ?? event.key) {
|
|
1724
|
+
case DOWN_ARROW:
|
|
1725
|
+
event.preventDefault();
|
|
1726
|
+
this._moveRowFocus(Math.min(index + 1, lastIndex));
|
|
1727
|
+
break;
|
|
1728
|
+
case UP_ARROW:
|
|
1729
|
+
event.preventDefault();
|
|
1730
|
+
this._moveRowFocus(Math.max(index - 1, 0));
|
|
1731
|
+
break;
|
|
1732
|
+
case 'Home':
|
|
1733
|
+
event.preventDefault();
|
|
1734
|
+
this._moveRowFocus(0);
|
|
1735
|
+
break;
|
|
1736
|
+
case 'End':
|
|
1737
|
+
event.preventDefault();
|
|
1738
|
+
this._moveRowFocus(lastIndex);
|
|
1739
|
+
break;
|
|
1740
|
+
case ' ':
|
|
1741
|
+
case 'Enter':
|
|
1742
|
+
if (this.selectable()) {
|
|
1743
|
+
event.preventDefault();
|
|
1744
|
+
this.toggleRowSelection(row);
|
|
1745
|
+
}
|
|
1746
|
+
break;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* @private Move the roving tabindex and DOM focus to the row at `targetIndex`.
|
|
1751
|
+
* In virtual-scroll mode the target may be recycled out of the DOM, so it is
|
|
1752
|
+
* scrolled into view first and focused after the next render.
|
|
1753
|
+
*/
|
|
1754
|
+
_moveRowFocus(targetIndex) {
|
|
1755
|
+
if (targetIndex < 0)
|
|
1756
|
+
return;
|
|
1757
|
+
this._focusedRowIndex.set(targetIndex);
|
|
1758
|
+
if (this.virtualScroll()) {
|
|
1759
|
+
this._virtualViewportRef()?.scrollToIndex(targetIndex, 'smooth');
|
|
1760
|
+
}
|
|
1761
|
+
afterNextRender(() => this._focusRowElement(targetIndex), {
|
|
1762
|
+
injector: this._injector,
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
/** @private Focus the rendered `<tr>` for the given flat-rows index, if present. */
|
|
1766
|
+
_focusRowElement(index) {
|
|
1767
|
+
const host = this._el.nativeElement;
|
|
1768
|
+
const rowEl = host.querySelector(`[data-row-index="${index}"]`);
|
|
1769
|
+
rowEl?.focus();
|
|
1770
|
+
}
|
|
1771
|
+
// ---- Infinite scroll ---------------------------------------------------------
|
|
1772
|
+
/**
|
|
1773
|
+
* Handler wired to `MlvInfiniteScroll.loadMore` when `paginationMode === 'infinite'`.
|
|
1774
|
+
* Increments the tracked page counter and emits a table-level `MlvLoadMoreEvent`
|
|
1775
|
+
* whose `page` field tells the consumer which page to fetch next.
|
|
1776
|
+
*/
|
|
1777
|
+
onInfiniteScrollLoadMore(trigger) {
|
|
1778
|
+
const nextPage = this.currentPage() + 1;
|
|
1779
|
+
this.currentPage.set(nextPage);
|
|
1780
|
+
this.loadMore.emit({
|
|
1781
|
+
page: nextPage,
|
|
1782
|
+
perPage: this.currentPerPage(),
|
|
1783
|
+
distance: trigger.distance,
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
/** @internal Applies a transient paginator page change without a snapshot. */
|
|
1787
|
+
_onPageChange(page) {
|
|
1788
|
+
this.currentPage.set(Math.max(1, Math.floor(page)));
|
|
1789
|
+
}
|
|
1790
|
+
/** Applies a durable paginator page-size change and emits one snapshot. */
|
|
1791
|
+
_onPerPageChange(perPage) {
|
|
1792
|
+
this.currentPerPage.set(this._normalizePerPage(perPage));
|
|
1793
|
+
this.currentPage.set(1);
|
|
1794
|
+
this._emitPresentationStateChange();
|
|
1795
|
+
}
|
|
1796
|
+
// ---- Row selection -----------------------------------------------------------
|
|
1797
|
+
/** Whether a specific row is currently selected. */
|
|
1798
|
+
isRowSelected(row) {
|
|
1799
|
+
return this.selectedRows().has(this._ref(row));
|
|
1800
|
+
}
|
|
1801
|
+
/** Toggle selection for a single row. */
|
|
1802
|
+
toggleRowSelection(row) {
|
|
1803
|
+
const ref = this._ref(row);
|
|
1804
|
+
const current = this.selectedRows();
|
|
1805
|
+
const next = new Set(current);
|
|
1806
|
+
const mode = this.selectable();
|
|
1807
|
+
if (mode === 'single') {
|
|
1808
|
+
if (next.has(ref)) {
|
|
1809
|
+
next.clear();
|
|
1810
|
+
}
|
|
1811
|
+
else {
|
|
1812
|
+
next.clear();
|
|
1813
|
+
next.add(ref);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
else if (mode === 'multi') {
|
|
1817
|
+
if (next.has(ref)) {
|
|
1818
|
+
next.delete(ref);
|
|
1819
|
+
}
|
|
1820
|
+
else {
|
|
1821
|
+
next.add(ref);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
this.selectedRows.set(next);
|
|
1825
|
+
this.selectionChange.emit({ selectedRows: next, row: ref });
|
|
1826
|
+
}
|
|
1827
|
+
/** Toggle select-all / deselect-all. */
|
|
1828
|
+
toggleSelectAll() {
|
|
1829
|
+
const rows = this.flatRows();
|
|
1830
|
+
const allSelected = this.allRowsSelected();
|
|
1831
|
+
const next = new Set();
|
|
1832
|
+
if (!allSelected) {
|
|
1833
|
+
for (const row of rows) {
|
|
1834
|
+
next.add(this._ref(row));
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
this.selectedRows.set(next);
|
|
1838
|
+
this.selectionChange.emit({ selectedRows: next });
|
|
1839
|
+
}
|
|
1840
|
+
// ---- Column visibility -------------------------------------------------------
|
|
1841
|
+
/** Whether a column is currently hidden by the user. */
|
|
1842
|
+
isColumnHidden(key) {
|
|
1843
|
+
return this._visibility.isHidden(key);
|
|
1844
|
+
}
|
|
1845
|
+
/** Toggle visibility of a hideable column. */
|
|
1846
|
+
toggleColumnVisibility(key) {
|
|
1847
|
+
this._visibility.toggle(key);
|
|
1848
|
+
this._emitPresentationStateChange();
|
|
1849
|
+
}
|
|
1850
|
+
/**
|
|
1851
|
+
* @protected Returns focus to the toolbar "Filters" trigger when the filter
|
|
1852
|
+
* dialog popup closes (Apply / Clear / Escape / backdrop), so keyboard focus
|
|
1853
|
+
* is never stranded on a destroyed overlay control.
|
|
1854
|
+
*/
|
|
1855
|
+
_onFiltersClosed() {
|
|
1856
|
+
this._filterTriggerRef()?.nativeElement.focus();
|
|
1857
|
+
}
|
|
1858
|
+
/** Commits a search-field event and resets table pagination. */
|
|
1859
|
+
onSearch(query) {
|
|
1860
|
+
this.searchQuery.set(query);
|
|
1861
|
+
this.currentPage.set(1);
|
|
1862
|
+
}
|
|
1863
|
+
/** Whether a column currently has a committed filter. */
|
|
1864
|
+
isColumnFiltered(key) {
|
|
1865
|
+
return this.activeFilters().some((filter) => filter.key === key);
|
|
1866
|
+
}
|
|
1867
|
+
/** Accessible label for a column filter trigger. */
|
|
1868
|
+
getFilterLabel(col) {
|
|
1869
|
+
return this._resolver.resolve(this._i18n(), this.isColumnFiltered(col.key) ? 'filterColumnActive' : 'filterColumn', { column: col.title ?? col.key });
|
|
1870
|
+
}
|
|
1871
|
+
/**
|
|
1872
|
+
* Merges a scoped editor result against the table's current committed state.
|
|
1873
|
+
* The table remains authoritative here because an overlay may hold an older
|
|
1874
|
+
* input snapshot while another column is committed.
|
|
1875
|
+
*/
|
|
1876
|
+
onColumnFiltersChange(key, scopedFilters) {
|
|
1877
|
+
this.activeFilters.update((current) => [
|
|
1878
|
+
...current.filter((filter) => filter.key !== key),
|
|
1879
|
+
...scopedFilters
|
|
1880
|
+
.filter((filter) => filter.key === key)
|
|
1881
|
+
.map((filter) => ({
|
|
1882
|
+
...filter,
|
|
1883
|
+
value: Array.isArray(filter.value) ? [...filter.value] : filter.value,
|
|
1884
|
+
})),
|
|
1885
|
+
]);
|
|
1886
|
+
}
|
|
1887
|
+
/** Single-column list consumed by the scoped filter editor. */
|
|
1888
|
+
getColumnFilterColumns(col) {
|
|
1889
|
+
const cached = this._columnFilterLists.get(col.key);
|
|
1890
|
+
if (cached?.[0] === col)
|
|
1891
|
+
return cached;
|
|
1892
|
+
const next = [col];
|
|
1893
|
+
this._columnFilterLists.set(col.key, next);
|
|
1894
|
+
return next;
|
|
1895
|
+
}
|
|
1896
|
+
/** Restores focus to the header filter trigger for a popup that just closed. */
|
|
1897
|
+
focusColumnFilterTrigger(key) {
|
|
1898
|
+
const host = this._el.nativeElement;
|
|
1899
|
+
const triggers = host.querySelectorAll('.mlv-data-table__column-filter');
|
|
1900
|
+
for (const trigger of triggers) {
|
|
1901
|
+
if (trigger.dataset['columnKey'] === key) {
|
|
1902
|
+
trigger.focus();
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
// ---- Footer template ----------------------------------------------------------
|
|
1908
|
+
/** Retrieves the footer summary template. */
|
|
1909
|
+
getFooterTemplate() {
|
|
1910
|
+
const list = this.footerTemplate();
|
|
1911
|
+
return list.length > 0 ? list[0].templateRef : null;
|
|
1912
|
+
}
|
|
1913
|
+
// ---- Pin/Unpin ---------------------------------------------------------------
|
|
1914
|
+
/**
|
|
1915
|
+
* Returns the list of sides the user may pin a column to, based on `col.pinnable`.
|
|
1916
|
+
* - `true` → `['left', 'right']`
|
|
1917
|
+
* - `'left'` / `'right'` → single-element list
|
|
1918
|
+
* - `MlvPinSide[]` → the list as provided (duplicates preserved by caller)
|
|
1919
|
+
* - falsy → `[]` (not user-pinnable)
|
|
1920
|
+
*/
|
|
1921
|
+
getPinnableSides(col) {
|
|
1922
|
+
return this._pinning.getPinnableSides(col);
|
|
1923
|
+
}
|
|
1924
|
+
/** Pin a column to the given side, or unpin if it is already pinned. */
|
|
1925
|
+
togglePin(col, side = 'left') {
|
|
1926
|
+
this._pinning.togglePin(col, side);
|
|
1927
|
+
this._emitPresentationStateChange();
|
|
1928
|
+
}
|
|
1929
|
+
/** Pin a column to a specific side, overriding any current pin state. */
|
|
1930
|
+
pinTo(col, side) {
|
|
1931
|
+
this._pinning.pinTo(col, side);
|
|
1932
|
+
this._emitPresentationStateChange();
|
|
1933
|
+
}
|
|
1934
|
+
/** Explicitly unpin a column, regardless of its current side. */
|
|
1935
|
+
unpin(col) {
|
|
1936
|
+
this._pinning.unpin(col);
|
|
1937
|
+
this._emitPresentationStateChange();
|
|
1938
|
+
}
|
|
1939
|
+
/** Whether a column is currently pinned (accounting for overrides). */
|
|
1940
|
+
isColumnPinned(col) {
|
|
1941
|
+
return this._pinning.isPinned(col);
|
|
1942
|
+
}
|
|
1943
|
+
/** Returns the current pin side for a column (considering overrides), or `null` if it is not pinned. */
|
|
1944
|
+
getColumnPinSide(col) {
|
|
1945
|
+
return this._pinning.getPinSide(col);
|
|
1946
|
+
}
|
|
1947
|
+
isRowExpanded(row) {
|
|
1948
|
+
return this._expanded().has(this._ref(row));
|
|
1949
|
+
}
|
|
1950
|
+
hasChildren(row) {
|
|
1951
|
+
const original = this._ref(row);
|
|
1952
|
+
return (Array.isArray(original['_mlvChildren']) &&
|
|
1953
|
+
original['_mlvChildren'].length > 0);
|
|
1954
|
+
}
|
|
1955
|
+
getDepth(row) {
|
|
1956
|
+
return row['_mlvDepth'] ?? 0;
|
|
1957
|
+
}
|
|
1958
|
+
toggleExpand(row, event) {
|
|
1959
|
+
event.stopPropagation();
|
|
1960
|
+
const original = this._ref(row);
|
|
1961
|
+
const current = this._expanded();
|
|
1962
|
+
const next = new Set(current);
|
|
1963
|
+
if (next.has(original)) {
|
|
1964
|
+
next.delete(original);
|
|
1965
|
+
}
|
|
1966
|
+
else {
|
|
1967
|
+
next.add(original);
|
|
1968
|
+
}
|
|
1969
|
+
this._expanded.set(next);
|
|
1970
|
+
}
|
|
1971
|
+
// ---- Sorting ----------------------------------------------------------------
|
|
1972
|
+
onSortClick(col) {
|
|
1973
|
+
if (!col.sortable)
|
|
1974
|
+
return;
|
|
1975
|
+
const current = this.currentSort();
|
|
1976
|
+
if (!current || current.key !== col.key) {
|
|
1977
|
+
this.currentSort.set({ key: col.key, direction: 'asc' });
|
|
1978
|
+
}
|
|
1979
|
+
else if (current.direction === 'asc') {
|
|
1980
|
+
this.currentSort.set({ key: col.key, direction: 'desc' });
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
this.currentSort.set(null);
|
|
1984
|
+
}
|
|
1985
|
+
this.currentPage.set(1);
|
|
1986
|
+
this._emitPresentationStateChange();
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* @protected Applies a Sort-menu action, resets pagination, and emits exactly
|
|
1990
|
+
* one presentation snapshot. Programmatic snapshot application remains silent.
|
|
1991
|
+
*/
|
|
1992
|
+
_applyMenuSort(column, direction) {
|
|
1993
|
+
if (!column.sortable)
|
|
1994
|
+
return;
|
|
1995
|
+
this.currentSort.set(direction === null ? null : { key: column.key, direction });
|
|
1996
|
+
this.currentPage.set(1);
|
|
1997
|
+
this._emitPresentationStateChange();
|
|
1998
|
+
}
|
|
1999
|
+
getSortDirection(col) {
|
|
2000
|
+
const s = this.currentSort();
|
|
2001
|
+
return s && s.key === col.key ? s.direction : null;
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* Accessible label for a sortable column header button. Resolves the
|
|
2005
|
+
* `sortByColumn` ICU string ("Sort by {column}") — describing intent rather
|
|
2006
|
+
* than a mouse-specific "click to sort" instruction.
|
|
2007
|
+
*/
|
|
2008
|
+
getSortLabel(col) {
|
|
2009
|
+
return this._resolver.resolve(this._i18n(), 'sortByColumn', { column: col.title ?? col.key });
|
|
2010
|
+
}
|
|
2011
|
+
// ---- Column styles ----------------------------------------------------------
|
|
2012
|
+
getColStyle(col) {
|
|
2013
|
+
return columnWidthStyles(col);
|
|
2014
|
+
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Returns the value to apply to a `<col>` element's `width` style.
|
|
2017
|
+
* Used by the shared `<colgroup>` template to keep column widths in sync between the
|
|
2018
|
+
* three split tables in virtual scroll mode (header / body / footer).
|
|
2019
|
+
*/
|
|
2020
|
+
getColWidth(col) {
|
|
2021
|
+
if (col._currentWidth !== undefined)
|
|
2022
|
+
return col._currentWidth + 'px';
|
|
2023
|
+
if (col.width)
|
|
2024
|
+
return col.width;
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
/** Exact frozen width styles for a selection or actions utility column. */
|
|
2028
|
+
getAuxiliaryColumnStyle(kind) {
|
|
2029
|
+
return this._auxiliaryColumnStyles()[kind];
|
|
2030
|
+
}
|
|
2031
|
+
/** Exact frozen `<col>` width for a selection or actions utility column. */
|
|
2032
|
+
getAuxiliaryColumnWidth(kind) {
|
|
2033
|
+
return this._auxiliaryColumnStyles()[kind]?.['width'] ?? null;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* trackBy used by `*cdkVirtualFor` in virtual scroll mode. Falls back to the row index
|
|
2037
|
+
* for plain row references and to `_mlvRef` identity for tree rows so expanded children
|
|
2038
|
+
* are reconciled correctly when the user scrolls.
|
|
2039
|
+
*/
|
|
2040
|
+
trackByRow = (index, row) => {
|
|
2041
|
+
return row['_mlvRef'] ?? index;
|
|
2042
|
+
};
|
|
2043
|
+
/**
|
|
2044
|
+
* Inline `[style]` object (width / min-width, plus sticky offsets for pinned columns)
|
|
2045
|
+
* for a column's header and body cells. Reads the memoized {@link _columnStyles} map
|
|
2046
|
+
* so the returned reference is stable across change-detection cycles (no per-cell
|
|
2047
|
+
* allocation). Every visible column is present in the map; the on-the-fly fallback is
|
|
2048
|
+
* a defensive path for a column outside the current visible set.
|
|
2049
|
+
*/
|
|
2050
|
+
getCellStyle(col) {
|
|
2051
|
+
return (this._columnStyles().get(col.key) ??
|
|
2052
|
+
columnCellStyles(col, this.columnOffsets()));
|
|
2053
|
+
}
|
|
2054
|
+
getAlignClass(col) {
|
|
2055
|
+
return col.align ? `mlv-data-table__cell--align-${col.align}` : '';
|
|
2056
|
+
}
|
|
2057
|
+
// ---- Column resize ----------------------------------------------------------
|
|
2058
|
+
/**
|
|
2059
|
+
* @private In-flight pointer resize state. The originating pointer id prevents
|
|
2060
|
+
* secondary touches or unrelated pointers from moving or ending the drag.
|
|
2061
|
+
*/
|
|
2062
|
+
_resizeState = null;
|
|
2063
|
+
/**
|
|
2064
|
+
* @private rAF handle coalescing live-width signal writes to one per frame
|
|
2065
|
+
* during a pointer drag.
|
|
2066
|
+
*/
|
|
2067
|
+
_resizeRafId = 0;
|
|
2068
|
+
/**
|
|
2069
|
+
* @private Bound pointer-move handler retained so add/removeEventListener use
|
|
2070
|
+
* the same function reference.
|
|
2071
|
+
*/
|
|
2072
|
+
_onResizeMoveBound = (event) => {
|
|
2073
|
+
this._onResizeMove(event);
|
|
2074
|
+
};
|
|
2075
|
+
/**
|
|
2076
|
+
* @private Bound pointer-up handler retained so add/removeEventListener use
|
|
2077
|
+
* the same function reference.
|
|
2078
|
+
*/
|
|
2079
|
+
_onResizeEndBound = (event) => {
|
|
2080
|
+
this._onResizeEnd(event);
|
|
2081
|
+
};
|
|
2082
|
+
/**
|
|
2083
|
+
* @private Bound pointer-cancel handler. Cancellation restores the previously
|
|
2084
|
+
* committed width and never emits a commit event.
|
|
2085
|
+
*/
|
|
2086
|
+
_onResizeCancelBound = (event) => {
|
|
2087
|
+
this._onResizeCancel(event);
|
|
2088
|
+
};
|
|
2089
|
+
/**
|
|
2090
|
+
* @private Cancels an active drag if the browser unexpectedly revokes the
|
|
2091
|
+
* initiating handle's pointer capture.
|
|
2092
|
+
*/
|
|
2093
|
+
_onResizeLostCaptureBound = (event) => {
|
|
2094
|
+
this._onResizeLostCapture(event);
|
|
2095
|
+
};
|
|
2096
|
+
/**
|
|
2097
|
+
* Starts a column resize with Pointer Events and captures the initiating
|
|
2098
|
+
* pointer on the separator. The rendered header width is measured instead of
|
|
2099
|
+
* trusting the declared CSS width, so `rem`, `%`, and flex/table layout widths
|
|
2100
|
+
* begin without a jump.
|
|
2101
|
+
*/
|
|
2102
|
+
onResizeStart(col, event) {
|
|
2103
|
+
if (event.button !== 0 || this._resizeState)
|
|
2104
|
+
return;
|
|
2105
|
+
const target = event.currentTarget;
|
|
2106
|
+
if (!(target instanceof HTMLElement))
|
|
2107
|
+
return;
|
|
2108
|
+
event.preventDefault();
|
|
2109
|
+
this._measureHeaderWidths();
|
|
2110
|
+
const bounds = this._resolveColumnResizeBounds(col, target);
|
|
2111
|
+
this._cacheColumnResizeBounds(col.key, bounds);
|
|
2112
|
+
const startWidth = this._clampColumnWidth(this._measureHeaderWidth(col, target), bounds);
|
|
2113
|
+
this._resizeState = {
|
|
2114
|
+
key: col.key,
|
|
2115
|
+
pointerId: event.pointerId,
|
|
2116
|
+
target,
|
|
2117
|
+
startX: event.clientX,
|
|
2118
|
+
startWidth,
|
|
2119
|
+
latestWidth: startWidth,
|
|
2120
|
+
moved: false,
|
|
2121
|
+
...bounds,
|
|
2122
|
+
};
|
|
2123
|
+
this._ngZone.runOutsideAngular(() => {
|
|
2124
|
+
this._document.addEventListener('pointermove', this._onResizeMoveBound);
|
|
2125
|
+
this._document.addEventListener('pointerup', this._onResizeEndBound);
|
|
2126
|
+
this._document.addEventListener('pointercancel', this._onResizeCancelBound);
|
|
2127
|
+
target.addEventListener('lostpointercapture', this._onResizeLostCaptureBound);
|
|
2128
|
+
if (typeof target.setPointerCapture === 'function') {
|
|
2129
|
+
try {
|
|
2130
|
+
target.setPointerCapture(event.pointerId);
|
|
2131
|
+
}
|
|
2132
|
+
catch {
|
|
2133
|
+
// Document listeners preserve drag/end behavior when capture is
|
|
2134
|
+
// unavailable, rejected, or exercised by a synthetic event.
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Handles keyboard resizing for the focusable separator. ArrowLeft/ArrowRight
|
|
2141
|
+
* use an 8px step (32px with Shift); Home/End jump to the resolved bounds.
|
|
2142
|
+
*/
|
|
2143
|
+
onColumnResizeKeydown(col, event) {
|
|
2144
|
+
if (event.key === 'Enter') {
|
|
2145
|
+
event.preventDefault();
|
|
2146
|
+
this.resetColumnWidth(col.key);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
const key = this._rtlService.normalizeArrowKey(event);
|
|
2150
|
+
const supported = key === LEFT_ARROW ||
|
|
2151
|
+
key === RIGHT_ARROW ||
|
|
2152
|
+
event.key === 'Home' ||
|
|
2153
|
+
event.key === 'End';
|
|
2154
|
+
if (!supported)
|
|
2155
|
+
return;
|
|
2156
|
+
const target = event.currentTarget instanceof HTMLElement
|
|
2157
|
+
? event.currentTarget
|
|
2158
|
+
: undefined;
|
|
2159
|
+
this._measureHeaderWidths();
|
|
2160
|
+
const bounds = this._resolveColumnResizeBounds(col, target);
|
|
2161
|
+
this._cacheColumnResizeBounds(col.key, bounds);
|
|
2162
|
+
const currentWidth = this._clampColumnWidth(this._measureHeaderWidth(col, target), bounds);
|
|
2163
|
+
const step = event.shiftKey
|
|
2164
|
+
? COLUMN_RESIZE_KEYBOARD_LARGE_STEP
|
|
2165
|
+
: COLUMN_RESIZE_KEYBOARD_STEP;
|
|
2166
|
+
let nextWidth = currentWidth;
|
|
2167
|
+
if (event.key === 'Home')
|
|
2168
|
+
nextWidth = bounds.min;
|
|
2169
|
+
if (event.key === 'End')
|
|
2170
|
+
nextWidth = bounds.max;
|
|
2171
|
+
if (key === LEFT_ARROW)
|
|
2172
|
+
nextWidth = currentWidth - step;
|
|
2173
|
+
if (key === RIGHT_ARROW)
|
|
2174
|
+
nextWidth = currentWidth + step;
|
|
2175
|
+
event.preventDefault();
|
|
2176
|
+
this._commitColumnWidth(col.key, this._clampColumnWidth(nextWidth, bounds), 'keyboard');
|
|
2177
|
+
}
|
|
2178
|
+
/** Localized accessible name for a column's resize separator. */
|
|
2179
|
+
getColumnResizeLabel(col) {
|
|
2180
|
+
return this._resolver.resolve(this._i18n(), 'resizeColumn', { column: col.title ?? col.key });
|
|
2181
|
+
}
|
|
2182
|
+
/** Current separator value in CSS pixels for ARIA. */
|
|
2183
|
+
getColumnResizeValue(col) {
|
|
2184
|
+
const bounds = this._columnResizeBounds(col);
|
|
2185
|
+
const active = this._resizeState?.key === col.key
|
|
2186
|
+
? this._resizeState.latestWidth
|
|
2187
|
+
: undefined;
|
|
2188
|
+
const measured = this._measuredColumnWidths().get(col.key);
|
|
2189
|
+
return this._normalizeColumnWidth(active ??
|
|
2190
|
+
col._currentWidth ??
|
|
2191
|
+
measured ??
|
|
2192
|
+
parsePixelWidth(col.width) ??
|
|
2193
|
+
DEFAULT_COLUMN_WIDTH, bounds);
|
|
2194
|
+
}
|
|
2195
|
+
/** Minimum separator value in CSS pixels for ARIA and Home. */
|
|
2196
|
+
getColumnResizeMin(col) {
|
|
2197
|
+
return this._roundColumnWidth(this._columnResizeBounds(col).min);
|
|
2198
|
+
}
|
|
2199
|
+
/** Maximum separator value in CSS pixels for ARIA and End. */
|
|
2200
|
+
getColumnResizeMax(col) {
|
|
2201
|
+
return this._roundColumnWidth(this._columnResizeBounds(col).max);
|
|
2202
|
+
}
|
|
2203
|
+
/** Localized text alternative that makes the separator's pixel unit explicit. */
|
|
2204
|
+
getColumnResizeValueText(col) {
|
|
2205
|
+
return this._resolver.resolve(this._i18n(), 'columnWidthPixels', { width: this.getColumnResizeValue(col) });
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Removes committed user widths. Passing a key resets that column and emits a
|
|
2209
|
+
* reset even when no override exists (useful for clearing persisted state);
|
|
2210
|
+
* omitting it resets every currently overridden column.
|
|
2211
|
+
*/
|
|
2212
|
+
resetColumnWidth(key) {
|
|
2213
|
+
const active = this._resizeState;
|
|
2214
|
+
if (active && (key === undefined || active.key === key)) {
|
|
2215
|
+
this._cleanupResize();
|
|
2216
|
+
this._liveResize.set(null);
|
|
2217
|
+
}
|
|
2218
|
+
const widths = this._columnWidths();
|
|
2219
|
+
if (key !== undefined) {
|
|
2220
|
+
if (!this.columns().some((column) => column.key === key))
|
|
2221
|
+
return;
|
|
2222
|
+
if (widths.has(key)) {
|
|
2223
|
+
const updated = new Map(widths);
|
|
2224
|
+
updated.delete(key);
|
|
2225
|
+
this._columnWidths.set(updated);
|
|
2226
|
+
}
|
|
2227
|
+
this.columnResize.emit({ key, width: null, source: 'reset' });
|
|
2228
|
+
this._emitPresentationStateChange();
|
|
2229
|
+
afterNextRender(() => this._measureHeaderWidths(), {
|
|
2230
|
+
injector: this._injector,
|
|
2231
|
+
});
|
|
2232
|
+
return;
|
|
2233
|
+
}
|
|
2234
|
+
const resetKeys = [...widths.keys()];
|
|
2235
|
+
if (!resetKeys.length)
|
|
2236
|
+
return;
|
|
2237
|
+
this._columnWidths.set(new Map());
|
|
2238
|
+
for (const resetKey of resetKeys) {
|
|
2239
|
+
this.columnResize.emit({
|
|
2240
|
+
key: resetKey,
|
|
2241
|
+
width: null,
|
|
2242
|
+
source: 'reset',
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
this._emitPresentationStateChange();
|
|
2246
|
+
afterNextRender(() => this._measureHeaderWidths(), {
|
|
2247
|
+
injector: this._injector,
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* @private Pointer-move handler (outside Angular). It synchronously updates
|
|
2252
|
+
* the latest bounded value, then publishes at most one live signal update per
|
|
2253
|
+
* animation frame.
|
|
2254
|
+
*/
|
|
2255
|
+
_onResizeMove(event) {
|
|
2256
|
+
const state = this._resizeState;
|
|
2257
|
+
if (!state || event.pointerId !== state.pointerId)
|
|
2258
|
+
return;
|
|
2259
|
+
const delta = event.clientX - state.startX;
|
|
2260
|
+
if (delta !== 0)
|
|
2261
|
+
state.moved = true;
|
|
2262
|
+
state.latestWidth = this._clampColumnWidth(state.startWidth + delta, state);
|
|
2263
|
+
if (!state.moved)
|
|
2264
|
+
return;
|
|
2265
|
+
if (this._resizeRafId)
|
|
2266
|
+
return;
|
|
2267
|
+
this._resizeRafId = requestAnimationFrame(() => {
|
|
2268
|
+
this._resizeRafId = 0;
|
|
2269
|
+
const s = this._resizeState;
|
|
2270
|
+
if (!s || s.pointerId !== event.pointerId)
|
|
2271
|
+
return;
|
|
2272
|
+
this._ngZone.run(() => this._liveResize.set({ key: s.key, width: s.latestWidth }));
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* @private Pointer-up handler that commits exactly once for the initiating
|
|
2277
|
+
* pointer. A press/release without movement remains a no-op, which keeps a
|
|
2278
|
+
* double-click reset from producing intermediate resize commits.
|
|
2279
|
+
*/
|
|
2280
|
+
_onResizeEnd(event) {
|
|
2281
|
+
const state = this._resizeState;
|
|
2282
|
+
if (!state || event.pointerId !== state.pointerId)
|
|
2283
|
+
return;
|
|
2284
|
+
this._cleanupResize();
|
|
2285
|
+
if (!state.moved) {
|
|
2286
|
+
this._ngZone.run(() => this._liveResize.set(null));
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
this._commitColumnWidth(state.key, state.latestWidth, 'pointer');
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* @private Cancels only the matching active pointer, dropping the optimistic
|
|
2293
|
+
* live width while preserving the last committed map entry.
|
|
2294
|
+
*/
|
|
2295
|
+
_onResizeCancel(event) {
|
|
2296
|
+
const state = this._resizeState;
|
|
2297
|
+
if (!state || event.pointerId !== state.pointerId)
|
|
2298
|
+
return;
|
|
2299
|
+
this._cleanupResize();
|
|
2300
|
+
this._ngZone.run(() => this._liveResize.set(null));
|
|
2301
|
+
}
|
|
2302
|
+
/**
|
|
2303
|
+
* @private Treats unexpected capture loss as cancellation. Normal cleanup
|
|
2304
|
+
* removes this listener before explicitly releasing capture, so pointer-up
|
|
2305
|
+
* commits cannot be mistaken for cancellation.
|
|
2306
|
+
*/
|
|
2307
|
+
_onResizeLostCapture(event) {
|
|
2308
|
+
const state = this._resizeState;
|
|
2309
|
+
if (!state || event.pointerId !== state.pointerId)
|
|
2310
|
+
return;
|
|
2311
|
+
this._cleanupResize();
|
|
2312
|
+
this._ngZone.run(() => this._liveResize.set(null));
|
|
2313
|
+
}
|
|
2314
|
+
/**
|
|
2315
|
+
* @private Commits a bounded pixel width with one map clone and emits the
|
|
2316
|
+
* public persistence event in the same Angular-zone turn.
|
|
2317
|
+
*/
|
|
2318
|
+
_commitColumnWidth(key, width, source) {
|
|
2319
|
+
const col = this.columns().find((column) => column.key === key);
|
|
2320
|
+
const bounds = col
|
|
2321
|
+
? this._columnResizeBounds(col)
|
|
2322
|
+
: {
|
|
2323
|
+
min: DEFAULT_COLUMN_MIN_WIDTH,
|
|
2324
|
+
max: DEFAULT_COLUMN_MAX_WIDTH,
|
|
2325
|
+
};
|
|
2326
|
+
const committedWidth = this._normalizeColumnWidth(width, bounds);
|
|
2327
|
+
this._ngZone.run(() => {
|
|
2328
|
+
const updated = new Map(this._columnWidths());
|
|
2329
|
+
updated.set(key, committedWidth);
|
|
2330
|
+
this._columnWidths.set(updated);
|
|
2331
|
+
this._liveResize.set(null);
|
|
2332
|
+
this.columnResize.emit({ key, width: committedWidth, source });
|
|
2333
|
+
this._emitPresentationStateChange();
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* @private Returns the latest DOM-resolved bounds when available, otherwise
|
|
2338
|
+
* resolves strict pixel metadata with safe finite defaults.
|
|
2339
|
+
*/
|
|
2340
|
+
_columnResizeBounds(col) {
|
|
2341
|
+
return (this._resolvedResizeBounds().get(col.key) ??
|
|
2342
|
+
this._resolveColumnResizeBounds(col));
|
|
2343
|
+
}
|
|
2344
|
+
/** @private Stores DOM-resolved bounds with a signal-safe map replacement. */
|
|
2345
|
+
_cacheColumnResizeBounds(key, bounds) {
|
|
2346
|
+
this._resolvedResizeBounds.update((current) => {
|
|
2347
|
+
const updated = new Map(current);
|
|
2348
|
+
updated.set(key, bounds);
|
|
2349
|
+
return updated;
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
/**
|
|
2353
|
+
* @private Resolves resize bounds. Non-pixel metadata is read back from the
|
|
2354
|
+
* rendered header's computed style where the browser exposes a pixel value.
|
|
2355
|
+
*/
|
|
2356
|
+
_resolveColumnResizeBounds(col, target) {
|
|
2357
|
+
const headerCell = target?.closest('th');
|
|
2358
|
+
let min = this._resolveColumnBound(col.minWidth, headerCell);
|
|
2359
|
+
let max = this._resolveColumnBound(col.maxWidth, headerCell);
|
|
2360
|
+
if (headerCell &&
|
|
2361
|
+
((col.minWidth && min === undefined) ||
|
|
2362
|
+
(col.maxWidth && max === undefined))) {
|
|
2363
|
+
const computedStyle = headerCell.ownerDocument.defaultView?.getComputedStyle(headerCell);
|
|
2364
|
+
if (computedStyle && col.minWidth && min === undefined) {
|
|
2365
|
+
min = parsePixelWidth(computedStyle.minWidth);
|
|
2366
|
+
}
|
|
2367
|
+
if (computedStyle && col.maxWidth && max === undefined) {
|
|
2368
|
+
max = parsePixelWidth(computedStyle.maxWidth);
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
const resolvedMin = this._roundColumnWidth(min ?? DEFAULT_COLUMN_MIN_WIDTH);
|
|
2372
|
+
const resolvedMax = this._roundColumnWidth(Math.max(resolvedMin, max ?? DEFAULT_COLUMN_MAX_WIDTH));
|
|
2373
|
+
return { min: resolvedMin, max: resolvedMax };
|
|
2374
|
+
}
|
|
2375
|
+
/**
|
|
2376
|
+
* @private Resolves a declared bound to CSS pixels. Complete pixel values are
|
|
2377
|
+
* direct; complete percentages use the rendered header table width, matching
|
|
2378
|
+
* the containing table against which cell percentages are laid out.
|
|
2379
|
+
*/
|
|
2380
|
+
_resolveColumnBound(value, headerCell) {
|
|
2381
|
+
const pixels = parsePixelWidth(value);
|
|
2382
|
+
if (pixels !== undefined)
|
|
2383
|
+
return pixels;
|
|
2384
|
+
const percentage = this._parseCssPercentage(value);
|
|
2385
|
+
if (percentage === undefined || !headerCell)
|
|
2386
|
+
return undefined;
|
|
2387
|
+
const table = headerCell.closest('table');
|
|
2388
|
+
const tableRectWidth = table?.getBoundingClientRect().width ?? 0;
|
|
2389
|
+
const referenceWidth = tableRectWidth > 0 ? tableRectWidth : (table?.clientWidth ?? 0);
|
|
2390
|
+
if (!Number.isFinite(referenceWidth) || referenceWidth <= 0) {
|
|
2391
|
+
return undefined;
|
|
2392
|
+
}
|
|
2393
|
+
return this._roundColumnWidth(referenceWidth * percentage);
|
|
2394
|
+
}
|
|
2395
|
+
/** @private Parses a complete, non-negative CSS percentage as a fraction. */
|
|
2396
|
+
_parseCssPercentage(value) {
|
|
2397
|
+
if (!value)
|
|
2398
|
+
return undefined;
|
|
2399
|
+
const match = value.trim().match(/^(?:\d+(?:\.\d+)?|\.\d+)%$/);
|
|
2400
|
+
if (!match)
|
|
2401
|
+
return undefined;
|
|
2402
|
+
const parsed = Number.parseFloat(match[0]);
|
|
2403
|
+
return Number.isFinite(parsed) ? parsed / 100 : undefined;
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* @private Re-applies outer horizontal position after virtual DOM/geometry
|
|
2407
|
+
* changes that do not themselves emit another wrapper scroll event.
|
|
2408
|
+
*/
|
|
2409
|
+
_syncVirtualHorizontalScroll() {
|
|
2410
|
+
const wrapper = this.tableWrapperRef()?.nativeElement;
|
|
2411
|
+
const viewport = this._virtualViewportRef()?.elementRef.nativeElement;
|
|
2412
|
+
if (!wrapper || !viewport)
|
|
2413
|
+
return;
|
|
2414
|
+
if (viewport.scrollLeft !== wrapper.scrollLeft) {
|
|
2415
|
+
viewport.scrollLeft = wrapper.scrollLeft;
|
|
2416
|
+
}
|
|
2417
|
+
this._updateVirtualScrollGeometry(wrapper, viewport);
|
|
2418
|
+
}
|
|
2419
|
+
/**
|
|
2420
|
+
* @private Publishes both the native vertical-scrollbar width and an inert
|
|
2421
|
+
* outer extent whose maximum scroll position exactly matches the viewport.
|
|
2422
|
+
*/
|
|
2423
|
+
_updateVirtualScrollGeometry(wrapper, viewport) {
|
|
2424
|
+
const gutter = Math.max(0, viewport.offsetWidth - viewport.clientWidth);
|
|
2425
|
+
const horizontalRange = Math.max(0, viewport.scrollWidth - viewport.clientWidth);
|
|
2426
|
+
const extent = wrapper.clientWidth + horizontalRange;
|
|
2427
|
+
const gutterChanged = gutter !== untracked(this._virtualScrollbarGutter);
|
|
2428
|
+
const extentChanged = extent !== untracked(this._virtualHorizontalScrollExtent);
|
|
2429
|
+
if (!gutterChanged && !extentChanged)
|
|
2430
|
+
return;
|
|
2431
|
+
this._ngZone.run(() => {
|
|
2432
|
+
if (gutterChanged)
|
|
2433
|
+
this._virtualScrollbarGutter.set(gutter);
|
|
2434
|
+
if (extentChanged)
|
|
2435
|
+
this._virtualHorizontalScrollExtent.set(extent);
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* @private Measures the actual rendered header cell width and falls back to
|
|
2440
|
+
* the current strict-pixel state only in non-layout environments such as
|
|
2441
|
+
* server rendering and jsdom.
|
|
2442
|
+
*/
|
|
2443
|
+
_measureHeaderWidth(col, target) {
|
|
2444
|
+
const headerCell = target?.closest('th');
|
|
2445
|
+
const rectWidth = headerCell?.getBoundingClientRect().width ?? 0;
|
|
2446
|
+
if (Number.isFinite(rectWidth) && rectWidth > 0)
|
|
2447
|
+
return rectWidth;
|
|
2448
|
+
const offsetWidth = headerCell?.offsetWidth ?? 0;
|
|
2449
|
+
if (offsetWidth > 0)
|
|
2450
|
+
return offsetWidth;
|
|
2451
|
+
return (col._currentWidth ?? parsePixelWidth(col.width) ?? DEFAULT_COLUMN_WIDTH);
|
|
2452
|
+
}
|
|
2453
|
+
/**
|
|
2454
|
+
* @private Measures the rendered header once per layout change. Before the
|
|
2455
|
+
* first user override these values track responsive/table layout; while the
|
|
2456
|
+
* table is frozen, existing baselines are preserved so reset restores the
|
|
2457
|
+
* original widths rather than another column's resized layout.
|
|
2458
|
+
*/
|
|
2459
|
+
_measureHeaderWidths() {
|
|
2460
|
+
const host = this._el.nativeElement;
|
|
2461
|
+
const header = host.querySelector('thead');
|
|
2462
|
+
if (!header)
|
|
2463
|
+
return;
|
|
2464
|
+
const preserveBaseline = this._liveResize() !== null || this._columnWidths().size > 0;
|
|
2465
|
+
const measured = preserveBaseline
|
|
2466
|
+
? new Map(this._measuredColumnWidths())
|
|
2467
|
+
: new Map();
|
|
2468
|
+
const resolvedBounds = preserveBaseline
|
|
2469
|
+
? new Map(this._resolvedResizeBounds())
|
|
2470
|
+
: new Map();
|
|
2471
|
+
for (const cell of header.querySelectorAll('th[data-mlv-column-key]')) {
|
|
2472
|
+
const key = cell.getAttribute('data-mlv-column-key');
|
|
2473
|
+
if (!key)
|
|
2474
|
+
continue;
|
|
2475
|
+
const width = cell.getBoundingClientRect().width;
|
|
2476
|
+
if ((!preserveBaseline || !measured.has(key)) &&
|
|
2477
|
+
Number.isFinite(width) &&
|
|
2478
|
+
width > 0) {
|
|
2479
|
+
measured.set(key, this._roundColumnWidth(width));
|
|
2480
|
+
}
|
|
2481
|
+
const column = this.columns().find((candidate) => candidate.key === key);
|
|
2482
|
+
if (column?.resizable) {
|
|
2483
|
+
resolvedBounds.set(key, this._resolveColumnResizeBounds(column, cell));
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
const selectionWidth = header
|
|
2487
|
+
.querySelector('.mlv-data-table__cell--select')
|
|
2488
|
+
?.getBoundingClientRect().width;
|
|
2489
|
+
const actionsWidth = header
|
|
2490
|
+
.querySelector('.mlv-data-table__cell--actions')
|
|
2491
|
+
?.getBoundingClientRect().width;
|
|
2492
|
+
const auxiliary = preserveBaseline
|
|
2493
|
+
? { ...this._measuredAuxiliaryWidths() }
|
|
2494
|
+
: {};
|
|
2495
|
+
if (selectionWidth !== undefined &&
|
|
2496
|
+
Number.isFinite(selectionWidth) &&
|
|
2497
|
+
selectionWidth > 0) {
|
|
2498
|
+
auxiliary.selection = this._roundColumnWidth(selectionWidth);
|
|
2499
|
+
}
|
|
2500
|
+
if (actionsWidth !== undefined &&
|
|
2501
|
+
Number.isFinite(actionsWidth) &&
|
|
2502
|
+
actionsWidth > 0) {
|
|
2503
|
+
auxiliary.actions = this._roundColumnWidth(actionsWidth);
|
|
2504
|
+
}
|
|
2505
|
+
this._measuredColumnWidths.set(measured);
|
|
2506
|
+
this._resolvedResizeBounds.set(resolvedBounds);
|
|
2507
|
+
this._measuredAuxiliaryWidths.set(auxiliary);
|
|
2508
|
+
}
|
|
2509
|
+
/**
|
|
2510
|
+
* @private CSS length used by a sticky offset. A rendered measurement is more
|
|
2511
|
+
* accurate than declared CSS under table redistribution; the declaration
|
|
2512
|
+
* remains the pre-render/SSR fallback.
|
|
2513
|
+
*/
|
|
2514
|
+
_columnOffsetWidth(col) {
|
|
2515
|
+
if (col._currentWidth !== undefined)
|
|
2516
|
+
return `${col._currentWidth}px`;
|
|
2517
|
+
const measured = this._measuredColumnWidths().get(col.key);
|
|
2518
|
+
if (measured !== undefined)
|
|
2519
|
+
return `${this._roundColumnWidth(measured)}px`;
|
|
2520
|
+
if (col.width)
|
|
2521
|
+
return col.width;
|
|
2522
|
+
return `${DEFAULT_COLUMN_WIDTH}px`;
|
|
2523
|
+
}
|
|
2524
|
+
/** @private Adds heterogeneous CSS lengths without converting their units. */
|
|
2525
|
+
_sumCssLengths(widths) {
|
|
2526
|
+
if (!widths.length)
|
|
2527
|
+
return '0px';
|
|
2528
|
+
if (widths.length === 1)
|
|
2529
|
+
return widths[0];
|
|
2530
|
+
return `calc(${widths.join(' + ')})`;
|
|
2531
|
+
}
|
|
2532
|
+
/** @private Rounds pixel values to hundredths without changing their bounds. */
|
|
2533
|
+
_roundColumnWidth(width) {
|
|
2534
|
+
return Math.round(width * 100) / 100;
|
|
2535
|
+
}
|
|
2536
|
+
/** @private Creates immutable exact width/min/max styles for a measured column. */
|
|
2537
|
+
_fixedColumnWidthStyles(width) {
|
|
2538
|
+
if (width === undefined || !Number.isFinite(width) || width < 0)
|
|
2539
|
+
return null;
|
|
2540
|
+
const value = `${this._roundColumnWidth(width)}px`;
|
|
2541
|
+
return {
|
|
2542
|
+
width: value,
|
|
2543
|
+
'min-width': value,
|
|
2544
|
+
'max-width': value,
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
/** @private Rounds and clamps a width against normalized finite bounds. */
|
|
2548
|
+
_normalizeColumnWidth(width, bounds) {
|
|
2549
|
+
return this._clampColumnWidth(this._roundColumnWidth(width), bounds);
|
|
2550
|
+
}
|
|
2551
|
+
/** @private Returns a positive whole-number page size or the all-items sentinel. */
|
|
2552
|
+
_normalizePerPage(perPage) {
|
|
2553
|
+
if (perPage === Infinity)
|
|
2554
|
+
return Infinity;
|
|
2555
|
+
return Number.isFinite(perPage) ? Math.max(1, Math.floor(perPage)) : 1;
|
|
2556
|
+
}
|
|
2557
|
+
/** @private Keeps only declared keys while preserving input-order uniqueness. */
|
|
2558
|
+
_knownPresentationKeys(keys, knownKeys) {
|
|
2559
|
+
return new Set(keys.filter((key) => knownKeys.has(key)));
|
|
2560
|
+
}
|
|
2561
|
+
/** @private Clones only a known sortable sort state. */
|
|
2562
|
+
_normalizePresentationSort(sort, columns) {
|
|
2563
|
+
if (!sort ||
|
|
2564
|
+
(sort.direction !== 'asc' && sort.direction !== 'desc') ||
|
|
2565
|
+
!columns.some((column) => column.key === sort.key && column.sortable)) {
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
return { key: sort.key, direction: sort.direction };
|
|
2569
|
+
}
|
|
2570
|
+
/** @private Emits one fresh normalized snapshot after a durable user gesture. */
|
|
2571
|
+
_emitPresentationStateChange() {
|
|
2572
|
+
this.presentationStateChange.emit(this.getPresentationState());
|
|
2573
|
+
}
|
|
2574
|
+
/** @private Clamps a width to finite normalized resize bounds. */
|
|
2575
|
+
_clampColumnWidth(width, bounds) {
|
|
2576
|
+
const finiteWidth = Number.isFinite(width) ? width : DEFAULT_COLUMN_WIDTH;
|
|
2577
|
+
return Math.min(bounds.max, Math.max(bounds.min, finiteWidth));
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* @private Detaches active pointer listeners, releases capture, cancels a
|
|
2581
|
+
* pending animation frame, and clears the drag state. Idempotent for pointer
|
|
2582
|
+
* up, pointer cancel, reset, and component destruction.
|
|
2583
|
+
*/
|
|
2584
|
+
_cleanupResize() {
|
|
2585
|
+
const state = this._resizeState;
|
|
2586
|
+
if (state) {
|
|
2587
|
+
this._document.removeEventListener('pointermove', this._onResizeMoveBound);
|
|
2588
|
+
this._document.removeEventListener('pointerup', this._onResizeEndBound);
|
|
2589
|
+
this._document.removeEventListener('pointercancel', this._onResizeCancelBound);
|
|
2590
|
+
state.target.removeEventListener('lostpointercapture', this._onResizeLostCaptureBound);
|
|
2591
|
+
const canRelease = typeof state.target.hasPointerCapture !== 'function' ||
|
|
2592
|
+
state.target.hasPointerCapture(state.pointerId);
|
|
2593
|
+
if (canRelease &&
|
|
2594
|
+
typeof state.target.releasePointerCapture === 'function') {
|
|
2595
|
+
try {
|
|
2596
|
+
state.target.releasePointerCapture(state.pointerId);
|
|
2597
|
+
}
|
|
2598
|
+
catch {
|
|
2599
|
+
// Capture may already have been released implicitly by the browser.
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
if (this._resizeRafId) {
|
|
2604
|
+
cancelAnimationFrame(this._resizeRafId);
|
|
2605
|
+
this._resizeRafId = 0;
|
|
2606
|
+
}
|
|
2607
|
+
this._resizeState = null;
|
|
2608
|
+
}
|
|
2609
|
+
// ---- Private helpers --------------------------------------------------------
|
|
2610
|
+
/** Returns the original (pre-spread) row reference for expand tracking. */
|
|
2611
|
+
_ref(row) {
|
|
2612
|
+
return originalRow(row);
|
|
2613
|
+
}
|
|
2614
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2615
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MlvDataTable, isStandalone: true, selector: "mlv-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, columnGroups: { classPropertyName: "columnGroups", publicName: "columnGroups", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, addRow: { classPropertyName: "addRow", publicName: "addRow", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, actionsHeaderLabel: { classPropertyName: "actionsHeaderLabel", publicName: "actionsHeaderLabel", isSignal: true, isRequired: false, transformFunction: null }, cellNavigation: { classPropertyName: "cellNavigation", publicName: "cellNavigation", isSignal: true, isRequired: false, transformFunction: null }, paginationMode: { classPropertyName: "paginationMode", publicName: "paginationMode", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, infiniteScrollThreshold: { classPropertyName: "infiniteScrollThreshold", publicName: "infiniteScrollThreshold", isSignal: true, isRequired: false, transformFunction: null }, filterDisplay: { classPropertyName: "filterDisplay", publicName: "filterDisplay", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showSortMenu: { classPropertyName: "showSortMenu", publicName: "showSortMenu", isSignal: true, isRequired: false, transformFunction: null }, searchTrigger: { classPropertyName: "searchTrigger", publicName: "searchTrigger", isSignal: true, isRequired: false, transformFunction: null }, searchDebounce: { classPropertyName: "searchDebounce", publicName: "searchDebounce", isSignal: true, isRequired: false, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null }, activeFilters: { classPropertyName: "activeFilters", publicName: "activeFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowEditStart: "rowEditStart", rowEditSave: "rowEditSave", rowEditCancel: "rowEditCancel", rowAdd: "rowAdd", rowClick: "rowClick", selectionChange: "selectionChange", retry: "retry", columnResize: "columnResize", presentationStateChange: "presentationStateChange", loadMore: "loadMore", selectedRows: "selectedRowsChange", searchQuery: "searchQueryChange", activeFilters: "activeFiltersChange" }, host: { classAttribute: "mlv-data-table" }, providers: [
|
|
2616
|
+
{ provide: MLV_DENSITY_ELEMENT, useValue: 'data-table' },
|
|
2617
|
+
MlvDataTableEditingService,
|
|
2618
|
+
MlvDataTableColumnVisibilityService,
|
|
2619
|
+
MlvDataTablePinningService,
|
|
2620
|
+
], queries: [{ propertyName: "cellTemplates", predicate: MlvDataTableCell, descendants: true, isSignal: true }, { propertyName: "editCellTemplates", predicate: MlvDataTableEditCell, descendants: true, isSignal: true }, { propertyName: "noDataTemplate", predicate: MlvDataTableNoData, descendants: true, isSignal: true }, { propertyName: "errorTemplate", predicate: MlvDataTableError, descendants: true, isSignal: true }, { propertyName: "footerTemplate", predicate: MlvDataTableFooter, descendants: true, isSignal: true }, { propertyName: "_toolbarActions", first: true, predicate: MlvDataTableToolbarActions, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "tableWrapperRef", first: true, predicate: ["tableWrapper"], descendants: true, isSignal: true }, { propertyName: "tableRef", first: true, predicate: ["tableEl"], descendants: true, isSignal: true }, { propertyName: "_resizeHandleRefs", predicate: ["resizeHandle"], descendants: true, isSignal: true }, { propertyName: "_filterTriggerRef", first: true, predicate: ["filterBtn"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_virtualViewportRef", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], hostDirectives: [{ directive: i1$1.MlvDensityDirective, inputs: ["mlvDensity", "mlvDensity"] }], ngImport: i0, template: "@if (hasToolbarContent()) {\n<div class=\"mlv-data-table__toolbar\">\n @if (showSearch() && hasSearchableColumns()) {\n <mlv-search-field\n class=\"mlv-data-table__search\"\n [value]=\"_searchDraft()\"\n (valueChange)=\"_searchDraft.set($event)\"\n [trigger]=\"searchTrigger()\"\n [debounce]=\"searchDebounce()\"\n [loading]=\"loading()\"\n [placeholder]=\"_i18n().searchPlaceholder\"\n [ariaLabel]=\"_i18n().searchLabel\"\n (search)=\"onSearch($event)\"\n />\n } @if (filterDisplay() !== 'none' && hasFilters()) {\n <span class=\"mlv-data-table__filter-badge\" aria-live=\"polite\">\n {{ activeFilterLabel() }}\n </span>\n }\n <div class=\"mlv-data-table__toolbar-actions\">\n @if (editable() && addRow()) {\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n (click)=\"onAddRow()\"\n [attr.aria-label]=\"_i18n().addNewRow\"\n >\n <svg lucidePlus mlvButtonIcon [size]=\"14\" />\n {{ _i18n().addRow }}\n </button>\n } @if (showSortMenu() && hasSortableColumns()) {\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n data-mlv-table-sort-trigger\n [mlvMenuTrigger]=\"sortMenu\"\n [attr.aria-label]=\"_i18n().sortMenu\"\n >\n <svg mlvButtonIcon lucideArrowUpDown [size]=\"14\" />\n {{ _i18n().sort }}\n </button>\n <mlv-menu #sortMenu [label]=\"_i18n().sortMenu\" mlvDensity=\"compact\">\n @for (column of columns(); track column.key) { @if (column.sortable) { @if\n (currentSort()?.key === column.key) {\n <mlv-list-item\n mlvMenuItem\n [mlvMenuTrigger]=\"directionMenu\"\n [isSubmenuTrigger]=\"true\"\n >\n {{ column.title ?? column.key }}\n </mlv-list-item>\n <mlv-menu\n #directionMenu\n [label]=\"getSortLabel(column)\"\n mlvDensity=\"compact\"\n >\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'asc')\">\n {{ _i18n().ascending }}\n </mlv-list-item>\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'desc')\">\n {{ _i18n().descending }}\n </mlv-list-item>\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, null)\">\n {{ _i18n().clearSort }}\n </mlv-list-item>\n </mlv-menu>\n } @else {\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'asc')\">\n {{ column.title ?? column.key }}\n </mlv-list-item>\n } } }\n </mlv-menu>\n } @if (hasHideableColumns()) {\n <button\n mlvButton\n [variant]=\"columnsPopup.opened() ? 'primary' : 'secondary'\"\n mlvDensity=\"compact\"\n type=\"button\"\n [mlvPopupTrigger]=\"columnsPopup\"\n #columnsTrigger=\"mlvPopupTrigger\"\n [attr.aria-label]=\"_i18n().toggleColumnVisibility\"\n >\n <svg mlvButtonIcon lucideEye [size]=\"14\" />\n {{ _i18n().columns }}\n </button>\n\n <mlv-popup #columnsPopup>\n <div *mlvPopupContent class=\"mlv-data-table__columns-dropdown\">\n @for (col of allColumns(); track col.key) { @if (col.hideable) {\n <div class=\"mlv-data-table__columns-item\">\n <mlv-checkbox\n [checked]=\"!isColumnHidden(col.key)\"\n [ariaLabel]=\"col.title ?? col.key\"\n (checkedChange)=\"toggleColumnVisibility(col.key)\"\n />\n <span>{{ col.title ?? col.key }}</span>\n </div>\n } }\n </div>\n </mlv-popup>\n } @if (filterDisplay() === 'toolbar' && hasFilterableColumns()) {\n <button\n #filterBtn\n mlvButton\n [variant]=\"filtersPopup.opened() ? 'primary' : 'secondary'\"\n mlvDensity=\"compact\"\n type=\"button\"\n [mlvPopupTrigger]=\"filtersPopup\"\n #trigger=\"mlvPopupTrigger\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_i18n().toggleFilters\"\n >\n <svg lucideFilter mlvButtonIcon [size]=\"14\" />\n {{ _i18n().filters }} @if (hasFilters()) {\n <mlv-badge tone=\"primary\" rounded>{{ activeFilters().length }}</mlv-badge>\n }\n </button>\n\n <mlv-popup\n #filtersPopup\n panelRole=\"dialog\"\n [ariaLabel]=\"_i18n().filters\"\n (afterClosed)=\"_onFiltersClosed()\"\n >\n <mlv-dt-filter-dropdown\n *mlvPopupContent\n [columns]=\"columns()\"\n [(activeFilters)]=\"activeFilters\"\n (closed)=\"trigger.close()\"\n />\n </mlv-popup>\n } @if (_toolbarActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" />\n }\n </div>\n</div>\n}\n\n<div\n class=\"mlv-data-table__wrapper\"\n [class.mlv-data-table__wrapper--virtual]=\"virtualScroll()\"\n [style.max-height]=\"virtualScroll() ? null : maxHeight()\"\n [style.--mlv-dt-virtual-scrollbar-gutter]=\"\n virtualScroll() ? _virtualScrollbarGutter() + 'px' : null\n \"\n #tableWrapper\n mlvInfiniteScroll\n [disabled]=\"paginationMode() !== 'infinite' || virtualScroll()\"\n [threshold]=\"infiniteScrollThreshold()\"\n [loading]=\"!!loading()\"\n [hasMore]=\"!!hasMore()\"\n (loadMore)=\"onInfiniteScrollLoadMore($event)\"\n>\n @if (virtualScroll()) {\n <!-- ==================== Virtual scroll mode ==================== -->\n <!-- Header table \u2014 sits naturally at the top of the wrapper, outside the viewport -->\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-header\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.flex]=\"resizedTableWidth() === null ? null : '0 0 auto'\"\n role=\"grid\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead class=\"mlv-data-table__head\">\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n </table>\n\n <!-- CDK virtual scroll viewport \u2014 owns the only vertical scroll surface in this mode.\n Infinite scroll is intentionally disabled in virtual mode: virtual scrolling is the\n rendering optimisation for already-loaded data, and the two strategies are mutually\n exclusive in this component. -->\n <cdk-virtual-scroll-viewport\n class=\"mlv-data-table__virtual-viewport\"\n [itemSize]=\"rowHeight()\"\n [style.height]=\"virtualViewportHeight()\"\n >\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-body\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n role=\"presentation\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else {\n <tr\n *cdkVirtualFor=\"\n let row of flatRows();\n let i = index;\n trackBy: trackByRow\n \"\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [style.height.px]=\"rowHeight()\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.tabindex]=\"_rowTabIndex(i)\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n (focus)=\"_onRowFocus(i)\"\n (keydown)=\"_onRowKeydown(i, row, $event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowCellsTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </tr>\n }\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n <!-- Footer summary table \u2014 only when a footer template is projected -->\n @if (getFooterTemplate(); as footerTpl) {\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-footer\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.flex]=\"resizedTableWidth() === null ? null : '0 0 auto'\"\n role=\"presentation\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <tfoot class=\"mlv-data-table__foot\">\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n </table>\n }\n\n <!-- Extends only the outer horizontal scroll range to match the viewport's\n native range, including a classic vertical scrollbar gutter. -->\n <div\n class=\"mlv-data-table__virtual-horizontal-sizer\"\n [style.width.px]=\"_virtualHorizontalScrollExtent()\"\n aria-hidden=\"true\"\n ></div>\n } @else if (_cellNav()) {\n <!-- ========= Experimental cell-level grid navigation (aria ngGrid) ========= -->\n <!--\n Opt-in via [cellNavigation]=\"true\" (non-virtual only). The aria Grid pattern owns\n roving focus, arrow/Home/End navigation across cells, and aria-activedescendant.\n Only the data <tbody> rows/cells are registered as grid rows/cells; header cells\n stay outside grid navigation. Interactive cells (edit inputs, action buttons)\n expose an ngGridCellWidget so Enter pauses grid nav to interact and Escape resumes.\n -->\n <table\n ngGrid\n rowWrap=\"nowrap\"\n colWrap=\"nowrap\"\n class=\"mlv-data-table__table\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.table-layout]=\"resizedTableWidth() === null ? null : 'fixed'\"\n role=\"grid\"\n #tableEl\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead\n class=\"mlv-data-table__head\"\n [class.mlv-data-table__head--sticky]=\"stickyHeader()\"\n >\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else { @for (row of flatRows(); track $index; let i = $index) {\n <tr\n ngGridRow\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n >\n @if (selectable()) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <mlv-checkbox\n [checked]=\"isRowSelected(row)\"\n [tabbable]=\"false\"\n (checkedChange)=\"toggleRowSelection(row)\"\n (click)=\"$event.stopPropagation()\"\n [ariaLabel]=\"'Select row ' + (i + 1)\"\n />\n </td>\n } @for (col of visibleColumns(); track col.key; let ci = $index) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n >\n @if ( editable() && isEditing(i) && getEditTemplate(col.key); as\n editTpl ) {\n <div\n ngGridCellWidget\n widgetType=\"editable\"\n class=\"mlv-data-table__cell-content\"\n >\n <ng-container\n [ngTemplateOutlet]=\"editTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"cellContentTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n index: i,\n col: col,\n ci: ci,\n }\"\n />\n }\n </td>\n } @if (editable()) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <div\n ngGridCellWidget\n widgetType=\"complex\"\n class=\"mlv-data-table__cell-content mlv-data-table__actions\"\n >\n <ng-container\n [ngTemplateOutlet]=\"actionsButtonsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n />\n </div>\n </td>\n }\n </tr>\n } }\n </tbody>\n\n @if (getFooterTemplate(); as footerTpl) {\n <tfoot\n class=\"mlv-data-table__foot\"\n [class.mlv-data-table__foot--sticky]=\"stickyHeader()\"\n >\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n }\n </table>\n\n @if (paginationMode() === 'infinite' && loading()) {\n <div\n class=\"mlv-data-table__loading-bottom\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"24\"\n ariaLabel=\"Loading more rows\"\n />\n </div>\n } } @else {\n <!-- ==================== Standard (non-virtual) mode ==================== -->\n <table\n class=\"mlv-data-table__table\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.table-layout]=\"resizedTableWidth() === null ? null : 'fixed'\"\n role=\"grid\"\n #tableEl\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead\n class=\"mlv-data-table__head\"\n [class.mlv-data-table__head--sticky]=\"stickyHeader()\"\n >\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else { @for (row of flatRows(); track $index; let i = $index) {\n <tr\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.tabindex]=\"_rowTabIndex(i)\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n (focus)=\"_onRowFocus(i)\"\n (keydown)=\"_onRowKeydown(i, row, $event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowCellsTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </tr>\n } }\n </tbody>\n\n @if (getFooterTemplate(); as footerTpl) {\n <tfoot\n class=\"mlv-data-table__foot\"\n [class.mlv-data-table__foot--sticky]=\"stickyHeader()\"\n >\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n }\n </table>\n\n @if (paginationMode() === 'infinite' && loading()) {\n <div\n class=\"mlv-data-table__loading-bottom\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"24\"\n ariaLabel=\"Loading more rows\"\n />\n </div>\n } }\n</div>\n\n@if (paginationMode() === 'paged' && !virtualScroll()) {\n<div class=\"mlv-data-table__footer\">\n <mlv-pagination\n [totalItems]=\"totalItems()\"\n [currentPage]=\"currentPage()\"\n [itemsPerPage]=\"currentPerPage()\"\n (currentPageChange)=\"_onPageChange($event)\"\n (itemsPerPageChange)=\"_onPerPageChange($event)\"\n />\n</div>\n} @if (paginationMode() === 'paged' && loading()) {\n<div\n class=\"mlv-data-table__loading-overlay\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n>\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"48\"\n ariaLabel=\"Loading table data\"\n />\n</div>\n}\n\n<!-- ==================== Reusable templates ==================== -->\n\n<!--\n Shared <colgroup> template \u2014 used by both the standard table and the three split tables in\n virtual mode (header / body / footer). Keeping the colgroup definitions identical and combining\n it with `table-layout: fixed` keeps column widths in sync between the split tables in virtual mode.\n-->\n<ng-template #colgroupTpl>\n <colgroup>\n @if (selectable() === 'multi' || selectable() === 'single') {\n <col\n class=\"mlv-data-table__col--select\"\n [style.width]=\"getAuxiliaryColumnWidth('selection')\"\n />\n } @for (col of visibleColumns(); track col.key) {\n <col [style.width]=\"getColWidth(col)\" />\n } @if (editable()) {\n <col\n class=\"mlv-data-table__col--actions\"\n [style.width]=\"getAuxiliaryColumnWidth('actions')\"\n />\n }\n </colgroup>\n</ng-template>\n\n<!-- Header rows \u2014 emits the same content the original `<thead>` did. -->\n<ng-template #headRowsTpl>\n @if (hasColumnGroups()) {\n <!-- Group header row -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--group-header\">\n @if (selectable() === 'multi') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n rowspan=\"2\"\n >\n <mlv-checkbox\n [checked]=\"allRowsSelected()\"\n [indeterminate]=\"someRowsSelected()\"\n (checkedChange)=\"toggleSelectAll()\"\n [ariaLabel]=\"_i18n().selectAllRows\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n rowspan=\"2\"\n ></th>\n } @for (col of visibleColumns(); track col.key) { @if (headerLayout(); as\n layout) { @if (layout.standaloneKeys.has(col.key)) {\n <!-- Standalone column spans both header rows -->\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--standalone\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n rowspan=\"2\"\n scope=\"col\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } @else {\n <!-- Check if this column is the first column of a group -->\n @for (group of columnGroups(); track group.title) { @if (group.columns[0]\n === col.key) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--group-header\"\n [class.mlv-data-table__cell--align-left]=\"\n group.align === 'left'\n \"\n [class.mlv-data-table__cell--align-center]=\"\n group.align === 'center' || !group.align\n \"\n [class.mlv-data-table__cell--align-right]=\"\n group.align === 'right'\n \"\n [attr.colspan]=\"group.columns.length\"\n scope=\"colgroup\"\n >\n {{ group.title }}\n </th>\n } } } } } @if (editable()) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n rowspan=\"2\"\n >\n <span class=\"mlv-data-table__visually-hidden\"\n >{{ actionsHeaderLabel() }}</span\n >\n </th>\n }\n </tr>\n <!-- Sub-header row for grouped columns -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--header\">\n @for (col of visibleColumns(); track col.key) { @if (headerLayout(); as\n layout) { @if (layout.groupedKeys.has(col.key)) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n scope=\"col\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } } }\n </tr>\n } @else {\n <!-- Standard single-row header -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--header\">\n @if (selectable() === 'multi') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <mlv-checkbox\n [checked]=\"allRowsSelected()\"\n [indeterminate]=\"someRowsSelected()\"\n (checkedChange)=\"toggleSelectAll()\"\n [ariaLabel]=\"_i18n().selectAllRows\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n ></th>\n } @for (col of visibleColumns(); track col.key) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n scope=\"col\"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } @if (editable()) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <span class=\"mlv-data-table__visually-hidden\"\n >{{ actionsHeaderLabel() }}</span\n >\n </th>\n }\n </tr>\n }\n</ng-template>\n\n<!--\n Shared inner content for a single header cell. Context: { $implicit: col }.\n Sortable columns wrap the label + sort icon in ONE native <button> (APG grid\n sort pattern) so the <th> stays a non-interactive cell carrying only aria-sort;\n the pin button is a sibling of the sort button, never nested inside it, so no\n interactive control is nested within another (avoids axe `nested-interactive`).\n-->\n<ng-template #headerCellInnerTpl let-col>\n <div class=\"mlv-data-table__cell-inner\">\n @if (col.sortable) {\n <button\n type=\"button\"\n class=\"mlv-data-table__sort-button\"\n [attr.aria-label]=\"getSortLabel(col)\"\n (click)=\"onSortClick(col)\"\n >\n <span class=\"mlv-data-table__header-title\"\n >{{ col.title ?? col.key }}</span\n >\n <span class=\"mlv-data-table__sort-icon\" aria-hidden=\"true\">\n @if (getSortDirection(col) === 'asc') {\n <svg lucideArrowUp />\n } @else if (getSortDirection(col) === 'desc') {\n <svg lucideArrowDown />\n } @else {\n <svg lucideChevronsUpDown class=\"mlv-data-table__sort-icon--inactive\" />\n }\n </span>\n </button>\n } @else {\n <span class=\"mlv-data-table__header-title\">{{ col.title ?? col.key }}</span>\n } @if (col.pinnable) {\n <ng-container\n [ngTemplateOutlet]=\"pinButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n } @if (filterDisplay() === 'column' && col.filterable) {\n <button\n mlvButton\n class=\"mlv-data-table__column-filter\"\n [class.mlv-data-table__column-filter--active]=\"\n isColumnFiltered(col.key)\n \"\n [variant]=\"\n columnFilterPopup.opened() || isColumnFiltered(col.key)\n ? 'primary'\n : 'transparent'\n \"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n [attr.data-column-key]=\"col.key\"\n [mlvPopupTrigger]=\"columnFilterPopup\"\n #columnFilterTrigger=\"mlvPopupTrigger\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"getFilterLabel(col)\"\n >\n <svg lucideFunnel mlvButtonIcon [size]=\"14\" />\n </button>\n\n <mlv-popup\n #columnFilterPopup\n panelRole=\"dialog\"\n [ariaLabel]=\"getFilterLabel(col)\"\n (afterClosed)=\"focusColumnFilterTrigger(col.key)\"\n >\n <mlv-dt-filter-dropdown\n *mlvPopupContent\n [columns]=\"getColumnFilterColumns(col)\"\n [activeFilters]=\"activeFilters()\"\n (activeFiltersChange)=\"onColumnFiltersChange(col.key, $event)\"\n (closed)=\"columnFilterTrigger.close()\"\n />\n </mlv-popup>\n }\n </div>\n @if (col.resizable) {\n <div\n #resizeHandle\n class=\"mlv-data-table__resize-handle\"\n [attr.data-column-key]=\"col.key\"\n role=\"separator\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n [attr.aria-label]=\"getColumnResizeLabel(col)\"\n [attr.aria-valuenow]=\"getColumnResizeValue(col)\"\n [attr.aria-valuemin]=\"getColumnResizeMin(col)\"\n [attr.aria-valuemax]=\"getColumnResizeMax(col)\"\n [attr.aria-valuetext]=\"getColumnResizeValueText(col)\"\n (pointerdown)=\"onResizeStart(col, $event)\"\n (keydown)=\"onColumnResizeKeydown(col, $event)\"\n (dblclick)=\"resetColumnWidth(col.key)\"\n ></div>\n }\n</ng-template>\n\n<!-- No-data fallback row, used by both rendering paths. -->\n<ng-template #noDataRowTpl>\n <tr class=\"mlv-data-table__row mlv-data-table__row--no-data\">\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--no-data\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n @if (getNoDataTemplate()) {\n <ng-container [ngTemplateOutlet]=\"getNoDataTemplate()!\" />\n } @else {\n <div class=\"mlv-data-table__no-data-default\">\n <svg lucideTable2 [size]=\"40\" aria-hidden=\"true\" />\n <span>No data available</span>\n </div>\n }\n </td>\n </tr>\n</ng-template>\n\n<!--\n Failed-request row, used by all three rendering paths. Takes precedence over both the\n data rows and #noDataRowTpl so a failed request never reads as an empty result set.\n The region is announced as an alert; the default block is an mlv-empty-state with a\n danger-toned icon and a Retry button wired to the (retry) output.\n-->\n<ng-template #errorRowTpl>\n <tr class=\"mlv-data-table__row mlv-data-table__row--error\">\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--error\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n <div class=\"mlv-data-table__error\" role=\"alert\" aria-live=\"assertive\">\n @if (getErrorTemplate(); as errorTpl) {\n <ng-container\n [ngTemplateOutlet]=\"errorTpl\"\n [ngTemplateOutletContext]=\"_errorContext()\"\n />\n } @else {\n <mlv-empty-state>\n <svg\n mlvEmptyStateIcon\n lucideTriangleAlert\n class=\"mlv-data-table__error-icon\"\n [size]=\"40\"\n aria-hidden=\"true\"\n />\n <span mlvEmptyStateTitle>{{ _i18n().errorTitle }}</span>\n <span mlvEmptyStateDescription>{{ errorMessage() }}</span>\n <button\n mlvEmptyStateActions\n mlvButton\n variant=\"secondary\"\n type=\"button\"\n class=\"mlv-data-table__error-retry\"\n (click)=\"onRetry()\"\n >\n {{ _i18n().retry }}\n </button>\n </mlv-empty-state>\n }\n </div>\n </td>\n </tr>\n</ng-template>\n\n<!--\n Per-row data cells. Emits the selection cell, the data cells, and the actions cell.\n The owning <tr> stays at the consumer site (either inside `@for` for the standard mode\n or `*cdkVirtualFor` inside the CDK viewport in virtual mode), so each rendering path can\n control its own row-level host bindings.\n-->\n<ng-template #rowCellsTpl let-row let-i=\"index\">\n @if (selectable()) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <!--\n [tabbable]=\"false\" keeps this checkbox out of the tab order so the row is\n the single tab stop: the row's Space/Enter toggles selection, and the\n checkbox stays operable via the mouse. Avoids a per-row double tab stop.\n -->\n <mlv-checkbox\n [checked]=\"isRowSelected(row)\"\n [tabbable]=\"false\"\n (checkedChange)=\"toggleRowSelection(row)\"\n (click)=\"$event.stopPropagation()\"\n [ariaLabel]=\"'Select row ' + (i + 1)\"\n />\n </td>\n } @for (col of visibleColumns(); track col.key; let ci = $index) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"cellContentTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n index: i,\n col: col,\n ci: ci,\n }\"\n />\n </td>\n } @if (editable()) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <div class=\"mlv-data-table__cell-content mlv-data-table__actions\">\n <ng-container\n [ngTemplateOutlet]=\"actionsButtonsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n />\n </div>\n </td>\n }\n</ng-template>\n\n<!--\n Shared edit/save/cancel action buttons for the actions column. Context: { $implicit: row, index: i }.\n-->\n<ng-template #actionsButtonsTpl let-row let-i=\"index\">\n @if (isEditing(i)) {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"saveEdit(row, i)\"\n [attr.aria-label]=\"_i18n().saveChanges\"\n >\n <svg lucideCheck mlvButtonIcon />\n </button>\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"cancelEdit(row, i)\"\n [attr.aria-label]=\"_i18n().cancelEditing\"\n >\n <svg lucideX mlvButtonIcon />\n </button>\n } @else {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"startEdit(row, i)\"\n [attr.aria-label]=\"_i18n().editRow\"\n >\n <svg lucidePencil mlvButtonIcon />\n </button>\n }\n</ng-template>\n\n<!--\n Shared inner content of a data cell (indent, expand button, edit/display template, raw value).\n Extracted so both the standard `#rowCellsTpl` `<td>` and the experimental cell-navigation grid\n `<td ngGridCell>` render identical content. Purely presentational \u2014 contains no aria grid\n directives \u2014 so it is safe to project via ngTemplateOutlet across the grid-cell boundary.\n Context: { $implicit: row, index: i, col, ci }.\n-->\n<ng-template #cellContentTpl let-row let-i=\"index\" let-col=\"col\" let-ci=\"ci\">\n <div class=\"mlv-data-table__cell-content\">\n @if (ci === 0 && getDepth(row) > 0) {\n <span\n class=\"mlv-data-table__indent\"\n [style.padding-left.rem]=\"getDepth(row) * 1.25\"\n aria-hidden=\"true\"\n ></span>\n } @if (ci === 0 && hasChildren(row)) {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n class=\"mlv-data-table__expand-btn\"\n (click)=\"toggleExpand(row, $event)\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n [attr.aria-label]=\"\n isRowExpanded(row) ? _i18n().collapseRow : _i18n().expandRow\n \"\n >\n <svg\n lucideChevronRight\n mlvButtonIcon\n class=\"mlv-data-table__expand-icon\"\n [class.mlv-data-table__expand-icon--open]=\"isRowExpanded(row)\"\n />\n </button>\n } @if (editable() && isEditing(i) && getEditTemplate(col.key); as editTpl) {\n <ng-container\n [ngTemplateOutlet]=\"editTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n } @else if (getTemplate(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n } @else {\n <!--\n Default cell renderer. `valueLabels` (or the `filterConfig.options` fallback)\n maps the raw value to a label; `tone` promotes the cell to a muted badge.\n -->\n @if (getCellTone(row, col); as tone) {\n <mlv-badge [tone]=\"tone\" muted\n >{{ getCellDisplayValue(row, col) }}</mlv-badge\n >\n } @else { {{ getCellDisplayValue(row, col) }} } }\n </div>\n</ng-template>\n\n<!-- Reusable pin button template. Rendered via ngTemplateOutlet from every header cell that supports pinning. -->\n<ng-template #pinButtonTpl let-col>\n @if (getPinnableSides(col); as sides) { @if (sides.length > 1) {\n <button\n class=\"mlv-data-table__pin-btn\"\n [class.mlv-data-table__pin-btn--active]=\"isColumnPinned(col)\"\n type=\"button\"\n [mlvPopupTrigger]=\"pinPopup\"\n #pinTrigger=\"mlvPopupTrigger\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"\n isColumnPinned(col) ? _i18n().changePinSide : _i18n().pinColumn\n \"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"pinPopup.opened()\"\n [attr.aria-pressed]=\"isColumnPinned(col)\"\n >\n @if (isColumnPinned(col)) {\n <svg lucidePinOff />\n } @else {\n <svg lucidePin />\n }\n </button>\n <mlv-popup #pinPopup>\n <div *mlvPopupContent class=\"mlv-data-table__pin-popup\" role=\"menu\">\n @for (side of sides; track side) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n class=\"mlv-data-table__pin-popup-item\"\n [class.mlv-data-table__pin-popup-item--active]=\"\n getColumnPinSide(col) === side\n \"\n [attr.aria-checked]=\"getColumnPinSide(col) === side\"\n (click)=\"\n pinTo(col, side); pinTrigger.close(); $event.stopPropagation()\n \"\n >\n <svg lucidePin [size]=\"14\" />\n @if (side === 'left') {\n <span>Pin left</span>\n } @else {\n <span>Pin right</span>\n }\n </button>\n } @if (isColumnPinned(col)) {\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"mlv-data-table__pin-popup-item mlv-data-table__pin-popup-item--unpin\"\n (click)=\"unpin(col); pinTrigger.close(); $event.stopPropagation()\"\n >\n <svg lucidePinOff [size]=\"14\" />\n <span>{{ _i18n().unpin }}</span>\n </button>\n }\n </div>\n </mlv-popup>\n } @else {\n <button\n class=\"mlv-data-table__pin-btn\"\n [class.mlv-data-table__pin-btn--active]=\"isColumnPinned(col)\"\n type=\"button\"\n (click)=\"togglePin(col, sides[0]); $event.stopPropagation()\"\n [attr.aria-label]=\"\n isColumnPinned(col) ? _i18n().unpinColumn : _i18n().pinColumn\n \"\n [attr.aria-pressed]=\"isColumnPinned(col)\"\n >\n @if (isColumnPinned(col)) {\n <svg lucidePinOff />\n } @else {\n <svg lucidePin />\n }\n </button>\n } }\n</ng-template>\n", styles: ["@layer mlv.components{.mlv-data-table{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-dt-font-size)}.mlv-data-table *{box-sizing:border-box}.mlv-data-table{--mlv-dt-row-height: calc(var(--mlv-height-m) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.25rem;--mlv-dt-header-height: 3rem;--mlv-dt-font-size: var(--mlv-font-size-m);--mlv-dt-header-font-size: var(--mlv-font-size-m);--mlv-dt-icon-size: 1rem;--mlv-dt-toolbar-gap: .5rem;--mlv-dt-toolbar-padding: .75rem 0;display:flex;flex-direction:column;width:100%;position:relative;color:var(--mlv-text-primary)}[class*=--tight] .mlv-data-table:not([class*=--compact],[class*=--comfortable],[class*=--spacious],[class*=--airy]),.mlv-data-table[class*=--tight]{--mlv-dt-row-height: calc(var(--mlv-height-xs) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: .75rem;--mlv-dt-header-height: 2.25rem;--mlv-dt-font-size: var(--mlv-font-size-s);--mlv-dt-header-font-size: var(--mlv-font-size-s);--mlv-dt-icon-size: .75rem;--mlv-dt-toolbar-gap: .25rem;--mlv-dt-toolbar-padding: .375rem 0}[class*=--compact] .mlv-data-table:not([class*=--tight],[class*=--comfortable],[class*=--spacious],[class*=--airy]),.mlv-data-table[class*=--compact]{--mlv-dt-row-height: calc(var(--mlv-height-s) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1rem;--mlv-dt-header-height: 2.5rem;--mlv-dt-font-size: var(--mlv-font-size-s);--mlv-dt-header-font-size: var(--mlv-font-size-s);--mlv-dt-icon-size: .875rem;--mlv-dt-toolbar-gap: .375rem;--mlv-dt-toolbar-padding: .5rem 0}[class*=--spacious] .mlv-data-table:not([class*=--tight],[class*=--compact],[class*=--comfortable],[class*=--airy]),.mlv-data-table[class*=--spacious]{--mlv-dt-row-height: calc(var(--mlv-height-l) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.5rem;--mlv-dt-header-height: 3.25rem;--mlv-dt-font-size: var(--mlv-font-size-l);--mlv-dt-header-font-size: var(--mlv-font-size-l);--mlv-dt-icon-size: 1.125rem;--mlv-dt-toolbar-gap: .75rem;--mlv-dt-toolbar-padding: .75rem 0}[class*=--airy] .mlv-data-table:not([class*=--tight],[class*=--compact],[class*=--comfortable],[class*=--spacious]),.mlv-data-table[class*=--airy]{--mlv-dt-row-height: calc(var(--mlv-height-xl) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.75rem;--mlv-dt-header-height: 3.75rem;--mlv-dt-font-size: var(--mlv-font-size-l);--mlv-dt-header-font-size: var(--mlv-font-size-l);--mlv-dt-icon-size: 1.25rem;--mlv-dt-toolbar-gap: 1rem;--mlv-dt-toolbar-padding: 1rem 0}.mlv-data-table__toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:var(--mlv-dt-toolbar-gap);padding:var(--mlv-dt-toolbar-padding);position:relative}.mlv-data-table__search{flex:1 1 16rem;width:min(100%,24rem);max-width:24rem}.mlv-data-table__toolbar-actions{display:flex;gap:var(--mlv-dt-toolbar-gap);margin-inline-start:auto}.mlv-data-table__filter-badge{font-size:var(--mlv-dt-font-size);color:var(--mlv-text-secondary)}.mlv-data-table__wrapper{width:100%;overflow-x:auto;overflow-y:auto;position:relative}.mlv-data-table__wrapper--virtual{overflow-y:visible;display:flex;flex-direction:column}.mlv-data-table__virtual-viewport{display:block;width:100%;min-width:0;max-width:100%;flex:0 0 auto;position:sticky;inset-inline-start:0;border-bottom:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__virtual-viewport.cdk-virtual-scrollable{overflow-x:hidden;overflow-y:auto}.mlv-data-table__virtual-horizontal-sizer{width:0;height:0;min-height:0;flex:0 0 0;align-self:flex-start;pointer-events:none}.mlv-data-table__table--virtual-header,.mlv-data-table__table--virtual-footer{--mlv-dt-pinned-right-correction: var( --mlv-dt-virtual-scrollbar-gutter, 0px )}.mlv-data-table__loading-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--mlv-background-base) 70%,transparent);-webkit-backdrop-filter:blur(.0625rem);backdrop-filter:blur(.0625rem);z-index:20;pointer-events:all}.mlv-data-table__loading-bottom{display:flex;align-items:center;justify-content:center;padding:1rem 0;color:var(--mlv-text-secondary)}.mlv-data-table__table{width:100%;border-collapse:collapse;table-layout:auto;font-size:var(--mlv-dt-font-size);color:var(--mlv-text-primary)}.mlv-data-table__table--striped .mlv-data-table__row--data:nth-child(2n){background:var(--mlv-background-sunken)}.mlv-data-table__table--striped .mlv-data-table__row--data:nth-child(2n) .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__table--bordered .mlv-data-table__cell{border-inline-end:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__table--bordered .mlv-data-table__cell:last-child{border-inline-end:none}.mlv-data-table__table--virtual{table-layout:fixed}.mlv-data-table__head--sticky{position:sticky;top:var(--mlv-dt-sticky-top, 0);z-index:3;background:var(--mlv-background-base)}.mlv-data-table__head--sticky .mlv-data-table__cell--pinned{z-index:4}.mlv-data-table__cell{padding:0;border-bottom:.0625rem solid var(--mlv-border-subtle);vertical-align:middle;background:inherit}.mlv-data-table__cell-content{display:flex;align-items:center;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.mlv-data-table__cell--header{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-header-font-size);color:color-mix(in srgb,var(--mlv-text-action) 65%,var(--mlv-text-secondary));position:relative;-webkit-user-select:none;user-select:none;border-bottom:.0625rem solid var(--mlv-border-normal)}.mlv-data-table__cell--sortable{cursor:pointer}.mlv-data-table__cell--sortable:hover .mlv-data-table__cell-inner{color:var(--mlv-text-action)}.mlv-data-table__cell--data{padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-row-height);font-size:var(--mlv-dt-font-size)}.mlv-data-table__cell--pinned{background:var(--mlv-background-base);z-index:1;transition:background var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__cell--pinned:after{content:\"\";position:absolute;top:0;bottom:0;width:.5rem;pointer-events:none}.mlv-data-table__cell--pinned-left:after{inset-inline-end:-.5rem;background:linear-gradient(to right,rgba(0,0,0,.04),transparent)}.mlv-data-table__cell--pinned-right:after{inset-inline-start:-.5rem;background:linear-gradient(to left,rgba(0,0,0,.04),transparent)}.mlv-data-table__cell--no-data,.mlv-data-table__cell--error{padding:3rem var(--mlv-dt-cell-padding-x);text-align:center}.mlv-data-table__cell--align-left{text-align:start}.mlv-data-table__cell--align-center{text-align:center}.mlv-data-table__cell--align-right{text-align:end}.mlv-data-table__cell-inner{display:flex;align-items:center;gap:.375rem;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);transition:color var(--mlv-duration-normal) var(--mlv-ease-default);border-radius:var(--mlv-radius-s)}.mlv-data-table__sort-button{display:inline-flex;align-items:center;gap:.375rem;flex:1;min-width:0;margin:0;padding:0;border:none;background:none;font:inherit;color:inherit;text-align:start;cursor:pointer;border-radius:var(--mlv-radius-s)}.mlv-data-table__sort-button:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-focus-ring-offset)}.mlv-data-table__visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-1px}.mlv-data-table__header-title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start}.mlv-data-table__column-filter{flex:0 0 auto}.mlv-data-table__column-filter--active{color:var(--mlv-text-action)}.mlv-data-table__sort-icon{display:inline-flex;flex-shrink:0;color:var(--mlv-text-action)}.mlv-data-table__sort-icon svg{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size)}.mlv-data-table__sort-icon--inactive{opacity:0;transition:opacity var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__cell--sortable:hover .mlv-data-table__sort-icon--inactive{opacity:.5}.mlv-data-table__pin-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;background:none;cursor:pointer;color:var(--mlv-text-tertiary);opacity:0;transition:opacity var(--mlv-duration-normal) var(--mlv-ease-default),color var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__pin-btn svg{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size)}.mlv-data-table__cell--header:hover .mlv-data-table__pin-btn{opacity:.6}.mlv-data-table__pin-btn:hover{opacity:1!important;color:var(--mlv-text-action)}.mlv-data-table__pin-btn--active{opacity:1;color:var(--mlv-text-action)}.mlv-data-table__cell--header:hover .mlv-data-table__pin-btn--active{opacity:1}.mlv-data-table__resize-handle{position:absolute;top:0;inset-inline-end:-.5rem;width:1rem;height:100%;cursor:col-resize;background:transparent;z-index:5;touch-action:none;-webkit-user-select:none;user-select:none}.mlv-data-table__resize-handle:after{content:\"\";position:absolute;top:.75rem;bottom:.75rem;left:50%;width:.0625rem;border-radius:var(--mlv-radius-full);background-color:var(--mlv-text-tertiary);transform:translate(-50%);transition:background-color var(--mlv-duration-fast) var(--mlv-ease-default),width var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-data-table__resize-handle:hover:after{width:.125rem;background-color:var(--mlv-background-accent-1)}.mlv-data-table__resize-handle:active:after,.mlv-data-table__resize-handle:focus-visible:after{width:.125rem;background-color:var(--mlv-background-accent-1)}.mlv-data-table__resize-handle:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:calc(var(--mlv-focus-ring-offset) * -1)}@media(pointer:coarse){.mlv-data-table__resize-handle{inset-inline-end:-.75rem;width:1.5rem}}.mlv-data-table__row{transition:background var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__row--data:hover,.mlv-data-table__row--data:hover .mlv-data-table__cell--pinned{background:var(--mlv-background-neutral-1-hover)}.mlv-data-table__row--expanded,.mlv-data-table__row--expanded .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__indent{display:inline-block}.mlv-data-table__expand-btn{margin-inline-end:.25rem;vertical-align:middle;flex-shrink:0}.mlv-data-table__expand-icon{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size);transition:transform var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__expand-icon--open{transform:rotate(90deg)}.mlv-data-table__no-data-default{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:3rem 0;color:var(--mlv-text-secondary)}.mlv-data-table__no-data-default svg{opacity:.2}.mlv-data-table__no-data-default span{font-size:var(--mlv-dt-font-size)}.mlv-data-table__error{display:block;text-align:initial}.mlv-data-table__error-icon{color:var(--mlv-text-negative)}.mlv-data-table__row--group-header .mlv-data-table__cell--group-header{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-header-font-size);color:color-mix(in srgb,var(--mlv-text-action) 65%,var(--mlv-text-secondary));text-align:center;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);border-bottom:.0625rem solid var(--mlv-border-subtle);vertical-align:middle}.mlv-data-table__row--group-header .mlv-data-table__cell--standalone{vertical-align:middle}.mlv-data-table__cell--actions{width:1%;white-space:nowrap;padding:0 var(--mlv-dt-cell-padding-x)!important}.mlv-data-table__actions{display:flex;align-items:center;gap:.25rem;justify-content:flex-end}.mlv-data-table__row--editing,.mlv-data-table__row--editing .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__cell--select{width:2.5rem;min-width:2.5rem;max-width:2.5rem;padding:0 .5rem!important;text-align:center}.mlv-data-table__col--select{width:2.5rem}.mlv-data-table__col--actions{width:5rem}.mlv-data-table__row--selected,.mlv-data-table__row--selected .mlv-data-table__cell--pinned{background:color-mix(in srgb,var(--mlv-background-accent-1) 8%,var(--mlv-background-base))}.mlv-data-table__pin-popup{display:flex;flex-direction:column;gap:.125rem;padding:.25rem;min-width:8rem}.mlv-data-table__pin-popup-item{display:flex;align-items:center;gap:.5rem;padding:.375rem .5rem;border:none;background:none;border-radius:var(--mlv-radius-s);cursor:pointer;font:inherit;font-size:var(--mlv-dt-font-size);color:var(--mlv-text-primary);text-align:start}.mlv-data-table__pin-popup-item svg{color:var(--mlv-text-secondary);flex-shrink:0}.mlv-data-table__pin-popup-item:hover{background:var(--mlv-background-sunken)}.mlv-data-table__pin-popup-item--active{color:var(--mlv-text-action)}.mlv-data-table__pin-popup-item--active svg{color:var(--mlv-text-action)}.mlv-data-table__pin-popup-item--unpin{color:var(--mlv-text-negative);border-top:.0625rem solid var(--mlv-border-subtle);margin-top:.125rem;padding-top:.5rem;border-radius:0 0 var(--mlv-radius-s) var(--mlv-radius-s)}.mlv-data-table__pin-popup-item--unpin svg{color:var(--mlv-text-negative)}.mlv-data-table__pin-popup-item--unpin:hover{background:color-mix(in srgb,var(--mlv-text-negative) 8%,transparent)}.mlv-data-table__columns-dropdown{display:flex;flex-direction:column;gap:.25rem;padding:.5rem;min-width:10rem}.mlv-data-table__columns-item{display:flex;align-items:center;gap:.5rem;padding:.25rem .5rem;border-radius:var(--mlv-radius-s);cursor:pointer;font-size:var(--mlv-dt-font-size)}.mlv-data-table__columns-item:hover{background:var(--mlv-background-sunken)}.mlv-data-table__foot{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-font-size);background:var(--mlv-background-base)}.mlv-data-table__foot--sticky{position:sticky;bottom:0;z-index:3}.mlv-data-table__foot .mlv-data-table__cell--pinned,.mlv-data-table__row--footer{background:inherit}.mlv-data-table__row--footer>:where(td,th){box-sizing:border-box;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);border-top:.125rem solid var(--mlv-border-normal);border-bottom:0;vertical-align:middle;background:inherit;font-size:inherit;font-weight:inherit}.mlv-data-table__table--bordered .mlv-data-table__row--footer>:where(td,th){border-inline-end:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__table--bordered .mlv-data-table__row--footer>:where(td,th):last-child{border-inline-end:none}.mlv-data-table__footer{padding-top:.75rem}@media(prefers-reduced-motion:reduce){.mlv-data-table,.mlv-data-table *,.mlv-data-table:before,.mlv-data-table:after,[class^=mlv-data-table__],[class*=\" mlv-data-table__\"],[class^=mlv-data-table--],[class*=\" mlv-data-table--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: MlvPagination, selector: "mlv-pagination", inputs: ["id", "mobile", "totalItems", "itemsPerPage", "perPageOptions", "displayTotalItems", "currentPage", "mlvDensity"], outputs: ["itemsPerPageChange", "currentPageChange"] }, { kind: "component", type: MlvSearchField, selector: "mlv-search-field", inputs: ["value", "trigger", "debounce", "placeholder", "ariaLabel", "disabled", "loading", "showSubmit", "clearable", "commitOnClear", "presentation", "overlay", "role", "ariaControls", "ariaActiveDescendant", "ariaAutocomplete", "ariaExpanded"], outputs: ["valueChange", "search", "navigate", "commit"] }, { kind: "component", type: MlvFilterDropdown, selector: "mlv-dt-filter-dropdown", inputs: ["columns", "activeFilters"], outputs: ["activeFiltersChange", "closed"] }, { kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "component", type: MlvBadge, selector: "mlv-badge", inputs: ["tone", "rounded", "muted"] }, { kind: "component", type: LucideArrowUp, selector: "svg[lucideArrowUp]" }, { kind: "component", type: LucideArrowDown, selector: "svg[lucideArrowDown]" }, { kind: "component", type: LucideChevronsUpDown, selector: "svg[lucideChevronsUpDown]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "component", type: LucideFilter, selector: "svg[lucideFunnel], svg[lucideFilter]" }, { kind: "component", type: LucideTable2, selector: "svg[lucideTable2]" }, { kind: "component", type: LucidePencil, selector: "svg[lucidePencil]" }, { kind: "component", type: LucideCheck, selector: "svg[lucideCheck]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucidePlus, selector: "svg[lucidePlus]" }, { kind: "component", type: LucidePin, selector: "svg[lucidePin]" }, { kind: "component", type: LucidePinOff, selector: "svg[lucidePinOff]" }, { kind: "component", type: LucideEye, selector: "svg[lucideEye]" }, { kind: "component", type: LucideTriangleAlert, selector: "svg[lucideTriangleAlert], svg[lucideAlertTriangle]" }, { kind: "component", type: LucideArrowUpDown, selector: "svg[lucideArrowUpDown]" }, { kind: "component", type: MlvEmptyState, selector: "mlv-empty-state" }, { kind: "component", type: MlvLoader, selector: "mlv-loader", inputs: ["variant", "tone", "value", "max", "indeterminate", "size", "strokeWidth", "ariaLabel", "showHint", "color", "trackColor", "glow"] }, { kind: "component", type: MlvCheckbox, selector: "mlv-checkbox", inputs: ["ariaLabelledBy", "checked", "indeterminate", "tabbable"], outputs: ["checkedChange"] }, { kind: "directive", type: MlvPopupTrigger, selector: "[mlvPopupTrigger]", inputs: ["mlvPopupTrigger", "triggerOn", "ariaHasPopup"], exportAs: ["mlvPopupTrigger"] }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "directive", type: MlvInfiniteScroll, selector: "[mlvInfiniteScroll]", inputs: ["threshold", "loading", "hasMore", "disabled", "orientation", "scrollContainer"], outputs: ["loadMore"], exportAs: ["mlvInfiniteScroll"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: Grid, selector: "[ngGrid]", inputs: ["enableSelection", "disabled", "softDisabled", "focusMode", "rowWrap", "colWrap", "multi", "selectionMode", "tabindex"], exportAs: ["ngGrid"] }, { kind: "directive", type: GridRow, selector: "[ngGridRow]", inputs: ["rowIndex"], exportAs: ["ngGridRow"] }, { kind: "directive", type: GridCell, selector: "[ngGridCell]", inputs: ["id", "role", "rowSpan", "colSpan", "rowIndex", "colIndex", "disabled", "selected", "selectable", "tabindex"], outputs: ["selectedChange"], exportAs: ["ngGridCell"] }, { kind: "directive", type: GridCellWidget, selector: "[ngGridCellWidget]", inputs: ["id", "widgetType", "disabled", "focusTarget", "tabindex"], outputs: ["activated", "deactivated"], exportAs: ["ngGridCellWidget"] }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
2621
|
+
}
|
|
2622
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvDataTable, decorators: [{
|
|
2623
|
+
type: Component,
|
|
2624
|
+
args: [{ selector: 'mlv-data-table', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
2625
|
+
NgTemplateOutlet,
|
|
2626
|
+
ScrollingModule,
|
|
2627
|
+
MlvPagination,
|
|
2628
|
+
MlvSearchField,
|
|
2629
|
+
MlvFilterDropdown,
|
|
2630
|
+
MlvButton,
|
|
2631
|
+
MlvBadge,
|
|
2632
|
+
LucideArrowUp,
|
|
2633
|
+
LucideArrowDown,
|
|
2634
|
+
LucideChevronsUpDown,
|
|
2635
|
+
LucideChevronRight,
|
|
2636
|
+
LucideFilter,
|
|
2637
|
+
LucideTable2,
|
|
2638
|
+
LucideFunnel,
|
|
2639
|
+
LucidePencil,
|
|
2640
|
+
LucideCheck,
|
|
2641
|
+
LucideX,
|
|
2642
|
+
LucidePlus,
|
|
2643
|
+
LucidePin,
|
|
2644
|
+
LucidePinOff,
|
|
2645
|
+
LucideEye,
|
|
2646
|
+
LucideTriangleAlert,
|
|
2647
|
+
LucideArrowUpDown,
|
|
2648
|
+
MlvEmptyState,
|
|
2649
|
+
MlvLoader,
|
|
2650
|
+
MlvCheckbox,
|
|
2651
|
+
MlvPopupTrigger,
|
|
2652
|
+
MlvPopup,
|
|
2653
|
+
MlvPopupContent,
|
|
2654
|
+
MlvInfiniteScroll,
|
|
2655
|
+
MlvButtonIcon,
|
|
2656
|
+
Grid,
|
|
2657
|
+
GridRow,
|
|
2658
|
+
GridCell,
|
|
2659
|
+
GridCellWidget,
|
|
2660
|
+
MlvListItem,
|
|
2661
|
+
MlvMenu,
|
|
2662
|
+
MlvMenuItem,
|
|
2663
|
+
MlvMenuTrigger,
|
|
2664
|
+
], providers: [
|
|
2665
|
+
{ provide: MLV_DENSITY_ELEMENT, useValue: 'data-table' },
|
|
2666
|
+
MlvDataTableEditingService,
|
|
2667
|
+
MlvDataTableColumnVisibilityService,
|
|
2668
|
+
MlvDataTablePinningService,
|
|
2669
|
+
], hostDirectives: [
|
|
2670
|
+
{
|
|
2671
|
+
directive: MlvDensityDirective,
|
|
2672
|
+
inputs: ['mlvDensity'],
|
|
2673
|
+
},
|
|
2674
|
+
], host: {
|
|
2675
|
+
class: 'mlv-data-table',
|
|
2676
|
+
}, template: "@if (hasToolbarContent()) {\n<div class=\"mlv-data-table__toolbar\">\n @if (showSearch() && hasSearchableColumns()) {\n <mlv-search-field\n class=\"mlv-data-table__search\"\n [value]=\"_searchDraft()\"\n (valueChange)=\"_searchDraft.set($event)\"\n [trigger]=\"searchTrigger()\"\n [debounce]=\"searchDebounce()\"\n [loading]=\"loading()\"\n [placeholder]=\"_i18n().searchPlaceholder\"\n [ariaLabel]=\"_i18n().searchLabel\"\n (search)=\"onSearch($event)\"\n />\n } @if (filterDisplay() !== 'none' && hasFilters()) {\n <span class=\"mlv-data-table__filter-badge\" aria-live=\"polite\">\n {{ activeFilterLabel() }}\n </span>\n }\n <div class=\"mlv-data-table__toolbar-actions\">\n @if (editable() && addRow()) {\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n (click)=\"onAddRow()\"\n [attr.aria-label]=\"_i18n().addNewRow\"\n >\n <svg lucidePlus mlvButtonIcon [size]=\"14\" />\n {{ _i18n().addRow }}\n </button>\n } @if (showSortMenu() && hasSortableColumns()) {\n <button\n mlvButton\n variant=\"secondary\"\n mlvDensity=\"compact\"\n type=\"button\"\n data-mlv-table-sort-trigger\n [mlvMenuTrigger]=\"sortMenu\"\n [attr.aria-label]=\"_i18n().sortMenu\"\n >\n <svg mlvButtonIcon lucideArrowUpDown [size]=\"14\" />\n {{ _i18n().sort }}\n </button>\n <mlv-menu #sortMenu [label]=\"_i18n().sortMenu\" mlvDensity=\"compact\">\n @for (column of columns(); track column.key) { @if (column.sortable) { @if\n (currentSort()?.key === column.key) {\n <mlv-list-item\n mlvMenuItem\n [mlvMenuTrigger]=\"directionMenu\"\n [isSubmenuTrigger]=\"true\"\n >\n {{ column.title ?? column.key }}\n </mlv-list-item>\n <mlv-menu\n #directionMenu\n [label]=\"getSortLabel(column)\"\n mlvDensity=\"compact\"\n >\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'asc')\">\n {{ _i18n().ascending }}\n </mlv-list-item>\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'desc')\">\n {{ _i18n().descending }}\n </mlv-list-item>\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, null)\">\n {{ _i18n().clearSort }}\n </mlv-list-item>\n </mlv-menu>\n } @else {\n <mlv-list-item mlvMenuItem (itemClick)=\"_applyMenuSort(column, 'asc')\">\n {{ column.title ?? column.key }}\n </mlv-list-item>\n } } }\n </mlv-menu>\n } @if (hasHideableColumns()) {\n <button\n mlvButton\n [variant]=\"columnsPopup.opened() ? 'primary' : 'secondary'\"\n mlvDensity=\"compact\"\n type=\"button\"\n [mlvPopupTrigger]=\"columnsPopup\"\n #columnsTrigger=\"mlvPopupTrigger\"\n [attr.aria-label]=\"_i18n().toggleColumnVisibility\"\n >\n <svg mlvButtonIcon lucideEye [size]=\"14\" />\n {{ _i18n().columns }}\n </button>\n\n <mlv-popup #columnsPopup>\n <div *mlvPopupContent class=\"mlv-data-table__columns-dropdown\">\n @for (col of allColumns(); track col.key) { @if (col.hideable) {\n <div class=\"mlv-data-table__columns-item\">\n <mlv-checkbox\n [checked]=\"!isColumnHidden(col.key)\"\n [ariaLabel]=\"col.title ?? col.key\"\n (checkedChange)=\"toggleColumnVisibility(col.key)\"\n />\n <span>{{ col.title ?? col.key }}</span>\n </div>\n } }\n </div>\n </mlv-popup>\n } @if (filterDisplay() === 'toolbar' && hasFilterableColumns()) {\n <button\n #filterBtn\n mlvButton\n [variant]=\"filtersPopup.opened() ? 'primary' : 'secondary'\"\n mlvDensity=\"compact\"\n type=\"button\"\n [mlvPopupTrigger]=\"filtersPopup\"\n #trigger=\"mlvPopupTrigger\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_i18n().toggleFilters\"\n >\n <svg lucideFilter mlvButtonIcon [size]=\"14\" />\n {{ _i18n().filters }} @if (hasFilters()) {\n <mlv-badge tone=\"primary\" rounded>{{ activeFilters().length }}</mlv-badge>\n }\n </button>\n\n <mlv-popup\n #filtersPopup\n panelRole=\"dialog\"\n [ariaLabel]=\"_i18n().filters\"\n (afterClosed)=\"_onFiltersClosed()\"\n >\n <mlv-dt-filter-dropdown\n *mlvPopupContent\n [columns]=\"columns()\"\n [(activeFilters)]=\"activeFilters\"\n (closed)=\"trigger.close()\"\n />\n </mlv-popup>\n } @if (_toolbarActions(); as actions) {\n <ng-container [ngTemplateOutlet]=\"actions.templateRef\" />\n }\n </div>\n</div>\n}\n\n<div\n class=\"mlv-data-table__wrapper\"\n [class.mlv-data-table__wrapper--virtual]=\"virtualScroll()\"\n [style.max-height]=\"virtualScroll() ? null : maxHeight()\"\n [style.--mlv-dt-virtual-scrollbar-gutter]=\"\n virtualScroll() ? _virtualScrollbarGutter() + 'px' : null\n \"\n #tableWrapper\n mlvInfiniteScroll\n [disabled]=\"paginationMode() !== 'infinite' || virtualScroll()\"\n [threshold]=\"infiniteScrollThreshold()\"\n [loading]=\"!!loading()\"\n [hasMore]=\"!!hasMore()\"\n (loadMore)=\"onInfiniteScrollLoadMore($event)\"\n>\n @if (virtualScroll()) {\n <!-- ==================== Virtual scroll mode ==================== -->\n <!-- Header table \u2014 sits naturally at the top of the wrapper, outside the viewport -->\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-header\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.flex]=\"resizedTableWidth() === null ? null : '0 0 auto'\"\n role=\"grid\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead class=\"mlv-data-table__head\">\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n </table>\n\n <!-- CDK virtual scroll viewport \u2014 owns the only vertical scroll surface in this mode.\n Infinite scroll is intentionally disabled in virtual mode: virtual scrolling is the\n rendering optimisation for already-loaded data, and the two strategies are mutually\n exclusive in this component. -->\n <cdk-virtual-scroll-viewport\n class=\"mlv-data-table__virtual-viewport\"\n [itemSize]=\"rowHeight()\"\n [style.height]=\"virtualViewportHeight()\"\n >\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-body\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n role=\"presentation\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else {\n <tr\n *cdkVirtualFor=\"\n let row of flatRows();\n let i = index;\n trackBy: trackByRow\n \"\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [style.height.px]=\"rowHeight()\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.tabindex]=\"_rowTabIndex(i)\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n (focus)=\"_onRowFocus(i)\"\n (keydown)=\"_onRowKeydown(i, row, $event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowCellsTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </tr>\n }\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n <!-- Footer summary table \u2014 only when a footer template is projected -->\n @if (getFooterTemplate(); as footerTpl) {\n <table\n class=\"mlv-data-table__table mlv-data-table__table--virtual mlv-data-table__table--virtual-footer\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.flex]=\"resizedTableWidth() === null ? null : '0 0 auto'\"\n role=\"presentation\"\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <tfoot class=\"mlv-data-table__foot\">\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n </table>\n }\n\n <!-- Extends only the outer horizontal scroll range to match the viewport's\n native range, including a classic vertical scrollbar gutter. -->\n <div\n class=\"mlv-data-table__virtual-horizontal-sizer\"\n [style.width.px]=\"_virtualHorizontalScrollExtent()\"\n aria-hidden=\"true\"\n ></div>\n } @else if (_cellNav()) {\n <!-- ========= Experimental cell-level grid navigation (aria ngGrid) ========= -->\n <!--\n Opt-in via [cellNavigation]=\"true\" (non-virtual only). The aria Grid pattern owns\n roving focus, arrow/Home/End navigation across cells, and aria-activedescendant.\n Only the data <tbody> rows/cells are registered as grid rows/cells; header cells\n stay outside grid navigation. Interactive cells (edit inputs, action buttons)\n expose an ngGridCellWidget so Enter pauses grid nav to interact and Escape resumes.\n -->\n <table\n ngGrid\n rowWrap=\"nowrap\"\n colWrap=\"nowrap\"\n class=\"mlv-data-table__table\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.table-layout]=\"resizedTableWidth() === null ? null : 'fixed'\"\n role=\"grid\"\n #tableEl\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead\n class=\"mlv-data-table__head\"\n [class.mlv-data-table__head--sticky]=\"stickyHeader()\"\n >\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else { @for (row of flatRows(); track $index; let i = $index) {\n <tr\n ngGridRow\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n >\n @if (selectable()) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <mlv-checkbox\n [checked]=\"isRowSelected(row)\"\n [tabbable]=\"false\"\n (checkedChange)=\"toggleRowSelection(row)\"\n (click)=\"$event.stopPropagation()\"\n [ariaLabel]=\"'Select row ' + (i + 1)\"\n />\n </td>\n } @for (col of visibleColumns(); track col.key; let ci = $index) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n >\n @if ( editable() && isEditing(i) && getEditTemplate(col.key); as\n editTpl ) {\n <div\n ngGridCellWidget\n widgetType=\"editable\"\n class=\"mlv-data-table__cell-content\"\n >\n <ng-container\n [ngTemplateOutlet]=\"editTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"cellContentTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n index: i,\n col: col,\n ci: ci,\n }\"\n />\n }\n </td>\n } @if (editable()) {\n <td\n ngGridCell\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <div\n ngGridCellWidget\n widgetType=\"complex\"\n class=\"mlv-data-table__cell-content mlv-data-table__actions\"\n >\n <ng-container\n [ngTemplateOutlet]=\"actionsButtonsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n />\n </div>\n </td>\n }\n </tr>\n } }\n </tbody>\n\n @if (getFooterTemplate(); as footerTpl) {\n <tfoot\n class=\"mlv-data-table__foot\"\n [class.mlv-data-table__foot--sticky]=\"stickyHeader()\"\n >\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n }\n </table>\n\n @if (paginationMode() === 'infinite' && loading()) {\n <div\n class=\"mlv-data-table__loading-bottom\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"24\"\n ariaLabel=\"Loading more rows\"\n />\n </div>\n } } @else {\n <!-- ==================== Standard (non-virtual) mode ==================== -->\n <table\n class=\"mlv-data-table__table\"\n [class.mlv-data-table__table--striped]=\"striped()\"\n [class.mlv-data-table__table--bordered]=\"bordered()\"\n [style.width.px]=\"resizedTableWidth()\"\n [style.table-layout]=\"resizedTableWidth() === null ? null : 'fixed'\"\n role=\"grid\"\n #tableEl\n >\n <ng-container [ngTemplateOutlet]=\"colgroupTpl\" />\n <thead\n class=\"mlv-data-table__head\"\n [class.mlv-data-table__head--sticky]=\"stickyHeader()\"\n >\n <ng-container [ngTemplateOutlet]=\"headRowsTpl\" />\n </thead>\n\n <tbody class=\"mlv-data-table__body\">\n @if (showError()) {\n <ng-container [ngTemplateOutlet]=\"errorRowTpl\" />\n } @else if (flatRows().length === 0) {\n <ng-container [ngTemplateOutlet]=\"noDataRowTpl\" />\n } @else { @for (row of flatRows(); track $index; let i = $index) {\n <tr\n class=\"mlv-data-table__row mlv-data-table__row--data\"\n [class.mlv-data-table__row--expanded]=\"isRowExpanded(row)\"\n [class.mlv-data-table__row--editing]=\"isEditing(i)\"\n [class.mlv-data-table__row--selected]=\"isRowSelected(row)\"\n [attr.aria-level]=\"getDepth(row) > 0 ? getDepth(row) + 1 : null\"\n [attr.aria-selected]=\"selectable() ? isRowSelected(row) : null\"\n [attr.tabindex]=\"_rowTabIndex(i)\"\n [attr.data-row-index]=\"i\"\n (click)=\"onRowClick(row, i, $event)\"\n (focus)=\"_onRowFocus(i)\"\n (keydown)=\"_onRowKeydown(i, row, $event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowCellsTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n </tr>\n } }\n </tbody>\n\n @if (getFooterTemplate(); as footerTpl) {\n <tfoot\n class=\"mlv-data-table__foot\"\n [class.mlv-data-table__foot--sticky]=\"stickyHeader()\"\n >\n <tr class=\"mlv-data-table__row mlv-data-table__row--footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleColumns() }\"\n />\n </tr>\n </tfoot>\n }\n </table>\n\n @if (paginationMode() === 'infinite' && loading()) {\n <div\n class=\"mlv-data-table__loading-bottom\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"24\"\n ariaLabel=\"Loading more rows\"\n />\n </div>\n } }\n</div>\n\n@if (paginationMode() === 'paged' && !virtualScroll()) {\n<div class=\"mlv-data-table__footer\">\n <mlv-pagination\n [totalItems]=\"totalItems()\"\n [currentPage]=\"currentPage()\"\n [itemsPerPage]=\"currentPerPage()\"\n (currentPageChange)=\"_onPageChange($event)\"\n (itemsPerPageChange)=\"_onPerPageChange($event)\"\n />\n</div>\n} @if (paginationMode() === 'paged' && loading()) {\n<div\n class=\"mlv-data-table__loading-overlay\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n>\n <mlv-loader\n variant=\"circle\"\n [indeterminate]=\"true\"\n [size]=\"48\"\n ariaLabel=\"Loading table data\"\n />\n</div>\n}\n\n<!-- ==================== Reusable templates ==================== -->\n\n<!--\n Shared <colgroup> template \u2014 used by both the standard table and the three split tables in\n virtual mode (header / body / footer). Keeping the colgroup definitions identical and combining\n it with `table-layout: fixed` keeps column widths in sync between the split tables in virtual mode.\n-->\n<ng-template #colgroupTpl>\n <colgroup>\n @if (selectable() === 'multi' || selectable() === 'single') {\n <col\n class=\"mlv-data-table__col--select\"\n [style.width]=\"getAuxiliaryColumnWidth('selection')\"\n />\n } @for (col of visibleColumns(); track col.key) {\n <col [style.width]=\"getColWidth(col)\" />\n } @if (editable()) {\n <col\n class=\"mlv-data-table__col--actions\"\n [style.width]=\"getAuxiliaryColumnWidth('actions')\"\n />\n }\n </colgroup>\n</ng-template>\n\n<!-- Header rows \u2014 emits the same content the original `<thead>` did. -->\n<ng-template #headRowsTpl>\n @if (hasColumnGroups()) {\n <!-- Group header row -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--group-header\">\n @if (selectable() === 'multi') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n rowspan=\"2\"\n >\n <mlv-checkbox\n [checked]=\"allRowsSelected()\"\n [indeterminate]=\"someRowsSelected()\"\n (checkedChange)=\"toggleSelectAll()\"\n [ariaLabel]=\"_i18n().selectAllRows\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n rowspan=\"2\"\n ></th>\n } @for (col of visibleColumns(); track col.key) { @if (headerLayout(); as\n layout) { @if (layout.standaloneKeys.has(col.key)) {\n <!-- Standalone column spans both header rows -->\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--standalone\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n rowspan=\"2\"\n scope=\"col\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } @else {\n <!-- Check if this column is the first column of a group -->\n @for (group of columnGroups(); track group.title) { @if (group.columns[0]\n === col.key) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--group-header\"\n [class.mlv-data-table__cell--align-left]=\"\n group.align === 'left'\n \"\n [class.mlv-data-table__cell--align-center]=\"\n group.align === 'center' || !group.align\n \"\n [class.mlv-data-table__cell--align-right]=\"\n group.align === 'right'\n \"\n [attr.colspan]=\"group.columns.length\"\n scope=\"colgroup\"\n >\n {{ group.title }}\n </th>\n } } } } } @if (editable()) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n rowspan=\"2\"\n >\n <span class=\"mlv-data-table__visually-hidden\"\n >{{ actionsHeaderLabel() }}</span\n >\n </th>\n }\n </tr>\n <!-- Sub-header row for grouped columns -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--header\">\n @for (col of visibleColumns(); track col.key) { @if (headerLayout(); as\n layout) { @if (layout.groupedKeys.has(col.key)) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n scope=\"col\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } } }\n </tr>\n } @else {\n <!-- Standard single-row header -->\n <tr class=\"mlv-data-table__row mlv-data-table__row--header\">\n @if (selectable() === 'multi') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <mlv-checkbox\n [checked]=\"allRowsSelected()\"\n [indeterminate]=\"someRowsSelected()\"\n (checkedChange)=\"toggleSelectAll()\"\n [ariaLabel]=\"_i18n().selectAllRows\"\n />\n </th>\n } @else if (selectable() === 'single') {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n ></th>\n } @for (col of visibleColumns(); track col.key) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header\"\n [class.mlv-data-table__cell--sortable]=\"col.sortable\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n [attr.data-mlv-column-key]=\"col.key\"\n [attr.aria-sort]=\"\n col.sortable\n ? getSortDirection(col) === 'asc'\n ? 'ascending'\n : getSortDirection(col) === 'desc'\n ? 'descending'\n : 'none'\n : null\n \"\n scope=\"col\"\n >\n <ng-container\n [ngTemplateOutlet]=\"headerCellInnerTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n </th>\n } @if (editable()) {\n <th\n class=\"mlv-data-table__cell mlv-data-table__cell--header mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <span class=\"mlv-data-table__visually-hidden\"\n >{{ actionsHeaderLabel() }}</span\n >\n </th>\n }\n </tr>\n }\n</ng-template>\n\n<!--\n Shared inner content for a single header cell. Context: { $implicit: col }.\n Sortable columns wrap the label + sort icon in ONE native <button> (APG grid\n sort pattern) so the <th> stays a non-interactive cell carrying only aria-sort;\n the pin button is a sibling of the sort button, never nested inside it, so no\n interactive control is nested within another (avoids axe `nested-interactive`).\n-->\n<ng-template #headerCellInnerTpl let-col>\n <div class=\"mlv-data-table__cell-inner\">\n @if (col.sortable) {\n <button\n type=\"button\"\n class=\"mlv-data-table__sort-button\"\n [attr.aria-label]=\"getSortLabel(col)\"\n (click)=\"onSortClick(col)\"\n >\n <span class=\"mlv-data-table__header-title\"\n >{{ col.title ?? col.key }}</span\n >\n <span class=\"mlv-data-table__sort-icon\" aria-hidden=\"true\">\n @if (getSortDirection(col) === 'asc') {\n <svg lucideArrowUp />\n } @else if (getSortDirection(col) === 'desc') {\n <svg lucideArrowDown />\n } @else {\n <svg lucideChevronsUpDown class=\"mlv-data-table__sort-icon--inactive\" />\n }\n </span>\n </button>\n } @else {\n <span class=\"mlv-data-table__header-title\">{{ col.title ?? col.key }}</span>\n } @if (col.pinnable) {\n <ng-container\n [ngTemplateOutlet]=\"pinButtonTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: col }\"\n />\n } @if (filterDisplay() === 'column' && col.filterable) {\n <button\n mlvButton\n class=\"mlv-data-table__column-filter\"\n [class.mlv-data-table__column-filter--active]=\"\n isColumnFiltered(col.key)\n \"\n [variant]=\"\n columnFilterPopup.opened() || isColumnFiltered(col.key)\n ? 'primary'\n : 'transparent'\n \"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n [attr.data-column-key]=\"col.key\"\n [mlvPopupTrigger]=\"columnFilterPopup\"\n #columnFilterTrigger=\"mlvPopupTrigger\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"getFilterLabel(col)\"\n >\n <svg lucideFunnel mlvButtonIcon [size]=\"14\" />\n </button>\n\n <mlv-popup\n #columnFilterPopup\n panelRole=\"dialog\"\n [ariaLabel]=\"getFilterLabel(col)\"\n (afterClosed)=\"focusColumnFilterTrigger(col.key)\"\n >\n <mlv-dt-filter-dropdown\n *mlvPopupContent\n [columns]=\"getColumnFilterColumns(col)\"\n [activeFilters]=\"activeFilters()\"\n (activeFiltersChange)=\"onColumnFiltersChange(col.key, $event)\"\n (closed)=\"columnFilterTrigger.close()\"\n />\n </mlv-popup>\n }\n </div>\n @if (col.resizable) {\n <div\n #resizeHandle\n class=\"mlv-data-table__resize-handle\"\n [attr.data-column-key]=\"col.key\"\n role=\"separator\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n [attr.aria-label]=\"getColumnResizeLabel(col)\"\n [attr.aria-valuenow]=\"getColumnResizeValue(col)\"\n [attr.aria-valuemin]=\"getColumnResizeMin(col)\"\n [attr.aria-valuemax]=\"getColumnResizeMax(col)\"\n [attr.aria-valuetext]=\"getColumnResizeValueText(col)\"\n (pointerdown)=\"onResizeStart(col, $event)\"\n (keydown)=\"onColumnResizeKeydown(col, $event)\"\n (dblclick)=\"resetColumnWidth(col.key)\"\n ></div>\n }\n</ng-template>\n\n<!-- No-data fallback row, used by both rendering paths. -->\n<ng-template #noDataRowTpl>\n <tr class=\"mlv-data-table__row mlv-data-table__row--no-data\">\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--no-data\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n @if (getNoDataTemplate()) {\n <ng-container [ngTemplateOutlet]=\"getNoDataTemplate()!\" />\n } @else {\n <div class=\"mlv-data-table__no-data-default\">\n <svg lucideTable2 [size]=\"40\" aria-hidden=\"true\" />\n <span>No data available</span>\n </div>\n }\n </td>\n </tr>\n</ng-template>\n\n<!--\n Failed-request row, used by all three rendering paths. Takes precedence over both the\n data rows and #noDataRowTpl so a failed request never reads as an empty result set.\n The region is announced as an alert; the default block is an mlv-empty-state with a\n danger-toned icon and a Retry button wired to the (retry) output.\n-->\n<ng-template #errorRowTpl>\n <tr class=\"mlv-data-table__row mlv-data-table__row--error\">\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--error\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n <div class=\"mlv-data-table__error\" role=\"alert\" aria-live=\"assertive\">\n @if (getErrorTemplate(); as errorTpl) {\n <ng-container\n [ngTemplateOutlet]=\"errorTpl\"\n [ngTemplateOutletContext]=\"_errorContext()\"\n />\n } @else {\n <mlv-empty-state>\n <svg\n mlvEmptyStateIcon\n lucideTriangleAlert\n class=\"mlv-data-table__error-icon\"\n [size]=\"40\"\n aria-hidden=\"true\"\n />\n <span mlvEmptyStateTitle>{{ _i18n().errorTitle }}</span>\n <span mlvEmptyStateDescription>{{ errorMessage() }}</span>\n <button\n mlvEmptyStateActions\n mlvButton\n variant=\"secondary\"\n type=\"button\"\n class=\"mlv-data-table__error-retry\"\n (click)=\"onRetry()\"\n >\n {{ _i18n().retry }}\n </button>\n </mlv-empty-state>\n }\n </div>\n </td>\n </tr>\n</ng-template>\n\n<!--\n Per-row data cells. Emits the selection cell, the data cells, and the actions cell.\n The owning <tr> stays at the consumer site (either inside `@for` for the standard mode\n or `*cdkVirtualFor` inside the CDK viewport in virtual mode), so each rendering path can\n control its own row-level host bindings.\n-->\n<ng-template #rowCellsTpl let-row let-i=\"index\">\n @if (selectable()) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--select\"\n [style]=\"getAuxiliaryColumnStyle('selection')\"\n >\n <!--\n [tabbable]=\"false\" keeps this checkbox out of the tab order so the row is\n the single tab stop: the row's Space/Enter toggles selection, and the\n checkbox stays operable via the mouse. Avoids a per-row double tab stop.\n -->\n <mlv-checkbox\n [checked]=\"isRowSelected(row)\"\n [tabbable]=\"false\"\n (checkedChange)=\"toggleRowSelection(row)\"\n (click)=\"$event.stopPropagation()\"\n [ariaLabel]=\"'Select row ' + (i + 1)\"\n />\n </td>\n } @for (col of visibleColumns(); track col.key; let ci = $index) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data\"\n [class.mlv-data-table__cell--pinned]=\"col.pinned\"\n [class.mlv-data-table__cell--pinned-left]=\"\n col.pinned && col.pinSide !== 'right'\n \"\n [class.mlv-data-table__cell--pinned-right]=\"\n col.pinned && col.pinSide === 'right'\n \"\n [class]=\"getAlignClass(col)\"\n [style]=\"getCellStyle(col)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"cellContentTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n index: i,\n col: col,\n ci: ci,\n }\"\n />\n </td>\n } @if (editable()) {\n <td\n class=\"mlv-data-table__cell mlv-data-table__cell--data mlv-data-table__cell--actions\"\n [style]=\"getAuxiliaryColumnStyle('actions')\"\n >\n <div class=\"mlv-data-table__cell-content mlv-data-table__actions\">\n <ng-container\n [ngTemplateOutlet]=\"actionsButtonsTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\n />\n </div>\n </td>\n }\n</ng-template>\n\n<!--\n Shared edit/save/cancel action buttons for the actions column. Context: { $implicit: row, index: i }.\n-->\n<ng-template #actionsButtonsTpl let-row let-i=\"index\">\n @if (isEditing(i)) {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"saveEdit(row, i)\"\n [attr.aria-label]=\"_i18n().saveChanges\"\n >\n <svg lucideCheck mlvButtonIcon />\n </button>\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"cancelEdit(row, i)\"\n [attr.aria-label]=\"_i18n().cancelEditing\"\n >\n <svg lucideX mlvButtonIcon />\n </button>\n } @else {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n (click)=\"startEdit(row, i)\"\n [attr.aria-label]=\"_i18n().editRow\"\n >\n <svg lucidePencil mlvButtonIcon />\n </button>\n }\n</ng-template>\n\n<!--\n Shared inner content of a data cell (indent, expand button, edit/display template, raw value).\n Extracted so both the standard `#rowCellsTpl` `<td>` and the experimental cell-navigation grid\n `<td ngGridCell>` render identical content. Purely presentational \u2014 contains no aria grid\n directives \u2014 so it is safe to project via ngTemplateOutlet across the grid-cell boundary.\n Context: { $implicit: row, index: i, col, ci }.\n-->\n<ng-template #cellContentTpl let-row let-i=\"index\" let-col=\"col\" let-ci=\"ci\">\n <div class=\"mlv-data-table__cell-content\">\n @if (ci === 0 && getDepth(row) > 0) {\n <span\n class=\"mlv-data-table__indent\"\n [style.padding-left.rem]=\"getDepth(row) * 1.25\"\n aria-hidden=\"true\"\n ></span>\n } @if (ci === 0 && hasChildren(row)) {\n <button\n mlvButton\n variant=\"transparent\"\n shape=\"square\"\n mlvDensity=\"tight\"\n type=\"button\"\n class=\"mlv-data-table__expand-btn\"\n (click)=\"toggleExpand(row, $event)\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n [attr.aria-label]=\"\n isRowExpanded(row) ? _i18n().collapseRow : _i18n().expandRow\n \"\n >\n <svg\n lucideChevronRight\n mlvButtonIcon\n class=\"mlv-data-table__expand-icon\"\n [class.mlv-data-table__expand-icon--open]=\"isRowExpanded(row)\"\n />\n </button>\n } @if (editable() && isEditing(i) && getEditTemplate(col.key); as editTpl) {\n <ng-container\n [ngTemplateOutlet]=\"editTpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n } @else if (getTemplate(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"getCellContext(row, i)\"\n />\n } @else {\n <!--\n Default cell renderer. `valueLabels` (or the `filterConfig.options` fallback)\n maps the raw value to a label; `tone` promotes the cell to a muted badge.\n -->\n @if (getCellTone(row, col); as tone) {\n <mlv-badge [tone]=\"tone\" muted\n >{{ getCellDisplayValue(row, col) }}</mlv-badge\n >\n } @else { {{ getCellDisplayValue(row, col) }} } }\n </div>\n</ng-template>\n\n<!-- Reusable pin button template. Rendered via ngTemplateOutlet from every header cell that supports pinning. -->\n<ng-template #pinButtonTpl let-col>\n @if (getPinnableSides(col); as sides) { @if (sides.length > 1) {\n <button\n class=\"mlv-data-table__pin-btn\"\n [class.mlv-data-table__pin-btn--active]=\"isColumnPinned(col)\"\n type=\"button\"\n [mlvPopupTrigger]=\"pinPopup\"\n #pinTrigger=\"mlvPopupTrigger\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"\n isColumnPinned(col) ? _i18n().changePinSide : _i18n().pinColumn\n \"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"pinPopup.opened()\"\n [attr.aria-pressed]=\"isColumnPinned(col)\"\n >\n @if (isColumnPinned(col)) {\n <svg lucidePinOff />\n } @else {\n <svg lucidePin />\n }\n </button>\n <mlv-popup #pinPopup>\n <div *mlvPopupContent class=\"mlv-data-table__pin-popup\" role=\"menu\">\n @for (side of sides; track side) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n class=\"mlv-data-table__pin-popup-item\"\n [class.mlv-data-table__pin-popup-item--active]=\"\n getColumnPinSide(col) === side\n \"\n [attr.aria-checked]=\"getColumnPinSide(col) === side\"\n (click)=\"\n pinTo(col, side); pinTrigger.close(); $event.stopPropagation()\n \"\n >\n <svg lucidePin [size]=\"14\" />\n @if (side === 'left') {\n <span>Pin left</span>\n } @else {\n <span>Pin right</span>\n }\n </button>\n } @if (isColumnPinned(col)) {\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"mlv-data-table__pin-popup-item mlv-data-table__pin-popup-item--unpin\"\n (click)=\"unpin(col); pinTrigger.close(); $event.stopPropagation()\"\n >\n <svg lucidePinOff [size]=\"14\" />\n <span>{{ _i18n().unpin }}</span>\n </button>\n }\n </div>\n </mlv-popup>\n } @else {\n <button\n class=\"mlv-data-table__pin-btn\"\n [class.mlv-data-table__pin-btn--active]=\"isColumnPinned(col)\"\n type=\"button\"\n (click)=\"togglePin(col, sides[0]); $event.stopPropagation()\"\n [attr.aria-label]=\"\n isColumnPinned(col) ? _i18n().unpinColumn : _i18n().pinColumn\n \"\n [attr.aria-pressed]=\"isColumnPinned(col)\"\n >\n @if (isColumnPinned(col)) {\n <svg lucidePinOff />\n } @else {\n <svg lucidePin />\n }\n </button>\n } }\n</ng-template>\n", styles: ["@layer mlv.components{.mlv-data-table{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-dt-font-size)}.mlv-data-table *{box-sizing:border-box}.mlv-data-table{--mlv-dt-row-height: calc(var(--mlv-height-m) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.25rem;--mlv-dt-header-height: 3rem;--mlv-dt-font-size: var(--mlv-font-size-m);--mlv-dt-header-font-size: var(--mlv-font-size-m);--mlv-dt-icon-size: 1rem;--mlv-dt-toolbar-gap: .5rem;--mlv-dt-toolbar-padding: .75rem 0;display:flex;flex-direction:column;width:100%;position:relative;color:var(--mlv-text-primary)}[class*=--tight] .mlv-data-table:not([class*=--compact],[class*=--comfortable],[class*=--spacious],[class*=--airy]),.mlv-data-table[class*=--tight]{--mlv-dt-row-height: calc(var(--mlv-height-xs) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: .75rem;--mlv-dt-header-height: 2.25rem;--mlv-dt-font-size: var(--mlv-font-size-s);--mlv-dt-header-font-size: var(--mlv-font-size-s);--mlv-dt-icon-size: .75rem;--mlv-dt-toolbar-gap: .25rem;--mlv-dt-toolbar-padding: .375rem 0}[class*=--compact] .mlv-data-table:not([class*=--tight],[class*=--comfortable],[class*=--spacious],[class*=--airy]),.mlv-data-table[class*=--compact]{--mlv-dt-row-height: calc(var(--mlv-height-s) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1rem;--mlv-dt-header-height: 2.5rem;--mlv-dt-font-size: var(--mlv-font-size-s);--mlv-dt-header-font-size: var(--mlv-font-size-s);--mlv-dt-icon-size: .875rem;--mlv-dt-toolbar-gap: .375rem;--mlv-dt-toolbar-padding: .5rem 0}[class*=--spacious] .mlv-data-table:not([class*=--tight],[class*=--compact],[class*=--comfortable],[class*=--airy]),.mlv-data-table[class*=--spacious]{--mlv-dt-row-height: calc(var(--mlv-height-l) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.5rem;--mlv-dt-header-height: 3.25rem;--mlv-dt-font-size: var(--mlv-font-size-l);--mlv-dt-header-font-size: var(--mlv-font-size-l);--mlv-dt-icon-size: 1.125rem;--mlv-dt-toolbar-gap: .75rem;--mlv-dt-toolbar-padding: .75rem 0}[class*=--airy] .mlv-data-table:not([class*=--tight],[class*=--compact],[class*=--comfortable],[class*=--spacious]),.mlv-data-table[class*=--airy]{--mlv-dt-row-height: calc(var(--mlv-height-xl) + var(--mlv-spacing-4));--mlv-dt-cell-padding-x: 1.75rem;--mlv-dt-header-height: 3.75rem;--mlv-dt-font-size: var(--mlv-font-size-l);--mlv-dt-header-font-size: var(--mlv-font-size-l);--mlv-dt-icon-size: 1.25rem;--mlv-dt-toolbar-gap: 1rem;--mlv-dt-toolbar-padding: 1rem 0}.mlv-data-table__toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:var(--mlv-dt-toolbar-gap);padding:var(--mlv-dt-toolbar-padding);position:relative}.mlv-data-table__search{flex:1 1 16rem;width:min(100%,24rem);max-width:24rem}.mlv-data-table__toolbar-actions{display:flex;gap:var(--mlv-dt-toolbar-gap);margin-inline-start:auto}.mlv-data-table__filter-badge{font-size:var(--mlv-dt-font-size);color:var(--mlv-text-secondary)}.mlv-data-table__wrapper{width:100%;overflow-x:auto;overflow-y:auto;position:relative}.mlv-data-table__wrapper--virtual{overflow-y:visible;display:flex;flex-direction:column}.mlv-data-table__virtual-viewport{display:block;width:100%;min-width:0;max-width:100%;flex:0 0 auto;position:sticky;inset-inline-start:0;border-bottom:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__virtual-viewport.cdk-virtual-scrollable{overflow-x:hidden;overflow-y:auto}.mlv-data-table__virtual-horizontal-sizer{width:0;height:0;min-height:0;flex:0 0 0;align-self:flex-start;pointer-events:none}.mlv-data-table__table--virtual-header,.mlv-data-table__table--virtual-footer{--mlv-dt-pinned-right-correction: var( --mlv-dt-virtual-scrollbar-gutter, 0px )}.mlv-data-table__loading-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--mlv-background-base) 70%,transparent);-webkit-backdrop-filter:blur(.0625rem);backdrop-filter:blur(.0625rem);z-index:20;pointer-events:all}.mlv-data-table__loading-bottom{display:flex;align-items:center;justify-content:center;padding:1rem 0;color:var(--mlv-text-secondary)}.mlv-data-table__table{width:100%;border-collapse:collapse;table-layout:auto;font-size:var(--mlv-dt-font-size);color:var(--mlv-text-primary)}.mlv-data-table__table--striped .mlv-data-table__row--data:nth-child(2n){background:var(--mlv-background-sunken)}.mlv-data-table__table--striped .mlv-data-table__row--data:nth-child(2n) .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__table--bordered .mlv-data-table__cell{border-inline-end:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__table--bordered .mlv-data-table__cell:last-child{border-inline-end:none}.mlv-data-table__table--virtual{table-layout:fixed}.mlv-data-table__head--sticky{position:sticky;top:var(--mlv-dt-sticky-top, 0);z-index:3;background:var(--mlv-background-base)}.mlv-data-table__head--sticky .mlv-data-table__cell--pinned{z-index:4}.mlv-data-table__cell{padding:0;border-bottom:.0625rem solid var(--mlv-border-subtle);vertical-align:middle;background:inherit}.mlv-data-table__cell-content{display:flex;align-items:center;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.mlv-data-table__cell--header{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-header-font-size);color:color-mix(in srgb,var(--mlv-text-action) 65%,var(--mlv-text-secondary));position:relative;-webkit-user-select:none;user-select:none;border-bottom:.0625rem solid var(--mlv-border-normal)}.mlv-data-table__cell--sortable{cursor:pointer}.mlv-data-table__cell--sortable:hover .mlv-data-table__cell-inner{color:var(--mlv-text-action)}.mlv-data-table__cell--data{padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-row-height);font-size:var(--mlv-dt-font-size)}.mlv-data-table__cell--pinned{background:var(--mlv-background-base);z-index:1;transition:background var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__cell--pinned:after{content:\"\";position:absolute;top:0;bottom:0;width:.5rem;pointer-events:none}.mlv-data-table__cell--pinned-left:after{inset-inline-end:-.5rem;background:linear-gradient(to right,rgba(0,0,0,.04),transparent)}.mlv-data-table__cell--pinned-right:after{inset-inline-start:-.5rem;background:linear-gradient(to left,rgba(0,0,0,.04),transparent)}.mlv-data-table__cell--no-data,.mlv-data-table__cell--error{padding:3rem var(--mlv-dt-cell-padding-x);text-align:center}.mlv-data-table__cell--align-left{text-align:start}.mlv-data-table__cell--align-center{text-align:center}.mlv-data-table__cell--align-right{text-align:end}.mlv-data-table__cell-inner{display:flex;align-items:center;gap:.375rem;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);transition:color var(--mlv-duration-normal) var(--mlv-ease-default);border-radius:var(--mlv-radius-s)}.mlv-data-table__sort-button{display:inline-flex;align-items:center;gap:.375rem;flex:1;min-width:0;margin:0;padding:0;border:none;background:none;font:inherit;color:inherit;text-align:start;cursor:pointer;border-radius:var(--mlv-radius-s)}.mlv-data-table__sort-button:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-focus-ring-offset)}.mlv-data-table__visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-1px}.mlv-data-table__header-title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start}.mlv-data-table__column-filter{flex:0 0 auto}.mlv-data-table__column-filter--active{color:var(--mlv-text-action)}.mlv-data-table__sort-icon{display:inline-flex;flex-shrink:0;color:var(--mlv-text-action)}.mlv-data-table__sort-icon svg{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size)}.mlv-data-table__sort-icon--inactive{opacity:0;transition:opacity var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__cell--sortable:hover .mlv-data-table__sort-icon--inactive{opacity:.5}.mlv-data-table__pin-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;background:none;cursor:pointer;color:var(--mlv-text-tertiary);opacity:0;transition:opacity var(--mlv-duration-normal) var(--mlv-ease-default),color var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__pin-btn svg{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size)}.mlv-data-table__cell--header:hover .mlv-data-table__pin-btn{opacity:.6}.mlv-data-table__pin-btn:hover{opacity:1!important;color:var(--mlv-text-action)}.mlv-data-table__pin-btn--active{opacity:1;color:var(--mlv-text-action)}.mlv-data-table__cell--header:hover .mlv-data-table__pin-btn--active{opacity:1}.mlv-data-table__resize-handle{position:absolute;top:0;inset-inline-end:-.5rem;width:1rem;height:100%;cursor:col-resize;background:transparent;z-index:5;touch-action:none;-webkit-user-select:none;user-select:none}.mlv-data-table__resize-handle:after{content:\"\";position:absolute;top:.75rem;bottom:.75rem;left:50%;width:.0625rem;border-radius:var(--mlv-radius-full);background-color:var(--mlv-text-tertiary);transform:translate(-50%);transition:background-color var(--mlv-duration-fast) var(--mlv-ease-default),width var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-data-table__resize-handle:hover:after{width:.125rem;background-color:var(--mlv-background-accent-1)}.mlv-data-table__resize-handle:active:after,.mlv-data-table__resize-handle:focus-visible:after{width:.125rem;background-color:var(--mlv-background-accent-1)}.mlv-data-table__resize-handle:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:calc(var(--mlv-focus-ring-offset) * -1)}@media(pointer:coarse){.mlv-data-table__resize-handle{inset-inline-end:-.75rem;width:1.5rem}}.mlv-data-table__row{transition:background var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__row--data:hover,.mlv-data-table__row--data:hover .mlv-data-table__cell--pinned{background:var(--mlv-background-neutral-1-hover)}.mlv-data-table__row--expanded,.mlv-data-table__row--expanded .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__indent{display:inline-block}.mlv-data-table__expand-btn{margin-inline-end:.25rem;vertical-align:middle;flex-shrink:0}.mlv-data-table__expand-icon{width:var(--mlv-dt-icon-size);height:var(--mlv-dt-icon-size);transition:transform var(--mlv-duration-normal) var(--mlv-ease-default)}.mlv-data-table__expand-icon--open{transform:rotate(90deg)}.mlv-data-table__no-data-default{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:3rem 0;color:var(--mlv-text-secondary)}.mlv-data-table__no-data-default svg{opacity:.2}.mlv-data-table__no-data-default span{font-size:var(--mlv-dt-font-size)}.mlv-data-table__error{display:block;text-align:initial}.mlv-data-table__error-icon{color:var(--mlv-text-negative)}.mlv-data-table__row--group-header .mlv-data-table__cell--group-header{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-header-font-size);color:color-mix(in srgb,var(--mlv-text-action) 65%,var(--mlv-text-secondary));text-align:center;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);border-bottom:.0625rem solid var(--mlv-border-subtle);vertical-align:middle}.mlv-data-table__row--group-header .mlv-data-table__cell--standalone{vertical-align:middle}.mlv-data-table__cell--actions{width:1%;white-space:nowrap;padding:0 var(--mlv-dt-cell-padding-x)!important}.mlv-data-table__actions{display:flex;align-items:center;gap:.25rem;justify-content:flex-end}.mlv-data-table__row--editing,.mlv-data-table__row--editing .mlv-data-table__cell--pinned{background:var(--mlv-background-sunken)}.mlv-data-table__cell--select{width:2.5rem;min-width:2.5rem;max-width:2.5rem;padding:0 .5rem!important;text-align:center}.mlv-data-table__col--select{width:2.5rem}.mlv-data-table__col--actions{width:5rem}.mlv-data-table__row--selected,.mlv-data-table__row--selected .mlv-data-table__cell--pinned{background:color-mix(in srgb,var(--mlv-background-accent-1) 8%,var(--mlv-background-base))}.mlv-data-table__pin-popup{display:flex;flex-direction:column;gap:.125rem;padding:.25rem;min-width:8rem}.mlv-data-table__pin-popup-item{display:flex;align-items:center;gap:.5rem;padding:.375rem .5rem;border:none;background:none;border-radius:var(--mlv-radius-s);cursor:pointer;font:inherit;font-size:var(--mlv-dt-font-size);color:var(--mlv-text-primary);text-align:start}.mlv-data-table__pin-popup-item svg{color:var(--mlv-text-secondary);flex-shrink:0}.mlv-data-table__pin-popup-item:hover{background:var(--mlv-background-sunken)}.mlv-data-table__pin-popup-item--active{color:var(--mlv-text-action)}.mlv-data-table__pin-popup-item--active svg{color:var(--mlv-text-action)}.mlv-data-table__pin-popup-item--unpin{color:var(--mlv-text-negative);border-top:.0625rem solid var(--mlv-border-subtle);margin-top:.125rem;padding-top:.5rem;border-radius:0 0 var(--mlv-radius-s) var(--mlv-radius-s)}.mlv-data-table__pin-popup-item--unpin svg{color:var(--mlv-text-negative)}.mlv-data-table__pin-popup-item--unpin:hover{background:color-mix(in srgb,var(--mlv-text-negative) 8%,transparent)}.mlv-data-table__columns-dropdown{display:flex;flex-direction:column;gap:.25rem;padding:.5rem;min-width:10rem}.mlv-data-table__columns-item{display:flex;align-items:center;gap:.5rem;padding:.25rem .5rem;border-radius:var(--mlv-radius-s);cursor:pointer;font-size:var(--mlv-dt-font-size)}.mlv-data-table__columns-item:hover{background:var(--mlv-background-sunken)}.mlv-data-table__foot{font-weight:var(--mlv-font-weight-medium);font-size:var(--mlv-dt-font-size);background:var(--mlv-background-base)}.mlv-data-table__foot--sticky{position:sticky;bottom:0;z-index:3}.mlv-data-table__foot .mlv-data-table__cell--pinned,.mlv-data-table__row--footer{background:inherit}.mlv-data-table__row--footer>:where(td,th){box-sizing:border-box;padding:0 var(--mlv-dt-cell-padding-x);height:var(--mlv-dt-header-height);border-top:.125rem solid var(--mlv-border-normal);border-bottom:0;vertical-align:middle;background:inherit;font-size:inherit;font-weight:inherit}.mlv-data-table__table--bordered .mlv-data-table__row--footer>:where(td,th){border-inline-end:.0625rem solid var(--mlv-border-subtle)}.mlv-data-table__table--bordered .mlv-data-table__row--footer>:where(td,th):last-child{border-inline-end:none}.mlv-data-table__footer{padding-top:.75rem}@media(prefers-reduced-motion:reduce){.mlv-data-table,.mlv-data-table *,.mlv-data-table:before,.mlv-data-table:after,[class^=mlv-data-table__],[class*=\" mlv-data-table__\"],[class^=mlv-data-table--],[class*=\" mlv-data-table--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"] }]
|
|
2677
|
+
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], columnGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnGroups", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], addRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "addRow", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], actionsHeaderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionsHeaderLabel", required: false }] }], cellNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellNavigation", required: false }] }], paginationMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationMode", required: false }] }], hasMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMore", required: false }] }], infiniteScrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "infiniteScrollThreshold", required: false }] }], filterDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterDisplay", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showSortMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSortMenu", required: false }] }], searchTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTrigger", required: false }] }], searchDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchDebounce", required: false }] }], rowEditStart: [{ type: i0.Output, args: ["rowEditStart"] }], rowEditSave: [{ type: i0.Output, args: ["rowEditSave"] }], rowEditCancel: [{ type: i0.Output, args: ["rowEditCancel"] }], rowAdd: [{ type: i0.Output, args: ["rowAdd"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], retry: [{ type: i0.Output, args: ["retry"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], presentationStateChange: [{ type: i0.Output, args: ["presentationStateChange"] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], selectedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRows", required: false }] }, { type: i0.Output, args: ["selectedRowsChange"] }], searchQuery: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchQuery", required: false }] }, { type: i0.Output, args: ["searchQueryChange"] }], cellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvDataTableCell), { ...{
|
|
2678
|
+
descendants: true,
|
|
2679
|
+
}, isSignal: true }] }], editCellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvDataTableEditCell), { ...{
|
|
2680
|
+
descendants: true,
|
|
2681
|
+
}, isSignal: true }] }], noDataTemplate: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvDataTableNoData), { ...{
|
|
2682
|
+
descendants: true,
|
|
2683
|
+
}, isSignal: true }] }], errorTemplate: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvDataTableError), { ...{
|
|
2684
|
+
descendants: true,
|
|
2685
|
+
}, isSignal: true }] }], footerTemplate: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvDataTableFooter), { ...{
|
|
2686
|
+
descendants: true,
|
|
2687
|
+
}, isSignal: true }] }], _toolbarActions: [{ type: i0.ContentChild, args: [i0.forwardRef(() => MlvDataTableToolbarActions), { isSignal: true }] }], tableWrapperRef: [{ type: i0.ViewChild, args: ['tableWrapper', { isSignal: true }] }], tableRef: [{ type: i0.ViewChild, args: ['tableEl', { isSignal: true }] }], _resizeHandleRefs: [{ type: i0.ViewChildren, args: ['resizeHandle', { isSignal: true }] }], _filterTriggerRef: [{ type: i0.ViewChild, args: ['filterBtn', { ...{
|
|
2688
|
+
read: ElementRef,
|
|
2689
|
+
}, isSignal: true }] }], _virtualViewportRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], activeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilters", required: false }] }, { type: i0.Output, args: ["activeFiltersChange"] }] } });
|
|
2690
|
+
|
|
2691
|
+
/**
|
|
2692
|
+
* Generated bundle index. Do not edit.
|
|
2693
|
+
*/
|
|
2694
|
+
|
|
2695
|
+
export { MlvDataTable, MlvDataTableCell, MlvDataTableEditCell, MlvDataTableError, MlvDataTableFooter, MlvDataTableNoData, MlvDataTableToolbarActions };
|
|
2696
|
+
//# sourceMappingURL=malva-ui-core-data-table.mjs.map
|