@rt-tools/ui-kit-v2 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/fesm2022/rt-tools-ui-kit-v2-accordion.mjs +79 -0
- package/fesm2022/rt-tools-ui-kit-v2-accordion.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs +227 -0
- package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-aside-section.mjs +47 -0
- package/fesm2022/rt-tools-ui-kit-v2-aside-section.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-aside.mjs +702 -0
- package/fesm2022/rt-tools-ui-kit-v2-aside.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +214 -0
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-bar-list.mjs +53 -0
- package/fesm2022/rt-tools-ui-kit-v2-bar-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-bottom-sheet.mjs +88 -0
- package/fesm2022/rt-tools-ui-kit-v2-bottom-sheet.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs +365 -0
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs +152 -0
- package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-card.mjs +72 -0
- package/fesm2022/rt-tools-ui-kit-v2-card.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs +111 -0
- package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-collapsible-text.mjs +76 -0
- package/fesm2022/rt-tools-ui-kit-v2-collapsible-text.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs +255 -0
- package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-container.mjs +1326 -0
- package/fesm2022/rt-tools-ui-kit-v2-container.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +2590 -0
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-counter-row.mjs +45 -0
- package/fesm2022/rt-tools-ui-kit-v2-counter-row.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-counter.mjs +158 -0
- package/fesm2022/rt-tools-ui-kit-v2-counter.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +894 -0
- package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs +1217 -0
- package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +779 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +573 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-delta-view.mjs +141 -0
- package/fesm2022/rt-tools-ui-kit-v2-delta-view.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-detail-list.mjs +68 -0
- package/fesm2022/rt-tools-ui-kit-v2-detail-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dialog.mjs +478 -0
- package/fesm2022/rt-tools-ui-kit-v2-dialog.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dot-field.mjs +183 -0
- package/fesm2022/rt-tools-ui-kit-v2-dot-field.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-download-link.mjs +44 -0
- package/fesm2022/rt-tools-ui-kit-v2-download-link.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +260 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +937 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-empty-state.mjs +56 -0
- package/fesm2022/rt-tools-ui-kit-v2-empty-state.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs +107 -0
- package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs +183 -0
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs +219 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-drop.mjs +214 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-drop.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-input.mjs +117 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-input.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-list.mjs +32 -0
- package/fesm2022/rt-tools-ui-kit-v2-file-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs +91 -0
- package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs +220 -0
- package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-header.mjs +72 -0
- package/fesm2022/rt-tools-ui-kit-v2-header.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs +163 -0
- package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-icon.mjs +674 -0
- package/fesm2022/rt-tools-ui-kit-v2-icon.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-image-cropper.mjs +540 -0
- package/fesm2022/rt-tools-ui-kit-v2-image-cropper.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs +227 -0
- package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-info-item.mjs +37 -0
- package/fesm2022/rt-tools-ui-kit-v2-info-item.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs +361 -0
- package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-input.mjs +143 -0
- package/fesm2022/rt-tools-ui-kit-v2-input.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-live-badge.mjs +49 -0
- package/fesm2022/rt-tools-ui-kit-v2-live-badge.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-logo.mjs +97 -0
- package/fesm2022/rt-tools-ui-kit-v2-logo.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs +57 -0
- package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-menu.mjs +537 -0
- package/fesm2022/rt-tools-ui-kit-v2-menu.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-message.mjs +105 -0
- package/fesm2022/rt-tools-ui-kit-v2-message.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-money-list.mjs +71 -0
- package/fesm2022/rt-tools-ui-kit-v2-money-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +315 -0
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-night-grid.mjs +51 -0
- package/fesm2022/rt-tools-ui-kit-v2-night-grid.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-note.mjs +44 -0
- package/fesm2022/rt-tools-ui-kit-v2-note.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-notifications-bell.mjs +54 -0
- package/fesm2022/rt-tools-ui-kit-v2-notifications-bell.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +339 -0
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs +187 -0
- package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-photo-viewer.mjs +170 -0
- package/fesm2022/rt-tools-ui-kit-v2-photo-viewer.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-popover.mjs +312 -0
- package/fesm2022/rt-tools-ui-kit-v2-popover.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs +174 -0
- package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-radius.mjs +56 -0
- package/fesm2022/rt-tools-ui-kit-v2-radius.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +96 -41
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-ripple.mjs +118 -0
- package/fesm2022/rt-tools-ui-kit-v2-ripple.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs +290 -0
- package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-section-nav.mjs +37 -0
- package/fesm2022/rt-tools-ui-kit-v2-section-nav.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs +495 -0
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +1493 -0
- package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-skeleton-wrapper.mjs +49 -0
- package/fesm2022/rt-tools-ui-kit-v2-skeleton-wrapper.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-skeleton.mjs +123 -0
- package/fesm2022/rt-tools-ui-kit-v2-skeleton.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-spinner.mjs +70 -0
- package/fesm2022/rt-tools-ui-kit-v2-spinner.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs +92 -0
- package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-stat-tile.mjs +147 -0
- package/fesm2022/rt-tools-ui-kit-v2-stat-tile.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs +117 -0
- package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs +1636 -0
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +350 -0
- package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +122 -0
- package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs +85 -0
- package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs +73 -0
- package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +196 -0
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-timeline.mjs +39 -0
- package/fesm2022/rt-tools-ui-kit-v2-timeline.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-toast.mjs +338 -0
- package/fesm2022/rt-tools-ui-kit-v2-toast.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs +132 -0
- package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-toggle-switch.mjs +162 -0
- package/fesm2022/rt-tools-ui-kit-v2-toggle-switch.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs +135 -0
- package/fesm2022/rt-tools-ui-kit-v2-toolbar.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs +214 -0
- package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-welcome-dialog.mjs +64 -0
- package/fesm2022/rt-tools-ui-kit-v2-welcome-dialog.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +263 -0
- package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +296 -0
- package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2.mjs +91 -23164
- package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
- package/package.json +349 -1
- package/rt-tools-ui-kit-v2-0.18.0.tgz +0 -0
- package/src/lib/components/action-bar/CONTEXT.md +5 -0
- package/src/lib/components/action-bar/rt-action-bar.component.scss +30 -16
- package/src/lib/components/aside/CONTEXT.md +9 -1
- package/src/lib/components/aside/footer/rt-aside-footer.component.scss +7 -8
- package/src/lib/components/aside/header/rt-aside-header.component.scss +16 -1
- package/src/lib/components/aside/rt-aside.component.scss +17 -1
- package/src/lib/components/button/CONTEXT.md +12 -11
- package/src/lib/components/button/rt-button.directive.scss +36 -0
- package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +2 -2
- package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
- package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
- package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
- package/src/lib/components/dialog/CONTEXT.md +9 -0
- package/src/lib/components/dialog/content/rt-dialog-content.component.scss +20 -0
- package/src/lib/components/dialog/footer/rt-dialog-footer.component.scss +18 -2
- package/src/lib/components/dialog/header/rt-dialog-header.component.scss +21 -3
- package/src/lib/components/dialog/rt-dialog.component.scss +9 -3
- package/src/lib/components/dot-field/CONTEXT.md +31 -0
- package/src/lib/components/dot-field/rt-dot-field.component.scss +20 -0
- package/src/lib/components/dot-field/stories/component/CONTEXT.md +14 -0
- package/src/lib/components/dot-field/stories/component/test-dot-field.component.scss +31 -0
- package/src/lib/components/dynamic-selector/CONTEXT.md +6 -0
- package/src/lib/components/field/CONTEXT.md +18 -2
- package/src/lib/components/header/CONTEXT.md +2 -2
- package/src/lib/components/icon/CONTEXT.md +11 -7
- package/src/lib/components/icon/rt-icon.component.scss +47 -0
- package/src/lib/components/icon-button/CONTEXT.md +27 -20
- package/src/lib/components/icon-button/rt-icon-button.component.scss +51 -25
- package/src/lib/components/image-upload/CONTEXT.md +20 -15
- package/src/lib/components/image-upload/rt-image-upload.component.scss +14 -2
- package/src/lib/components/pagination/rt-pagination.component.scss +1 -1
- package/src/lib/components/scroll-area/CONTEXT.md +2 -0
- package/src/lib/components/scroll-area/rt-scroll-area.component.scss +20 -3
- package/src/lib/components/select/rt-select.component.scss +4 -0
- package/src/lib/components/side-menu/CONTEXT.md +7 -2
- package/src/lib/components/spinner/CONTEXT.md +15 -8
- package/src/lib/components/spinner/rt-spinner.component.scss +108 -9
- package/src/lib/components/tag/rt-tag.component.scss +43 -23
- package/src/lib/components/toast/CONTEXT.md +8 -0
- package/src/lib/components/toast/rt-toast.component.scss +74 -15
- package/src/lib/components/toast/rt-toaster.component.scss +5 -1
- package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +35 -37
- package/src/lib/components/toggle-switch/CONTEXT.md +11 -3
- package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +53 -14
- package/src/lib/components/toolbar/rt-toolbar.component.scss +15 -4
- package/src/lib/components/tooltip/CONTEXT.md +5 -5
- package/src/rich-editor/lib/components/chat/CONTEXT.md +7 -2
- package/src/rich-editor/lib/components/chat/rt-chat.component.scss +25 -0
- package/src/styles/_semantic.scss +1 -1
- package/styles/tokens.css +43 -8
- package/types/rt-tools-ui-kit-v2-accordion.d.ts +30 -0
- package/types/rt-tools-ui-kit-v2-action-bar.d.ts +140 -0
- package/types/rt-tools-ui-kit-v2-aside-section.d.ts +25 -0
- package/types/rt-tools-ui-kit-v2-aside.d.ts +436 -0
- package/types/rt-tools-ui-kit-v2-autocomplete.d.ts +78 -0
- package/types/rt-tools-ui-kit-v2-bar-list.d.ts +41 -0
- package/types/rt-tools-ui-kit-v2-bottom-sheet.d.ts +20 -0
- package/types/rt-tools-ui-kit-v2-button.d.ts +76 -0
- package/types/rt-tools-ui-kit-v2-calendar.d.ts +96 -0
- package/types/rt-tools-ui-kit-v2-card.d.ts +38 -0
- package/types/rt-tools-ui-kit-v2-checkbox.d.ts +46 -0
- package/types/rt-tools-ui-kit-v2-collapsible-text.d.ts +20 -0
- package/types/rt-tools-ui-kit-v2-confirm-popover.d.ts +85 -0
- package/types/rt-tools-ui-kit-v2-container.d.ts +425 -0
- package/types/rt-tools-ui-kit-v2-core.d.ts +1222 -0
- package/types/rt-tools-ui-kit-v2-counter-row.d.ts +22 -0
- package/types/rt-tools-ui-kit-v2-counter.d.ts +70 -0
- package/types/rt-tools-ui-kit-v2-data-list.d.ts +334 -0
- package/types/rt-tools-ui-kit-v2-data-table.d.ts +494 -0
- package/types/rt-tools-ui-kit-v2-date-picker.d.ts +181 -0
- package/types/rt-tools-ui-kit-v2-date-range.d.ts +98 -0
- package/types/rt-tools-ui-kit-v2-delta-view.d.ts +20 -0
- package/types/rt-tools-ui-kit-v2-detail-list.d.ts +33 -0
- package/types/rt-tools-ui-kit-v2-dialog.d.ts +287 -0
- package/types/rt-tools-ui-kit-v2-dot-field.d.ts +17 -0
- package/types/rt-tools-ui-kit-v2-download-link.d.ts +17 -0
- package/types/rt-tools-ui-kit-v2-dynamic-list.d.ts +139 -0
- package/types/rt-tools-ui-kit-v2-dynamic-selector.d.ts +384 -0
- package/types/rt-tools-ui-kit-v2-empty-state.d.ts +29 -0
- package/types/rt-tools-ui-kit-v2-expansion-panel.d.ts +57 -0
- package/types/rt-tools-ui-kit-v2-field.d.ts +82 -0
- package/types/rt-tools-ui-kit-v2-file-card.d.ts +114 -0
- package/types/rt-tools-ui-kit-v2-file-drop.d.ts +75 -0
- package/types/rt-tools-ui-kit-v2-file-input.d.ts +48 -0
- package/types/rt-tools-ui-kit-v2-file-list.d.ts +13 -0
- package/types/rt-tools-ui-kit-v2-filter-control.d.ts +72 -0
- package/types/rt-tools-ui-kit-v2-form-control.d.ts +74 -0
- package/types/rt-tools-ui-kit-v2-header.d.ts +40 -0
- package/types/rt-tools-ui-kit-v2-icon-button.d.ts +113 -0
- package/types/rt-tools-ui-kit-v2-icon.d.ts +238 -0
- package/types/rt-tools-ui-kit-v2-image-cropper.d.ts +168 -0
- package/types/rt-tools-ui-kit-v2-image-upload.d.ts +102 -0
- package/types/rt-tools-ui-kit-v2-info-item.d.ts +13 -0
- package/types/rt-tools-ui-kit-v2-input-number.d.ts +67 -0
- package/types/rt-tools-ui-kit-v2-input.d.ts +54 -0
- package/types/rt-tools-ui-kit-v2-live-badge.d.ts +23 -0
- package/types/rt-tools-ui-kit-v2-logo.d.ts +58 -0
- package/types/rt-tools-ui-kit-v2-markdown-text.d.ts +30 -0
- package/types/rt-tools-ui-kit-v2-menu.d.ts +217 -0
- package/types/rt-tools-ui-kit-v2-message.d.ts +56 -0
- package/types/rt-tools-ui-kit-v2-money-list.d.ts +34 -0
- package/types/rt-tools-ui-kit-v2-multiselect.d.ts +93 -0
- package/types/rt-tools-ui-kit-v2-night-grid.d.ts +39 -0
- package/types/rt-tools-ui-kit-v2-note.d.ts +21 -0
- package/types/rt-tools-ui-kit-v2-notifications-bell.d.ts +23 -0
- package/types/rt-tools-ui-kit-v2-page-header.d.ts +173 -0
- package/types/rt-tools-ui-kit-v2-pagination.d.ts +64 -0
- package/types/rt-tools-ui-kit-v2-photo-viewer.d.ts +98 -0
- package/types/rt-tools-ui-kit-v2-popover.d.ts +79 -0
- package/types/rt-tools-ui-kit-v2-radio-button.d.ts +61 -0
- package/types/rt-tools-ui-kit-v2-radius.d.ts +37 -0
- package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +16 -20
- package/types/rt-tools-ui-kit-v2-ripple.d.ts +39 -0
- package/types/rt-tools-ui-kit-v2-scroll-area.d.ts +91 -0
- package/types/rt-tools-ui-kit-v2-section-nav.d.ts +23 -0
- package/types/rt-tools-ui-kit-v2-select.d.ts +215 -0
- package/types/rt-tools-ui-kit-v2-side-menu.d.ts +483 -0
- package/types/rt-tools-ui-kit-v2-skeleton-wrapper.d.ts +32 -0
- package/types/rt-tools-ui-kit-v2-skeleton.d.ts +41 -0
- package/types/rt-tools-ui-kit-v2-spinner.d.ts +56 -0
- package/types/rt-tools-ui-kit-v2-split-button.d.ts +72 -0
- package/types/rt-tools-ui-kit-v2-stat-tile.d.ts +81 -0
- package/types/rt-tools-ui-kit-v2-stepper.d.ts +51 -0
- package/types/rt-tools-ui-kit-v2-table.d.ts +739 -0
- package/types/rt-tools-ui-kit-v2-tabs.d.ts +153 -0
- package/types/rt-tools-ui-kit-v2-tag.d.ts +70 -0
- package/types/rt-tools-ui-kit-v2-textarea.d.ts +36 -0
- package/types/rt-tools-ui-kit-v2-theme-toggle.d.ts +43 -0
- package/types/rt-tools-ui-kit-v2-thread-list.d.ts +111 -0
- package/types/rt-tools-ui-kit-v2-timeline.d.ts +35 -0
- package/types/rt-tools-ui-kit-v2-toast.d.ts +103 -0
- package/types/rt-tools-ui-kit-v2-toggle-button-group.d.ts +109 -0
- package/types/rt-tools-ui-kit-v2-toggle-switch.d.ts +85 -0
- package/types/rt-tools-ui-kit-v2-toolbar.d.ts +66 -0
- package/types/rt-tools-ui-kit-v2-tooltip.d.ts +74 -0
- package/types/rt-tools-ui-kit-v2-welcome-dialog.d.ts +33 -0
- package/types/rt-tools-ui-kit-v2-workspace-details.d.ts +128 -0
- package/types/rt-tools-ui-kit-v2-workspace.d.ts +84 -0
- package/types/rt-tools-ui-kit-v2.d.ts +87 -9290
- package/rt-tools-ui-kit-v2-0.16.0.tgz +0 -0
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
import { isString, isNumber, areArraysEqual, isEmpty, EListSortOrder, EFilterOperatorType, FILTER_OPERATORS, transformArrayInput } from '@rt-tools/utils';
|
|
2
|
+
import { iconMaterialMap, RtIconComponent } from '@rt-tools/ui-kit-v2/icon';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, DestroyRef, signal, Injectable, TemplateRef, Directive, InjectionToken, ElementRef, input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, output, linkedSignal, viewChild, contentChild, forwardRef, Injector, effect, untracked } from '@angular/core';
|
|
5
|
+
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { Subject } from 'rxjs';
|
|
7
|
+
import { switchMap, take, takeUntil, map, concatMap, filter } from 'rxjs/operators';
|
|
8
|
+
import { IDBStorageService, PlatformService, BlockDirective, ElemDirective, ModDirective, EmptyToDashPipe, ConcatClassesPipe } from '@rt-tools/core';
|
|
9
|
+
import { Clipboard } from '@angular/cdk/clipboard';
|
|
10
|
+
import { NgTemplateOutlet, TitleCasePipe } from '@angular/common';
|
|
11
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
12
|
+
import { BreakpointsService, rtKitLabel, RT_KIT_TRANSLATOR, ERtDataTableFilterType, rtKitDefault, ERtDataTableColumnType, RT_DATA_TABLE_PRESET_FROM_HOST, RT_PRESET_MATERIAL_CLASS } from '@rt-tools/ui-kit-v2/core';
|
|
13
|
+
import { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';
|
|
14
|
+
import { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';
|
|
15
|
+
import * as i1 from '@angular/forms';
|
|
16
|
+
import { FormsModule } from '@angular/forms';
|
|
17
|
+
import { RtDatePickerComponent } from '@rt-tools/ui-kit-v2/date-picker';
|
|
18
|
+
import { RtInputNumberComponent } from '@rt-tools/ui-kit-v2/input-number';
|
|
19
|
+
import { RtInputComponent } from '@rt-tools/ui-kit-v2/input';
|
|
20
|
+
import { RtMenuComponent, RtMenuItemComponent } from '@rt-tools/ui-kit-v2/menu';
|
|
21
|
+
import { RtSelectComponent } from '@rt-tools/ui-kit-v2/select';
|
|
22
|
+
import { RtCheckboxComponent } from '@rt-tools/ui-kit-v2/checkbox';
|
|
23
|
+
import { RtRadioButtonComponent } from '@rt-tools/ui-kit-v2/radio-button';
|
|
24
|
+
|
|
25
|
+
/** Значение ячейки: как его отдала запись или как его переделала колонка. */
|
|
26
|
+
function dataTableCellValue(row, column) {
|
|
27
|
+
const transform = column.transform;
|
|
28
|
+
const raw = row[column.propName];
|
|
29
|
+
return transform ? transform(raw) : raw;
|
|
30
|
+
}
|
|
31
|
+
/** Текст значения для подсказки и буфера — так же, как первый кит: строка, число, иначе JSON. */
|
|
32
|
+
function dataTableCellText(value) {
|
|
33
|
+
if (isString(value)) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
if (isNumber(value)) {
|
|
37
|
+
return value.toString();
|
|
38
|
+
}
|
|
39
|
+
return JSON.stringify(value);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Сторона кнопки копирования: заданная колонкой, иначе противоположная выравниванию значения —
|
|
43
|
+
* справа выровненное значение копируется кнопкой слева.
|
|
44
|
+
*/
|
|
45
|
+
function dataTableCopyButtonSide(column) {
|
|
46
|
+
return column.copyBtnAlign ?? (column.align === 'right' ? 'left' : 'right');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Значок набора кита для имени первого кита, либо `null`, если пары нет.
|
|
50
|
+
*
|
|
51
|
+
* Идёт через перечень соответствий кита, а не своим списком: второй список разошёлся бы с
|
|
52
|
+
* перечнем молча, и одно имя рисовалось бы в двух местах двумя рисунками.
|
|
53
|
+
*/
|
|
54
|
+
function dataTableIconName(glyph) {
|
|
55
|
+
return iconMaterialMap.find((entry) => entry.from === glyph)?.to ?? null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Порядок имён колонок для сверки двух наборов.
|
|
60
|
+
*
|
|
61
|
+
* Какой именно порядок, значения не имеет: оба набора выстраиваются одним и тем же и сравниваются
|
|
62
|
+
* на равенство. Важно лишь, чтобы порядок был один и не зависел от вида значения, — умолчание
|
|
63
|
+
* `sort()` приводит элементы к строке по-своему и на числовых ключах даёт лексикографический.
|
|
64
|
+
*/
|
|
65
|
+
function comparePropNames(a, b) {
|
|
66
|
+
return String(a).localeCompare(String(b));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Настройки таблицы в хранилище браузера: порядок и видимость столбцов, полосы прокрутки.
|
|
70
|
+
*
|
|
71
|
+
* Перенесено из первого кита как есть: ключ — тот, что дало приложение, форма записи — та же.
|
|
72
|
+
* Поэтому настройки, сохранённые таблицей первого кита, читаются здесь без переделки.
|
|
73
|
+
*/
|
|
74
|
+
class RtDataTableConfigService {
|
|
75
|
+
#destroyRef;
|
|
76
|
+
#iDBStorageService;
|
|
77
|
+
/** Просьбы прочитать сохранённую настройку. */
|
|
78
|
+
#readSource;
|
|
79
|
+
/** Настройку поменяли здесь: чтение, начатое раньше, отвечать уже не должно. */
|
|
80
|
+
#updatedSource;
|
|
81
|
+
/** Просьбы записать и снять настройку — один источник на оба действия. */
|
|
82
|
+
#writeSource;
|
|
83
|
+
#tableConfig;
|
|
84
|
+
/**
|
|
85
|
+
* Потоки чтения и записи объявлены один раз, а методы только толкают в них просьбы.
|
|
86
|
+
*
|
|
87
|
+
* Чтение — `switchMap`: отвечает последний вызов, потому что настройка, прочитанная под
|
|
88
|
+
* прежний состав столбцов, к нынешнему уже не относится. Чтение, ещё не вернувшееся к
|
|
89
|
+
* `updateConfig`, гасится им: иначе прочитанное позже затёрло бы то, что поменяли после.
|
|
90
|
+
* Запись и снятие — один поток и `concatMap`: разведённые по двум, они теряют порядок между
|
|
91
|
+
* собой, и снятие, обогнавшее запись, оставляет в хранилище снятое.
|
|
92
|
+
*/
|
|
93
|
+
constructor() {
|
|
94
|
+
this.#destroyRef = inject(DestroyRef);
|
|
95
|
+
this.#iDBStorageService = inject(IDBStorageService);
|
|
96
|
+
/** Просьбы прочитать сохранённую настройку. */
|
|
97
|
+
this.#readSource = new Subject();
|
|
98
|
+
/** Настройку поменяли здесь: чтение, начатое раньше, отвечать уже не должно. */
|
|
99
|
+
this.#updatedSource = new Subject();
|
|
100
|
+
/** Просьбы записать и снять настройку — один источник на оба действия. */
|
|
101
|
+
this.#writeSource = new Subject();
|
|
102
|
+
this.#tableConfig = signal({
|
|
103
|
+
isVerticalScrollbarShown: false,
|
|
104
|
+
isHorizontalScrollbarShown: false,
|
|
105
|
+
columns: [],
|
|
106
|
+
}, /* @ts-ignore */
|
|
107
|
+
...(ngDevMode ? [{ debugName: "#tableConfig" }] : /* istanbul ignore next */ []));
|
|
108
|
+
this.tableConfig = this.#tableConfig.asReadonly();
|
|
109
|
+
this.#readSource
|
|
110
|
+
.pipe(switchMap((read) => this.#iDBStorageService.get(read.storageKey).pipe(take(1), takeUntil(this.#updatedSource), map((savedConfig) => this.#configOf(read.config, savedConfig)))), takeUntilDestroyed(this.#destroyRef))
|
|
111
|
+
.subscribe((config) => {
|
|
112
|
+
this.#tableConfig.set(config);
|
|
113
|
+
});
|
|
114
|
+
this.#writeSource
|
|
115
|
+
.pipe(concatMap((write) => this.#writeOf(write).pipe(take(1))), takeUntilDestroyed(this.#destroyRef))
|
|
116
|
+
.subscribe();
|
|
117
|
+
}
|
|
118
|
+
initConfig(storageKey, config) {
|
|
119
|
+
this.#readSource.next({ storageKey, config });
|
|
120
|
+
}
|
|
121
|
+
updateConfig(storageKey, config) {
|
|
122
|
+
this.#updatedSource.next();
|
|
123
|
+
this.#writeSource.next({ kind: 'set', storageKey, config });
|
|
124
|
+
this.#tableConfig.set(config);
|
|
125
|
+
}
|
|
126
|
+
deleteConfig(storageKey) {
|
|
127
|
+
this.#writeSource.next({ kind: 'remove', storageKey });
|
|
128
|
+
}
|
|
129
|
+
/** Обращение к хранилищу под просьбу записи или снятия. */
|
|
130
|
+
#writeOf(write) {
|
|
131
|
+
if (write.kind === 'remove') {
|
|
132
|
+
return this.#iDBStorageService.remove(write.storageKey);
|
|
133
|
+
}
|
|
134
|
+
const storedColumns = write.config.columns.map((el) => ({
|
|
135
|
+
displayName: el.header.label ?? el.propName.toString(),
|
|
136
|
+
propName: el.propName,
|
|
137
|
+
width: el?.width ?? 'auto',
|
|
138
|
+
orderIndex: el?.orderIndex ?? 0,
|
|
139
|
+
hidden: !!el?.hidden,
|
|
140
|
+
fixed: !!el?.fixed,
|
|
141
|
+
}));
|
|
142
|
+
return this.#iDBStorageService.set(write.storageKey, { ...write.config, columns: storedColumns });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Настройка, которую показывает таблица: сохранённая, если она сходится с нынешним составом
|
|
146
|
+
* столбцов, иначе — собранная из самого состава.
|
|
147
|
+
*/
|
|
148
|
+
#configOf(config, savedConfig) {
|
|
149
|
+
if (!savedConfig?.columns || !this.#isSavedConfigConsistent(config, savedConfig.columns)) {
|
|
150
|
+
return {
|
|
151
|
+
isVerticalScrollbarShown: false,
|
|
152
|
+
isHorizontalScrollbarShown: true,
|
|
153
|
+
columns: config.map((el, index) => ({
|
|
154
|
+
...el,
|
|
155
|
+
orderIndex: index,
|
|
156
|
+
displayName: el?.header?.label?.length ? el.header.label : el.propName.toString(),
|
|
157
|
+
})),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const updatedColumns = savedConfig.columns.map((el) => {
|
|
161
|
+
const declared = config.find((item) => el.propName === item.propName);
|
|
162
|
+
return {
|
|
163
|
+
// Сверка составов выше гарантирует, что столбец с этим именем объявлен.
|
|
164
|
+
...declared,
|
|
165
|
+
displayName: declared?.header?.label?.length ? declared.header.label : el?.propName?.toString(),
|
|
166
|
+
propName: el.propName,
|
|
167
|
+
width: el?.width ?? 'auto',
|
|
168
|
+
orderIndex: el?.orderIndex ?? 0,
|
|
169
|
+
hidden: !!el?.hidden,
|
|
170
|
+
fixed: !!el?.fixed,
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
isVerticalScrollbarShown: !!savedConfig?.isVerticalScrollbarShown,
|
|
175
|
+
isHorizontalScrollbarShown: !!savedConfig?.isHorizontalScrollbarShown,
|
|
176
|
+
columns: updatedColumns,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
#isSavedConfigConsistent(declared, saved) {
|
|
180
|
+
return (!!declared?.length &&
|
|
181
|
+
!!saved?.length &&
|
|
182
|
+
declared.length === saved.length &&
|
|
183
|
+
areArraysEqual(declared.map((el) => el.propName).toSorted(comparePropNames), saved.map((el) => el.propName).toSorted(comparePropNames)));
|
|
184
|
+
}
|
|
185
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
186
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableConfigService }); }
|
|
187
|
+
}
|
|
188
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableConfigService, decorators: [{
|
|
189
|
+
type: Injectable
|
|
190
|
+
}], ctorParameters: () => [] });
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Шаблон значка, который приложение отдаёт таблице.
|
|
194
|
+
*
|
|
195
|
+
* Когда он дан, значки шапки и ячеек, названные в описании колонок, рисует он, а перечень
|
|
196
|
+
* соответствий кита не спрашивается. Это выход для имени, которому в наборе кита нет пары.
|
|
197
|
+
*
|
|
198
|
+
* ```html
|
|
199
|
+
* <rt-data-table ...>
|
|
200
|
+
* <ng-template rtDataTableIcon let-name let-row="row">
|
|
201
|
+
* <rt-icon [name]="iconOf(name)" />
|
|
202
|
+
* </ng-template>
|
|
203
|
+
* </rt-data-table>
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
class RtDataTableIconDirective {
|
|
207
|
+
constructor() {
|
|
208
|
+
this.template = inject(TemplateRef);
|
|
209
|
+
}
|
|
210
|
+
static ngTemplateContextGuard(_directive,
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- второй довод стража контекста шаблона стоит только в типе-предикате; убрать его нечем, подпись задаёт каркас
|
|
212
|
+
context) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
216
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: RtDataTableIconDirective, isStandalone: true, selector: "ng-template[rtDataTableIcon]", exportAs: ["rtDataTableIcon"], ngImport: i0 }); }
|
|
217
|
+
}
|
|
218
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableIconDirective, decorators: [{
|
|
219
|
+
type: Directive,
|
|
220
|
+
args: [{
|
|
221
|
+
selector: 'ng-template[rtDataTableIcon]',
|
|
222
|
+
exportAs: 'rtDataTableIcon',
|
|
223
|
+
}]
|
|
224
|
+
}] });
|
|
225
|
+
|
|
226
|
+
/** Атрибут части строки, нажатие на которую до строки не доходит. */
|
|
227
|
+
const RT_DATA_TABLE_STOP_ROW_CLICK_ATTRIBUTE = 'rt-data-table-stop-row-click';
|
|
228
|
+
const RT_DATA_TABLE_ROW_HOST = new InjectionToken('RtDataTableRowHost');
|
|
229
|
+
/** Попало ли нажатие в часть строки, помеченную как не доходящую до строки. */
|
|
230
|
+
function isInsideStopNode(event) {
|
|
231
|
+
return event.target instanceof Element && !!event.target.closest(`[${RT_DATA_TABLE_STOP_ROW_CLICK_ATTRIBUTE}]`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Помечает часть строки, нажатие на которую до строки не доходит, — картинку, кнопку приложения,
|
|
235
|
+
* блок текста в своей ячейке.
|
|
236
|
+
*/
|
|
237
|
+
class RtDataTableStopRowClickDirective {
|
|
238
|
+
#platformService = inject(PlatformService);
|
|
239
|
+
#elementRef = inject((ElementRef));
|
|
240
|
+
ngOnInit() {
|
|
241
|
+
if (this.#platformService.isPlatformBrowser) {
|
|
242
|
+
this.#elementRef.nativeElement.setAttribute(RT_DATA_TABLE_STOP_ROW_CLICK_ATTRIBUTE, '');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableStopRowClickDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
246
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: RtDataTableStopRowClickDirective, isStandalone: true, selector: "[rtDataTableStopRowClick]", ngImport: i0 }); }
|
|
247
|
+
}
|
|
248
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableStopRowClickDirective, decorators: [{
|
|
249
|
+
type: Directive,
|
|
250
|
+
args: [{
|
|
251
|
+
selector: '[rtDataTableStopRowClick]',
|
|
252
|
+
}]
|
|
253
|
+
}] });
|
|
254
|
+
/**
|
|
255
|
+
* Нажатие и двойное нажатие строки — как в первом ките.
|
|
256
|
+
*
|
|
257
|
+
* О нажатии строка сообщает, когда кнопка опускается, а не когда отпускается, и любой кнопкой:
|
|
258
|
+
* так было в первом ките, и так переносится. Двойное нажатие поэтому приходит после двух нажатий
|
|
259
|
+
* строки.
|
|
260
|
+
*/
|
|
261
|
+
class RtDataTableRowClickDirective {
|
|
262
|
+
constructor() {
|
|
263
|
+
this.#host = inject(RT_DATA_TABLE_ROW_HOST);
|
|
264
|
+
/** Запись строки. */
|
|
265
|
+
this.entity = input.required({ ...(ngDevMode ? { debugName: "entity" } : /* istanbul ignore next */ {}), alias: 'rtDataTableRowClick' });
|
|
266
|
+
/** Строка сообщает о нажатиях. */
|
|
267
|
+
this.isTableRowClickable = input(true, { ...(ngDevMode ? { debugName: "isTableRowClickable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
268
|
+
}
|
|
269
|
+
#host;
|
|
270
|
+
onMouseDown(event) {
|
|
271
|
+
if (!this.isTableRowClickable() || isInsideStopNode(event)) {
|
|
272
|
+
event.stopPropagation();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
this.#host.onRowClick(this.entity(), event);
|
|
276
|
+
}
|
|
277
|
+
onDoubleClick(event) {
|
|
278
|
+
if (!this.isTableRowClickable() || isInsideStopNode(event)) {
|
|
279
|
+
event.stopPropagation();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.#host.onRowDoubleClick(this.entity());
|
|
283
|
+
}
|
|
284
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableRowClickDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
285
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: RtDataTableRowClickDirective, isStandalone: true, selector: "[rtDataTableRowClick]", inputs: { entity: { classPropertyName: "entity", publicName: "rtDataTableRowClick", isSignal: true, isRequired: true, transformFunction: null }, isTableRowClickable: { classPropertyName: "isTableRowClickable", publicName: "isTableRowClickable", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mousedown": "onMouseDown($event)", "dblclick": "onDoubleClick($event)" } }, ngImport: i0 }); }
|
|
286
|
+
}
|
|
287
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableRowClickDirective, decorators: [{
|
|
288
|
+
type: Directive,
|
|
289
|
+
args: [{
|
|
290
|
+
selector: '[rtDataTableRowClick]',
|
|
291
|
+
host: {
|
|
292
|
+
'(mousedown)': 'onMouseDown($event)',
|
|
293
|
+
'(dblclick)': 'onDoubleClick($event)',
|
|
294
|
+
},
|
|
295
|
+
}]
|
|
296
|
+
}], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "rtDataTableRowClick", required: true }] }], isTableRowClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTableRowClickable", required: false }] }] } });
|
|
297
|
+
|
|
298
|
+
const BEM_BLOCK$3 = 'rt-data-table-cell';
|
|
299
|
+
/** Сколько держать «скопировано» перед возвратом кнопки — как в первом ките. */
|
|
300
|
+
const COPIED_DELAY_MS = 2000;
|
|
301
|
+
/**
|
|
302
|
+
* Готовая ячейка `rt-data-table` — ячейка первого кита без Material.
|
|
303
|
+
*
|
|
304
|
+
* Значение рисуется как пришло или как его переделала колонка; пустое — прочерком. Длинное
|
|
305
|
+
* обрезается в строку, и подсказка со значением целиком бывает только у обрезанного. Значок —
|
|
306
|
+
* набором кита по имени первого кита либо шаблоном значка приложения. Кнопка копирования
|
|
307
|
+
* проявляется при наведении и стоит на стороне, противоположной выравниванию значения.
|
|
308
|
+
*/
|
|
309
|
+
class RtDataTableCellComponent {
|
|
310
|
+
#breakpoints;
|
|
311
|
+
#clipboard;
|
|
312
|
+
#sanitizer;
|
|
313
|
+
#host;
|
|
314
|
+
#copiedTimer;
|
|
315
|
+
#copyLabel;
|
|
316
|
+
#copiedLabel;
|
|
317
|
+
constructor() {
|
|
318
|
+
this.#breakpoints = inject(BreakpointsService);
|
|
319
|
+
this.#clipboard = inject(Clipboard);
|
|
320
|
+
this.#sanitizer = inject(DomSanitizer);
|
|
321
|
+
this.#host = inject(ElementRef);
|
|
322
|
+
this.#copiedTimer = null;
|
|
323
|
+
this.#copyLabel = rtKitLabel('dataTableCopy');
|
|
324
|
+
this.#copiedLabel = rtKitLabel('dataTableCopied');
|
|
325
|
+
/** Экран узкий: подсказки гаснут. Что кнопка копирования там видна всегда, решают стили. */
|
|
326
|
+
this.narrow = this.#breakpoints.narrow;
|
|
327
|
+
this.value = computed(() => dataTableCellValue(this.row(), this.column()), /* @ts-ignore */
|
|
328
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
329
|
+
/**
|
|
330
|
+
* Копировать нечего: значение пусто. Считается той же утилитой, что рисует прочерк вместо
|
|
331
|
+
* значения, — второй ответ на этот вопрос разошёлся бы с прочерком молча.
|
|
332
|
+
*/
|
|
333
|
+
this.empty = computed(() => isEmpty(this.value()), /* @ts-ignore */
|
|
334
|
+
...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
|
|
335
|
+
this.copyable = computed(() => this.column().copyable && !this.empty(), /* @ts-ignore */
|
|
336
|
+
...(ngDevMode ? [{ debugName: "copyable" }] : /* istanbul ignore next */ []));
|
|
337
|
+
/**
|
|
338
|
+
* Значок колонки. Его видимость, цвет и подсказку ячейка не читает — как первый кит: поля
|
|
339
|
+
* приняты ради переезда без правок и ничего не меняют.
|
|
340
|
+
*/
|
|
341
|
+
this.icon = computed(() => this.column().icon ?? null, /* @ts-ignore */
|
|
342
|
+
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
343
|
+
/** Значок набора кита для имени первого кита; без пары — ничего. */
|
|
344
|
+
this.kitIcon = computed(() => {
|
|
345
|
+
const icon = this.icon();
|
|
346
|
+
return icon ? dataTableIconName(icon.glyph) : null;
|
|
347
|
+
}, /* @ts-ignore */
|
|
348
|
+
...(ngDevMode ? [{ debugName: "kitIcon" }] : /* istanbul ignore next */ []));
|
|
349
|
+
/**
|
|
350
|
+
* Имя без пары в перечне соответствий: его ячейка рисует глифом шрифта Material Symbols, как
|
|
351
|
+
* первый кит рисовал любой глиф. Шрифт кит не везёт — глиф виден там, где шрифт подключило
|
|
352
|
+
* приложение, а без шрифта на месте значка стоит его имя.
|
|
353
|
+
*/
|
|
354
|
+
this.glyph = computed(() => {
|
|
355
|
+
const icon = this.icon();
|
|
356
|
+
return icon && !this.kitIcon() ? icon.glyph : null;
|
|
357
|
+
}, /* @ts-ignore */
|
|
358
|
+
...(ngDevMode ? [{ debugName: "glyph" }] : /* istanbul ignore next */ []));
|
|
359
|
+
/** Залитый глиф — как залитый значок набора: контурным его делает `outlined` колонки. */
|
|
360
|
+
this.glyphMods = computed(() => ({ filled: this.icon()?.outlined !== true }), /* @ts-ignore */
|
|
361
|
+
...(ngDevMode ? [{ debugName: "glyphMods" }] : /* istanbul ignore next */ []));
|
|
362
|
+
this.iconContext = computed(() => {
|
|
363
|
+
const icon = this.icon();
|
|
364
|
+
return icon ? { $implicit: icon.glyph, column: this.column(), row: this.row() } : null;
|
|
365
|
+
}, /* @ts-ignore */
|
|
366
|
+
...(ngDevMode ? [{ debugName: "iconContext" }] : /* istanbul ignore next */ []));
|
|
367
|
+
/**
|
|
368
|
+
* Стиль значка, посчитанный колонкой по значению строки, — строкой, как в первом ките.
|
|
369
|
+
* Это одна из странностей первого кита, перенесённых как есть: такую строку не перекрашивает
|
|
370
|
+
* ни набор, ни тёмная тема.
|
|
371
|
+
*/
|
|
372
|
+
this.iconStyle = computed(() => {
|
|
373
|
+
const transform = this.column().iconTransform;
|
|
374
|
+
// eslint-disable-next-line sonarjs/no-angular-bypass-sanitization -- строка стиля собрана описанием колонок приложения, а не значением, введённым человеком
|
|
375
|
+
return transform ? this.#sanitizer.bypassSecurityTrustStyle(transform(this.row()[this.column().propName])) : null;
|
|
376
|
+
}, /* @ts-ignore */
|
|
377
|
+
...(ngDevMode ? [{ debugName: "iconStyle" }] : /* istanbul ignore next */ []));
|
|
378
|
+
this.hovered = signal(false, /* @ts-ignore */
|
|
379
|
+
...(ngDevMode ? [{ debugName: "hovered" }] : /* istanbul ignore next */ []));
|
|
380
|
+
this.copied = signal(false, /* @ts-ignore */
|
|
381
|
+
...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
|
|
382
|
+
/** Подсказка: заданная колонкой, иначе значение целиком — и только у обрезанного. */
|
|
383
|
+
this.hint = signal('', /* @ts-ignore */
|
|
384
|
+
...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
385
|
+
this.copyLabel = computed(() => (this.copied() ? this.#copiedLabel() : this.#copyLabel()), /* @ts-ignore */
|
|
386
|
+
...(ngDevMode ? [{ debugName: "copyLabel" }] : /* istanbul ignore next */ []));
|
|
387
|
+
this.copyIcon = computed(() => (this.copied() ? 'check' : 'copy'), /* @ts-ignore */
|
|
388
|
+
...(ngDevMode ? [{ debugName: "copyIcon" }] : /* istanbul ignore next */ []));
|
|
389
|
+
this.titleMods = computed(() => ({ align: this.column().align }), /* @ts-ignore */
|
|
390
|
+
...(ngDevMode ? [{ debugName: "titleMods" }] : /* istanbul ignore next */ []));
|
|
391
|
+
this.copyMods = computed(() => ({
|
|
392
|
+
position: dataTableCopyButtonSide(this.column()),
|
|
393
|
+
complete: this.copied(),
|
|
394
|
+
visible: this.hovered(),
|
|
395
|
+
}), /* @ts-ignore */
|
|
396
|
+
...(ngDevMode ? [{ debugName: "copyMods" }] : /* istanbul ignore next */ []));
|
|
397
|
+
this.row = input.required(/* @ts-ignore */
|
|
398
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
399
|
+
this.column = input.required(/* @ts-ignore */
|
|
400
|
+
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
401
|
+
/** Шаблон значка приложения; когда он дан, перечень кита не спрашивается. */
|
|
402
|
+
this.iconTemplate = input(null, /* @ts-ignore */
|
|
403
|
+
...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
|
|
404
|
+
inject(DestroyRef).onDestroy(() => this.#clearTimer());
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Наведение: проявить кнопку копирования и замерить обрезку.
|
|
408
|
+
*
|
|
409
|
+
* Ширина известна только отрисованному узлу, а меняется она и от переезда столбца, и от
|
|
410
|
+
* ширины окна: посчитанная один раз, она соврала бы при первом же изменении.
|
|
411
|
+
*/
|
|
412
|
+
onMouseEnter() {
|
|
413
|
+
this.hovered.set(true);
|
|
414
|
+
const text = this.#host.nativeElement.querySelector(`.${BEM_BLOCK$3}__text`);
|
|
415
|
+
const cut = text !== null && text.scrollWidth > text.clientWidth;
|
|
416
|
+
this.hint.set(!this.narrow() && cut ? (this.column().tooltip ?? dataTableCellText(this.value())) : '');
|
|
417
|
+
}
|
|
418
|
+
onCopy() {
|
|
419
|
+
this.#clipboard.copy(dataTableCellText(this.value()));
|
|
420
|
+
this.copied.set(true);
|
|
421
|
+
this.#clearTimer();
|
|
422
|
+
this.#copiedTimer = setTimeout(() => this.copied.set(false), COPIED_DELAY_MS);
|
|
423
|
+
}
|
|
424
|
+
#clearTimer() {
|
|
425
|
+
if (this.#copiedTimer !== null) {
|
|
426
|
+
clearTimeout(this.#copiedTimer);
|
|
427
|
+
this.#copiedTimer = null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
431
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: RtDataTableCellComponent, isStandalone: true, selector: "rt-data-table-cell", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "hovered.set(false)" }, properties: { "style.width": "column().width", "style.min-width": "column().minWidth" }, classAttribute: "rt-data-table-cell" }, ngImport: i0, template: "<ng-container rtBlock=\"rt-data-table-cell\">\n <ng-template #iconTpl>\n @if (iconTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"iconContext()\" />\n } @else if (kitIcon(); as name) {\n <rt-icon size=\"lg\" [name]=\"name\" [fill]=\"icon()?.outlined !== true\" [style]=\"iconStyle()\" />\n } @else if (glyph(); as name) {\n <span rtElem=\"glyph\" aria-hidden=\"true\" qa-dataid=\"data-table-cell-glyph\" [rtMod]=\"glyphMods()\" [style]=\"iconStyle()\">\n {{ name }}\n </span>\n }\n </ng-template>\n\n @if (icon()?.placement === 'left') {\n <span rtElem=\"prefix\" qa-dataid=\"data-table-cell-prefix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n <div rtElem=\"title\" [rtMod]=\"titleMods()\">\n <div rtElem=\"text\" qa-dataid=\"data-table-cell-text\" [rtTooltip]=\"hint()\">{{ value() | emptyToDash }}</div>\n </div>\n\n @if (icon()?.placement === 'right') {\n <span rtElem=\"suffix\" qa-dataid=\"data-table-cell-suffix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n @if (copyable()) {\n <rt-icon-button\n rtElem=\"copy-button\"\n rtDataTableStopRowClick\n qa-dataid=\"data-table-cell-copy\"\n size=\"sm\"\n [rtMod]=\"copyMods()\"\n [icon]=\"copyIcon()\"\n [ariaLabel]=\"copyLabel()\"\n [tooltip]=\"narrow() ? '' : copyLabel()\"\n (clicked)=\"onCopy()\" />\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-cell{--rt-data-table-cell-transition-duration: var(--rt-duration-fast);--rt-data-table-cell-glyph-size: var(--rt-size-6);position:relative;display:flex;width:100%;height:100%;align-items:center;gap:var(--rt-space-sm)}.rt-data-table-cell__glyph{display:inline-block;overflow:hidden;width:var(--rt-data-table-cell-glyph-size);font-family:Material Symbols Outlined,sans-serif;font-feature-settings:\"liga\";font-size:var(--rt-data-table-cell-glyph-size);font-style:normal;font-weight:var(--rt-font-weight-regular);letter-spacing:normal;line-height:1;text-transform:none;white-space:nowrap}.rt-data-table-cell__glyph--filled{font-variation-settings:\"FILL\" 1}.rt-data-table-cell__prefix,.rt-data-table-cell__suffix{display:inline-flex;min-width:fit-content;flex:0 0 auto}.rt-data-table-cell__title{display:table;width:100%;table-layout:fixed}.rt-data-table-cell__title--align--left{text-align:left}.rt-data-table-cell__title--align--center{text-align:center}.rt-data-table-cell__title--align--right{text-align:right}.rt-data-table-cell__text{overflow:hidden;width:100%;padding:var(--rt-space-sm) var(--rt-space-sm) var(--rt-space-sm) 0;text-overflow:ellipsis;white-space:nowrap}.rt-data-table-cell__copy-button{position:absolute;transition:visibility var(--rt-data-table-cell-transition-duration) linear;visibility:hidden}@media(hover:none){.rt-data-table-cell__copy-button{visibility:visible}}.rt-data-table-cell__copy-button{--rt-icon-button-color: var(--rt-list-copy-button-color)}.rt-data-table-cell__copy-button .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-copy-button-size);--rt-icon-button-radius: var(--rt-list-copy-button-radius);--rt-icon-button-color-hover: var(--rt-color-text-primary);--rt-icon-button-color-bg-hover: var(--rt-list-copy-button-bg-hover);background-color:var(--rt-list-copy-button-bg)}.rt-data-table-cell__copy-button--position--left{left:var(--rt-space-xs)}.rt-data-table-cell__copy-button--position--right{right:var(--rt-space-xs)}.rt-data-table-cell__copy-button--complete{cursor:not-allowed}.rt-data-table-cell__copy-button--visible{visibility:visible}}\n"], dependencies: [{ kind: "component", type:
|
|
432
|
+
// components
|
|
433
|
+
RtIconButtonComponent, selector: "rt-icon-button", inputs: ["icon", "glyph", "ariaLabel", "variant", "iconColor", "iconFill", "size", "iconSize", "type", "tooltip", "tabIndex", "loading", "disabled", "active", "indicator"], outputs: ["clicked"] }, { kind: "component", type: RtIconComponent, selector: "rt-icon", inputs: ["name", "glyph", "size", "color", "fill", "spin", "rotate"] }, { kind: "directive", type:
|
|
434
|
+
// directives
|
|
435
|
+
BlockDirective, selector: "[rtBlock]", inputs: ["rtMod"] }, { kind: "directive", type: ElemDirective, selector: "[rtElem]", inputs: ["rtMod"] }, { kind: "directive", type: ModDirective, selector: "[rtMod]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RtDataTableStopRowClickDirective, selector: "[rtDataTableStopRowClick]" }, { kind: "directive", type: RtTooltipDirective, selector: "[rtTooltip]", inputs: ["rtTooltip", "rtTooltipPlacement", "rtTooltipWhenTruncated"], exportAs: ["rtTooltip"] }, { kind: "pipe", type:
|
|
436
|
+
// pipes
|
|
437
|
+
EmptyToDashPipe, name: "emptyToDash" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
438
|
+
}
|
|
439
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableCellComponent, decorators: [{
|
|
440
|
+
type: Component,
|
|
441
|
+
args: [{ selector: 'rt-data-table-cell', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
442
|
+
// components
|
|
443
|
+
RtIconButtonComponent,
|
|
444
|
+
RtIconComponent,
|
|
445
|
+
// directives
|
|
446
|
+
BlockDirective,
|
|
447
|
+
ElemDirective,
|
|
448
|
+
ModDirective,
|
|
449
|
+
NgTemplateOutlet,
|
|
450
|
+
RtDataTableStopRowClickDirective,
|
|
451
|
+
RtTooltipDirective,
|
|
452
|
+
// pipes
|
|
453
|
+
EmptyToDashPipe,
|
|
454
|
+
], host: {
|
|
455
|
+
class: BEM_BLOCK$3,
|
|
456
|
+
'[style.width]': 'column().width',
|
|
457
|
+
'[style.min-width]': 'column().minWidth',
|
|
458
|
+
'(mouseenter)': 'onMouseEnter()',
|
|
459
|
+
'(mouseleave)': 'hovered.set(false)',
|
|
460
|
+
}, template: "<ng-container rtBlock=\"rt-data-table-cell\">\n <ng-template #iconTpl>\n @if (iconTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"iconContext()\" />\n } @else if (kitIcon(); as name) {\n <rt-icon size=\"lg\" [name]=\"name\" [fill]=\"icon()?.outlined !== true\" [style]=\"iconStyle()\" />\n } @else if (glyph(); as name) {\n <span rtElem=\"glyph\" aria-hidden=\"true\" qa-dataid=\"data-table-cell-glyph\" [rtMod]=\"glyphMods()\" [style]=\"iconStyle()\">\n {{ name }}\n </span>\n }\n </ng-template>\n\n @if (icon()?.placement === 'left') {\n <span rtElem=\"prefix\" qa-dataid=\"data-table-cell-prefix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n <div rtElem=\"title\" [rtMod]=\"titleMods()\">\n <div rtElem=\"text\" qa-dataid=\"data-table-cell-text\" [rtTooltip]=\"hint()\">{{ value() | emptyToDash }}</div>\n </div>\n\n @if (icon()?.placement === 'right') {\n <span rtElem=\"suffix\" qa-dataid=\"data-table-cell-suffix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n @if (copyable()) {\n <rt-icon-button\n rtElem=\"copy-button\"\n rtDataTableStopRowClick\n qa-dataid=\"data-table-cell-copy\"\n size=\"sm\"\n [rtMod]=\"copyMods()\"\n [icon]=\"copyIcon()\"\n [ariaLabel]=\"copyLabel()\"\n [tooltip]=\"narrow() ? '' : copyLabel()\"\n (clicked)=\"onCopy()\" />\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-cell{--rt-data-table-cell-transition-duration: var(--rt-duration-fast);--rt-data-table-cell-glyph-size: var(--rt-size-6);position:relative;display:flex;width:100%;height:100%;align-items:center;gap:var(--rt-space-sm)}.rt-data-table-cell__glyph{display:inline-block;overflow:hidden;width:var(--rt-data-table-cell-glyph-size);font-family:Material Symbols Outlined,sans-serif;font-feature-settings:\"liga\";font-size:var(--rt-data-table-cell-glyph-size);font-style:normal;font-weight:var(--rt-font-weight-regular);letter-spacing:normal;line-height:1;text-transform:none;white-space:nowrap}.rt-data-table-cell__glyph--filled{font-variation-settings:\"FILL\" 1}.rt-data-table-cell__prefix,.rt-data-table-cell__suffix{display:inline-flex;min-width:fit-content;flex:0 0 auto}.rt-data-table-cell__title{display:table;width:100%;table-layout:fixed}.rt-data-table-cell__title--align--left{text-align:left}.rt-data-table-cell__title--align--center{text-align:center}.rt-data-table-cell__title--align--right{text-align:right}.rt-data-table-cell__text{overflow:hidden;width:100%;padding:var(--rt-space-sm) var(--rt-space-sm) var(--rt-space-sm) 0;text-overflow:ellipsis;white-space:nowrap}.rt-data-table-cell__copy-button{position:absolute;transition:visibility var(--rt-data-table-cell-transition-duration) linear;visibility:hidden}@media(hover:none){.rt-data-table-cell__copy-button{visibility:visible}}.rt-data-table-cell__copy-button{--rt-icon-button-color: var(--rt-list-copy-button-color)}.rt-data-table-cell__copy-button .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-copy-button-size);--rt-icon-button-radius: var(--rt-list-copy-button-radius);--rt-icon-button-color-hover: var(--rt-color-text-primary);--rt-icon-button-color-bg-hover: var(--rt-list-copy-button-bg-hover);background-color:var(--rt-list-copy-button-bg)}.rt-data-table-cell__copy-button--position--left{left:var(--rt-space-xs)}.rt-data-table-cell__copy-button--position--right{right:var(--rt-space-xs)}.rt-data-table-cell__copy-button--complete{cursor:not-allowed}.rt-data-table-cell__copy-button--visible{visibility:visible}}\n"] }]
|
|
461
|
+
}], ctorParameters: () => [], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }] } });
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Какой порядок просит нажатие на шапку — как в первом ките: по возрастанию, а после возрастания
|
|
465
|
+
* по убыванию. Снятия порядка нет: после убывания снова возрастание.
|
|
466
|
+
*/
|
|
467
|
+
function dataTableNextSortOrder(current) {
|
|
468
|
+
return current?.sortDirection?.toLowerCase() === EListSortOrder.ASC ? EListSortOrder.DESC : EListSortOrder.ASC;
|
|
469
|
+
}
|
|
470
|
+
/** Порядок таблицы сейчас стоит по этой колонке. */
|
|
471
|
+
function dataTableSortActive(sort, current) {
|
|
472
|
+
return !!current?.propertyName && !!sort?.propertyName && current.propertyName === sort.propertyName;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* `aria-sort` сортируемой колонки: порядок по ней, если он стоит по ней, иначе `none`. Колонке
|
|
476
|
+
* без сортировки атрибут не положен вовсе — `null` снимает его.
|
|
477
|
+
*/
|
|
478
|
+
function dataTableAriaSort(sort, current) {
|
|
479
|
+
if (!sort?.propertyName) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
if (!dataTableSortActive(sort, current)) {
|
|
483
|
+
return 'none';
|
|
484
|
+
}
|
|
485
|
+
const direction = current?.sortDirection?.toLowerCase();
|
|
486
|
+
if (direction === EListSortOrder.ASC) {
|
|
487
|
+
return 'ascending';
|
|
488
|
+
}
|
|
489
|
+
return direction === EListSortOrder.DESC ? 'descending' : 'none';
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const BEM_BLOCK$2 = 'rt-data-table-header-cell';
|
|
493
|
+
/**
|
|
494
|
+
* Ячейка шапки `rt-data-table` — шапка первого кита без Material.
|
|
495
|
+
*
|
|
496
|
+
* Нажатие на шапку сортируемой колонки просит порядок: по возрастанию, затем по убыванию, и так
|
|
497
|
+
* по кругу — снятия порядка нет. С клавиатуры то же делают Enter и пробел. Стрелки порядка видны
|
|
498
|
+
* при наведении, при фокусе и у колонки, по которой порядок стоит. Значок шапки — набором кита по имени первого кита либо шаблоном приложения.
|
|
499
|
+
*/
|
|
500
|
+
class RtDataTableHeaderCellComponent {
|
|
501
|
+
constructor() {
|
|
502
|
+
/** Шапка сортируемой колонки нажимается и с клавиатуры: у неё фокус и роль кнопки. */
|
|
503
|
+
this.sortable = computed(() => !!this.sortModel()?.propertyName, /* @ts-ignore */
|
|
504
|
+
...(ngDevMode ? [{ debugName: "sortable" }] : /* istanbul ignore next */ []));
|
|
505
|
+
this.active = computed(() => dataTableSortActive(this.sortModel(), this.currentSortModel()), /* @ts-ignore */
|
|
506
|
+
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
507
|
+
this.labelMods = computed(() => ({ align: this.headerModel().align }), /* @ts-ignore */
|
|
508
|
+
...(ngDevMode ? [{ debugName: "labelMods" }] : /* istanbul ignore next */ []));
|
|
509
|
+
this.arrowsMods = computed(() => ({ active: this.active() }), /* @ts-ignore */
|
|
510
|
+
...(ngDevMode ? [{ debugName: "arrowsMods" }] : /* istanbul ignore next */ []));
|
|
511
|
+
this.descMods = computed(() => ({
|
|
512
|
+
active: this.active() && this.currentSortModel()?.sortDirection?.toLowerCase() === EListSortOrder.DESC,
|
|
513
|
+
first: true,
|
|
514
|
+
}), /* @ts-ignore */
|
|
515
|
+
...(ngDevMode ? [{ debugName: "descMods" }] : /* istanbul ignore next */ []));
|
|
516
|
+
this.ascMods = computed(() => ({
|
|
517
|
+
active: this.active() && this.currentSortModel()?.sortDirection?.toLowerCase() === EListSortOrder.ASC,
|
|
518
|
+
second: true,
|
|
519
|
+
}), /* @ts-ignore */
|
|
520
|
+
...(ngDevMode ? [{ debugName: "ascMods" }] : /* istanbul ignore next */ []));
|
|
521
|
+
/** Значок шапки; его цвет и видимость, как в первом ките, ничего не меняют. */
|
|
522
|
+
this.icon = computed(() => this.headerModel().icon ?? null, /* @ts-ignore */
|
|
523
|
+
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
524
|
+
this.kitIcon = computed(() => {
|
|
525
|
+
const icon = this.icon();
|
|
526
|
+
return icon ? dataTableIconName(icon.glyph) : null;
|
|
527
|
+
}, /* @ts-ignore */
|
|
528
|
+
...(ngDevMode ? [{ debugName: "kitIcon" }] : /* istanbul ignore next */ []));
|
|
529
|
+
/** Имя без пары в перечне шапка рисует глифом Material Symbols — так же, как ячейка. */
|
|
530
|
+
this.glyph = computed(() => {
|
|
531
|
+
const icon = this.icon();
|
|
532
|
+
return icon && !this.kitIcon() ? icon.glyph : null;
|
|
533
|
+
}, /* @ts-ignore */
|
|
534
|
+
...(ngDevMode ? [{ debugName: "glyph" }] : /* istanbul ignore next */ []));
|
|
535
|
+
/** Залитый глиф — как залитый значок набора: контурным его делает `outlined` колонки. */
|
|
536
|
+
this.glyphMods = computed(() => ({ filled: this.icon()?.outlined !== true }), /* @ts-ignore */
|
|
537
|
+
...(ngDevMode ? [{ debugName: "glyphMods" }] : /* istanbul ignore next */ []));
|
|
538
|
+
this.iconContext = computed(() => {
|
|
539
|
+
const icon = this.icon();
|
|
540
|
+
const column = this.column();
|
|
541
|
+
return icon && column ? { column, $implicit: icon.glyph, row: null } : null;
|
|
542
|
+
}, /* @ts-ignore */
|
|
543
|
+
...(ngDevMode ? [{ debugName: "iconContext" }] : /* istanbul ignore next */ []));
|
|
544
|
+
this.headerModel = input.required(/* @ts-ignore */
|
|
545
|
+
...(ngDevMode ? [{ debugName: "headerModel" }] : /* istanbul ignore next */ []));
|
|
546
|
+
this.sortModel = input.required(/* @ts-ignore */
|
|
547
|
+
...(ngDevMode ? [{ debugName: "sortModel" }] : /* istanbul ignore next */ []));
|
|
548
|
+
this.currentSortModel = input.required(/* @ts-ignore */
|
|
549
|
+
...(ngDevMode ? [{ debugName: "currentSortModel" }] : /* istanbul ignore next */ []));
|
|
550
|
+
/** Колонка шапки — её получает шаблон значка приложения. */
|
|
551
|
+
this.column = input(null, /* @ts-ignore */
|
|
552
|
+
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
553
|
+
/** Шаблон значка приложения; когда он дан, перечень кита не спрашивается. */
|
|
554
|
+
this.iconTemplate = input(null, /* @ts-ignore */
|
|
555
|
+
...(ngDevMode ? [{ debugName: "iconTemplate" }] : /* istanbul ignore next */ []));
|
|
556
|
+
this.sortChange = output();
|
|
557
|
+
}
|
|
558
|
+
/** Enter и пробел просят порядок так же, как нажатие; пробел иначе прокрутил бы страницу. */
|
|
559
|
+
onKey(event) {
|
|
560
|
+
if (this.sortable()) {
|
|
561
|
+
event.preventDefault();
|
|
562
|
+
this.onClick();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
onClick() {
|
|
566
|
+
const propertyName = this.sortModel()?.propertyName;
|
|
567
|
+
if (propertyName) {
|
|
568
|
+
this.sortChange.emit({ propertyName, sortDirection: dataTableNextSortOrder(this.currentSortModel()) });
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableHeaderCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
572
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: RtDataTableHeaderCellComponent, isStandalone: true, selector: "rt-data-table-header-cell", inputs: { headerModel: { classPropertyName: "headerModel", publicName: "headerModel", isSignal: true, isRequired: true, transformFunction: null }, sortModel: { classPropertyName: "sortModel", publicName: "sortModel", isSignal: true, isRequired: true, transformFunction: null }, currentSortModel: { classPropertyName: "currentSortModel", publicName: "currentSortModel", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, iconTemplate: { classPropertyName: "iconTemplate", publicName: "iconTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange" }, host: { listeners: { "click": "onClick()", "keydown.enter": "onKey($event)", "keydown.space": "onKey($event)" }, properties: { "style.text-align": "headerModel().align", "attr.tabindex": "sortable() ? 0 : null", "attr.role": "sortable() ? \"button\" : null" }, classAttribute: "rt-data-table-header-cell" }, ngImport: i0, template: "<ng-container rtBlock=\"rt-data-table-header-cell\">\n <ng-template #iconTpl>\n @if (iconTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"iconContext()\" />\n } @else if (kitIcon(); as name) {\n <rt-icon size=\"lg\" [name]=\"name\" [fill]=\"icon()?.outlined !== true\" />\n } @else if (glyph(); as name) {\n <span rtElem=\"glyph\" aria-hidden=\"true\" qa-dataid=\"data-table-header-glyph\" [rtMod]=\"glyphMods()\">{{ name }}</span>\n }\n </ng-template>\n\n <div rtElem=\"label\" [rtMod]=\"labelMods()\">\n @if (icon()?.placement === 'left') {\n <span rtElem=\"prefix\" qa-dataid=\"data-table-header-prefix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n <div\n rtElem=\"text\"\n qa-dataid=\"data-table-header-text\"\n [class]=\"[headerModel().className] | concatClasses\"\n [rtTooltip]=\"headerModel().tooltip ?? ''\">\n {{ headerModel().label }}\n </div>\n\n @if (icon()?.placement === 'right') {\n <span rtElem=\"suffix\" qa-dataid=\"data-table-header-suffix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n </div>\n\n @if (sortModel()) {\n <div rtElem=\"arrows\" qa-dataid=\"data-table-header-sort\" [rtMod]=\"arrowsMods()\">\n <div rtElem=\"arrow\" [rtMod]=\"descMods()\"></div>\n <div rtElem=\"arrow\" [rtMod]=\"ascMods()\"></div>\n </div>\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-header-cell{--rt-data-table-header-cell-arrow-side: var(--rt-border-width-thick);--rt-data-table-header-cell-arrow-height: var(--rt-size-1);--rt-data-table-header-cell-focus-shadow: var(--rt-shadow-focus-ring);display:flex;align-items:center;justify-content:space-between;cursor:pointer}.rt-data-table-header-cell:hover .rt-data-table-header-cell__arrows,.rt-data-table-header-cell:focus-visible .rt-data-table-header-cell__arrows{visibility:visible}.rt-data-table-header-cell:focus-visible{box-shadow:var(--rt-data-table-header-cell-focus-shadow);outline:none}.rt-data-table-header-cell__label{display:flex;flex-grow:1;align-items:center;gap:var(--rt-space-sm)}.rt-data-table-header-cell__label--align--left{justify-content:flex-start}.rt-data-table-header-cell__label--align--center{justify-content:center}.rt-data-table-header-cell__label--align--right{justify-content:flex-end}.rt-data-table-header-cell__prefix,.rt-data-table-header-cell__suffix{display:inline-flex;min-width:fit-content}.rt-data-table-header-cell__glyph{display:inline-block;overflow:hidden;width:var(--rt-size-6);font-family:Material Symbols Outlined,sans-serif;font-feature-settings:\"liga\";font-size:var(--rt-size-6);font-style:normal;font-weight:var(--rt-font-weight-regular);letter-spacing:normal;line-height:1;text-transform:none;white-space:nowrap}.rt-data-table-header-cell__glyph--filled{font-variation-settings:\"FILL\" 1}.rt-data-table-header-cell__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rt-data-table-header-cell__arrows{display:flex;flex-direction:column;align-items:center;justify-content:center;margin-left:var(--rt-space-md);visibility:hidden}.rt-data-table-header-cell__arrows--active{visibility:visible}.rt-data-table-header-cell__arrow{width:0;height:0;border-right:var(--rt-data-table-header-cell-arrow-side) solid transparent;border-bottom:var(--rt-data-table-header-cell-arrow-height) solid var(--rt-color-text-muted);border-left:var(--rt-data-table-header-cell-arrow-side) solid transparent}.rt-data-table-header-cell__arrow--second{margin-top:var(--rt-space-2xs);transform:scaleY(-1)}.rt-data-table-header-cell__arrow--active{border-bottom-color:var(--rt-color-text-primary)}}\n"], dependencies: [{ kind: "component", type:
|
|
573
|
+
// components
|
|
574
|
+
RtIconComponent, selector: "rt-icon", inputs: ["name", "glyph", "size", "color", "fill", "spin", "rotate"] }, { kind: "directive", type:
|
|
575
|
+
// directives
|
|
576
|
+
BlockDirective, selector: "[rtBlock]", inputs: ["rtMod"] }, { kind: "directive", type: ElemDirective, selector: "[rtElem]", inputs: ["rtMod"] }, { kind: "directive", type: ModDirective, selector: "[rtMod]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RtTooltipDirective, selector: "[rtTooltip]", inputs: ["rtTooltip", "rtTooltipPlacement", "rtTooltipWhenTruncated"], exportAs: ["rtTooltip"] }, { kind: "pipe", type:
|
|
577
|
+
// pipes
|
|
578
|
+
ConcatClassesPipe, name: "concatClasses" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
579
|
+
}
|
|
580
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableHeaderCellComponent, decorators: [{
|
|
581
|
+
type: Component,
|
|
582
|
+
args: [{ selector: 'rt-data-table-header-cell', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
583
|
+
// components
|
|
584
|
+
RtIconComponent,
|
|
585
|
+
// directives
|
|
586
|
+
BlockDirective,
|
|
587
|
+
ElemDirective,
|
|
588
|
+
ModDirective,
|
|
589
|
+
NgTemplateOutlet,
|
|
590
|
+
RtTooltipDirective,
|
|
591
|
+
// pipes
|
|
592
|
+
ConcatClassesPipe,
|
|
593
|
+
], host: {
|
|
594
|
+
class: BEM_BLOCK$2,
|
|
595
|
+
'[style.text-align]': 'headerModel().align',
|
|
596
|
+
'[attr.tabindex]': 'sortable() ? 0 : null',
|
|
597
|
+
'[attr.role]': 'sortable() ? "button" : null',
|
|
598
|
+
'(click)': 'onClick()',
|
|
599
|
+
'(keydown.enter)': 'onKey($event)',
|
|
600
|
+
'(keydown.space)': 'onKey($event)',
|
|
601
|
+
}, template: "<ng-container rtBlock=\"rt-data-table-header-cell\">\n <ng-template #iconTpl>\n @if (iconTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"iconContext()\" />\n } @else if (kitIcon(); as name) {\n <rt-icon size=\"lg\" [name]=\"name\" [fill]=\"icon()?.outlined !== true\" />\n } @else if (glyph(); as name) {\n <span rtElem=\"glyph\" aria-hidden=\"true\" qa-dataid=\"data-table-header-glyph\" [rtMod]=\"glyphMods()\">{{ name }}</span>\n }\n </ng-template>\n\n <div rtElem=\"label\" [rtMod]=\"labelMods()\">\n @if (icon()?.placement === 'left') {\n <span rtElem=\"prefix\" qa-dataid=\"data-table-header-prefix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n\n <div\n rtElem=\"text\"\n qa-dataid=\"data-table-header-text\"\n [class]=\"[headerModel().className] | concatClasses\"\n [rtTooltip]=\"headerModel().tooltip ?? ''\">\n {{ headerModel().label }}\n </div>\n\n @if (icon()?.placement === 'right') {\n <span rtElem=\"suffix\" qa-dataid=\"data-table-header-suffix\"><ng-container [ngTemplateOutlet]=\"iconTpl\" /></span>\n }\n </div>\n\n @if (sortModel()) {\n <div rtElem=\"arrows\" qa-dataid=\"data-table-header-sort\" [rtMod]=\"arrowsMods()\">\n <div rtElem=\"arrow\" [rtMod]=\"descMods()\"></div>\n <div rtElem=\"arrow\" [rtMod]=\"ascMods()\"></div>\n </div>\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-header-cell{--rt-data-table-header-cell-arrow-side: var(--rt-border-width-thick);--rt-data-table-header-cell-arrow-height: var(--rt-size-1);--rt-data-table-header-cell-focus-shadow: var(--rt-shadow-focus-ring);display:flex;align-items:center;justify-content:space-between;cursor:pointer}.rt-data-table-header-cell:hover .rt-data-table-header-cell__arrows,.rt-data-table-header-cell:focus-visible .rt-data-table-header-cell__arrows{visibility:visible}.rt-data-table-header-cell:focus-visible{box-shadow:var(--rt-data-table-header-cell-focus-shadow);outline:none}.rt-data-table-header-cell__label{display:flex;flex-grow:1;align-items:center;gap:var(--rt-space-sm)}.rt-data-table-header-cell__label--align--left{justify-content:flex-start}.rt-data-table-header-cell__label--align--center{justify-content:center}.rt-data-table-header-cell__label--align--right{justify-content:flex-end}.rt-data-table-header-cell__prefix,.rt-data-table-header-cell__suffix{display:inline-flex;min-width:fit-content}.rt-data-table-header-cell__glyph{display:inline-block;overflow:hidden;width:var(--rt-size-6);font-family:Material Symbols Outlined,sans-serif;font-feature-settings:\"liga\";font-size:var(--rt-size-6);font-style:normal;font-weight:var(--rt-font-weight-regular);letter-spacing:normal;line-height:1;text-transform:none;white-space:nowrap}.rt-data-table-header-cell__glyph--filled{font-variation-settings:\"FILL\" 1}.rt-data-table-header-cell__text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rt-data-table-header-cell__arrows{display:flex;flex-direction:column;align-items:center;justify-content:center;margin-left:var(--rt-space-md);visibility:hidden}.rt-data-table-header-cell__arrows--active{visibility:visible}.rt-data-table-header-cell__arrow{width:0;height:0;border-right:var(--rt-data-table-header-cell-arrow-side) solid transparent;border-bottom:var(--rt-data-table-header-cell-arrow-height) solid var(--rt-color-text-muted);border-left:var(--rt-data-table-header-cell-arrow-side) solid transparent}.rt-data-table-header-cell__arrow--second{margin-top:var(--rt-space-2xs);transform:scaleY(-1)}.rt-data-table-header-cell__arrow--active{border-bottom-color:var(--rt-color-text-primary)}}\n"] }]
|
|
602
|
+
}], propDecorators: { headerModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerModel", required: true }] }], sortModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortModel", required: true }] }], currentSortModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSortModel", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: false }] }], iconTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconTemplate", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }] } });
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Значок вида сравнения — имя первого кита; набор кита рисует его по перечню соответствий.
|
|
606
|
+
* «Начинается с» и «заканчивается на» первый кит объявлял, но значка и пункта меню им не давал.
|
|
607
|
+
*/
|
|
608
|
+
const DATA_TABLE_FILTER_OPERATOR_GLYPHS = {
|
|
609
|
+
[EFilterOperatorType.EQUALS]: 'drag_handle',
|
|
610
|
+
[EFilterOperatorType.NOT_EQUALS]: 'block',
|
|
611
|
+
[EFilterOperatorType.STARTS_WITH]: null,
|
|
612
|
+
[EFilterOperatorType.ENDS_WITH]: null,
|
|
613
|
+
[EFilterOperatorType.CONTAINS]: 'more_horiz',
|
|
614
|
+
[EFilterOperatorType.GREATER_THAN]: 'chevron_right',
|
|
615
|
+
[EFilterOperatorType.LESS_THAN]: 'chevron_left',
|
|
616
|
+
};
|
|
617
|
+
/** Пункты меню видов сравнения в порядке первого кита. */
|
|
618
|
+
const DATA_TABLE_FILTER_MENU_OPERATORS = [
|
|
619
|
+
EFilterOperatorType.EQUALS,
|
|
620
|
+
EFilterOperatorType.NOT_EQUALS,
|
|
621
|
+
EFilterOperatorType.CONTAINS,
|
|
622
|
+
EFilterOperatorType.GREATER_THAN,
|
|
623
|
+
EFilterOperatorType.LESS_THAN,
|
|
624
|
+
];
|
|
625
|
+
/** Вид сравнения колонки по умолчанию: незнакомое и пустое значение дают «равно». */
|
|
626
|
+
function dataTableDefaultOperator(operator) {
|
|
627
|
+
return operator && FILTER_OPERATORS.includes(operator) ? operator : EFilterOperatorType.EQUALS;
|
|
628
|
+
}
|
|
629
|
+
/** Условие колонки из набора приложения, а без него — пустое условие с видом по умолчанию. */
|
|
630
|
+
function dataTableColumnFilter(filters, propertyName, defaultOperator) {
|
|
631
|
+
return (filters.find((filter) => filter.propertyName === propertyName) ?? {
|
|
632
|
+
propertyName,
|
|
633
|
+
operatorType: defaultOperator,
|
|
634
|
+
value: '',
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Набор условий после смены значения колонки; `null` — приложению сообщать нечего.
|
|
639
|
+
* Пустое значение снимает условие колонки, значение на колонке без условия добавляет его.
|
|
640
|
+
*/
|
|
641
|
+
function dataTableFiltersWithValue(filters, current, value) {
|
|
642
|
+
const hasCondition = filters.some((filter) => filter.propertyName === current.propertyName);
|
|
643
|
+
if (hasCondition) {
|
|
644
|
+
return value
|
|
645
|
+
? filters.map((filter) => (filter.propertyName === current.propertyName ? { ...filter, value } : filter))
|
|
646
|
+
: filters.filter((filter) => filter.propertyName !== current.propertyName);
|
|
647
|
+
}
|
|
648
|
+
return value ? [...filters, { propertyName: current.propertyName, operatorType: current.operatorType, value }] : null;
|
|
649
|
+
}
|
|
650
|
+
/** Набор условий после смены вида сравнения; `null` — ни условия, ни значения, спрашивать нечего. */
|
|
651
|
+
function dataTableFiltersWithOperator(filters, current, operatorType) {
|
|
652
|
+
const hasCondition = filters.some((filter) => filter.propertyName === current.propertyName);
|
|
653
|
+
if (hasCondition) {
|
|
654
|
+
return filters.map((filter) => filter.propertyName === current.propertyName ? { ...filter, operatorType } : filter);
|
|
655
|
+
}
|
|
656
|
+
return current.value ? [...filters, { operatorType, propertyName: current.propertyName, value: current.value }] : null;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* День поля даты кита (`2025-01-01`) — в момент ISO, как отдавал первый кит: полночь дня по
|
|
660
|
+
* местному времени. Пустая строка остаётся пустой — она снимает условие.
|
|
661
|
+
*/
|
|
662
|
+
function dataTableDayToIso(day) {
|
|
663
|
+
const [year, month, date] = day.split('-').map(Number);
|
|
664
|
+
const complete = [year, month, date].every((part) => !!part);
|
|
665
|
+
return complete ? new Date(year, month - 1, date).toISOString() : '';
|
|
666
|
+
}
|
|
667
|
+
/** Обратно: момент условия — в день поля даты по местному времени; нераспознанное даёт пустое. */
|
|
668
|
+
function dataTableIsoToDay(value) {
|
|
669
|
+
const moment = new Date(typeof value === 'string' ? value : '');
|
|
670
|
+
if (Number.isNaN(moment.getTime())) {
|
|
671
|
+
return '';
|
|
672
|
+
}
|
|
673
|
+
const month = String(moment.getMonth() + 1).padStart(2, '0');
|
|
674
|
+
const date = String(moment.getDate()).padStart(2, '0');
|
|
675
|
+
return `${moment.getFullYear()}-${month}-${date}`;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const BEM_BLOCK$1 = 'rt-data-table-filter-cell';
|
|
679
|
+
/** Значок кнопки вида сравнения, которому первый кит значка не дал. */
|
|
680
|
+
const FALLBACK_OPERATOR_ICON = 'ellipsis-h';
|
|
681
|
+
const OPERATOR_LABELS = {
|
|
682
|
+
[EFilterOperatorType.EQUALS]: 'dataTableFilterOperatorEquals',
|
|
683
|
+
[EFilterOperatorType.NOT_EQUALS]: 'dataTableFilterOperatorNotEquals',
|
|
684
|
+
[EFilterOperatorType.CONTAINS]: 'dataTableFilterOperatorContains',
|
|
685
|
+
[EFilterOperatorType.GREATER_THAN]: 'dataTableFilterOperatorGreaterThan',
|
|
686
|
+
[EFilterOperatorType.LESS_THAN]: 'dataTableFilterOperatorLessThan',
|
|
687
|
+
};
|
|
688
|
+
/** Одно и то же условие: колонка, вид сравнения и значение совпадают. */
|
|
689
|
+
function sameFilter(a, b) {
|
|
690
|
+
return a.propertyName === b.propertyName && a.operatorType === b.operatorType && a.value === b.value;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Ячейка строки отбора `rt-data-table` — ячейка отбора первого кита на полях кита.
|
|
694
|
+
*
|
|
695
|
+
* Своих условий у ячейки нет: она читает набор приложения и отдаёт ему новый при каждой смене.
|
|
696
|
+
* Текст и число фиксируются по Enter и уходу с поля, дата — выбором дня, список — выбором пункта;
|
|
697
|
+
* пустое значение снимает условие колонки. Кнопка вида сравнения предлагает остальные виды.
|
|
698
|
+
*/
|
|
699
|
+
class RtDataTableFilterCellComponent {
|
|
700
|
+
constructor() {
|
|
701
|
+
this.#translate = inject(RT_KIT_TRANSLATOR);
|
|
702
|
+
this.#titleCase = new TitleCasePipe();
|
|
703
|
+
/** Набранное, но ещё не зафиксированное значение текстового и числового поля. */
|
|
704
|
+
this.#draft = null;
|
|
705
|
+
this.filterTypes = ERtDataTableFilterType;
|
|
706
|
+
this.valuePlaceholder = rtKitLabel('dataTableFilterValuePlaceholder');
|
|
707
|
+
this.selectPlaceholder = rtKitLabel('dataTableFilterSelectPlaceholder');
|
|
708
|
+
this.clearLabel = rtKitLabel('dataTableFilterClear');
|
|
709
|
+
/**
|
|
710
|
+
* Условие своей колонки из набора приложения. Сверяется по содержимому: набор меняется целиком
|
|
711
|
+
* и по чужой колонке, а своё условие при этом остаётся тем же — и выбранный здесь вид
|
|
712
|
+
* сравнения пустой колонки сбрасывать нечем.
|
|
713
|
+
*/
|
|
714
|
+
this.#ownFilter = computed(() => dataTableColumnFilter(this.filterModel(), this.filterProperty(), dataTableDefaultOperator(this.defaultFilterOperator())), { ...(ngDevMode ? { debugName: "#ownFilter" } : /* istanbul ignore next */ {}), equal: sameFilter });
|
|
715
|
+
/** Условие колонки: из набора приложения, а вид сравнения без условия помнит сама ячейка. */
|
|
716
|
+
this.currentFilter = linkedSignal(() => this.#ownFilter(), /* @ts-ignore */
|
|
717
|
+
...(ngDevMode ? [{ debugName: "currentFilter" }] : /* istanbul ignore next */ []));
|
|
718
|
+
this.hasValue = computed(() => !!this.currentFilter().value, /* @ts-ignore */
|
|
719
|
+
...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
|
|
720
|
+
this.day = computed(() => dataTableIsoToDay(this.currentFilter().value), /* @ts-ignore */
|
|
721
|
+
...(ngDevMode ? [{ debugName: "day" }] : /* istanbul ignore next */ []));
|
|
722
|
+
this.number = computed(() => {
|
|
723
|
+
const value = Number(this.currentFilter().value);
|
|
724
|
+
return this.currentFilter().value === '' || Number.isNaN(value) ? null : value;
|
|
725
|
+
}, /* @ts-ignore */
|
|
726
|
+
...(ngDevMode ? [{ debugName: "number" }] : /* istanbul ignore next */ []));
|
|
727
|
+
this.operatorIcon = computed(() => this.#operatorIcon(this.currentFilter().operatorType), /* @ts-ignore */
|
|
728
|
+
...(ngDevMode ? [{ debugName: "operatorIcon" }] : /* istanbul ignore next */ []));
|
|
729
|
+
this.operatorLabel = computed(() => this.#operatorLabel(this.#translate(), this.currentFilter().operatorType), /* @ts-ignore */
|
|
730
|
+
...(ngDevMode ? [{ debugName: "operatorLabel" }] : /* istanbul ignore next */ []));
|
|
731
|
+
/**
|
|
732
|
+
* Пункты меню — предложенные колонкой виды в порядке первого кита, кроме нынешнего: его первый кит
|
|
733
|
+
* в меню не выводит, нынешний вид показывает кнопка.
|
|
734
|
+
*/
|
|
735
|
+
this.operatorItems = computed(() => {
|
|
736
|
+
const translate = this.#translate();
|
|
737
|
+
const current = this.currentFilter().operatorType;
|
|
738
|
+
return DATA_TABLE_FILTER_MENU_OPERATORS.filter((operator) => operator !== current && this.filterOperators().includes(operator)).map((operator) => ({
|
|
739
|
+
operator,
|
|
740
|
+
icon: this.#operatorIcon(operator),
|
|
741
|
+
label: this.#operatorLabel(translate, operator),
|
|
742
|
+
}));
|
|
743
|
+
}, /* @ts-ignore */
|
|
744
|
+
...(ngDevMode ? [{ debugName: "operatorItems" }] : /* istanbul ignore next */ []));
|
|
745
|
+
this.selectOptions = computed(() => this.filterSelectOptions().map((option) => ({ label: this.#titleCase.transform(option), value: option })), /* @ts-ignore */
|
|
746
|
+
...(ngDevMode ? [{ debugName: "selectOptions" }] : /* istanbul ignore next */ []));
|
|
747
|
+
/** Колонка, по которой отбирает ячейка. */
|
|
748
|
+
/** Вид полей отбора: `outline` — рамка со всех сторон, `fill` — залитое поле с чертой снизу. */
|
|
749
|
+
this.appearance = input('outline', /* @ts-ignore */
|
|
750
|
+
...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
751
|
+
this.filterProperty = input.required(/* @ts-ignore */
|
|
752
|
+
...(ngDevMode ? [{ debugName: "filterProperty" }] : /* istanbul ignore next */ []));
|
|
753
|
+
this.filterType = input.required(/* @ts-ignore */
|
|
754
|
+
...(ngDevMode ? [{ debugName: "filterType" }] : /* istanbul ignore next */ []));
|
|
755
|
+
/** Весь набор условий приложения. */
|
|
756
|
+
this.filterModel = input([], { ...(ngDevMode ? { debugName: "filterModel" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
757
|
+
this.defaultFilterOperator = input(null, /* @ts-ignore */
|
|
758
|
+
...(ngDevMode ? [{ debugName: "defaultFilterOperator" }] : /* istanbul ignore next */ []));
|
|
759
|
+
this.filterOperators = input([], { ...(ngDevMode ? { debugName: "filterOperators" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
760
|
+
this.filterSelectOptions = input([], { ...(ngDevMode ? { debugName: "filterSelectOptions" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
761
|
+
this.filterChange = output();
|
|
762
|
+
}
|
|
763
|
+
#translate;
|
|
764
|
+
#titleCase;
|
|
765
|
+
/** Набранное, но ещё не зафиксированное значение текстового и числового поля. */
|
|
766
|
+
#draft;
|
|
767
|
+
/**
|
|
768
|
+
* Условие своей колонки из набора приложения. Сверяется по содержимому: набор меняется целиком
|
|
769
|
+
* и по чужой колонке, а своё условие при этом остаётся тем же — и выбранный здесь вид
|
|
770
|
+
* сравнения пустой колонки сбрасывать нечем.
|
|
771
|
+
*/
|
|
772
|
+
#ownFilter;
|
|
773
|
+
/** Набор в поле: пустое поле — это очистка, она фиксируется сразу, как у первого кита. */
|
|
774
|
+
onDraft(value) {
|
|
775
|
+
this.#draft = value ?? '';
|
|
776
|
+
if (this.#draft === '') {
|
|
777
|
+
this.onCommit();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
/** Enter и уход с поля фиксируют набранное. */
|
|
781
|
+
onCommit() {
|
|
782
|
+
if (this.#draft !== null) {
|
|
783
|
+
this.onValueChange(this.#draft);
|
|
784
|
+
this.#draft = null;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
onNumberDraft(value) {
|
|
788
|
+
this.onDraft(value === null ? '' : String(value));
|
|
789
|
+
}
|
|
790
|
+
onDayChange(day) {
|
|
791
|
+
this.onValueChange(dataTableDayToIso(day ?? ''));
|
|
792
|
+
}
|
|
793
|
+
onValueChange(value) {
|
|
794
|
+
const next = value ?? '';
|
|
795
|
+
const current = this.currentFilter();
|
|
796
|
+
if (next === current.value) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
const filters = dataTableFiltersWithValue(this.filterModel(), current, next);
|
|
800
|
+
if (filters) {
|
|
801
|
+
this.filterChange.emit(filters);
|
|
802
|
+
}
|
|
803
|
+
this.currentFilter.set({ ...current, value: next });
|
|
804
|
+
}
|
|
805
|
+
onOperatorChange(operatorType) {
|
|
806
|
+
const current = this.currentFilter();
|
|
807
|
+
const filters = dataTableFiltersWithOperator(this.filterModel(), current, operatorType);
|
|
808
|
+
if (filters) {
|
|
809
|
+
this.filterChange.emit(filters);
|
|
810
|
+
}
|
|
811
|
+
this.currentFilter.set({ ...current, operatorType });
|
|
812
|
+
}
|
|
813
|
+
#operatorIcon(operator) {
|
|
814
|
+
const glyph = DATA_TABLE_FILTER_OPERATOR_GLYPHS[operator];
|
|
815
|
+
return (glyph && dataTableIconName(glyph)) || FALLBACK_OPERATOR_ICON;
|
|
816
|
+
}
|
|
817
|
+
#operatorLabel(translate, operator) {
|
|
818
|
+
const key = OPERATOR_LABELS[operator];
|
|
819
|
+
return key ? translate(key) : this.#titleCase.transform(operator);
|
|
820
|
+
}
|
|
821
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableFilterCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
822
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: RtDataTableFilterCellComponent, isStandalone: true, selector: "rt-data-table-filter-cell", inputs: { appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, filterProperty: { classPropertyName: "filterProperty", publicName: "filterProperty", isSignal: true, isRequired: true, transformFunction: null }, filterType: { classPropertyName: "filterType", publicName: "filterType", isSignal: true, isRequired: true, transformFunction: null }, filterModel: { classPropertyName: "filterModel", publicName: "filterModel", isSignal: true, isRequired: false, transformFunction: null }, defaultFilterOperator: { classPropertyName: "defaultFilterOperator", publicName: "defaultFilterOperator", isSignal: true, isRequired: false, transformFunction: null }, filterOperators: { classPropertyName: "filterOperators", publicName: "filterOperators", isSignal: true, isRequired: false, transformFunction: null }, filterSelectOptions: { classPropertyName: "filterSelectOptions", publicName: "filterSelectOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, host: { classAttribute: "rt-data-table-filter-cell" }, ngImport: i0, template: "<ng-container rtBlock=\"rt-data-table-filter-cell\">\n @if (filterOperators().length) {\n <rt-menu qa-dataid=\"data-table-filter-operator\" align=\"start\" [icon]=\"operatorIcon()\" [ariaLabel]=\"operatorLabel()\">\n @for (item of operatorItems(); track item.operator) {\n <rt-menu-item\n qa-dataid=\"data-table-filter-operator-item\"\n [icon]=\"item.icon\"\n [label]=\"item.label\"\n (selected)=\"onOperatorChange(item.operator)\" />\n }\n </rt-menu>\n }\n\n @switch (filterType()) {\n @case (filterTypes.TEXT) {\n <rt-input\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-input\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [placeholder]=\"valuePlaceholder()\"\n [ngModel]=\"currentFilter().value\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onDraft($event)\"\n (keydown.enter)=\"onCommit()\"\n (focusout)=\"onCommit()\" />\n }\n @case (filterTypes.NUMBER) {\n <rt-input-number\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-number\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [placeholder]=\"valuePlaceholder()\"\n [ngModel]=\"number()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onNumberDraft($event)\"\n (keydown.enter)=\"onCommit()\"\n (focusout)=\"onCommit()\" />\n }\n @case (filterTypes.DATE) {\n <rt-icon-button\n qa-dataid=\"data-table-filter-clear\"\n icon=\"close\"\n [ariaLabel]=\"clearLabel()\"\n [tooltip]=\"clearLabel()\"\n [disabled]=\"!hasValue()\"\n (clicked)=\"onValueChange('')\" />\n\n <rt-date-picker\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-date\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [clearable]=\"false\"\n [ngModel]=\"day()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onDayChange($event)\" />\n }\n @case (filterTypes.SELECT) {\n <rt-icon-button\n qa-dataid=\"data-table-filter-clear\"\n icon=\"close\"\n [ariaLabel]=\"clearLabel()\"\n [tooltip]=\"clearLabel()\"\n [disabled]=\"!hasValue()\"\n (clicked)=\"onValueChange('')\" />\n\n <rt-select\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-select\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [clearable]=\"false\"\n [options]=\"selectOptions()\"\n [placeholder]=\"selectPlaceholder()\"\n [ngModel]=\"currentFilter().value || null\"\n [ngModelOptions]=\"{ standalone: true }\"\n (selectionChange)=\"onValueChange($event)\" />\n }\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-filter-cell{display:flex;width:100%;align-items:center;justify-content:flex-start;gap:var(--rt-space-sm)}.rt-data-table-filter-cell__field{--rt-input-height-sm: var(--rt-list-search-height);--rt-input-font-size: var(--rt-list-search-font-size);--rt-input-color-border: var(--rt-list-search-color-border);--rt-input-color-bg: var(--rt-list-search-color-bg);--rt-input-color-text-placeholder: var(--rt-list-search-color-placeholder);--rt-input-line-height: var(--rt-list-filter-line-height);min-width:0;flex-grow:1}.rt-data-table-filter-cell .rt-data-table-filter-cell__field{width:calc(180px + 2 * var(--rt-space-4))}.rt-data-table-filter-cell rt-icon-button{--rt-icon-button-color: var(--rt-list-table-icon-color)}.rt-data-table-filter-cell .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-table-button-size);--rt-icon-button-radius: var(--rt-list-table-button-radius)}.rt-data-table-filter-cell .rt-icon-button__icon{min-width:var(--rt-list-table-icon-size);min-height:var(--rt-list-table-icon-size)}}\n"], dependencies: [{ kind: "component", type:
|
|
823
|
+
// components
|
|
824
|
+
RtDatePickerComponent, selector: "rt-date-picker", inputs: ["appearance", "type", "min", "max", "minuteStep"] }, { kind: "component", type: RtIconButtonComponent, selector: "rt-icon-button", inputs: ["icon", "glyph", "ariaLabel", "variant", "iconColor", "iconFill", "size", "iconSize", "type", "tooltip", "tabIndex", "loading", "disabled", "active", "indicator"], outputs: ["clicked"] }, { kind: "component", type: RtInputComponent, selector: "rt-input", inputs: ["appearance", "type", "placeholder", "iconLeft", "iconRight", "passwordToggle", "autocomplete"] }, { kind: "component", type: RtInputNumberComponent, selector: "rt-input-number", inputs: ["appearance", "iconLeft", "prefix", "placeholder", "min", "max", "minFractionDigits", "maxFractionDigits", "grouped"] }, { kind: "component", type: RtMenuComponent, selector: "rt-menu", inputs: ["icon", "ariaLabel", "align", "panelClass", "size", "disabled"], outputs: ["openedChange"] }, { kind: "component", type: RtMenuItemComponent, selector: "rt-menu-item", inputs: ["icon", "label", "danger", "success", "glyph", "fill", "current", "disabled", "confirmMessage", "confirmTitle", "confirmLabel", "confirmCancelLabel", "confirmTone", "link"], outputs: ["selected"] }, { kind: "component", type: RtSelectComponent, selector: "rt-select", inputs: ["appearance", "options", "placeholder", "iconLeft", "filter", "filterPlaceholder", "panelWidth", "panelMaxHeight"], outputs: ["selectionChange"] }, { kind: "directive", type:
|
|
825
|
+
// directives
|
|
826
|
+
BlockDirective, selector: "[rtBlock]", inputs: ["rtMod"] }, { kind: "directive", type: ElemDirective, selector: "[rtElem]", inputs: ["rtMod"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
827
|
+
}
|
|
828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableFilterCellComponent, decorators: [{
|
|
829
|
+
type: Component,
|
|
830
|
+
args: [{ selector: 'rt-data-table-filter-cell', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
831
|
+
// components
|
|
832
|
+
RtDatePickerComponent,
|
|
833
|
+
RtIconButtonComponent,
|
|
834
|
+
RtInputComponent,
|
|
835
|
+
RtInputNumberComponent,
|
|
836
|
+
RtMenuComponent,
|
|
837
|
+
RtMenuItemComponent,
|
|
838
|
+
RtSelectComponent,
|
|
839
|
+
// directives
|
|
840
|
+
BlockDirective,
|
|
841
|
+
ElemDirective,
|
|
842
|
+
FormsModule,
|
|
843
|
+
], host: { class: BEM_BLOCK$1 }, template: "<ng-container rtBlock=\"rt-data-table-filter-cell\">\n @if (filterOperators().length) {\n <rt-menu qa-dataid=\"data-table-filter-operator\" align=\"start\" [icon]=\"operatorIcon()\" [ariaLabel]=\"operatorLabel()\">\n @for (item of operatorItems(); track item.operator) {\n <rt-menu-item\n qa-dataid=\"data-table-filter-operator-item\"\n [icon]=\"item.icon\"\n [label]=\"item.label\"\n (selected)=\"onOperatorChange(item.operator)\" />\n }\n </rt-menu>\n }\n\n @switch (filterType()) {\n @case (filterTypes.TEXT) {\n <rt-input\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-input\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [placeholder]=\"valuePlaceholder()\"\n [ngModel]=\"currentFilter().value\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onDraft($event)\"\n (keydown.enter)=\"onCommit()\"\n (focusout)=\"onCommit()\" />\n }\n @case (filterTypes.NUMBER) {\n <rt-input-number\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-number\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [placeholder]=\"valuePlaceholder()\"\n [ngModel]=\"number()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onNumberDraft($event)\"\n (keydown.enter)=\"onCommit()\"\n (focusout)=\"onCommit()\" />\n }\n @case (filterTypes.DATE) {\n <rt-icon-button\n qa-dataid=\"data-table-filter-clear\"\n icon=\"close\"\n [ariaLabel]=\"clearLabel()\"\n [tooltip]=\"clearLabel()\"\n [disabled]=\"!hasValue()\"\n (clicked)=\"onValueChange('')\" />\n\n <rt-date-picker\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-date\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [clearable]=\"false\"\n [ngModel]=\"day()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onDayChange($event)\" />\n }\n @case (filterTypes.SELECT) {\n <rt-icon-button\n qa-dataid=\"data-table-filter-clear\"\n icon=\"close\"\n [ariaLabel]=\"clearLabel()\"\n [tooltip]=\"clearLabel()\"\n [disabled]=\"!hasValue()\"\n (clicked)=\"onValueChange('')\" />\n\n <rt-select\n rtElem=\"field\"\n qa-dataid=\"data-table-filter-select\"\n size=\"sm\"\n [appearance]=\"appearance()\"\n [clearable]=\"false\"\n [options]=\"selectOptions()\"\n [placeholder]=\"selectPlaceholder()\"\n [ngModel]=\"currentFilter().value || null\"\n [ngModelOptions]=\"{ standalone: true }\"\n (selectionChange)=\"onValueChange($event)\" />\n }\n }\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table-filter-cell{display:flex;width:100%;align-items:center;justify-content:flex-start;gap:var(--rt-space-sm)}.rt-data-table-filter-cell__field{--rt-input-height-sm: var(--rt-list-search-height);--rt-input-font-size: var(--rt-list-search-font-size);--rt-input-color-border: var(--rt-list-search-color-border);--rt-input-color-bg: var(--rt-list-search-color-bg);--rt-input-color-text-placeholder: var(--rt-list-search-color-placeholder);--rt-input-line-height: var(--rt-list-filter-line-height);min-width:0;flex-grow:1}.rt-data-table-filter-cell .rt-data-table-filter-cell__field{width:calc(180px + 2 * var(--rt-space-4))}.rt-data-table-filter-cell rt-icon-button{--rt-icon-button-color: var(--rt-list-table-icon-color)}.rt-data-table-filter-cell .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-table-button-size);--rt-icon-button-radius: var(--rt-list-table-button-radius)}.rt-data-table-filter-cell .rt-icon-button__icon{min-width:var(--rt-list-table-icon-size);min-height:var(--rt-list-table-icon-size)}}\n"] }]
|
|
844
|
+
}], propDecorators: { appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], filterProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterProperty", required: true }] }], filterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterType", required: true }] }], filterModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterModel", required: false }] }], defaultFilterOperator: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultFilterOperator", required: false }] }], filterOperators: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterOperators", required: false }] }], filterSelectOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterSelectOptions", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Шаблоны пользовательских ячеек: имя свойства колонки — шаблон её ячейки.
|
|
848
|
+
*
|
|
849
|
+
* Колонку типа «custom» таблица рисует этим шаблоном и готовой ячейки не берёт.
|
|
850
|
+
*/
|
|
851
|
+
class RtDataTableCustomCellsDirective {
|
|
852
|
+
constructor() {
|
|
853
|
+
this.cellsTemplates = input.required({ ...(ngDevMode ? { debugName: "cellsTemplates" } : /* istanbul ignore next */ {}), alias: 'rtDataTableCustomCells' });
|
|
854
|
+
}
|
|
855
|
+
getTemplateByPropName(propName) {
|
|
856
|
+
return this.cellsTemplates()[propName] ?? null;
|
|
857
|
+
}
|
|
858
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableCustomCellsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
859
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: RtDataTableCustomCellsDirective, isStandalone: true, selector: "[rtDataTableCustomCells]", inputs: { cellsTemplates: { classPropertyName: "cellsTemplates", publicName: "rtDataTableCustomCells", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
860
|
+
}
|
|
861
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableCustomCellsDirective, decorators: [{
|
|
862
|
+
type: Directive,
|
|
863
|
+
args: [{
|
|
864
|
+
selector: '[rtDataTableCustomCells]',
|
|
865
|
+
}]
|
|
866
|
+
}], propDecorators: { cellsTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "rtDataTableCustomCells", required: true }] }] } });
|
|
867
|
+
/** Пункты меню строки: шаблон раскрывается в панели меню кита. */
|
|
868
|
+
class RtDataTableRowActionsDirective {
|
|
869
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableRowActionsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
870
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: RtDataTableRowActionsDirective, isStandalone: true, selector: "[rtDataTableRowActions]", ngImport: i0 }); }
|
|
871
|
+
}
|
|
872
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableRowActionsDirective, decorators: [{
|
|
873
|
+
type: Directive,
|
|
874
|
+
args: [{
|
|
875
|
+
selector: '[rtDataTableRowActions]',
|
|
876
|
+
}]
|
|
877
|
+
}] });
|
|
878
|
+
/** Действия строки рядом с кнопкой меню: шаблон рисуется в полосе действий. */
|
|
879
|
+
class RtDataTableAdditionalRowActionsDirective {
|
|
880
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableAdditionalRowActionsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
881
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: RtDataTableAdditionalRowActionsDirective, isStandalone: true, selector: "[rtDataTableAdditionalRowActions]", ngImport: i0 }); }
|
|
882
|
+
}
|
|
883
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableAdditionalRowActionsDirective, decorators: [{
|
|
884
|
+
type: Directive,
|
|
885
|
+
args: [{
|
|
886
|
+
selector: '[rtDataTableAdditionalRowActions]',
|
|
887
|
+
}]
|
|
888
|
+
}] });
|
|
889
|
+
|
|
890
|
+
/** Ключи записей списка. */
|
|
891
|
+
function dataTableKeysOf(entities, keyExp) {
|
|
892
|
+
return entities.map((entity) => entity[keyExp]);
|
|
893
|
+
}
|
|
894
|
+
/** Записи страницы, добавленные к отмеченным; повторов не будет. */
|
|
895
|
+
function dataTableWithPageEntities(selected, page, keyExp) {
|
|
896
|
+
const keys = dataTableKeysOf(selected, keyExp);
|
|
897
|
+
return [...selected, ...page.filter((entity) => !keys.includes(entity[keyExp]))];
|
|
898
|
+
}
|
|
899
|
+
/** Отмеченные без записей страницы. */
|
|
900
|
+
function dataTableWithoutPageEntities(selected, page, keyExp) {
|
|
901
|
+
const keys = dataTableKeysOf(page, keyExp);
|
|
902
|
+
return selected.filter((entity) => !keys.includes(entity[keyExp]));
|
|
903
|
+
}
|
|
904
|
+
/** Отмеченные после отметки или снятия одной записи. */
|
|
905
|
+
function dataTableWithEntity(selected, entity, checked, keyExp) {
|
|
906
|
+
const without = selected.filter((el) => el[keyExp] !== entity[keyExp]);
|
|
907
|
+
return checked ? [...without, entity] : without;
|
|
908
|
+
}
|
|
909
|
+
/** Хоть одна запись страницы отмечена. */
|
|
910
|
+
function dataTableAnyOnPage(page, selectedKeys, keyExp) {
|
|
911
|
+
return page.some((entity) => selectedKeys.includes(entity[keyExp]));
|
|
912
|
+
}
|
|
913
|
+
/** Отмечены все записи страницы; пустая страница у первого кита считается отмеченной целиком. */
|
|
914
|
+
function dataTableAllOnPage(page, selectedKeys, keyExp) {
|
|
915
|
+
return page.every((entity) => selectedKeys.includes(entity[keyExp]));
|
|
916
|
+
}
|
|
917
|
+
/** Записи первой страницы, чьи ключи названы приложением как отмеченные заранее. */
|
|
918
|
+
function dataTablePresetEntities(entities, keys, keyExp) {
|
|
919
|
+
return entities.filter((entity) => keys.includes(entity[keyExp]));
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
const BEM_BLOCK = 'rt-data-table';
|
|
923
|
+
/**
|
|
924
|
+
* Таблица записей первого кита во втором — без Material.
|
|
925
|
+
*
|
|
926
|
+
* Колонки берутся у службы настроек, строки приходят входом. Таблица рисует шапку, строку
|
|
927
|
+
* отбора, готовые или пользовательские ячейки, колонку выбора флажком либо радиокнопкой и полосу
|
|
928
|
+
* действий в конце строки. Своего отбора и своего порядка она не ведёт: обо всём просит
|
|
929
|
+
* приложение. Отметками строк занимается директива выбора — она ставит их сюда.
|
|
930
|
+
*/
|
|
931
|
+
class RtDataTableComponent {
|
|
932
|
+
constructor() {
|
|
933
|
+
this.#configService = inject(RtDataTableConfigService);
|
|
934
|
+
/* Вид считается из настроек при объявлении входа: вход в разметке по-прежнему перебивает всё. */
|
|
935
|
+
this.#look = rtKitDefault('dataTable', (it) => it.look, 'material');
|
|
936
|
+
/** Полоса действий и две ячейки, которым она отдаёт свою ширину, — приём первого кита. */
|
|
937
|
+
this.rowActionsRef = viewChild('rowActions', /* @ts-ignore */
|
|
938
|
+
...(ngDevMode ? [{ debugName: "rowActionsRef" }] : /* istanbul ignore next */ []));
|
|
939
|
+
this.headerSpacerRef = viewChild('headerSpacer', /* @ts-ignore */
|
|
940
|
+
...(ngDevMode ? [{ debugName: "headerSpacerRef" }] : /* istanbul ignore next */ []));
|
|
941
|
+
this.rowSpacerRef = viewChild('rowSpacer', /* @ts-ignore */
|
|
942
|
+
...(ngDevMode ? [{ debugName: "rowSpacerRef" }] : /* istanbul ignore next */ []));
|
|
943
|
+
this.columnTypes = ERtDataTableColumnType;
|
|
944
|
+
/** Набор даёт узел вокруг — список; тогда класс набора на самой таблице не ставится. */
|
|
945
|
+
this.presetFromHost = inject(RT_DATA_TABLE_PRESET_FROM_HOST, { optional: true }) ?? false;
|
|
946
|
+
/** Классы меню строки: оно открывается поверх страницы и вид семьи получает от неё. */
|
|
947
|
+
this.menuPanelClass = computed(() => (this.look() === 'material' ? [RT_PRESET_MATERIAL_CLASS] : []), /* @ts-ignore */
|
|
948
|
+
...(ngDevMode ? [{ debugName: "menuPanelClass" }] : /* istanbul ignore next */ []));
|
|
949
|
+
this.actionsLabel = rtKitLabel('dataTableActions');
|
|
950
|
+
this.selectRowLabel = rtKitLabel('dataTableSelectRow');
|
|
951
|
+
this.selectPageLabel = rtKitLabel('dataTableSelectPage');
|
|
952
|
+
/** Полоса действий рисуется, когда приложение дало меню строки или действия рядом с ним. */
|
|
953
|
+
this.hasRowActions = computed(() => !!this.rowActionsTpl() || !!this.additionalRowActionsTpl(), /* @ts-ignore */
|
|
954
|
+
...(ngDevMode ? [{ debugName: "hasRowActions" }] : /* istanbul ignore next */ []));
|
|
955
|
+
this.visibleColumns = computed(() => this.columns().filter((column) => !column.hidden), /* @ts-ignore */
|
|
956
|
+
...(ngDevMode ? [{ debugName: "visibleColumns" }] : /* istanbul ignore next */ []));
|
|
957
|
+
/** `aria-sort` каждой показанной колонки по её имени: шаблон читает готовое, а не зовёт расчёт. */
|
|
958
|
+
this.ariaSorts = computed(() => Object.fromEntries(this.visibleColumns().map((column) => [
|
|
959
|
+
column.propName,
|
|
960
|
+
dataTableAriaSort(column.sorting, this.currentSortModel()),
|
|
961
|
+
])), /* @ts-ignore */
|
|
962
|
+
...(ngDevMode ? [{ debugName: "ariaSorts" }] : /* istanbul ignore next */ []));
|
|
963
|
+
/** Колонки — из службы настроек: их порядок и видимость помнит она. */
|
|
964
|
+
/** Вид полей отбора: `outline` — рамка со всех сторон, `fill` — залитое поле с чертой снизу. */
|
|
965
|
+
/**
|
|
966
|
+
* Вид семьи. Материальный набор стоит на самом узле, а не на странице: семья выглядит как первый
|
|
967
|
+
* кит, где бы её ни поставили, и соседи на странице своего вида не теряют.
|
|
968
|
+
*/
|
|
969
|
+
this.look = input(this.#look, /* @ts-ignore */
|
|
970
|
+
...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
|
|
971
|
+
this.filterAppearance = input('outline', /* @ts-ignore */
|
|
972
|
+
...(ngDevMode ? [{ debugName: "filterAppearance" }] : /* istanbul ignore next */ []));
|
|
973
|
+
this.columns = computed(() => this.#configService.tableConfig().columns, /* @ts-ignore */
|
|
974
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
975
|
+
this.isTableRowsClickable = input(false, { ...(ngDevMode ? { debugName: "isTableRowsClickable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
976
|
+
/** Свойство, которым записи отличаются друг от друга. */
|
|
977
|
+
this.keyExp = input('id', /* @ts-ignore */
|
|
978
|
+
...(ngDevMode ? [{ debugName: "keyExp" }] : /* istanbul ignore next */ []));
|
|
979
|
+
this.entities = input.required({ ...(ngDevMode ? { debugName: "entities" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
980
|
+
this.currentSortModel = input.required(/* @ts-ignore */
|
|
981
|
+
...(ngDevMode ? [{ debugName: "currentSortModel" }] : /* istanbul ignore next */ []));
|
|
982
|
+
/**
|
|
983
|
+
* Условия отбора. Их ключ — имя свойства колонки, а не ключ записи: отбирают по колонке, и
|
|
984
|
+
* ключ записи здесь оказался бы уже нужного — строка отбора зовёт ячейку именем колонки.
|
|
985
|
+
*/
|
|
986
|
+
this.filterModel = input([], { ...(ngDevMode ? { debugName: "filterModel" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
987
|
+
this.isFiltersShown = input(false, { ...(ngDevMode ? { debugName: "isFiltersShown" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
988
|
+
this.rowClick = output();
|
|
989
|
+
this.rowDoubleClick = output();
|
|
990
|
+
this.sortChange = output();
|
|
991
|
+
this.filterChange = output();
|
|
992
|
+
this.customCellsTpl = contentChild(RtDataTableCustomCellsDirective, /* @ts-ignore */
|
|
993
|
+
...(ngDevMode ? [{ debugName: "customCellsTpl" }] : /* istanbul ignore next */ []));
|
|
994
|
+
this.rowActionsTpl = contentChild(RtDataTableRowActionsDirective, { ...(ngDevMode ? { debugName: "rowActionsTpl" } : /* istanbul ignore next */ {}), read: TemplateRef });
|
|
995
|
+
this.additionalRowActionsTpl = contentChild(RtDataTableAdditionalRowActionsDirective, { ...(ngDevMode ? { debugName: "additionalRowActionsTpl" } : /* istanbul ignore next */ {}), read: TemplateRef });
|
|
996
|
+
/** Шаблон значка приложения: его получают и шапка, и готовая ячейка. */
|
|
997
|
+
this.iconTpl = contentChild(RtDataTableIconDirective, /* @ts-ignore */
|
|
998
|
+
...(ngDevMode ? [{ debugName: "iconTpl" }] : /* istanbul ignore next */ []));
|
|
999
|
+
/** Ключи отмеченных записей; их ставит директива выбора. */
|
|
1000
|
+
this.selectedEntitiesIds = signal([], /* @ts-ignore */
|
|
1001
|
+
...(ngDevMode ? [{ debugName: "selectedEntitiesIds" }] : /* istanbul ignore next */ []));
|
|
1002
|
+
this.isPageEntitiesSelected = signal(false, /* @ts-ignore */
|
|
1003
|
+
...(ngDevMode ? [{ debugName: "isPageEntitiesSelected" }] : /* istanbul ignore next */ []));
|
|
1004
|
+
this.isPageEntitiesIndeterminate = signal(false, /* @ts-ignore */
|
|
1005
|
+
...(ngDevMode ? [{ debugName: "isPageEntitiesIndeterminate" }] : /* istanbul ignore next */ []));
|
|
1006
|
+
this.isMultiSelect = signal(true, /* @ts-ignore */
|
|
1007
|
+
...(ngDevMode ? [{ debugName: "isMultiSelect" }] : /* istanbul ignore next */ []));
|
|
1008
|
+
this.isSelectorsColumnShown = signal(false, /* @ts-ignore */
|
|
1009
|
+
...(ngDevMode ? [{ debugName: "isSelectorsColumnShown" }] : /* istanbul ignore next */ []));
|
|
1010
|
+
this.isSelectorsColumnDisabled = signal(false, /* @ts-ignore */
|
|
1011
|
+
...(ngDevMode ? [{ debugName: "isSelectorsColumnDisabled" }] : /* istanbul ignore next */ []));
|
|
1012
|
+
/** Строка с открытым меню; у первого кита она подсвечена, пока меню открыто. */
|
|
1013
|
+
this.activeRowIndex = signal(null, /* @ts-ignore */
|
|
1014
|
+
...(ngDevMode ? [{ debugName: "activeRowIndex" }] : /* istanbul ignore next */ []));
|
|
1015
|
+
/** Отметить запись; метод ставит директива выбора, без неё колонки выбора нет вовсе. */
|
|
1016
|
+
this.onToggleEntity = () => undefined;
|
|
1017
|
+
/** Отметить все строки показанной страницы; метод ставит директива выбора. */
|
|
1018
|
+
this.onTogglePageEntities = () => undefined;
|
|
1019
|
+
}
|
|
1020
|
+
#configService;
|
|
1021
|
+
/* Вид считается из настроек при объявлении входа: вход в разметке по-прежнему перебивает всё. */
|
|
1022
|
+
#look;
|
|
1023
|
+
ngAfterViewChecked() {
|
|
1024
|
+
this.#syncSpacerWidth();
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Имя колонки приходит строкой, а наружу уходит ключом домена: приведение сверяется с тем же
|
|
1028
|
+
* набором колонок, который рисует таблица. Несовпавшее не отдаётся вовсе — приём первого кита.
|
|
1029
|
+
*/
|
|
1030
|
+
onSortChange(sortModel) {
|
|
1031
|
+
const names = this.columns().map((column) => String(column.propName));
|
|
1032
|
+
if (names.includes(sortModel.propertyName)) {
|
|
1033
|
+
this.sortChange.emit({ ...sortModel, propertyName: sortModel.propertyName });
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
onFilterChange(filterModel) {
|
|
1037
|
+
this.filterChange.emit(filterModel);
|
|
1038
|
+
}
|
|
1039
|
+
onRowClick(row, event) {
|
|
1040
|
+
this.rowClick.emit({ row, event });
|
|
1041
|
+
}
|
|
1042
|
+
onRowDoubleClick(row) {
|
|
1043
|
+
this.rowDoubleClick.emit(row);
|
|
1044
|
+
}
|
|
1045
|
+
onMenuOpenedChange(index, opened) {
|
|
1046
|
+
this.activeRowIndex.set(opened ? index : null);
|
|
1047
|
+
}
|
|
1048
|
+
defaultOperator(column) {
|
|
1049
|
+
return column.defaultFilterOperator ?? EFilterOperatorType.EQUALS;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Полоса действий висит над концом строки, и место под неё держат две пустые ячейки — в
|
|
1053
|
+
* шапке и в строке. Ширину им таблица ставит по ширине самой полосы, как первый кит.
|
|
1054
|
+
*/
|
|
1055
|
+
#syncSpacerWidth() {
|
|
1056
|
+
const strip = this.rowActionsRef()?.nativeElement;
|
|
1057
|
+
if (!strip) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const width = `${strip.offsetWidth}px`;
|
|
1061
|
+
[this.headerSpacerRef()?.nativeElement, this.rowSpacerRef()?.nativeElement].forEach((spacer) => {
|
|
1062
|
+
if (spacer && spacer.style.width !== width) {
|
|
1063
|
+
spacer.style.width = width;
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1068
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: RtDataTableComponent, isStandalone: true, selector: "rt-data-table", inputs: { look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, filterAppearance: { classPropertyName: "filterAppearance", publicName: "filterAppearance", isSignal: true, isRequired: false, transformFunction: null }, isTableRowsClickable: { classPropertyName: "isTableRowsClickable", publicName: "isTableRowsClickable", isSignal: true, isRequired: false, transformFunction: null }, keyExp: { classPropertyName: "keyExp", publicName: "keyExp", isSignal: true, isRequired: false, transformFunction: null }, entities: { classPropertyName: "entities", publicName: "entities", isSignal: true, isRequired: true, transformFunction: null }, currentSortModel: { classPropertyName: "currentSortModel", publicName: "currentSortModel", isSignal: true, isRequired: true, transformFunction: null }, filterModel: { classPropertyName: "filterModel", publicName: "filterModel", isSignal: true, isRequired: false, transformFunction: null }, isFiltersShown: { classPropertyName: "isFiltersShown", publicName: "isFiltersShown", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", sortChange: "sortChange", filterChange: "filterChange" }, host: { properties: { "class.rt-preset-material": "look() === 'material' && !presetFromHost" }, classAttribute: "rt-data-table" }, providers: [{ provide: RT_DATA_TABLE_ROW_HOST, useExisting: forwardRef(() => RtDataTableComponent) }], queries: [{ propertyName: "customCellsTpl", first: true, predicate: RtDataTableCustomCellsDirective, descendants: true, isSignal: true }, { propertyName: "rowActionsTpl", first: true, predicate: RtDataTableRowActionsDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "additionalRowActionsTpl", first: true, predicate: RtDataTableAdditionalRowActionsDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "iconTpl", first: true, predicate: RtDataTableIconDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "rowActionsRef", first: true, predicate: ["rowActions"], descendants: true, isSignal: true }, { propertyName: "headerSpacerRef", first: true, predicate: ["headerSpacer"], descendants: true, isSignal: true }, { propertyName: "rowSpacerRef", first: true, predicate: ["rowSpacer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container rtBlock=\"rt-data-table\">\n <table rtElem=\"table\">\n <thead rtElem=\"head\">\n <tr>\n @if (isSelectorsColumnShown()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, selectable: true }\">\n @if (isMultiSelect()) {\n <rt-checkbox\n qa-dataid=\"data-table-page-checkbox\"\n [ariaLabel]=\"selectPageLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [indeterminate]=\"isPageEntitiesIndeterminate() && !isPageEntitiesSelected()\"\n [ngModel]=\"isPageEntitiesSelected()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onTogglePageEntities($event)\" />\n }\n </th>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <th\n rtElem=\"cell\"\n qa-dataid=\"data-table-header-cell\"\n [attr.aria-sort]=\"ariaSorts()[column.propName]\"\n [rtMod]=\"{ head: true, sortable: !!column.sorting }\">\n <rt-data-table-header-cell\n [headerModel]=\"column.header\"\n [sortModel]=\"column.sorting\"\n [currentSortModel]=\"currentSortModel()\"\n [column]=\"column\"\n [iconTemplate]=\"iconTpl()?.template ?? null\"\n (sortChange)=\"onSortChange($event)\" />\n </th>\n }\n\n @if (hasRowActions()) {\n <th #headerSpacer rtElem=\"cell\" qa-dataid=\"data-table-actions-header\" [rtMod]=\"{ head: true }\">{{ actionsLabel() }}</th>\n }\n </tr>\n\n @if (isFiltersShown()) {\n <tr qa-dataid=\"data-table-filter-row\">\n @if (isSelectorsColumnShown()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true, empty: true }\"></th>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true }\">\n @if (column.filterType; as filterType) {\n <rt-data-table-filter-cell\n [filterProperty]=\"column.propName\"\n [filterType]=\"filterType\"\n [filterModel]=\"filterModel()\"\n [defaultFilterOperator]=\"column.defaultFilterOperator\"\n [filterOperators]=\"column.filterOperators\"\n [filterSelectOptions]=\"column.filterSelectOptions\"\n [appearance]=\"filterAppearance()\"\n (filterChange)=\"onFilterChange($event)\" />\n }\n </th>\n }\n\n @if (hasRowActions()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true }\"></th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n @for (row of entities(); track row[keyExp()]; let index = $index) {\n <tr\n rtElem=\"row\"\n qa-dataid=\"data-table-row\"\n [rtDataTableRowClick]=\"row\"\n [isTableRowClickable]=\"isTableRowsClickable()\"\n [rtMod]=\"{ clickable: isTableRowsClickable(), active: activeRowIndex() === index }\">\n @if (isSelectorsColumnShown()) {\n <td rtElem=\"cell\" [rtMod]=\"{ selectable: true }\" [attr.rt-data-table-stop-row-click]=\"''\">\n @if (isMultiSelect()) {\n <rt-checkbox\n qa-dataid=\"data-table-row-checkbox\"\n [ariaLabel]=\"selectRowLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [ngModel]=\"selectedEntitiesIds().includes(row[keyExp()])\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onToggleEntity(row, $event)\" />\n } @else {\n <rt-radio-button\n qa-dataid=\"data-table-row-radio\"\n [value]=\"row[keyExp()]\"\n [ariaLabel]=\"selectRowLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [checked]=\"selectedEntitiesIds().includes(row[keyExp()])\"\n (checkedChange)=\"onToggleEntity(row, true)\" />\n }\n </td>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <td rtElem=\"cell\" qa-dataid=\"data-table-cell\" [rtMod]=\"{ copyable: !!column.copyable }\">\n @if (column.type === columnTypes.CUSTOM) {\n <ng-container\n [ngTemplateOutlet]=\"customCellsTpl()?.getTemplateByPropName(column.propName) ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n } @else {\n <rt-data-table-cell [row]=\"row\" [column]=\"column\" [iconTemplate]=\"iconTpl()?.template ?? null\" />\n }\n </td>\n }\n\n @if (hasRowActions()) {\n <td #rowSpacer rtElem=\"cell\" [rtMod]=\"{ spacer: true }\"></td>\n\n <div rtBlock=\"rt-data-table-actions\" [rtMod]=\"{ hidden: activeRowIndex() !== index }\">\n <div #rowActions rtElem=\"container\" qa-dataid=\"data-table-actions\">\n @if (additionalRowActionsTpl(); as additional) {\n <ng-container [ngTemplateOutlet]=\"additional\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n\n @if (rowActionsTpl(); as actions) {\n <rt-menu\n rtElem=\"action\"\n qa-dataid=\"data-table-row-menu\"\n icon=\"ellipsis-v\"\n size=\"sm\"\n [panelClass]=\"menuPanelClass()\"\n [attr.rt-data-table-stop-row-click]=\"''\"\n [ariaLabel]=\"actionsLabel()\"\n (openedChange)=\"onMenuOpenedChange(index, $event)\">\n <ng-container [ngTemplateOutlet]=\"actions\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </rt-menu>\n }\n </div>\n </div>\n }\n </tr>\n }\n </tbody>\n </table>\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table{--rt-data-table-row-height: var(--rt-control-height-lg);--rt-data-table-head-height: calc(var(--rt-control-height-lg) - var(--rt-space-1));--rt-data-table-border-width: var(--rt-border-width-thin);--rt-data-table-cell-padding: calc(var(--rt-space-2) + var(--rt-space-0-5));--rt-data-table-row-transition-duration: var(--rt-duration-base);--rt-data-table-padding-bottom: var(--rt-list-content-padding-bottom);--rt-data-table-head-color: var(--rt-color-text-primary);--rt-data-table-head-font-weight: var(--rt-font-weight-medium);--rt-data-table-filter-bg: color-mix(in srgb, var(--rt-color-table-head-bg), var(--rt-color-bg-surface) 50%);display:block;overflow:auto;width:100%;height:100%;box-sizing:border-box;padding-bottom:var(--rt-data-table-padding-bottom);scrollbar-color:var(--rt-data-table-scrollbar-color, transparent transparent);scrollbar-width:var(--rt-data-table-scrollbar-width, thin)}.rt-data-table::-webkit-scrollbar{width:var(--rt-data-table-scrollbar-vertical-width, var(--rt-size-3));height:var(--rt-data-table-scrollbar-horizontal-height, var(--rt-size-3))}.rt-data-table:hover,.rt-data-table:focus-within{scrollbar-color:var(--rt-data-table-scrollbar-color, var(--rt-color-border-default) transparent)}@media(hover:none){.rt-data-table{scrollbar-color:var(--rt-data-table-scrollbar-color, var(--rt-color-border-default) transparent)}}.rt-data-table__table{width:100%;border-collapse:collapse}.rt-data-table thead{position:sticky;z-index:var(--rt-z-sticky);top:0}.rt-data-table thead tr:first-child{height:var(--rt-data-table-head-height)}.rt-data-table thead tr:last-child{border-bottom:var(--rt-data-table-border-width) solid var(--rt-color-border-default)}.rt-data-table tbody{font-size:var(--rt-text-sm)}.rt-data-table__row{height:var(--rt-data-table-row-height);border-bottom:var(--rt-data-table-border-width) solid var(--rt-color-border-subtle);color:var(--rt-color-text-primary);transform:translate(0)}.rt-data-table__row:hover{border-bottom-color:var(--rt-color-state-info);transition:border-bottom-color var(--rt-data-table-row-transition-duration)}.rt-data-table__row:hover .rt-data-table-actions{visibility:visible}.rt-data-table__row--active{border-bottom-color:var(--rt-color-state-info)}.rt-data-table__row--clickable{cursor:pointer}.rt-data-table__cell{width:fit-content;height:100%;padding:var(--rt-data-table-cell-padding)}.rt-data-table__cell--head{position:relative;background-color:var(--rt-color-table-head-bg);color:var(--rt-data-table-head-color);font-size:var(--rt-text-md);font-weight:var(--rt-data-table-head-font-weight);line-height:var(--rt-leading-tight);pointer-events:none;text-align:start}.rt-data-table__cell--sortable,.rt-data-table__cell--selectable,.rt-data-table__cell--filterable{pointer-events:auto}.rt-data-table__cell--selectable>rt-checkbox,.rt-data-table__cell--selectable>rt-radio-button{display:flex}.rt-data-table__cell--filterable{padding:var(--rt-space-xs) var(--rt-space-sm);background-color:var(--rt-data-table-filter-bg)}:is(.rt-preset-material,[data-preset=material]) .rt-data-table__cell--filterable{--rt-input-radius: var(--rt-radius-sm)}.rt-data-table__cell--head:not(:last-child,.rt-data-table__cell--selectable,.rt-data-table__cell--empty):after{position:absolute;top:25%;right:0;height:50%;border-right:var(--rt-data-table-border-width) solid var(--rt-list-table-head-divider-color);content:\"\";pointer-events:none}.rt-data-table__cell--spacer{padding:0}.rt-data-table-actions{--rt-data-table-actions-bg: var(--rt-table-actions-bg, var(--rt-color-bg-surface));position:absolute;z-index:var(--rt-z-base);top:0;right:0;display:flex;width:100%;height:100%;align-items:center;justify-content:flex-end;pointer-events:none}.rt-data-table-actions__container{position:sticky;right:0;display:flex;overflow:hidden;width:fit-content;height:calc(100% - var(--rt-data-table-border-width) * 2);align-items:center;justify-content:flex-end;padding:0 var(--rt-space-xs) 0 var(--rt-space-5);background:linear-gradient(to right,transparent 0%,color-mix(in srgb,var(--rt-data-table-actions-bg) 30%,transparent) 10%,var(--rt-data-table-actions-bg) 20%,var(--rt-data-table-actions-bg) 100%);gap:var(--rt-space-xs);pointer-events:none}.rt-data-table-actions__container>*{pointer-events:auto}.rt-data-table-actions__action{position:sticky}.rt-data-table-actions rt-icon-button{--rt-icon-button-color: var(--rt-list-table-icon-color)}.rt-data-table-actions .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-table-button-size);--rt-icon-button-radius: var(--rt-list-table-button-radius)}.rt-data-table-actions .rt-icon-button__icon{min-width:var(--rt-list-table-icon-size);min-height:var(--rt-list-table-icon-size)}@media(hover:hover){.rt-data-table-actions--hidden{opacity:0}.rt-data-table-actions--hidden .rt-data-table-actions__container>*{pointer-events:none}.rt-data-table__row:hover .rt-data-table-actions--hidden,.rt-data-table__row:has(:focus-visible) .rt-data-table-actions--hidden{opacity:1}.rt-data-table__row:hover .rt-data-table-actions--hidden .rt-data-table-actions__container>*,.rt-data-table__row:has(:focus-visible) .rt-data-table-actions--hidden .rt-data-table-actions__container>*{pointer-events:auto}}}\n"], dependencies: [{ kind: "component", type:
|
|
1069
|
+
// components
|
|
1070
|
+
RtCheckboxComponent, selector: "rt-checkbox", inputs: ["inputId", "ariaLabel", "disabled", "indeterminate"] }, { kind: "component", type: RtDataTableCellComponent, selector: "rt-data-table-cell", inputs: ["row", "column", "iconTemplate"] }, { kind: "component", type: RtDataTableFilterCellComponent, selector: "rt-data-table-filter-cell", inputs: ["appearance", "filterProperty", "filterType", "filterModel", "defaultFilterOperator", "filterOperators", "filterSelectOptions"], outputs: ["filterChange"] }, { kind: "component", type: RtDataTableHeaderCellComponent, selector: "rt-data-table-header-cell", inputs: ["headerModel", "sortModel", "currentSortModel", "column", "iconTemplate"], outputs: ["sortChange"] }, { kind: "component", type: RtMenuComponent, selector: "rt-menu", inputs: ["icon", "ariaLabel", "align", "panelClass", "size", "disabled"], outputs: ["openedChange"] }, { kind: "component", type: RtRadioButtonComponent, selector: "rt-radio-button", inputs: ["value", "checked", "disabled", "card", "label", "description", "ariaLabel"], outputs: ["clickAction", "checkedChange"] }, { kind: "directive", type:
|
|
1071
|
+
// directives
|
|
1072
|
+
BlockDirective, selector: "[rtBlock]", inputs: ["rtMod"] }, { kind: "directive", type: ElemDirective, selector: "[rtElem]", inputs: ["rtMod"] }, { 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: "directive", type: ModDirective, selector: "[rtMod]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RtDataTableRowClickDirective, selector: "[rtDataTableRowClick]", inputs: ["rtDataTableRowClick", "isTableRowClickable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1073
|
+
}
|
|
1074
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableComponent, decorators: [{
|
|
1075
|
+
type: Component,
|
|
1076
|
+
args: [{ selector: 'rt-data-table', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
1077
|
+
// components
|
|
1078
|
+
RtCheckboxComponent,
|
|
1079
|
+
RtDataTableCellComponent,
|
|
1080
|
+
RtDataTableFilterCellComponent,
|
|
1081
|
+
RtDataTableHeaderCellComponent,
|
|
1082
|
+
RtMenuComponent,
|
|
1083
|
+
RtRadioButtonComponent,
|
|
1084
|
+
// directives
|
|
1085
|
+
BlockDirective,
|
|
1086
|
+
ElemDirective,
|
|
1087
|
+
FormsModule,
|
|
1088
|
+
ModDirective,
|
|
1089
|
+
NgTemplateOutlet,
|
|
1090
|
+
RtDataTableRowClickDirective,
|
|
1091
|
+
], host: { class: BEM_BLOCK, '[class.rt-preset-material]': "look() === 'material' && !presetFromHost" }, providers: [{ provide: RT_DATA_TABLE_ROW_HOST, useExisting: forwardRef(() => RtDataTableComponent) }], template: "<ng-container rtBlock=\"rt-data-table\">\n <table rtElem=\"table\">\n <thead rtElem=\"head\">\n <tr>\n @if (isSelectorsColumnShown()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, selectable: true }\">\n @if (isMultiSelect()) {\n <rt-checkbox\n qa-dataid=\"data-table-page-checkbox\"\n [ariaLabel]=\"selectPageLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [indeterminate]=\"isPageEntitiesIndeterminate() && !isPageEntitiesSelected()\"\n [ngModel]=\"isPageEntitiesSelected()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onTogglePageEntities($event)\" />\n }\n </th>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <th\n rtElem=\"cell\"\n qa-dataid=\"data-table-header-cell\"\n [attr.aria-sort]=\"ariaSorts()[column.propName]\"\n [rtMod]=\"{ head: true, sortable: !!column.sorting }\">\n <rt-data-table-header-cell\n [headerModel]=\"column.header\"\n [sortModel]=\"column.sorting\"\n [currentSortModel]=\"currentSortModel()\"\n [column]=\"column\"\n [iconTemplate]=\"iconTpl()?.template ?? null\"\n (sortChange)=\"onSortChange($event)\" />\n </th>\n }\n\n @if (hasRowActions()) {\n <th #headerSpacer rtElem=\"cell\" qa-dataid=\"data-table-actions-header\" [rtMod]=\"{ head: true }\">{{ actionsLabel() }}</th>\n }\n </tr>\n\n @if (isFiltersShown()) {\n <tr qa-dataid=\"data-table-filter-row\">\n @if (isSelectorsColumnShown()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true, empty: true }\"></th>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true }\">\n @if (column.filterType; as filterType) {\n <rt-data-table-filter-cell\n [filterProperty]=\"column.propName\"\n [filterType]=\"filterType\"\n [filterModel]=\"filterModel()\"\n [defaultFilterOperator]=\"column.defaultFilterOperator\"\n [filterOperators]=\"column.filterOperators\"\n [filterSelectOptions]=\"column.filterSelectOptions\"\n [appearance]=\"filterAppearance()\"\n (filterChange)=\"onFilterChange($event)\" />\n }\n </th>\n }\n\n @if (hasRowActions()) {\n <th rtElem=\"cell\" [rtMod]=\"{ head: true, filterable: true }\"></th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n @for (row of entities(); track row[keyExp()]; let index = $index) {\n <tr\n rtElem=\"row\"\n qa-dataid=\"data-table-row\"\n [rtDataTableRowClick]=\"row\"\n [isTableRowClickable]=\"isTableRowsClickable()\"\n [rtMod]=\"{ clickable: isTableRowsClickable(), active: activeRowIndex() === index }\">\n @if (isSelectorsColumnShown()) {\n <td rtElem=\"cell\" [rtMod]=\"{ selectable: true }\" [attr.rt-data-table-stop-row-click]=\"''\">\n @if (isMultiSelect()) {\n <rt-checkbox\n qa-dataid=\"data-table-row-checkbox\"\n [ariaLabel]=\"selectRowLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [ngModel]=\"selectedEntitiesIds().includes(row[keyExp()])\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onToggleEntity(row, $event)\" />\n } @else {\n <rt-radio-button\n qa-dataid=\"data-table-row-radio\"\n [value]=\"row[keyExp()]\"\n [ariaLabel]=\"selectRowLabel()\"\n [disabled]=\"isSelectorsColumnDisabled()\"\n [checked]=\"selectedEntitiesIds().includes(row[keyExp()])\"\n (checkedChange)=\"onToggleEntity(row, true)\" />\n }\n </td>\n }\n\n @for (column of visibleColumns(); track column.propName) {\n <td rtElem=\"cell\" qa-dataid=\"data-table-cell\" [rtMod]=\"{ copyable: !!column.copyable }\">\n @if (column.type === columnTypes.CUSTOM) {\n <ng-container\n [ngTemplateOutlet]=\"customCellsTpl()?.getTemplateByPropName(column.propName) ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n } @else {\n <rt-data-table-cell [row]=\"row\" [column]=\"column\" [iconTemplate]=\"iconTpl()?.template ?? null\" />\n }\n </td>\n }\n\n @if (hasRowActions()) {\n <td #rowSpacer rtElem=\"cell\" [rtMod]=\"{ spacer: true }\"></td>\n\n <div rtBlock=\"rt-data-table-actions\" [rtMod]=\"{ hidden: activeRowIndex() !== index }\">\n <div #rowActions rtElem=\"container\" qa-dataid=\"data-table-actions\">\n @if (additionalRowActionsTpl(); as additional) {\n <ng-container [ngTemplateOutlet]=\"additional\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n }\n\n @if (rowActionsTpl(); as actions) {\n <rt-menu\n rtElem=\"action\"\n qa-dataid=\"data-table-row-menu\"\n icon=\"ellipsis-v\"\n size=\"sm\"\n [panelClass]=\"menuPanelClass()\"\n [attr.rt-data-table-stop-row-click]=\"''\"\n [ariaLabel]=\"actionsLabel()\"\n (openedChange)=\"onMenuOpenedChange(index, $event)\">\n <ng-container [ngTemplateOutlet]=\"actions\" [ngTemplateOutletContext]=\"{ $implicit: row }\" />\n </rt-menu>\n }\n </div>\n </div>\n }\n </tr>\n }\n </tbody>\n </table>\n</ng-container>\n", styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-data-table{--rt-data-table-row-height: var(--rt-control-height-lg);--rt-data-table-head-height: calc(var(--rt-control-height-lg) - var(--rt-space-1));--rt-data-table-border-width: var(--rt-border-width-thin);--rt-data-table-cell-padding: calc(var(--rt-space-2) + var(--rt-space-0-5));--rt-data-table-row-transition-duration: var(--rt-duration-base);--rt-data-table-padding-bottom: var(--rt-list-content-padding-bottom);--rt-data-table-head-color: var(--rt-color-text-primary);--rt-data-table-head-font-weight: var(--rt-font-weight-medium);--rt-data-table-filter-bg: color-mix(in srgb, var(--rt-color-table-head-bg), var(--rt-color-bg-surface) 50%);display:block;overflow:auto;width:100%;height:100%;box-sizing:border-box;padding-bottom:var(--rt-data-table-padding-bottom);scrollbar-color:var(--rt-data-table-scrollbar-color, transparent transparent);scrollbar-width:var(--rt-data-table-scrollbar-width, thin)}.rt-data-table::-webkit-scrollbar{width:var(--rt-data-table-scrollbar-vertical-width, var(--rt-size-3));height:var(--rt-data-table-scrollbar-horizontal-height, var(--rt-size-3))}.rt-data-table:hover,.rt-data-table:focus-within{scrollbar-color:var(--rt-data-table-scrollbar-color, var(--rt-color-border-default) transparent)}@media(hover:none){.rt-data-table{scrollbar-color:var(--rt-data-table-scrollbar-color, var(--rt-color-border-default) transparent)}}.rt-data-table__table{width:100%;border-collapse:collapse}.rt-data-table thead{position:sticky;z-index:var(--rt-z-sticky);top:0}.rt-data-table thead tr:first-child{height:var(--rt-data-table-head-height)}.rt-data-table thead tr:last-child{border-bottom:var(--rt-data-table-border-width) solid var(--rt-color-border-default)}.rt-data-table tbody{font-size:var(--rt-text-sm)}.rt-data-table__row{height:var(--rt-data-table-row-height);border-bottom:var(--rt-data-table-border-width) solid var(--rt-color-border-subtle);color:var(--rt-color-text-primary);transform:translate(0)}.rt-data-table__row:hover{border-bottom-color:var(--rt-color-state-info);transition:border-bottom-color var(--rt-data-table-row-transition-duration)}.rt-data-table__row:hover .rt-data-table-actions{visibility:visible}.rt-data-table__row--active{border-bottom-color:var(--rt-color-state-info)}.rt-data-table__row--clickable{cursor:pointer}.rt-data-table__cell{width:fit-content;height:100%;padding:var(--rt-data-table-cell-padding)}.rt-data-table__cell--head{position:relative;background-color:var(--rt-color-table-head-bg);color:var(--rt-data-table-head-color);font-size:var(--rt-text-md);font-weight:var(--rt-data-table-head-font-weight);line-height:var(--rt-leading-tight);pointer-events:none;text-align:start}.rt-data-table__cell--sortable,.rt-data-table__cell--selectable,.rt-data-table__cell--filterable{pointer-events:auto}.rt-data-table__cell--selectable>rt-checkbox,.rt-data-table__cell--selectable>rt-radio-button{display:flex}.rt-data-table__cell--filterable{padding:var(--rt-space-xs) var(--rt-space-sm);background-color:var(--rt-data-table-filter-bg)}:is(.rt-preset-material,[data-preset=material]) .rt-data-table__cell--filterable{--rt-input-radius: var(--rt-radius-sm)}.rt-data-table__cell--head:not(:last-child,.rt-data-table__cell--selectable,.rt-data-table__cell--empty):after{position:absolute;top:25%;right:0;height:50%;border-right:var(--rt-data-table-border-width) solid var(--rt-list-table-head-divider-color);content:\"\";pointer-events:none}.rt-data-table__cell--spacer{padding:0}.rt-data-table-actions{--rt-data-table-actions-bg: var(--rt-table-actions-bg, var(--rt-color-bg-surface));position:absolute;z-index:var(--rt-z-base);top:0;right:0;display:flex;width:100%;height:100%;align-items:center;justify-content:flex-end;pointer-events:none}.rt-data-table-actions__container{position:sticky;right:0;display:flex;overflow:hidden;width:fit-content;height:calc(100% - var(--rt-data-table-border-width) * 2);align-items:center;justify-content:flex-end;padding:0 var(--rt-space-xs) 0 var(--rt-space-5);background:linear-gradient(to right,transparent 0%,color-mix(in srgb,var(--rt-data-table-actions-bg) 30%,transparent) 10%,var(--rt-data-table-actions-bg) 20%,var(--rt-data-table-actions-bg) 100%);gap:var(--rt-space-xs);pointer-events:none}.rt-data-table-actions__container>*{pointer-events:auto}.rt-data-table-actions__action{position:sticky}.rt-data-table-actions rt-icon-button{--rt-icon-button-color: var(--rt-list-table-icon-color)}.rt-data-table-actions .rt-icon-button{--rt-icon-button-size-step: var(--rt-list-table-button-size);--rt-icon-button-radius: var(--rt-list-table-button-radius)}.rt-data-table-actions .rt-icon-button__icon{min-width:var(--rt-list-table-icon-size);min-height:var(--rt-list-table-icon-size)}@media(hover:hover){.rt-data-table-actions--hidden{opacity:0}.rt-data-table-actions--hidden .rt-data-table-actions__container>*{pointer-events:none}.rt-data-table__row:hover .rt-data-table-actions--hidden,.rt-data-table__row:has(:focus-visible) .rt-data-table-actions--hidden{opacity:1}.rt-data-table__row:hover .rt-data-table-actions--hidden .rt-data-table-actions__container>*,.rt-data-table__row:has(:focus-visible) .rt-data-table-actions--hidden .rt-data-table-actions__container>*{pointer-events:auto}}}\n"] }]
|
|
1092
|
+
}], propDecorators: { rowActionsRef: [{ type: i0.ViewChild, args: ['rowActions', { isSignal: true }] }], headerSpacerRef: [{ type: i0.ViewChild, args: ['headerSpacer', { isSignal: true }] }], rowSpacerRef: [{ type: i0.ViewChild, args: ['rowSpacer', { isSignal: true }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], filterAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterAppearance", required: false }] }], isTableRowsClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTableRowsClickable", required: false }] }], keyExp: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyExp", required: false }] }], entities: [{ type: i0.Input, args: [{ isSignal: true, alias: "entities", required: true }] }], currentSortModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSortModel", required: true }] }], filterModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterModel", required: false }] }], isFiltersShown: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFiltersShown", required: false }] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], rowDoubleClick: [{ type: i0.Output, args: ["rowDoubleClick"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], customCellsTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RtDataTableCustomCellsDirective), { isSignal: true }] }], rowActionsTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RtDataTableRowActionsDirective), { ...{ read: TemplateRef }, isSignal: true }] }], additionalRowActionsTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RtDataTableAdditionalRowActionsDirective), { ...{ read: TemplateRef }, isSignal: true }] }], iconTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RtDataTableIconDirective), { isSignal: true }] }] } });
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Выбор строк таблицы `rt-data-table` — колонка выбора первого кита.
|
|
1096
|
+
*
|
|
1097
|
+
* Директива ведёт отметки и ставит таблице всё, что та рисует: ключи отмеченных, состояние
|
|
1098
|
+
* флажка страницы и признаки колонки выбора. Приложение читает отмеченные записи целиком —
|
|
1099
|
+
* запись, отмеченная на странице, которой уже нет на экране, остаётся отмеченной.
|
|
1100
|
+
*/
|
|
1101
|
+
class RtDataTableSelectorsDirective {
|
|
1102
|
+
#destroyRef;
|
|
1103
|
+
#injector;
|
|
1104
|
+
#table;
|
|
1105
|
+
#selectedEntities;
|
|
1106
|
+
#isPageEntitiesSelected;
|
|
1107
|
+
#isPageEntitiesIndeterminate;
|
|
1108
|
+
constructor() {
|
|
1109
|
+
this.#destroyRef = inject(DestroyRef);
|
|
1110
|
+
this.#injector = inject(Injector);
|
|
1111
|
+
this.#table = inject(RtDataTableComponent);
|
|
1112
|
+
this.#selectedEntities = signal([], /* @ts-ignore */
|
|
1113
|
+
...(ngDevMode ? [{ debugName: "#selectedEntities" }] : /* istanbul ignore next */ []));
|
|
1114
|
+
this.#isPageEntitiesSelected = signal(false, /* @ts-ignore */
|
|
1115
|
+
...(ngDevMode ? [{ debugName: "#isPageEntitiesSelected" }] : /* istanbul ignore next */ []));
|
|
1116
|
+
this.#isPageEntitiesIndeterminate = signal(false, /* @ts-ignore */
|
|
1117
|
+
...(ngDevMode ? [{ debugName: "#isPageEntitiesIndeterminate" }] : /* istanbul ignore next */ []));
|
|
1118
|
+
this.isMultiSelect = input(true, { ...(ngDevMode ? { debugName: "isMultiSelect" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1119
|
+
this.isSelectorColumnShown = input(false, { ...(ngDevMode ? { debugName: "isSelectorColumnShown" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1120
|
+
this.isSelectorsColumnDisabled = input(false, { ...(ngDevMode ? { debugName: "isSelectorsColumnDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1121
|
+
/** Ключи записей, отмеченных заранее; они применяются один раз — к первым пришедшим строкам. */
|
|
1122
|
+
this.selectedEntitiesKeys = input([], { ...(ngDevMode ? { debugName: "selectedEntitiesKeys" } : /* istanbul ignore next */ {}), transform: transformArrayInput });
|
|
1123
|
+
/** Отмеченные записи целиком. */
|
|
1124
|
+
this.selectedEntities = this.#selectedEntities.asReadonly();
|
|
1125
|
+
this.selectedEntitiesIds = computed(() => dataTableKeysOf(this.selectedEntities(), this.#keyExp()), /* @ts-ignore */
|
|
1126
|
+
...(ngDevMode ? [{ debugName: "selectedEntitiesIds" }] : /* istanbul ignore next */ []));
|
|
1127
|
+
this.isPageEntitiesSelected = this.#isPageEntitiesSelected.asReadonly();
|
|
1128
|
+
this.isPageEntitiesIndeterminate = this.#isPageEntitiesIndeterminate.asReadonly();
|
|
1129
|
+
this.#table.onToggleEntity = (entity, checked) => this.toggleEntity(entity, checked);
|
|
1130
|
+
this.#table.onTogglePageEntities = (checked) => this.togglePageEntities(checked);
|
|
1131
|
+
/* Отметки ведёт директива, а рисует их таблица: каждое значение переливается в её поле.
|
|
1132
|
+
Обратного хода нет — таблица сама их не меняет. */
|
|
1133
|
+
effect(() => this.#table.selectedEntitiesIds.set(this.selectedEntitiesIds()));
|
|
1134
|
+
effect(() => this.#table.isPageEntitiesSelected.set(this.isPageEntitiesSelected()));
|
|
1135
|
+
effect(() => this.#table.isPageEntitiesIndeterminate.set(this.isPageEntitiesIndeterminate()));
|
|
1136
|
+
effect(() => this.#table.isMultiSelect.set(this.isMultiSelect()));
|
|
1137
|
+
effect(() => this.#table.isSelectorsColumnShown.set(this.isSelectorColumnShown()));
|
|
1138
|
+
effect(() => this.#table.isSelectorsColumnDisabled.set(this.isSelectorsColumnDisabled()));
|
|
1139
|
+
/* Новая страница — новый флажок страницы: он считается по её строкам, а не остаётся от
|
|
1140
|
+
прежней. Отметки читаются без слежки — пересчёт идёт только на смену строк. */
|
|
1141
|
+
effect(() => {
|
|
1142
|
+
this.#table.entities();
|
|
1143
|
+
untracked(() => this.setExistingEntitiesState());
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
ngOnInit() {
|
|
1147
|
+
/** Отметки, названные заранее, ставятся один раз: к первым непустым строкам. */
|
|
1148
|
+
toObservable(this.#table.entities, { injector: this.#injector })
|
|
1149
|
+
.pipe(filter((entities) => !!entities.length), take(1), switchMap(() => toObservable(this.selectedEntitiesKeys, { injector: this.#injector }).pipe(filter((keys) => !!keys.length), take(1))), takeUntilDestroyed(this.#destroyRef))
|
|
1150
|
+
.subscribe(() => {
|
|
1151
|
+
this.#selectedEntities.set(dataTablePresetEntities(this.#table.entities(), this.selectedEntitiesKeys(), this.#keyExp()));
|
|
1152
|
+
this.setExistingEntitiesState();
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
/** Отметить или снять все строки показанной страницы; других отметок это не трогает. */
|
|
1156
|
+
togglePageEntities(checked) {
|
|
1157
|
+
const page = this.#table.entities();
|
|
1158
|
+
this.#isPageEntitiesSelected.set(checked);
|
|
1159
|
+
this.#selectedEntities.update((selected) => checked
|
|
1160
|
+
? dataTableWithPageEntities(selected, page, this.#keyExp())
|
|
1161
|
+
: dataTableWithoutPageEntities(selected, page, this.#keyExp()));
|
|
1162
|
+
this.#isPageEntitiesIndeterminate.set(dataTableAnyOnPage(page, this.selectedEntitiesIds(), this.#keyExp()));
|
|
1163
|
+
}
|
|
1164
|
+
/** Отметить или снять одну запись; при выборе по одной прежняя отметка уходит. */
|
|
1165
|
+
toggleEntity(entity, checked) {
|
|
1166
|
+
if (!this.isMultiSelect()) {
|
|
1167
|
+
this.#selectedEntities.set([entity]);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
this.#selectedEntities.update((selected) => dataTableWithEntity(selected, entity, checked, this.#keyExp()));
|
|
1171
|
+
const page = this.#table.entities();
|
|
1172
|
+
const keys = this.selectedEntitiesIds();
|
|
1173
|
+
if (keys.length) {
|
|
1174
|
+
this.#isPageEntitiesSelected.set(dataTableAllOnPage(page, keys, this.#keyExp()));
|
|
1175
|
+
this.#isPageEntitiesIndeterminate.set(true);
|
|
1176
|
+
}
|
|
1177
|
+
else {
|
|
1178
|
+
this.#isPageEntitiesSelected.set(false);
|
|
1179
|
+
this.#isPageEntitiesIndeterminate.set(dataTableAnyOnPage(page, keys, this.#keyExp()));
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
/** Снять все отметки. */
|
|
1183
|
+
clearSelectedList() {
|
|
1184
|
+
this.#selectedEntities.set([]);
|
|
1185
|
+
this.#isPageEntitiesSelected.set(false);
|
|
1186
|
+
this.#isPageEntitiesIndeterminate.set(false);
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Пересчитать флажок страницы по показанным строкам: отмечен, когда отмечены все строки
|
|
1190
|
+
* страницы, промежуточен, когда отмечена часть. Отметки других страниц здесь не в счёт.
|
|
1191
|
+
*/
|
|
1192
|
+
setExistingEntitiesState() {
|
|
1193
|
+
const page = this.#table.entities();
|
|
1194
|
+
const keys = this.selectedEntitiesIds();
|
|
1195
|
+
const all = !!page.length && dataTableAllOnPage(page, keys, this.#keyExp());
|
|
1196
|
+
this.#isPageEntitiesSelected.set(all);
|
|
1197
|
+
this.#isPageEntitiesIndeterminate.set(!all && dataTableAnyOnPage(page, keys, this.#keyExp()));
|
|
1198
|
+
}
|
|
1199
|
+
#keyExp() {
|
|
1200
|
+
return this.#table.keyExp();
|
|
1201
|
+
}
|
|
1202
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableSelectorsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1203
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: RtDataTableSelectorsDirective, isStandalone: true, selector: "rt-data-table[rtDataTableSelectors]", inputs: { isMultiSelect: { classPropertyName: "isMultiSelect", publicName: "isMultiSelect", isSignal: true, isRequired: false, transformFunction: null }, isSelectorColumnShown: { classPropertyName: "isSelectorColumnShown", publicName: "isSelectorColumnShown", isSignal: true, isRequired: false, transformFunction: null }, isSelectorsColumnDisabled: { classPropertyName: "isSelectorsColumnDisabled", publicName: "isSelectorsColumnDisabled", isSignal: true, isRequired: false, transformFunction: null }, selectedEntitiesKeys: { classPropertyName: "selectedEntitiesKeys", publicName: "selectedEntitiesKeys", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
|
|
1204
|
+
}
|
|
1205
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RtDataTableSelectorsDirective, decorators: [{
|
|
1206
|
+
type: Directive,
|
|
1207
|
+
args: [{
|
|
1208
|
+
selector: 'rt-data-table[rtDataTableSelectors]',
|
|
1209
|
+
}]
|
|
1210
|
+
}], ctorParameters: () => [], propDecorators: { isMultiSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiSelect", required: false }] }], isSelectorColumnShown: [{ type: i0.Input, args: [{ isSignal: true, alias: "isSelectorColumnShown", required: false }] }], isSelectorsColumnDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isSelectorsColumnDisabled", required: false }] }], selectedEntitiesKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedEntitiesKeys", required: false }] }] } });
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Generated bundle index. Do not edit.
|
|
1214
|
+
*/
|
|
1215
|
+
|
|
1216
|
+
export { DATA_TABLE_FILTER_MENU_OPERATORS, DATA_TABLE_FILTER_OPERATOR_GLYPHS, RT_DATA_TABLE_ROW_HOST, RT_DATA_TABLE_STOP_ROW_CLICK_ATTRIBUTE, RtDataTableAdditionalRowActionsDirective, RtDataTableCellComponent, RtDataTableComponent, RtDataTableConfigService, RtDataTableCustomCellsDirective, RtDataTableFilterCellComponent, RtDataTableHeaderCellComponent, RtDataTableIconDirective, RtDataTableRowActionsDirective, RtDataTableRowClickDirective, RtDataTableSelectorsDirective, RtDataTableStopRowClickDirective, comparePropNames, dataTableAllOnPage, dataTableAnyOnPage, dataTableAriaSort, dataTableCellText, dataTableCellValue, dataTableColumnFilter, dataTableCopyButtonSide, dataTableDayToIso, dataTableDefaultOperator, dataTableFiltersWithOperator, dataTableFiltersWithValue, dataTableIconName, dataTableIsoToDay, dataTableKeysOf, dataTableNextSortOrder, dataTablePresetEntities, dataTableSortActive, dataTableWithEntity, dataTableWithPageEntities, dataTableWithoutPageEntities };
|
|
1217
|
+
//# sourceMappingURL=rt-tools-ui-kit-v2-data-table.mjs.map
|