@ng-cn/core 1.0.11 → 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 +2 -1
- package/schematics/ng-add/index.js +2 -2
- package/schematics/ng-add/index.ts +2 -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,31 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
computed,
|
|
6
|
+
input,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typography List component (unordered list)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <TypographyList>
|
|
14
|
+
* <li>Item 1</li>
|
|
15
|
+
* <li>Item 2</li>
|
|
16
|
+
* </TypographyList>
|
|
17
|
+
*/
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'TypographyList',
|
|
20
|
+
template: `<ng-content />`,
|
|
21
|
+
host: {
|
|
22
|
+
'[class]': 'computedClass()',
|
|
23
|
+
},
|
|
24
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
|
+
})
|
|
26
|
+
export class TypographyList {
|
|
27
|
+
readonly class = input<string>('');
|
|
28
|
+
protected readonly computedClass = computed(() =>
|
|
29
|
+
cn('my-6 ml-6 list-disc [&>li]:mt-2', this.class())
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
computed,
|
|
6
|
+
input,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typography Muted component
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <TypographyMuted>Muted helper text</TypographyMuted>
|
|
14
|
+
*/
|
|
15
|
+
@Component({
|
|
16
|
+
selector: 'TypographyMuted',
|
|
17
|
+
template: `<ng-content />`,
|
|
18
|
+
host: {
|
|
19
|
+
'[class]': 'computedClass()',
|
|
20
|
+
},
|
|
21
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
22
|
+
})
|
|
23
|
+
export class TypographyMuted {
|
|
24
|
+
readonly class = input<string>('');
|
|
25
|
+
protected readonly computedClass = computed(() =>
|
|
26
|
+
cn('text-sm text-muted-foreground', this.class())
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
computed,
|
|
6
|
+
input,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typography P (paragraph) component
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <TypographyP>This is a paragraph of text.</TypographyP>
|
|
14
|
+
*/
|
|
15
|
+
@Component({
|
|
16
|
+
selector: 'TypographyP',
|
|
17
|
+
template: `<ng-content />`,
|
|
18
|
+
host: {
|
|
19
|
+
'[class]': 'computedClass()',
|
|
20
|
+
style: 'display: block',
|
|
21
|
+
},
|
|
22
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
23
|
+
})
|
|
24
|
+
export class TypographyP {
|
|
25
|
+
readonly class = input<string>('');
|
|
26
|
+
protected readonly computedClass = computed(() =>
|
|
27
|
+
cn('leading-7 [&:not(:first-child)]:mt-6', this.class())
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
computed,
|
|
6
|
+
input,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typography Small component
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <TypographySmall>Small text</TypographySmall>
|
|
14
|
+
*/
|
|
15
|
+
@Component({
|
|
16
|
+
selector: 'TypographySmall',
|
|
17
|
+
template: `<ng-content />`,
|
|
18
|
+
host: {
|
|
19
|
+
'[class]': 'computedClass()',
|
|
20
|
+
},
|
|
21
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
22
|
+
})
|
|
23
|
+
export class TypographySmall {
|
|
24
|
+
readonly class = input<string>('');
|
|
25
|
+
protected readonly computedClass = computed(() =>
|
|
26
|
+
cn('text-sm font-medium leading-none', this.class())
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Injectable, signal } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Service to generate and manage unique ARIA IDs for accessibility relationships.
|
|
5
|
+
* Handles aria-labelledby, aria-describedby, aria-controls, etc.
|
|
6
|
+
*/
|
|
7
|
+
@Injectable({ providedIn: 'root' })
|
|
8
|
+
export class AriaIdService {
|
|
9
|
+
private readonly counter = signal(0);
|
|
10
|
+
private readonly prefix = 'aria';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generates a unique ID with an optional prefix.
|
|
14
|
+
* @param customPrefix - Optional prefix for the ID (e.g., 'dialog', 'menu')
|
|
15
|
+
* @returns A unique string ID
|
|
16
|
+
*/
|
|
17
|
+
generateId(customPrefix?: string): string {
|
|
18
|
+
const count = this.counter();
|
|
19
|
+
this.counter.set(count + 1);
|
|
20
|
+
const basePrefix = customPrefix ? `${this.prefix}-${customPrefix}` : this.prefix;
|
|
21
|
+
return `${basePrefix}-${count}-${Math.random().toString(36).substring(2, 9)}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generates a set of related IDs for a component with title and description.
|
|
26
|
+
* Useful for dialogs, alerts, and other components needing ARIA relationships.
|
|
27
|
+
* @param prefix - Component type prefix (e.g., 'dialog', 'alert')
|
|
28
|
+
* @returns Object containing contentId, titleId, and descriptionId
|
|
29
|
+
*/
|
|
30
|
+
generateDialogIds(prefix: string = 'dialog'): AriaDialogIds {
|
|
31
|
+
const base = this.generateId(prefix);
|
|
32
|
+
return {
|
|
33
|
+
contentId: `${base}-content`,
|
|
34
|
+
titleId: `${base}-title`,
|
|
35
|
+
descriptionId: `${base}-description`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generates IDs for menu/listbox patterns.
|
|
41
|
+
* @param prefix - Component type prefix (e.g., 'menu', 'listbox', 'combobox')
|
|
42
|
+
* @returns Object containing triggerId, contentId, and a function to generate item IDs
|
|
43
|
+
*/
|
|
44
|
+
generateMenuIds(prefix: string = 'menu'): AriaMenuIds {
|
|
45
|
+
const base = this.generateId(prefix);
|
|
46
|
+
let itemCounter = 0;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
triggerId: `${base}-trigger`,
|
|
50
|
+
contentId: `${base}-content`,
|
|
51
|
+
labelId: `${base}-label`,
|
|
52
|
+
generateItemId: () => `${base}-item-${itemCounter++}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generates IDs for tab patterns.
|
|
58
|
+
* @param prefix - Component type prefix
|
|
59
|
+
* @returns Object with functions to generate tab and panel IDs
|
|
60
|
+
*/
|
|
61
|
+
generateTabIds(prefix: string = 'tabs'): AriaTabIds {
|
|
62
|
+
const base = this.generateId(prefix);
|
|
63
|
+
let tabCounter = 0;
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
tablistId: `${base}-tablist`,
|
|
67
|
+
generateTabId: () => {
|
|
68
|
+
const id = `${base}-tab-${tabCounter}`;
|
|
69
|
+
tabCounter++;
|
|
70
|
+
return id;
|
|
71
|
+
},
|
|
72
|
+
generatePanelId: (index: number) => `${base}-panel-${index}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generates IDs for accordion patterns.
|
|
78
|
+
* @param prefix - Component type prefix
|
|
79
|
+
* @returns Object with functions to generate trigger and content IDs
|
|
80
|
+
*/
|
|
81
|
+
generateAccordionIds(prefix: string = 'accordion'): AriaAccordionIds {
|
|
82
|
+
const base = this.generateId(prefix);
|
|
83
|
+
let itemCounter = 0;
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
generateTriggerId: () => {
|
|
87
|
+
const id = `${base}-trigger-${itemCounter}`;
|
|
88
|
+
itemCounter++;
|
|
89
|
+
return id;
|
|
90
|
+
},
|
|
91
|
+
generateContentId: (index: number) => `${base}-content-${index}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface AriaDialogIds {
|
|
97
|
+
contentId: string;
|
|
98
|
+
titleId: string;
|
|
99
|
+
descriptionId: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface AriaMenuIds {
|
|
103
|
+
triggerId: string;
|
|
104
|
+
contentId: string;
|
|
105
|
+
labelId: string;
|
|
106
|
+
generateItemId: () => string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface AriaTabIds {
|
|
110
|
+
tablistId: string;
|
|
111
|
+
generateTabId: () => string;
|
|
112
|
+
generatePanelId: (index: number) => string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface AriaAccordionIds {
|
|
116
|
+
generateTriggerId: () => string;
|
|
117
|
+
generateContentId: (index: number) => string;
|
|
118
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Directive,
|
|
3
|
+
ElementRef,
|
|
4
|
+
OnDestroy,
|
|
5
|
+
afterNextRender,
|
|
6
|
+
inject,
|
|
7
|
+
output,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Directive that detects clicks outside the host element.
|
|
12
|
+
* Uses CDK-grade event handling with proper cleanup.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <div (clickOutside)="onClickOutside()">
|
|
16
|
+
* Content here
|
|
17
|
+
* </div>
|
|
18
|
+
*/
|
|
19
|
+
@Directive({
|
|
20
|
+
selector: '[clickOutside]',
|
|
21
|
+
})
|
|
22
|
+
export class ClickOutsideDirective implements OnDestroy {
|
|
23
|
+
private readonly elementRef = inject(ElementRef);
|
|
24
|
+
|
|
25
|
+
/** Emits when a click occurs outside the host element */
|
|
26
|
+
readonly clickOutside = output<MouseEvent>();
|
|
27
|
+
|
|
28
|
+
private documentClickListener: ((event: MouseEvent) => void) | null = null;
|
|
29
|
+
private documentTouchListener: ((event: TouchEvent) => void) | null = null;
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
// Use afterNextRender for SSR compatibility
|
|
33
|
+
afterNextRender(() => {
|
|
34
|
+
this.setupListeners();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private setupListeners(): void {
|
|
39
|
+
// Use setTimeout to avoid capturing the opening click
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
this.documentClickListener = (event: MouseEvent) => {
|
|
42
|
+
this.handleEvent(event);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
this.documentTouchListener = (event: TouchEvent) => {
|
|
46
|
+
// Convert touch to a simulated mouse event for the handler
|
|
47
|
+
const touch = event.touches[0] || event.changedTouches[0];
|
|
48
|
+
if (touch) {
|
|
49
|
+
const mouseEvent = new MouseEvent('click', {
|
|
50
|
+
bubbles: true,
|
|
51
|
+
cancelable: true,
|
|
52
|
+
clientX: touch.clientX,
|
|
53
|
+
clientY: touch.clientY,
|
|
54
|
+
});
|
|
55
|
+
this.handleEvent(mouseEvent);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
document.addEventListener('click', this.documentClickListener, true);
|
|
60
|
+
document.addEventListener('touchstart', this.documentTouchListener, true);
|
|
61
|
+
}, 0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private handleEvent(event: MouseEvent): void {
|
|
65
|
+
const targetElement = event.target as HTMLElement;
|
|
66
|
+
|
|
67
|
+
// Check if click is outside the element
|
|
68
|
+
if (
|
|
69
|
+
targetElement &&
|
|
70
|
+
!this.elementRef.nativeElement.contains(targetElement) &&
|
|
71
|
+
this.elementRef.nativeElement !== targetElement
|
|
72
|
+
) {
|
|
73
|
+
this.clickOutside.emit(event);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ngOnDestroy(): void {
|
|
78
|
+
if (this.documentClickListener) {
|
|
79
|
+
document.removeEventListener('click', this.documentClickListener, true);
|
|
80
|
+
}
|
|
81
|
+
if (this.documentTouchListener) {
|
|
82
|
+
document.removeEventListener('touchstart', this.documentTouchListener, true);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { DOCUMENT } from '@angular/common';
|
|
2
|
+
import { Injectable, inject, signal } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Service to manage focus state across the application.
|
|
6
|
+
* Handles saving/restoring focus, tracking focus history, and managing focus on open/close.
|
|
7
|
+
*/
|
|
8
|
+
@Injectable({ providedIn: 'root' })
|
|
9
|
+
export class FocusManagementService {
|
|
10
|
+
private readonly document = inject(DOCUMENT);
|
|
11
|
+
private readonly focusStack = signal<HTMLElement[]>([]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Saves the currently focused element to the stack.
|
|
15
|
+
* Call this before opening a modal/overlay to restore focus later.
|
|
16
|
+
* @returns The element that was saved, or null if no element was focused
|
|
17
|
+
*/
|
|
18
|
+
saveFocus(): HTMLElement | null {
|
|
19
|
+
const activeElement = this.document.activeElement as HTMLElement | null;
|
|
20
|
+
if (activeElement && activeElement !== this.document.body) {
|
|
21
|
+
this.focusStack.update((stack) => [...stack, activeElement]);
|
|
22
|
+
return activeElement;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Restores focus to the last saved element and removes it from the stack.
|
|
29
|
+
* Call this when closing a modal/overlay.
|
|
30
|
+
* @returns The element that was focused, or null if stack was empty
|
|
31
|
+
*/
|
|
32
|
+
restoreFocus(): HTMLElement | null {
|
|
33
|
+
const stack = this.focusStack();
|
|
34
|
+
if (stack.length === 0) return null;
|
|
35
|
+
|
|
36
|
+
const lastElement = stack[stack.length - 1];
|
|
37
|
+
this.focusStack.update((s) => s.slice(0, -1));
|
|
38
|
+
|
|
39
|
+
if (lastElement && this.isElementFocusable(lastElement)) {
|
|
40
|
+
// Use setTimeout to ensure focus happens after any animations
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
lastElement.focus();
|
|
43
|
+
}, 0);
|
|
44
|
+
return lastElement;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Focuses the first focusable element within a container.
|
|
51
|
+
* @param container - The container element to search within
|
|
52
|
+
* @param options - Focus options
|
|
53
|
+
* @returns The element that was focused, or null if none found
|
|
54
|
+
*/
|
|
55
|
+
focusFirstFocusable(
|
|
56
|
+
container: HTMLElement,
|
|
57
|
+
options: FocusOptions = {}
|
|
58
|
+
): HTMLElement | null {
|
|
59
|
+
const focusable = this.getFocusableElements(container);
|
|
60
|
+
if (focusable.length > 0) {
|
|
61
|
+
const target = focusable[0];
|
|
62
|
+
this.focusElement(target, options);
|
|
63
|
+
return target;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Focuses the last focusable element within a container.
|
|
70
|
+
* @param container - The container element to search within
|
|
71
|
+
* @param options - Focus options
|
|
72
|
+
* @returns The element that was focused, or null if none found
|
|
73
|
+
*/
|
|
74
|
+
focusLastFocusable(
|
|
75
|
+
container: HTMLElement,
|
|
76
|
+
options: FocusOptions = {}
|
|
77
|
+
): HTMLElement | null {
|
|
78
|
+
const focusable = this.getFocusableElements(container);
|
|
79
|
+
if (focusable.length > 0) {
|
|
80
|
+
const target = focusable[focusable.length - 1];
|
|
81
|
+
this.focusElement(target, options);
|
|
82
|
+
return target;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Focuses a specific element with optional delay.
|
|
89
|
+
* @param element - The element to focus
|
|
90
|
+
* @param options - Focus options including preventScroll and delay
|
|
91
|
+
*/
|
|
92
|
+
focusElement(element: HTMLElement, options: FocusOptions = {}): void {
|
|
93
|
+
const { preventScroll = false, delay = 0 } = options;
|
|
94
|
+
|
|
95
|
+
const doFocus = () => {
|
|
96
|
+
if (this.isElementFocusable(element)) {
|
|
97
|
+
element.focus({ preventScroll });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
if (delay > 0) {
|
|
102
|
+
setTimeout(doFocus, delay);
|
|
103
|
+
} else {
|
|
104
|
+
doFocus();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets all focusable elements within a container.
|
|
110
|
+
* @param container - The container element to search within
|
|
111
|
+
* @returns Array of focusable HTML elements
|
|
112
|
+
*/
|
|
113
|
+
getFocusableElements(container: HTMLElement): HTMLElement[] {
|
|
114
|
+
const selector = [
|
|
115
|
+
'a[href]',
|
|
116
|
+
'button:not([disabled])',
|
|
117
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
118
|
+
'select:not([disabled])',
|
|
119
|
+
'textarea:not([disabled])',
|
|
120
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
121
|
+
'[contenteditable="true"]',
|
|
122
|
+
'audio[controls]',
|
|
123
|
+
'video[controls]',
|
|
124
|
+
'details > summary:first-of-type',
|
|
125
|
+
].join(', ');
|
|
126
|
+
|
|
127
|
+
const elements = Array.from(
|
|
128
|
+
container.querySelectorAll<HTMLElement>(selector)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
return elements.filter((el) => this.isElementVisible(el));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Gets all tabbable elements (excludes tabindex="-1").
|
|
136
|
+
* @param container - The container element to search within
|
|
137
|
+
* @returns Array of tabbable HTML elements
|
|
138
|
+
*/
|
|
139
|
+
getTabbableElements(container: HTMLElement): HTMLElement[] {
|
|
140
|
+
return this.getFocusableElements(container).filter((el) => {
|
|
141
|
+
const tabindex = el.getAttribute('tabindex');
|
|
142
|
+
return tabindex !== '-1';
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Checks if an element is currently focusable.
|
|
148
|
+
* @param element - The element to check
|
|
149
|
+
* @returns true if the element can receive focus
|
|
150
|
+
*/
|
|
151
|
+
isElementFocusable(element: HTMLElement): boolean {
|
|
152
|
+
if (!element || !this.document.body.contains(element)) return false;
|
|
153
|
+
if (!this.isElementVisible(element)) return false;
|
|
154
|
+
|
|
155
|
+
const tabindex = element.getAttribute('tabindex');
|
|
156
|
+
if (tabindex !== null && parseInt(tabindex, 10) < 0) return false;
|
|
157
|
+
|
|
158
|
+
// Check for disabled state
|
|
159
|
+
if (
|
|
160
|
+
element instanceof HTMLButtonElement ||
|
|
161
|
+
element instanceof HTMLInputElement ||
|
|
162
|
+
element instanceof HTMLSelectElement ||
|
|
163
|
+
element instanceof HTMLTextAreaElement
|
|
164
|
+
) {
|
|
165
|
+
return !element.disabled;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check if element is naturally focusable
|
|
169
|
+
const focusableSelectors = [
|
|
170
|
+
'a[href]',
|
|
171
|
+
'button',
|
|
172
|
+
'input',
|
|
173
|
+
'select',
|
|
174
|
+
'textarea',
|
|
175
|
+
'[tabindex]',
|
|
176
|
+
'[contenteditable="true"]',
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
return focusableSelectors.some((selector) => element.matches(selector));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Checks if an element is visible (not hidden by CSS).
|
|
184
|
+
* @param element - The element to check
|
|
185
|
+
* @returns true if the element is visible
|
|
186
|
+
*/
|
|
187
|
+
private isElementVisible(element: HTMLElement): boolean {
|
|
188
|
+
if (!element) return false;
|
|
189
|
+
|
|
190
|
+
const style = getComputedStyle(element);
|
|
191
|
+
if (style.display === 'none' || style.visibility === 'hidden') return false;
|
|
192
|
+
if (element.hasAttribute('hidden')) return false;
|
|
193
|
+
|
|
194
|
+
// Check if any ancestor is hidden
|
|
195
|
+
let parent = element.parentElement;
|
|
196
|
+
while (parent) {
|
|
197
|
+
const parentStyle = getComputedStyle(parent);
|
|
198
|
+
if (
|
|
199
|
+
parentStyle.display === 'none' ||
|
|
200
|
+
parentStyle.visibility === 'hidden'
|
|
201
|
+
) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (parent.hasAttribute('hidden')) return false;
|
|
205
|
+
parent = parent.parentElement;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Clears the focus history stack.
|
|
213
|
+
*/
|
|
214
|
+
clearFocusHistory(): void {
|
|
215
|
+
this.focusStack.set([]);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Gets the current focus stack length.
|
|
220
|
+
*/
|
|
221
|
+
getFocusStackDepth(): number {
|
|
222
|
+
return this.focusStack().length;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface FocusOptions {
|
|
227
|
+
/** Prevents scrolling to the focused element */
|
|
228
|
+
preventScroll?: boolean;
|
|
229
|
+
/** Delay in ms before focusing */
|
|
230
|
+
delay?: number;
|
|
231
|
+
}
|