@ng-cn/core 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/app/lib/components/ui/accordion/accordion-content.component.ts +53 -0
- package/src/app/lib/components/ui/accordion/accordion-context.ts +33 -0
- package/src/app/lib/components/ui/accordion/accordion-item.component.ts +86 -0
- package/src/app/lib/components/ui/accordion/accordion-trigger.component.ts +73 -0
- package/src/app/lib/components/ui/accordion/accordion.component.ts +197 -0
- package/src/app/lib/components/ui/accordion/index.ts +15 -0
- package/src/app/lib/components/ui/alert/alert-description.component.ts +33 -0
- package/src/app/lib/components/ui/alert/alert-title.component.ts +30 -0
- package/src/app/lib/components/ui/alert/alert-variants.ts +23 -0
- package/src/app/lib/components/ui/alert/alert.component.ts +50 -0
- package/src/app/lib/components/ui/alert/index.ts +5 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-action.component.ts +44 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-cancel.component.ts +45 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-content.component.ts +146 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-context.ts +14 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-description.component.ts +37 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-footer.component.ts +35 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-header.component.ts +35 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-title.component.ts +37 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-trigger.component.ts +44 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog.component.ts +91 -0
- package/src/app/lib/components/ui/alert-dialog/index.ts +11 -0
- package/src/app/lib/components/ui/aspect-ratio/aspect-ratio.component.ts +63 -0
- package/src/app/lib/components/ui/aspect-ratio/index.ts +1 -0
- package/src/app/lib/components/ui/avatar/avatar-fallback.component.ts +34 -0
- package/src/app/lib/components/ui/avatar/avatar-image.component.ts +31 -0
- package/src/app/lib/components/ui/avatar/avatar.component.ts +37 -0
- package/src/app/lib/components/ui/avatar/index.ts +5 -0
- package/src/app/lib/components/ui/avatar/ui-avatar.component.ts +52 -0
- package/src/app/lib/components/ui/badge/badge-variants.ts +28 -0
- package/src/app/lib/components/ui/badge/badge.component.ts +50 -0
- package/src/app/lib/components/ui/badge/index.ts +3 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-ellipsis.component.ts +48 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-item.component.ts +28 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-link.component.ts +32 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-list.component.ts +31 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-page.component.ts +31 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-separator.component.ts +47 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb.component.ts +43 -0
- package/src/app/lib/components/ui/breadcrumb/index.ts +8 -0
- package/src/app/lib/components/ui/button/button-variants.ts +38 -0
- package/src/app/lib/components/ui/button/button.component.ts +103 -0
- package/src/app/lib/components/ui/button/index.ts +3 -0
- package/src/app/lib/components/ui/button-group/button-group-variants.ts +24 -0
- package/src/app/lib/components/ui/button-group/button-group.component.ts +57 -0
- package/src/app/lib/components/ui/button-group/index.ts +6 -0
- package/src/app/lib/components/ui/calendar/calendar.component.ts +368 -0
- package/src/app/lib/components/ui/calendar/index.ts +1 -0
- package/src/app/lib/components/ui/card/card-action.component.ts +39 -0
- package/src/app/lib/components/ui/card/card-content.component.ts +31 -0
- package/src/app/lib/components/ui/card/card-description.component.ts +31 -0
- package/src/app/lib/components/ui/card/card-footer.component.ts +34 -0
- package/src/app/lib/components/ui/card/card-header.component.ts +37 -0
- package/src/app/lib/components/ui/card/card-title.component.ts +31 -0
- package/src/app/lib/components/ui/card/card.component.ts +41 -0
- package/src/app/lib/components/ui/card/index.ts +8 -0
- package/src/app/lib/components/ui/carousel/carousel-content.component.ts +38 -0
- package/src/app/lib/components/ui/carousel/carousel-context.ts +18 -0
- package/src/app/lib/components/ui/carousel/carousel-item.component.ts +32 -0
- package/src/app/lib/components/ui/carousel/carousel-next.component.ts +54 -0
- package/src/app/lib/components/ui/carousel/carousel-previous.component.ts +54 -0
- package/src/app/lib/components/ui/carousel/carousel.component.ts +125 -0
- package/src/app/lib/components/ui/carousel/index.ts +7 -0
- package/src/app/lib/components/ui/chart/chart-container.component.ts +81 -0
- package/src/app/lib/components/ui/chart/chart-context.ts +38 -0
- package/src/app/lib/components/ui/chart/chart-legend-content.component.ts +51 -0
- package/src/app/lib/components/ui/chart/chart-legend.component.ts +28 -0
- package/src/app/lib/components/ui/chart/chart-tooltip-content.component.ts +37 -0
- package/src/app/lib/components/ui/chart/chart-tooltip.component.ts +28 -0
- package/src/app/lib/components/ui/chart/chart.component.ts +308 -0
- package/src/app/lib/components/ui/chart/index.ts +16 -0
- package/src/app/lib/components/ui/checkbox/checkbox.component.ts +203 -0
- package/src/app/lib/components/ui/checkbox/index.ts +1 -0
- package/src/app/lib/components/ui/collapsible/collapsible-content.component.ts +58 -0
- package/src/app/lib/components/ui/collapsible/collapsible-context.ts +17 -0
- package/src/app/lib/components/ui/collapsible/collapsible-trigger.component.ts +56 -0
- package/src/app/lib/components/ui/collapsible/collapsible.component.ts +102 -0
- package/src/app/lib/components/ui/collapsible/index.ts +5 -0
- package/src/app/lib/components/ui/combobox/combobox-content.component.ts +59 -0
- package/src/app/lib/components/ui/combobox/combobox-context.ts +49 -0
- package/src/app/lib/components/ui/combobox/combobox-empty.component.ts +35 -0
- package/src/app/lib/components/ui/combobox/combobox-group.component.ts +32 -0
- package/src/app/lib/components/ui/combobox/combobox-input.component.ts +89 -0
- package/src/app/lib/components/ui/combobox/combobox-item.component.ts +129 -0
- package/src/app/lib/components/ui/combobox/combobox-list.component.ts +40 -0
- package/src/app/lib/components/ui/combobox/combobox-trigger.component.ts +53 -0
- package/src/app/lib/components/ui/combobox/combobox-value.component.ts +47 -0
- package/src/app/lib/components/ui/combobox/combobox.component.ts +290 -0
- package/src/app/lib/components/ui/combobox/index.ts +15 -0
- package/src/app/lib/components/ui/command/command-context.ts +24 -0
- package/src/app/lib/components/ui/command/command-dialog.component.ts +69 -0
- package/src/app/lib/components/ui/command/command-empty.component.ts +23 -0
- package/src/app/lib/components/ui/command/command-group.component.ts +66 -0
- package/src/app/lib/components/ui/command/command-input.component.ts +137 -0
- package/src/app/lib/components/ui/command/command-item.component.ts +148 -0
- package/src/app/lib/components/ui/command/command-list.component.ts +30 -0
- package/src/app/lib/components/ui/command/command-separator.component.ts +23 -0
- package/src/app/lib/components/ui/command/command-shortcut.component.ts +23 -0
- package/src/app/lib/components/ui/command/command.component.ts +105 -0
- package/src/app/lib/components/ui/command/index.ts +11 -0
- package/src/app/lib/components/ui/context-menu/context-menu-checkbox-item.component.ts +68 -0
- package/src/app/lib/components/ui/context-menu/context-menu-content.component.ts +213 -0
- package/src/app/lib/components/ui/context-menu/context-menu-context.ts +17 -0
- package/src/app/lib/components/ui/context-menu/context-menu-item.component.ts +63 -0
- package/src/app/lib/components/ui/context-menu/context-menu-label.component.ts +30 -0
- package/src/app/lib/components/ui/context-menu/context-menu-radio-group.component.ts +36 -0
- package/src/app/lib/components/ui/context-menu/context-menu-radio-item.component.ts +71 -0
- package/src/app/lib/components/ui/context-menu/context-menu-separator.component.ts +24 -0
- package/src/app/lib/components/ui/context-menu/context-menu-shortcut.component.ts +23 -0
- package/src/app/lib/components/ui/context-menu/context-menu-sub-content.component.ts +51 -0
- package/src/app/lib/components/ui/context-menu/context-menu-sub-trigger.component.ts +50 -0
- package/src/app/lib/components/ui/context-menu/context-menu-sub.component.ts +31 -0
- package/src/app/lib/components/ui/context-menu/context-menu-trigger.component.ts +51 -0
- package/src/app/lib/components/ui/context-menu/context-menu.component.ts +27 -0
- package/src/app/lib/components/ui/context-menu/index.ts +15 -0
- package/src/app/lib/components/ui/data-table/data-table-content.component.ts +226 -0
- package/src/app/lib/components/ui/data-table/data-table-context.ts +49 -0
- package/src/app/lib/components/ui/data-table/data-table-pagination.component.ts +138 -0
- package/src/app/lib/components/ui/data-table/data-table-search.component.ts +52 -0
- package/src/app/lib/components/ui/data-table/data-table-toolbar.component.ts +27 -0
- package/src/app/lib/components/ui/data-table/data-table-view-options.component.ts +92 -0
- package/src/app/lib/components/ui/data-table/data-table.component.ts +131 -0
- package/src/app/lib/components/ui/data-table/index.ts +16 -0
- package/src/app/lib/components/ui/date-picker/date-picker.component.ts +94 -0
- package/src/app/lib/components/ui/date-picker/index.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-close.component.ts +31 -0
- package/src/app/lib/components/ui/dialog/dialog-content.component.ts +177 -0
- package/src/app/lib/components/ui/dialog/dialog-context.ts +15 -0
- package/src/app/lib/components/ui/dialog/dialog-description.component.ts +34 -0
- package/src/app/lib/components/ui/dialog/dialog-footer.component.ts +28 -0
- package/src/app/lib/components/ui/dialog/dialog-header.component.ts +28 -0
- package/src/app/lib/components/ui/dialog/dialog-title.component.ts +34 -0
- package/src/app/lib/components/ui/dialog/dialog-trigger.component.ts +38 -0
- package/src/app/lib/components/ui/dialog/dialog.component.ts +87 -0
- package/src/app/lib/components/ui/dialog/index.ts +10 -0
- package/src/app/lib/components/ui/drawer/drawer-close.component.ts +31 -0
- package/src/app/lib/components/ui/drawer/drawer-content.component.ts +143 -0
- package/src/app/lib/components/ui/drawer/drawer-context.ts +17 -0
- package/src/app/lib/components/ui/drawer/drawer-description.component.ts +33 -0
- package/src/app/lib/components/ui/drawer/drawer-footer.component.ts +28 -0
- package/src/app/lib/components/ui/drawer/drawer-header.component.ts +28 -0
- package/src/app/lib/components/ui/drawer/drawer-title.component.ts +33 -0
- package/src/app/lib/components/ui/drawer/drawer-trigger.component.ts +38 -0
- package/src/app/lib/components/ui/drawer/drawer.component.ts +93 -0
- package/src/app/lib/components/ui/drawer/index.ts +10 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.component.ts +68 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-content.component.ts +234 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-context.ts +15 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-group.component.ts +15 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-item.component.ts +56 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-label.component.ts +30 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.component.ts +42 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.component.ts +71 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-separator.component.ts +24 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.component.ts +23 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.component.ts +51 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.component.ts +53 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub.component.ts +31 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-trigger.component.ts +45 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu.component.ts +32 -0
- package/src/app/lib/components/ui/dropdown-menu/index.ts +16 -0
- package/src/app/lib/components/ui/empty/empty-action.component.ts +28 -0
- package/src/app/lib/components/ui/empty/empty-description.component.ts +31 -0
- package/src/app/lib/components/ui/empty/empty-icon.component.ts +31 -0
- package/src/app/lib/components/ui/empty/empty-title.component.ts +28 -0
- package/src/app/lib/components/ui/empty/empty.component.ts +53 -0
- package/src/app/lib/components/ui/empty/index.ts +6 -0
- package/src/app/lib/components/ui/form/form-context.ts +34 -0
- package/src/app/lib/components/ui/form/form-control.component.ts +137 -0
- package/src/app/lib/components/ui/form/form-description.component.ts +37 -0
- package/src/app/lib/components/ui/form/form-field.component.ts +84 -0
- package/src/app/lib/components/ui/form/form-item.component.ts +42 -0
- package/src/app/lib/components/ui/form/form-label.component.ts +58 -0
- package/src/app/lib/components/ui/form/form-message.component.ts +107 -0
- package/src/app/lib/components/ui/form/form.component.ts +123 -0
- package/src/app/lib/components/ui/form/index.ts +17 -0
- package/src/app/lib/components/ui/hover-card/hover-card-content.component.ts +203 -0
- package/src/app/lib/components/ui/hover-card/hover-card-context.ts +25 -0
- package/src/app/lib/components/ui/hover-card/hover-card-trigger.component.ts +160 -0
- package/src/app/lib/components/ui/hover-card/hover-card.component.ts +147 -0
- package/src/app/lib/components/ui/hover-card/index.ts +13 -0
- package/src/app/lib/components/ui/index.ts +551 -0
- package/src/app/lib/components/ui/input/index.ts +1 -0
- package/src/app/lib/components/ui/input/input.component.ts +165 -0
- package/src/app/lib/components/ui/input-group/index.ts +4 -0
- package/src/app/lib/components/ui/input-group/input-group-addon.component.ts +43 -0
- package/src/app/lib/components/ui/input-group/input-group-input.component.ts +33 -0
- package/src/app/lib/components/ui/input-group/input-group.component.ts +53 -0
- package/src/app/lib/components/ui/input-otp/index.ts +14 -0
- package/src/app/lib/components/ui/input-otp/input-otp-context.ts +31 -0
- package/src/app/lib/components/ui/input-otp/input-otp-group.component.ts +23 -0
- package/src/app/lib/components/ui/input-otp/input-otp-separator.component.ts +31 -0
- package/src/app/lib/components/ui/input-otp/input-otp-slot.component.ts +67 -0
- package/src/app/lib/components/ui/input-otp/input-otp.component.ts +240 -0
- package/src/app/lib/components/ui/kbd/index.ts +3 -0
- package/src/app/lib/components/ui/kbd/kbd-variants.ts +23 -0
- package/src/app/lib/components/ui/kbd/kbd.component.ts +50 -0
- package/src/app/lib/components/ui/label/index.ts +1 -0
- package/src/app/lib/components/ui/label/label.component.ts +139 -0
- package/src/app/lib/components/ui/menubar/index.ts +26 -0
- package/src/app/lib/components/ui/menubar/menubar-checkbox-item.component.ts +66 -0
- package/src/app/lib/components/ui/menubar/menubar-content.component.ts +236 -0
- package/src/app/lib/components/ui/menubar/menubar-context.ts +63 -0
- package/src/app/lib/components/ui/menubar/menubar-item.component.ts +60 -0
- package/src/app/lib/components/ui/menubar/menubar-label.component.ts +30 -0
- package/src/app/lib/components/ui/menubar/menubar-menu.component.ts +40 -0
- package/src/app/lib/components/ui/menubar/menubar-radio-group.component.ts +36 -0
- package/src/app/lib/components/ui/menubar/menubar-radio-item.component.ts +66 -0
- package/src/app/lib/components/ui/menubar/menubar-separator.component.ts +24 -0
- package/src/app/lib/components/ui/menubar/menubar-shortcut.component.ts +23 -0
- package/src/app/lib/components/ui/menubar/menubar-sub-content.component.ts +51 -0
- package/src/app/lib/components/ui/menubar/menubar-sub-trigger.component.ts +50 -0
- package/src/app/lib/components/ui/menubar/menubar-sub.component.ts +29 -0
- package/src/app/lib/components/ui/menubar/menubar-trigger.component.ts +132 -0
- package/src/app/lib/components/ui/menubar/menubar.component.ts +158 -0
- package/src/app/lib/components/ui/native-select/index.ts +6 -0
- package/src/app/lib/components/ui/native-select/native-select-variants.ts +23 -0
- package/src/app/lib/components/ui/native-select/native-select.component.ts +74 -0
- package/src/app/lib/components/ui/navigation-menu/index.ts +21 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-content.component.ts +66 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-context.ts +55 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-indicator.component.ts +28 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-item.component.ts +29 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-link.component.ts +43 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-list.component.ts +26 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger-style.ts +7 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger.component.ts +58 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-viewport.component.ts +26 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu.component.ts +149 -0
- package/src/app/lib/components/ui/pagination/index.ts +8 -0
- package/src/app/lib/components/ui/pagination/pagination-content.component.ts +28 -0
- package/src/app/lib/components/ui/pagination/pagination-ellipsis.component.ts +47 -0
- package/src/app/lib/components/ui/pagination/pagination-item.component.ts +28 -0
- package/src/app/lib/components/ui/pagination/pagination-link.component.ts +46 -0
- package/src/app/lib/components/ui/pagination/pagination-next.component.ts +54 -0
- package/src/app/lib/components/ui/pagination/pagination-previous.component.ts +54 -0
- package/src/app/lib/components/ui/pagination/pagination.component.ts +48 -0
- package/src/app/lib/components/ui/popover/index.ts +14 -0
- package/src/app/lib/components/ui/popover/popover-anchor.component.ts +64 -0
- package/src/app/lib/components/ui/popover/popover-content.component.ts +231 -0
- package/src/app/lib/components/ui/popover/popover-context.ts +29 -0
- package/src/app/lib/components/ui/popover/popover-trigger.component.ts +100 -0
- package/src/app/lib/components/ui/popover/popover.component.ts +163 -0
- package/src/app/lib/components/ui/progress/index.ts +6 -0
- package/src/app/lib/components/ui/progress/progress.component.ts +212 -0
- package/src/app/lib/components/ui/radio-group/index.ts +10 -0
- package/src/app/lib/components/ui/radio-group/radio-group-context.ts +38 -0
- package/src/app/lib/components/ui/radio-group/radio-group-item.component.ts +298 -0
- package/src/app/lib/components/ui/radio-group/radio-group.component.ts +275 -0
- package/src/app/lib/components/ui/resizable/index.ts +5 -0
- package/src/app/lib/components/ui/resizable/resizable-context.ts +14 -0
- package/src/app/lib/components/ui/resizable/resizable-handle.component.ts +232 -0
- package/src/app/lib/components/ui/resizable/resizable-panel-group.component.ts +140 -0
- package/src/app/lib/components/ui/resizable/resizable-panel.component.ts +77 -0
- package/src/app/lib/components/ui/scroll-area/index.ts +8 -0
- package/src/app/lib/components/ui/scroll-area/scroll-area.component.ts +126 -0
- package/src/app/lib/components/ui/scroll-area/scroll-bar.component.ts +93 -0
- package/src/app/lib/components/ui/segmented/index.ts +13 -0
- package/src/app/lib/components/ui/segmented/segmented-context.ts +11 -0
- package/src/app/lib/components/ui/segmented/segmented-item.component.ts +72 -0
- package/src/app/lib/components/ui/segmented/segmented-variants.ts +40 -0
- package/src/app/lib/components/ui/segmented/segmented.component.ts +99 -0
- package/src/app/lib/components/ui/select/index.ts +19 -0
- package/src/app/lib/components/ui/select/select-content.component.ts +97 -0
- package/src/app/lib/components/ui/select/select-context.ts +53 -0
- package/src/app/lib/components/ui/select/select-group.component.ts +56 -0
- package/src/app/lib/components/ui/select/select-item.component.ts +163 -0
- package/src/app/lib/components/ui/select/select-label.component.ts +32 -0
- package/src/app/lib/components/ui/select/select-separator.component.ts +34 -0
- package/src/app/lib/components/ui/select/select-trigger.component.ts +164 -0
- package/src/app/lib/components/ui/select/select-value.component.ts +49 -0
- package/src/app/lib/components/ui/select/select.component.ts +263 -0
- package/src/app/lib/components/ui/separator/index.ts +6 -0
- package/src/app/lib/components/ui/separator/separator.component.ts +128 -0
- package/src/app/lib/components/ui/sheet/index.ts +11 -0
- package/src/app/lib/components/ui/sheet/sheet-close.component.ts +32 -0
- package/src/app/lib/components/ui/sheet/sheet-content.component.ts +157 -0
- package/src/app/lib/components/ui/sheet/sheet-context.ts +15 -0
- package/src/app/lib/components/ui/sheet/sheet-description.component.ts +34 -0
- package/src/app/lib/components/ui/sheet/sheet-footer.component.ts +28 -0
- package/src/app/lib/components/ui/sheet/sheet-header.component.ts +28 -0
- package/src/app/lib/components/ui/sheet/sheet-title.component.ts +34 -0
- package/src/app/lib/components/ui/sheet/sheet-trigger.component.ts +38 -0
- package/src/app/lib/components/ui/sheet/sheet-variants.ts +22 -0
- package/src/app/lib/components/ui/sheet/sheet.component.ts +97 -0
- package/src/app/lib/components/ui/sidebar/index.ts +41 -0
- package/src/app/lib/components/ui/sidebar/sidebar-content.component.ts +31 -0
- package/src/app/lib/components/ui/sidebar/sidebar-context.ts +33 -0
- package/src/app/lib/components/ui/sidebar/sidebar-footer.component.ts +28 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-action.component.ts +33 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-content.component.ts +28 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-label.component.ts +32 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group.component.ts +28 -0
- package/src/app/lib/components/ui/sidebar/sidebar-header.component.ts +28 -0
- package/src/app/lib/components/ui/sidebar/sidebar-input.component.ts +31 -0
- package/src/app/lib/components/ui/sidebar/sidebar-inset.component.ts +31 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-action.component.ts +56 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-badge.component.ts +42 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-button.component.ts +64 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-item.component.ts +32 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-skeleton.component.ts +39 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-button.component.ts +59 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-item.component.ts +25 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub.component.ts +32 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu.component.ts +31 -0
- package/src/app/lib/components/ui/sidebar/sidebar-provider.component.ts +141 -0
- package/src/app/lib/components/ui/sidebar/sidebar-rail.component.ts +47 -0
- package/src/app/lib/components/ui/sidebar/sidebar-route-active.service.ts +124 -0
- package/src/app/lib/components/ui/sidebar/sidebar-separator.component.ts +28 -0
- package/src/app/lib/components/ui/sidebar/sidebar-trigger.component.ts +57 -0
- package/src/app/lib/components/ui/sidebar/sidebar.component.ts +130 -0
- package/src/app/lib/components/ui/skeleton/index.ts +1 -0
- package/src/app/lib/components/ui/skeleton/skeleton.component.ts +52 -0
- package/src/app/lib/components/ui/slider/index.ts +6 -0
- package/src/app/lib/components/ui/slider/slider.component.ts +477 -0
- package/src/app/lib/components/ui/spinner/index.ts +3 -0
- package/src/app/lib/components/ui/spinner/spinner-variants.ts +32 -0
- package/src/app/lib/components/ui/spinner/spinner.component.ts +77 -0
- package/src/app/lib/components/ui/switch/index.ts +6 -0
- package/src/app/lib/components/ui/switch/switch.component.ts +282 -0
- package/src/app/lib/components/ui/table/index.ts +9 -0
- package/src/app/lib/components/ui/table/table-body.component.ts +28 -0
- package/src/app/lib/components/ui/table/table-caption.component.ts +28 -0
- package/src/app/lib/components/ui/table/table-cell.component.ts +31 -0
- package/src/app/lib/components/ui/table/table-footer.component.ts +28 -0
- package/src/app/lib/components/ui/table/table-head.component.ts +36 -0
- package/src/app/lib/components/ui/table/table-header.component.ts +28 -0
- package/src/app/lib/components/ui/table/table-row.component.ts +34 -0
- package/src/app/lib/components/ui/table/table.component.ts +52 -0
- package/src/app/lib/components/ui/tabs/index.ts +14 -0
- package/src/app/lib/components/ui/tabs/tabs-content.component.ts +132 -0
- package/src/app/lib/components/ui/tabs/tabs-context.ts +33 -0
- package/src/app/lib/components/ui/tabs/tabs-list.component.ts +228 -0
- package/src/app/lib/components/ui/tabs/tabs-trigger.component.ts +167 -0
- package/src/app/lib/components/ui/tabs/tabs.component.ts +203 -0
- package/src/app/lib/components/ui/textarea/index.ts +1 -0
- package/src/app/lib/components/ui/textarea/textarea.component.ts +44 -0
- package/src/app/lib/components/ui/toast/index.ts +16 -0
- package/src/app/lib/components/ui/toast/toast-action.component.ts +77 -0
- package/src/app/lib/components/ui/toast/toast-description.component.ts +52 -0
- package/src/app/lib/components/ui/toast/toast-title.component.ts +52 -0
- package/src/app/lib/components/ui/toast/toast-variants.ts +24 -0
- package/src/app/lib/components/ui/toast/toast.component.ts +177 -0
- package/src/app/lib/components/ui/toast/toast.service.ts +202 -0
- package/src/app/lib/components/ui/toast/toaster.component.ts +128 -0
- package/src/app/lib/components/ui/toggle/index.ts +6 -0
- package/src/app/lib/components/ui/toggle/toggle-variants.ts +30 -0
- package/src/app/lib/components/ui/toggle/toggle.component.ts +199 -0
- package/src/app/lib/components/ui/toggle-group/index.ts +11 -0
- package/src/app/lib/components/ui/toggle-group/toggle-group-context.ts +48 -0
- package/src/app/lib/components/ui/toggle-group/toggle-group-item.component.ts +241 -0
- package/src/app/lib/components/ui/toggle-group/toggle-group.component.ts +288 -0
- package/src/app/lib/components/ui/tooltip/index.ts +14 -0
- package/src/app/lib/components/ui/tooltip/tooltip-content.component.ts +154 -0
- package/src/app/lib/components/ui/tooltip/tooltip-context.ts +29 -0
- package/src/app/lib/components/ui/tooltip/tooltip-provider.component.ts +95 -0
- package/src/app/lib/components/ui/tooltip/tooltip-trigger.component.ts +138 -0
- package/src/app/lib/components/ui/tooltip/tooltip.component.ts +159 -0
- package/src/app/lib/components/ui/typography/index.ts +13 -0
- package/src/app/lib/components/ui/typography/typography-blockquote.component.ts +31 -0
- package/src/app/lib/components/ui/typography/typography-h1.component.ts +32 -0
- package/src/app/lib/components/ui/typography/typography-h2.component.ts +32 -0
- package/src/app/lib/components/ui/typography/typography-h3.component.ts +29 -0
- package/src/app/lib/components/ui/typography/typography-h4.component.ts +29 -0
- package/src/app/lib/components/ui/typography/typography-inline-code.component.ts +31 -0
- package/src/app/lib/components/ui/typography/typography-large.component.ts +28 -0
- package/src/app/lib/components/ui/typography/typography-lead.component.ts +31 -0
- package/src/app/lib/components/ui/typography/typography-list.component.ts +31 -0
- package/src/app/lib/components/ui/typography/typography-muted.component.ts +28 -0
- package/src/app/lib/components/ui/typography/typography-p.component.ts +29 -0
- package/src/app/lib/components/ui/typography/typography-small.component.ts +28 -0
- package/src/app/lib/index.ts +7 -0
- package/src/app/lib/utils/accessibility/aria-id.service.ts +118 -0
- package/src/app/lib/utils/accessibility/click-outside.directive.ts +85 -0
- package/src/app/lib/utils/accessibility/focus-management.service.ts +231 -0
- package/src/app/lib/utils/accessibility/focus-trap.directive.ts +203 -0
- package/src/app/lib/utils/accessibility/index.ts +23 -0
- package/src/app/lib/utils/accessibility/keyboard-navigation.directive.ts +440 -0
- package/src/app/lib/utils/accessibility/live-region.directive.ts +260 -0
- package/src/app/lib/utils/accessibility/touch-target.directive.ts +81 -0
- package/src/app/lib/utils/accessibility/visually-hidden.component.ts +79 -0
- package/src/app/lib/utils/animation/animated.directive.ts +191 -0
- package/src/app/lib/utils/animation/animation-tokens.service.ts +88 -0
- package/src/app/lib/utils/animation/animation.types.ts +55 -0
- package/src/app/lib/utils/animation/animation.utils.ts +158 -0
- package/src/app/lib/utils/animation/index.ts +17 -0
- package/src/app/lib/utils/animation/presence.component.ts +168 -0
- package/src/app/lib/utils/animation/presence.directive.ts +169 -0
- package/src/app/lib/utils/cn.ts +15 -0
- package/src/app/lib/utils/index.ts +11 -0
- package/src/app/lib/utils/positioning/index.ts +218 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation System Types - Radix-Ready Animation Layer for shadcn-angular
|
|
3
|
+
* Defines the animation lifecycle states and configuration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Animation lifecycle states
|
|
8
|
+
* Mirrors Radix UI's internal state management
|
|
9
|
+
*/
|
|
10
|
+
export type AnimationState = 'closed' | 'entering' | 'open' | 'exiting';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Positional information for directional animations
|
|
14
|
+
*/
|
|
15
|
+
export type AnimationSide = 'top' | 'bottom' | 'left' | 'right';
|
|
16
|
+
export type AnimationAlign = 'start' | 'center' | 'end';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Animation lifecycle configuration
|
|
20
|
+
*/
|
|
21
|
+
export interface AnimationConfig {
|
|
22
|
+
/** Duration in milliseconds */
|
|
23
|
+
duration?: number;
|
|
24
|
+
/** Easing function */
|
|
25
|
+
easing?: string;
|
|
26
|
+
/** CSS class to apply during animation */
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* State exposure API - all animated components must expose these attributes
|
|
32
|
+
*/
|
|
33
|
+
export interface AnimatedElementAttributes {
|
|
34
|
+
/** Current animation lifecycle state */
|
|
35
|
+
'data-state': AnimationState;
|
|
36
|
+
/** Positional side (if applicable) */
|
|
37
|
+
'data-side'?: AnimationSide;
|
|
38
|
+
/** Alignment (if applicable) */
|
|
39
|
+
'data-align'?: AnimationAlign;
|
|
40
|
+
/** Motion phase for directional animations */
|
|
41
|
+
'data-motion'?: 'from-start' | 'to-end';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Presence component token
|
|
46
|
+
* Keeps component in DOM until exit animation completes
|
|
47
|
+
*/
|
|
48
|
+
export interface PresenceToken {
|
|
49
|
+
/** Unique identifier for presence tracking */
|
|
50
|
+
id: string;
|
|
51
|
+
/** Current animation state */
|
|
52
|
+
state: AnimationState;
|
|
53
|
+
/** Callback when animation completes */
|
|
54
|
+
onAnimationEnd?: () => void;
|
|
55
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation Utility Functions
|
|
3
|
+
* Helper functions for managing animation states and CSS classes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { signal, Signal } from '@angular/core';
|
|
7
|
+
import type { AnimationAlign, AnimationSide, AnimationState } from './animation.types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Animation preset names matching shadcn/ui semantics
|
|
11
|
+
*/
|
|
12
|
+
export const ANIMATION_PRESETS = {
|
|
13
|
+
// Fade animations
|
|
14
|
+
fadeIn: 'animate-in fade-in-0',
|
|
15
|
+
fadeOut: 'animate-out fade-out-0',
|
|
16
|
+
|
|
17
|
+
// Scale/Zoom animations
|
|
18
|
+
scaleIn: 'animate-in zoom-in-95',
|
|
19
|
+
scaleOut: 'animate-out zoom-out-95',
|
|
20
|
+
|
|
21
|
+
// Slide animations
|
|
22
|
+
slideInFromTop: 'animate-in slide-in-from-top-2',
|
|
23
|
+
slideOutToTop: 'animate-out slide-out-to-top-2',
|
|
24
|
+
slideInFromRight: 'animate-in slide-in-from-right-2',
|
|
25
|
+
slideOutToRight: 'animate-out slide-out-to-right-2',
|
|
26
|
+
slideInFromBottom: 'animate-in slide-in-from-bottom-2',
|
|
27
|
+
slideOutToBottom: 'animate-out slide-out-to-bottom-2',
|
|
28
|
+
slideInFromLeft: 'animate-in slide-in-from-left-2',
|
|
29
|
+
slideOutToLeft: 'animate-out slide-out-to-left-2',
|
|
30
|
+
|
|
31
|
+
// Combined animations (common patterns)
|
|
32
|
+
fadeScale: 'animate-in fade-in-0 zoom-in-95',
|
|
33
|
+
fadeScaleOut: 'animate-out fade-out-0 zoom-out-95',
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create animation state signal
|
|
38
|
+
* Manages the 4-state animation lifecycle
|
|
39
|
+
*/
|
|
40
|
+
export function createAnimationState(
|
|
41
|
+
initialState: AnimationState = 'closed'
|
|
42
|
+
): Signal<AnimationState> {
|
|
43
|
+
return signal<AnimationState>(initialState);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Determine animation CSS classes based on state and direction
|
|
48
|
+
*/
|
|
49
|
+
export function getAnimationClasses(
|
|
50
|
+
state: AnimationState,
|
|
51
|
+
direction?: AnimationSide,
|
|
52
|
+
animate: boolean = true
|
|
53
|
+
): string {
|
|
54
|
+
if (!animate) return '';
|
|
55
|
+
|
|
56
|
+
const baseClasses = ['duration-200'];
|
|
57
|
+
|
|
58
|
+
switch (state) {
|
|
59
|
+
case 'closed':
|
|
60
|
+
return [...baseClasses, 'animate-out fade-out-0'].join(' ');
|
|
61
|
+
|
|
62
|
+
case 'entering':
|
|
63
|
+
return [...baseClasses, 'animate-in fade-in-0'].join(' ');
|
|
64
|
+
|
|
65
|
+
case 'open':
|
|
66
|
+
return [...baseClasses, 'animate-in fade-in-0'].join(' ');
|
|
67
|
+
|
|
68
|
+
case 'exiting':
|
|
69
|
+
return [...baseClasses, 'animate-out fade-out-0'].join(' ');
|
|
70
|
+
|
|
71
|
+
default:
|
|
72
|
+
return '';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get slide animation classes based on direction
|
|
78
|
+
*/
|
|
79
|
+
export function getSlideAnimationClasses(
|
|
80
|
+
state: AnimationState,
|
|
81
|
+
direction: AnimationSide
|
|
82
|
+
): string {
|
|
83
|
+
const baseClasses = ['duration-200'];
|
|
84
|
+
|
|
85
|
+
const directionMap: Record<AnimationState, Record<AnimationSide, string>> = {
|
|
86
|
+
entering: {
|
|
87
|
+
top: 'animate-in slide-in-from-top-2',
|
|
88
|
+
bottom: 'animate-in slide-in-from-bottom-2',
|
|
89
|
+
left: 'animate-in slide-in-from-left-2',
|
|
90
|
+
right: 'animate-in slide-in-from-right-2',
|
|
91
|
+
},
|
|
92
|
+
open: {
|
|
93
|
+
top: 'animate-in slide-in-from-top-2',
|
|
94
|
+
bottom: 'animate-in slide-in-from-bottom-2',
|
|
95
|
+
left: 'animate-in slide-in-from-left-2',
|
|
96
|
+
right: 'animate-in slide-in-from-right-2',
|
|
97
|
+
},
|
|
98
|
+
exiting: {
|
|
99
|
+
top: 'animate-out slide-out-to-top-2',
|
|
100
|
+
bottom: 'animate-out slide-out-to-bottom-2',
|
|
101
|
+
left: 'animate-out slide-out-to-left-2',
|
|
102
|
+
right: 'animate-out slide-out-to-right-2',
|
|
103
|
+
},
|
|
104
|
+
closed: {
|
|
105
|
+
top: 'animate-out slide-out-to-top-2',
|
|
106
|
+
bottom: 'animate-out slide-out-to-bottom-2',
|
|
107
|
+
left: 'animate-out slide-out-to-left-2',
|
|
108
|
+
right: 'animate-out slide-out-to-right-2',
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return [...baseClasses, directionMap[state]?.[direction] || ''].join(' ');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Build data attributes for animation state exposure
|
|
117
|
+
*/
|
|
118
|
+
export function buildAnimationAttributes(
|
|
119
|
+
state: AnimationState,
|
|
120
|
+
side?: AnimationSide,
|
|
121
|
+
align?: AnimationAlign
|
|
122
|
+
): Record<string, string | undefined> {
|
|
123
|
+
return {
|
|
124
|
+
'data-state': state,
|
|
125
|
+
'data-side': side,
|
|
126
|
+
'data-align': align,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Wait for animation to complete
|
|
132
|
+
* Useful for coordinating multiple animations
|
|
133
|
+
*/
|
|
134
|
+
export async function waitForAnimation(element: HTMLElement): Promise<void> {
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
const handleAnimationEnd = () => {
|
|
137
|
+
element.removeEventListener('animationend', handleAnimationEnd);
|
|
138
|
+
resolve();
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
element.addEventListener('animationend', handleAnimationEnd);
|
|
142
|
+
|
|
143
|
+
// Timeout fallback (300ms for safety)
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
element.removeEventListener('animationend', handleAnimationEnd);
|
|
146
|
+
resolve();
|
|
147
|
+
}, 300);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Check if animations are enabled (respects prefers-reduced-motion)
|
|
153
|
+
*/
|
|
154
|
+
export function areAnimationsEnabled(): boolean {
|
|
155
|
+
if (typeof window === 'undefined') return true;
|
|
156
|
+
|
|
157
|
+
return !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
158
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation System Index
|
|
3
|
+
* Exports all animation utilities and services
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type { AnimatedElementAttributes, AnimationAlign, AnimationConfig, AnimationSide, AnimationState, PresenceToken } from './animation.types';
|
|
7
|
+
|
|
8
|
+
export { AnimatedDirective } from './animated.directive';
|
|
9
|
+
export { AnimationTokensService } from './animation-tokens.service';
|
|
10
|
+
export {
|
|
11
|
+
ANIMATION_PRESETS, areAnimationsEnabled, buildAnimationAttributes, createAnimationState,
|
|
12
|
+
getAnimationClasses,
|
|
13
|
+
getSlideAnimationClasses, waitForAnimation
|
|
14
|
+
} from './animation.utils';
|
|
15
|
+
export { Presence, type PresenceState } from './presence.component';
|
|
16
|
+
export { PresenceIfDirective, PresenceService } from './presence.directive';
|
|
17
|
+
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presence Component
|
|
3
|
+
* Angular version of Radix UI's Presence primitive
|
|
4
|
+
* Keeps DOM elements present until exit animations complete
|
|
5
|
+
*
|
|
6
|
+
* This is the critical component for proper exit animations in:
|
|
7
|
+
* - Dialog
|
|
8
|
+
* - Popover
|
|
9
|
+
* - Dropdown Menu
|
|
10
|
+
* - Tooltip
|
|
11
|
+
* - Sheet
|
|
12
|
+
* - Toast
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
ChangeDetectionStrategy,
|
|
17
|
+
Component,
|
|
18
|
+
computed,
|
|
19
|
+
effect,
|
|
20
|
+
input,
|
|
21
|
+
OnDestroy,
|
|
22
|
+
signal
|
|
23
|
+
} from '@angular/core';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Presence state
|
|
27
|
+
*/
|
|
28
|
+
export type PresenceState = 'mounted' | 'unmountSuspended' | 'unmounted';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Presence Component
|
|
32
|
+
* Wraps content and manages its presence in the DOM based on animation state
|
|
33
|
+
*
|
|
34
|
+
* Usage:
|
|
35
|
+
* <Presence [present]="isOpen()">
|
|
36
|
+
* <div class="animate-in data-[state=closed]:animate-out">
|
|
37
|
+
* Content here
|
|
38
|
+
* </div>
|
|
39
|
+
* </Presence>
|
|
40
|
+
*/
|
|
41
|
+
@Component({
|
|
42
|
+
selector: 'Presence',
|
|
43
|
+
template: `
|
|
44
|
+
@if (shouldRender()) {
|
|
45
|
+
<ng-content />
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
host: {
|
|
49
|
+
class: 'contents',
|
|
50
|
+
'[attr.data-presence-state]': 'presenceState()',
|
|
51
|
+
'(animationend)': 'handleAnimationEnd($event)',
|
|
52
|
+
'(animationcancel)': 'handleAnimationEnd($event)',
|
|
53
|
+
},
|
|
54
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
55
|
+
})
|
|
56
|
+
export class Presence implements OnDestroy {
|
|
57
|
+
/** Whether the content should be present */
|
|
58
|
+
readonly present = input.required<boolean>();
|
|
59
|
+
|
|
60
|
+
/** Force presence (bypass animation waiting) */
|
|
61
|
+
readonly forceMount = input<boolean>(false);
|
|
62
|
+
|
|
63
|
+
/** Animation duration in ms (fallback if CSS animation doesn't fire) */
|
|
64
|
+
readonly exitDuration = input<number>(200);
|
|
65
|
+
|
|
66
|
+
/** Internal presence state */
|
|
67
|
+
private readonly state = signal<PresenceState>('unmounted');
|
|
68
|
+
|
|
69
|
+
/** Previous present value for change detection */
|
|
70
|
+
private prevPresent = false;
|
|
71
|
+
|
|
72
|
+
/** Timeout for fallback animation end */
|
|
73
|
+
private exitTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
74
|
+
|
|
75
|
+
/** Whether to render content */
|
|
76
|
+
readonly shouldRender = computed(() => {
|
|
77
|
+
if (this.forceMount()) return true;
|
|
78
|
+
|
|
79
|
+
const currentState = this.state();
|
|
80
|
+
return currentState === 'mounted' || currentState === 'unmountSuspended';
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/** Current presence state (exposed for debugging) */
|
|
84
|
+
readonly presenceState = computed(() => this.state());
|
|
85
|
+
|
|
86
|
+
constructor() {
|
|
87
|
+
// React to present changes
|
|
88
|
+
effect(() => {
|
|
89
|
+
const isPresent = this.present();
|
|
90
|
+
|
|
91
|
+
if (isPresent !== this.prevPresent) {
|
|
92
|
+
this.handlePresenceChange(isPresent);
|
|
93
|
+
this.prevPresent = isPresent;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
ngOnDestroy(): void {
|
|
99
|
+
this.clearExitTimeout();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Handle presence change
|
|
104
|
+
*/
|
|
105
|
+
private handlePresenceChange(isPresent: boolean): void {
|
|
106
|
+
this.clearExitTimeout();
|
|
107
|
+
|
|
108
|
+
if (isPresent) {
|
|
109
|
+
// Mount immediately
|
|
110
|
+
this.state.set('mounted');
|
|
111
|
+
} else {
|
|
112
|
+
// Start exit animation
|
|
113
|
+
this.state.set('unmountSuspended');
|
|
114
|
+
|
|
115
|
+
// Set fallback timeout in case animationend doesn't fire
|
|
116
|
+
this.exitTimeout = setTimeout(() => {
|
|
117
|
+
this.state.set('unmounted');
|
|
118
|
+
}, this.exitDuration());
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handle animation end
|
|
124
|
+
*/
|
|
125
|
+
protected handleAnimationEnd(event: AnimationEvent): void {
|
|
126
|
+
// Only handle if we're in exit state
|
|
127
|
+
if (this.state() === 'unmountSuspended') {
|
|
128
|
+
// Check if this is an exit animation (based on animation name or state)
|
|
129
|
+
const target = event.target as HTMLElement;
|
|
130
|
+
const animationName = event.animationName;
|
|
131
|
+
|
|
132
|
+
// Exit animations typically contain 'exit' or 'out' in the name
|
|
133
|
+
if (
|
|
134
|
+
animationName.includes('exit') ||
|
|
135
|
+
animationName.includes('out') ||
|
|
136
|
+
animationName.includes('leave')
|
|
137
|
+
) {
|
|
138
|
+
this.clearExitTimeout();
|
|
139
|
+
this.state.set('unmounted');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Clear exit timeout
|
|
146
|
+
*/
|
|
147
|
+
private clearExitTimeout(): void {
|
|
148
|
+
if (this.exitTimeout) {
|
|
149
|
+
clearTimeout(this.exitTimeout);
|
|
150
|
+
this.exitTimeout = null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Force unmount (skip animation)
|
|
156
|
+
*/
|
|
157
|
+
forceUnmount(): void {
|
|
158
|
+
this.clearExitTimeout();
|
|
159
|
+
this.state.set('unmounted');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if currently animating exit
|
|
164
|
+
*/
|
|
165
|
+
isExiting(): boolean {
|
|
166
|
+
return this.state() === 'unmountSuspended';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presence Directive & Service
|
|
3
|
+
* Keeps DOM elements in the tree until animations complete
|
|
4
|
+
* Critical for exit animations in modals, tooltips, popovers, etc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
DestroyRef,
|
|
9
|
+
Directive,
|
|
10
|
+
EmbeddedViewRef,
|
|
11
|
+
Injectable,
|
|
12
|
+
Input,
|
|
13
|
+
OnDestroy,
|
|
14
|
+
OnInit,
|
|
15
|
+
TemplateRef,
|
|
16
|
+
ViewContainerRef,
|
|
17
|
+
WritableSignal,
|
|
18
|
+
inject,
|
|
19
|
+
signal
|
|
20
|
+
} from '@angular/core';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Presence state for tracking animation lifecycle
|
|
24
|
+
*/
|
|
25
|
+
interface PresenceState {
|
|
26
|
+
isPresent: boolean;
|
|
27
|
+
isAnimating: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Manages presence state for animated components
|
|
32
|
+
* Ensures DOM elements stay in tree during exit animations
|
|
33
|
+
*/
|
|
34
|
+
@Injectable({
|
|
35
|
+
providedIn: 'root',
|
|
36
|
+
})
|
|
37
|
+
export class PresenceService {
|
|
38
|
+
private presenceMap = new Map<string, WritableSignal<PresenceState>>();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Register a presence element
|
|
42
|
+
*/
|
|
43
|
+
register(id: string, initialState: boolean = false): WritableSignal<PresenceState> {
|
|
44
|
+
if (!this.presenceMap.has(id)) {
|
|
45
|
+
this.presenceMap.set(
|
|
46
|
+
id,
|
|
47
|
+
signal<PresenceState>({
|
|
48
|
+
isPresent: initialState,
|
|
49
|
+
isAnimating: false,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return this.presenceMap.get(id)!;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Unregister a presence element
|
|
58
|
+
*/
|
|
59
|
+
unregister(id: string): void {
|
|
60
|
+
this.presenceMap.delete(id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Update presence state
|
|
65
|
+
*/
|
|
66
|
+
setState(id: string, state: Partial<PresenceState>): void {
|
|
67
|
+
const current = this.presenceMap.get(id);
|
|
68
|
+
if (current) {
|
|
69
|
+
current.update((prev) => ({ ...prev, ...state }));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get current presence state
|
|
75
|
+
*/
|
|
76
|
+
getState(id: string): PresenceState | undefined {
|
|
77
|
+
return this.presenceMap.get(id)?.();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Presence Directive
|
|
83
|
+
* Usage: <div *presenceIf="isVisible; duration: 300">Content</div>
|
|
84
|
+
*
|
|
85
|
+
* Keeps the element in DOM during exit animations, then removes it
|
|
86
|
+
* Properly handles animation completion before unmounting
|
|
87
|
+
*/
|
|
88
|
+
@Directive({
|
|
89
|
+
selector: '[presenceIf]',
|
|
90
|
+
})
|
|
91
|
+
export class PresenceIfDirective<T> implements OnInit, OnDestroy {
|
|
92
|
+
private readonly viewContainer = inject(ViewContainerRef);
|
|
93
|
+
private readonly presenceService = inject(PresenceService);
|
|
94
|
+
private readonly destroyRef = inject(DestroyRef);
|
|
95
|
+
|
|
96
|
+
@Input() presenceIfTemplate?: TemplateRef<T>;
|
|
97
|
+
@Input() set presenceIf(show: boolean) {
|
|
98
|
+
this.handlePresenceChange(show);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Input() presenceDuration: number = 200;
|
|
102
|
+
|
|
103
|
+
private viewRef: EmbeddedViewRef<T> | null = null;
|
|
104
|
+
private presenceId = `presence-${Math.random().toString(36).substr(2, 9)}`;
|
|
105
|
+
private isVisible = signal(false);
|
|
106
|
+
|
|
107
|
+
ngOnInit(): void {
|
|
108
|
+
this.presenceService.register(this.presenceId, false);
|
|
109
|
+
|
|
110
|
+
// Clean up on destroy
|
|
111
|
+
this.destroyRef.onDestroy(() => {
|
|
112
|
+
this.presenceService.unregister(this.presenceId);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
ngOnDestroy(): void {
|
|
117
|
+
this.presenceService.unregister(this.presenceId);
|
|
118
|
+
if (this.viewRef) {
|
|
119
|
+
this.viewRef.destroy();
|
|
120
|
+
this.viewRef = null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private handlePresenceChange(show: boolean): void {
|
|
125
|
+
if (show) {
|
|
126
|
+
this.showElement();
|
|
127
|
+
} else {
|
|
128
|
+
this.hideElement();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private showElement(): void {
|
|
133
|
+
if (!this.viewRef && this.presenceIfTemplate) {
|
|
134
|
+
this.viewRef = this.viewContainer.createEmbeddedView(this.presenceIfTemplate);
|
|
135
|
+
this.presenceService.setState(this.presenceId, {
|
|
136
|
+
isPresent: true,
|
|
137
|
+
isAnimating: true,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Mark animation as complete after duration
|
|
141
|
+
setTimeout(() => {
|
|
142
|
+
this.presenceService.setState(this.presenceId, {
|
|
143
|
+
isAnimating: false,
|
|
144
|
+
});
|
|
145
|
+
}, this.presenceDuration);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.isVisible.set(true);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private hideElement(): void {
|
|
152
|
+
this.isVisible.set(false);
|
|
153
|
+
this.presenceService.setState(this.presenceId, {
|
|
154
|
+
isAnimating: true,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Remove from DOM after animation completes
|
|
158
|
+
setTimeout(() => {
|
|
159
|
+
if (this.viewRef) {
|
|
160
|
+
this.viewRef.destroy();
|
|
161
|
+
this.viewRef = null;
|
|
162
|
+
}
|
|
163
|
+
this.presenceService.setState(this.presenceId, {
|
|
164
|
+
isPresent: false,
|
|
165
|
+
isAnimating: false,
|
|
166
|
+
});
|
|
167
|
+
}, this.presenceDuration);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { clsx, type ClassValue } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Utility function to merge Tailwind CSS classes with proper conflict resolution.
|
|
6
|
+
* Combines clsx for conditional classes with tailwind-merge for deduplication.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* cn('px-4 py-2', 'px-6') // => 'py-2 px-6'
|
|
10
|
+
* cn('bg-red-500', condition && 'bg-blue-500') // conditional classes
|
|
11
|
+
* cn('text-sm', ['font-bold', 'text-gray-500']) // array support
|
|
12
|
+
*/
|
|
13
|
+
export function cn(...inputs: ClassValue[]): string {
|
|
14
|
+
return twMerge(clsx(inputs));
|
|
15
|
+
}
|