@ng-cn/core 1.0.16 → 1.0.18
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 +6 -5
- package/src/app/lib/components/ui/accordion/accordion-content.component.ts +11 -14
- package/src/app/lib/components/ui/accordion/accordion-context.ts +1 -0
- package/src/app/lib/components/ui/accordion/accordion-item.component.ts +8 -0
- package/src/app/lib/components/ui/accordion/accordion-trigger.component.ts +5 -1
- package/src/app/lib/components/ui/accordion/accordion.component.ts +24 -6
- package/src/app/lib/components/ui/alert/alert-variants.ts +18 -4
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-action.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-cancel.component.ts +1 -1
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-content.component.ts +34 -17
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-description.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-footer.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-header.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-title.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/alert-dialog/alert-dialog.component.ts +4 -0
- package/src/app/lib/components/ui/aspect-ratio/aspect-ratio.component.ts +1 -0
- package/src/app/lib/components/ui/avatar/avatar-context.ts +9 -0
- package/src/app/lib/components/ui/avatar/avatar-fallback.component.ts +6 -9
- package/src/app/lib/components/ui/avatar/avatar-image.component.ts +40 -11
- package/src/app/lib/components/ui/avatar/avatar.component.ts +18 -13
- package/src/app/lib/components/ui/avatar/index.ts +1 -0
- package/src/app/lib/components/ui/avatar/ui-avatar.component.ts +13 -20
- package/src/app/lib/components/ui/badge/badge-variants.ts +1 -1
- package/src/app/lib/components/ui/badge/badge.component.ts +1 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-ellipsis.component.ts +1 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-item.component.ts +3 -7
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-link.component.ts +4 -11
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-list.component.ts +3 -7
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-page.component.ts +1 -0
- package/src/app/lib/components/ui/breadcrumb/breadcrumb-separator.component.ts +20 -24
- package/src/app/lib/components/ui/breadcrumb/breadcrumb.component.ts +1 -0
- package/src/app/lib/components/ui/button/button-variants.ts +3 -3
- package/src/app/lib/components/ui/button/button.component.ts +1 -0
- package/src/app/lib/components/ui/button-group/button-group.component.ts +1 -0
- package/src/app/lib/components/ui/calendar/calendar.component.ts +5 -1
- package/src/app/lib/components/ui/carousel/carousel-content.component.ts +1 -0
- package/src/app/lib/components/ui/carousel/carousel-item.component.ts +1 -0
- package/src/app/lib/components/ui/carousel/carousel-next.component.ts +1 -0
- package/src/app/lib/components/ui/carousel/carousel-previous.component.ts +1 -0
- package/src/app/lib/components/ui/carousel/carousel.component.ts +1 -0
- package/src/app/lib/components/ui/chart/chart-container.component.ts +1 -0
- package/src/app/lib/components/ui/chart/chart-legend-content.component.ts +1 -0
- package/src/app/lib/components/ui/chart/chart-legend.component.ts +5 -5
- package/src/app/lib/components/ui/chart/chart-tooltip-content.component.ts +5 -5
- package/src/app/lib/components/ui/chart/chart-tooltip.component.ts +5 -5
- package/src/app/lib/components/ui/chart/chart.component.ts +1 -0
- package/src/app/lib/components/ui/checkbox/checkbox.component.ts +1 -1
- package/src/app/lib/components/ui/collapsible/collapsible-content.component.ts +3 -1
- package/src/app/lib/components/ui/collapsible/collapsible-context.ts +1 -0
- package/src/app/lib/components/ui/collapsible/collapsible-trigger.component.ts +2 -0
- package/src/app/lib/components/ui/collapsible/collapsible.component.ts +4 -0
- package/src/app/lib/components/ui/combobox/combobox-content.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox-empty.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox-group.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox-input.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox-item.component.ts +1 -4
- package/src/app/lib/components/ui/combobox/combobox-list.component.ts +1 -1
- package/src/app/lib/components/ui/combobox/combobox-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox-value.component.ts +1 -0
- package/src/app/lib/components/ui/combobox/combobox.component.ts +1 -1
- package/src/app/lib/components/ui/command/command-dialog.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-empty.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-group.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-input.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-item.component.ts +2 -1
- package/src/app/lib/components/ui/command/command-list.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-separator.component.ts +1 -0
- package/src/app/lib/components/ui/command/command-shortcut.component.ts +1 -0
- package/src/app/lib/components/ui/command/command.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-checkbox-item.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-content.component.ts +49 -17
- package/src/app/lib/components/ui/context-menu/context-menu-item.component.ts +2 -1
- package/src/app/lib/components/ui/context-menu/context-menu-label.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-radio-group.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-radio-item.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-separator.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-shortcut.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu-sub-content.component.ts +3 -0
- package/src/app/lib/components/ui/context-menu/context-menu-sub-trigger.component.ts +32 -2
- package/src/app/lib/components/ui/context-menu/context-menu-sub.component.ts +4 -0
- package/src/app/lib/components/ui/context-menu/context-menu-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/context-menu/context-menu.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table-content.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table-pagination.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table-search.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table-toolbar.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table-view-options.component.ts +1 -0
- package/src/app/lib/components/ui/data-table/data-table.component.ts +1 -1
- package/src/app/lib/components/ui/date-picker/date-picker.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-close.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-content.component.ts +32 -21
- package/src/app/lib/components/ui/dialog/dialog-description.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-footer.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-header.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-title.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/dialog/dialog.component.ts +1 -0
- package/src/app/lib/components/ui/direction/direction-context.ts +9 -0
- package/src/app/lib/components/ui/direction/direction.component.ts +48 -0
- package/src/app/lib/components/ui/direction/index.ts +2 -0
- package/src/app/lib/components/ui/drawer/drawer-close.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer-content.component.ts +45 -0
- package/src/app/lib/components/ui/drawer/drawer-description.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer-footer.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer-header.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer-title.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/drawer/drawer.component.ts +4 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-content.component.ts +3 -2
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-group.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-item.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-label.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.component.ts +2 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-separator.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.component.ts +1 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.component.ts +3 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.component.ts +30 -3
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-sub.component.ts +4 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu-trigger.component.ts +26 -0
- package/src/app/lib/components/ui/dropdown-menu/dropdown-menu.component.ts +1 -0
- package/src/app/lib/components/ui/empty/empty-action.component.ts +1 -0
- package/src/app/lib/components/ui/empty/empty-description.component.ts +1 -0
- package/src/app/lib/components/ui/empty/empty-icon.component.ts +2 -1
- package/src/app/lib/components/ui/empty/empty-title.component.ts +1 -0
- package/src/app/lib/components/ui/empty/empty.component.ts +1 -0
- package/src/app/lib/components/ui/form/form-description.component.ts +2 -2
- package/src/app/lib/components/ui/hover-card/hover-card-content.component.ts +109 -60
- package/src/app/lib/components/ui/hover-card/hover-card-context.ts +4 -2
- package/src/app/lib/components/ui/hover-card/hover-card-trigger.component.ts +6 -3
- package/src/app/lib/components/ui/hover-card/hover-card.component.ts +9 -3
- package/src/app/lib/components/ui/input-group/input-group-addon.component.ts +1 -0
- package/src/app/lib/components/ui/input-group/input-group-input.component.ts +1 -0
- package/src/app/lib/components/ui/input-group/input-group.component.ts +1 -0
- package/src/app/lib/components/ui/input-otp/input-otp-group.component.ts +1 -0
- package/src/app/lib/components/ui/input-otp/input-otp-separator.component.ts +1 -0
- package/src/app/lib/components/ui/input-otp/input-otp-slot.component.ts +1 -0
- package/src/app/lib/components/ui/input-otp/input-otp.component.ts +1 -0
- package/src/app/lib/components/ui/kbd/kbd.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-checkbox-item.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-content.component.ts +2 -1
- package/src/app/lib/components/ui/menubar/menubar-item.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-label.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-menu.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-radio-group.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-radio-item.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-separator.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-shortcut.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-sub-content.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-sub-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-sub.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/menubar/menubar.component.ts +1 -0
- package/src/app/lib/components/ui/native-select/native-select.component.ts +1 -1
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-content.component.ts +8 -1
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-context.ts +14 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-indicator.component.ts +1 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-item.component.ts +10 -4
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-link.component.ts +1 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-list.component.ts +1 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-trigger.component.ts +70 -2
- package/src/app/lib/components/ui/navigation-menu/navigation-menu-viewport.component.ts +1 -0
- package/src/app/lib/components/ui/navigation-menu/navigation-menu.component.ts +36 -4
- package/src/app/lib/components/ui/pagination/pagination-content.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination-ellipsis.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination-item.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination-link.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination-next.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination-previous.component.ts +1 -0
- package/src/app/lib/components/ui/pagination/pagination.component.ts +4 -1
- package/src/app/lib/components/ui/popover/popover-anchor.component.ts +1 -0
- package/src/app/lib/components/ui/popover/popover-content.component.ts +12 -0
- package/src/app/lib/components/ui/popover/popover-context.ts +2 -0
- package/src/app/lib/components/ui/popover/popover-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/popover/popover.component.ts +5 -0
- package/src/app/lib/components/ui/progress/progress.component.ts +1 -2
- package/src/app/lib/components/ui/resizable/resizable-handle.component.ts +1 -0
- package/src/app/lib/components/ui/resizable/resizable-panel-group.component.ts +1 -0
- package/src/app/lib/components/ui/resizable/resizable-panel.component.ts +1 -0
- package/src/app/lib/components/ui/scroll-area/scroll-area.component.ts +8 -6
- package/src/app/lib/components/ui/scroll-area/scroll-bar.component.ts +1 -0
- package/src/app/lib/components/ui/segmented/segmented-item.component.ts +1 -0
- package/src/app/lib/components/ui/segmented/segmented.component.ts +1 -0
- package/src/app/lib/components/ui/select/select-content.component.ts +38 -17
- package/src/app/lib/components/ui/select/select-context.ts +10 -0
- package/src/app/lib/components/ui/select/select-item.component.ts +25 -7
- package/src/app/lib/components/ui/select/select-trigger.component.ts +6 -13
- package/src/app/lib/components/ui/select/select.component.ts +46 -0
- package/src/app/lib/components/ui/sheet/sheet-close.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet-content.component.ts +23 -5
- package/src/app/lib/components/ui/sheet/sheet-description.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet-footer.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet-header.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet-title.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/sheet/sheet.component.ts +4 -0
- package/src/app/lib/components/ui/sidebar/sidebar-content.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-footer.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-action.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-content.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group-label.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-group.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-header.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-input.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-inset.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-action.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-badge.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-button.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-item.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-skeleton.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-button.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub-item.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu-sub.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-menu.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-provider.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-rail.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-separator.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar-trigger.component.ts +1 -0
- package/src/app/lib/components/ui/sidebar/sidebar.component.ts +1 -0
- package/src/app/lib/components/ui/slider/slider.component.ts +2 -2
- package/src/app/lib/components/ui/sonner/index.ts +2 -0
- package/src/app/lib/components/ui/sonner/sonner.component.ts +70 -0
- package/src/app/lib/components/ui/spinner/spinner.component.ts +1 -0
- package/src/app/lib/components/ui/switch/switch.component.ts +1 -14
- package/src/app/lib/components/ui/table/table-body.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-caption.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-cell.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-footer.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-head.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-header.component.ts +1 -0
- package/src/app/lib/components/ui/table/table-row.component.ts +1 -0
- package/src/app/lib/components/ui/table/table.component.ts +1 -0
- package/src/app/lib/components/ui/tabs/tabs-content.component.ts +3 -6
- package/src/app/lib/components/ui/tabs/tabs-list.component.ts +19 -0
- package/src/app/lib/components/ui/tabs/tabs-trigger.component.ts +1 -1
- package/src/app/lib/components/ui/tabs/tabs.component.ts +1 -0
- package/src/app/lib/components/ui/toast/toast-action.component.ts +1 -0
- package/src/app/lib/components/ui/toast/toast-description.component.ts +1 -0
- package/src/app/lib/components/ui/toast/toast-title.component.ts +1 -0
- package/src/app/lib/components/ui/toast/toast.component.ts +1 -0
- package/src/app/lib/components/ui/toast/toaster.component.ts +1 -0
- package/src/app/lib/components/ui/toggle/toggle-variants.ts +1 -1
- package/src/app/lib/components/ui/toggle/toggle.component.ts +12 -6
- package/src/app/lib/components/ui/tooltip/tooltip-content.component.ts +142 -17
- package/src/app/lib/components/ui/tooltip/tooltip-context.ts +3 -1
- package/src/app/lib/components/ui/tooltip/tooltip-provider.component.ts +5 -1
- package/src/app/lib/components/ui/tooltip/tooltip-trigger.component.ts +6 -2
- package/src/app/lib/components/ui/tooltip/tooltip.component.ts +4 -1
- package/src/app/lib/components/ui/typography/typography-blockquote.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-h1.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-h2.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-h3.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-h4.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-inline-code.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-large.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-lead.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-list.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-muted.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-p.component.ts +1 -0
- package/src/app/lib/components/ui/typography/typography-small.component.ts +1 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { cn, Presence } from '@/lib/utils';
|
|
1
|
+
import { Align, cn, computePosition, getTransformOrigin, Presence, Side } from '@/lib/utils';
|
|
2
2
|
import {
|
|
3
|
+
afterNextRender,
|
|
3
4
|
ChangeDetectionStrategy,
|
|
4
5
|
Component,
|
|
5
6
|
computed,
|
|
7
|
+
effect,
|
|
6
8
|
ElementRef,
|
|
7
9
|
inject,
|
|
10
|
+
Injector,
|
|
8
11
|
input,
|
|
9
12
|
OnDestroy,
|
|
13
|
+
signal,
|
|
10
14
|
} from '@angular/core';
|
|
11
15
|
import { HOVER_CARD_CONTEXT, HoverCardAlign, HoverCardSide } from './hover-card-context';
|
|
12
16
|
|
|
@@ -38,31 +42,6 @@ export interface HoverCardContentProps {
|
|
|
38
42
|
* HoverCardContent displays the preview content. It stays open when
|
|
39
43
|
* hovered, allowing users to interact with the content.
|
|
40
44
|
*
|
|
41
|
-
* ## Features
|
|
42
|
-
* - Stays open when content is hovered
|
|
43
|
-
* - Configurable side and alignment
|
|
44
|
-
* - Smooth animations
|
|
45
|
-
* - Escape key to dismiss
|
|
46
|
-
*
|
|
47
|
-
* ## Accessibility
|
|
48
|
-
* - `role="dialog"` on the content
|
|
49
|
-
* - Focusable content items
|
|
50
|
-
* - Escape returns focus to trigger
|
|
51
|
-
*
|
|
52
|
-
* @example Basic usage
|
|
53
|
-
* ```html
|
|
54
|
-
* <HoverCardContent>
|
|
55
|
-
* <p>Preview content</p>
|
|
56
|
-
* </HoverCardContent>
|
|
57
|
-
* ```
|
|
58
|
-
*
|
|
59
|
-
* @example With positioning
|
|
60
|
-
* ```html
|
|
61
|
-
* <HoverCardContent side="right" align="start">
|
|
62
|
-
* <p>Right-aligned content</p>
|
|
63
|
-
* </HoverCardContent>
|
|
64
|
-
* ```
|
|
65
|
-
*
|
|
66
45
|
* @data-attributes
|
|
67
46
|
* - `data-state` - 'open' | 'closed'
|
|
68
47
|
* - `data-side` - 'top' | 'right' | 'bottom' | 'left'
|
|
@@ -78,9 +57,10 @@ export interface HoverCardContentProps {
|
|
|
78
57
|
[attr.aria-modal]="false"
|
|
79
58
|
tabindex="-1"
|
|
80
59
|
[class]="computedClass()"
|
|
60
|
+
[style]="positionStyles()"
|
|
81
61
|
[attr.data-state]="state()"
|
|
82
|
-
[attr.data-side]="
|
|
83
|
-
[attr.data-align]="
|
|
62
|
+
[attr.data-side]="computedSide()"
|
|
63
|
+
[attr.data-align]="computedAlign()"
|
|
84
64
|
data-slot="hover-card-content"
|
|
85
65
|
(mouseenter)="onMouseEnter()"
|
|
86
66
|
(mouseleave)="onMouseLeave()"
|
|
@@ -93,11 +73,31 @@ export interface HoverCardContentProps {
|
|
|
93
73
|
</Presence>
|
|
94
74
|
`,
|
|
95
75
|
host: {
|
|
76
|
+
'attr.data-slot': '"hover-card-content"',
|
|
96
77
|
class: 'contents',
|
|
97
78
|
},
|
|
98
79
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
99
80
|
})
|
|
100
81
|
export class HoverCardContent implements OnDestroy {
|
|
82
|
+
constructor() {
|
|
83
|
+
effect(() => {
|
|
84
|
+
const isOpen = this.context.open();
|
|
85
|
+
if (isOpen) {
|
|
86
|
+
this.isPositioned.set(false);
|
|
87
|
+
afterNextRender(
|
|
88
|
+
() => {
|
|
89
|
+
this.schedulePositionUpdate();
|
|
90
|
+
},
|
|
91
|
+
{ injector: this._injector },
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
this.cancelScheduledPositionUpdate();
|
|
95
|
+
this.isPositioned.set(false);
|
|
96
|
+
this.positionStyles.set({ position: 'fixed', top: '-9999px', left: '-9999px' });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
101
|
/** The preferred side of the trigger to render against */
|
|
102
102
|
readonly side = input<HoverCardSide>('bottom');
|
|
103
103
|
/** The distance in pixels from the trigger */
|
|
@@ -108,80 +108,129 @@ export class HoverCardContent implements OnDestroy {
|
|
|
108
108
|
readonly class = input<string>('');
|
|
109
109
|
|
|
110
110
|
private readonly _elementRef = inject(ElementRef<HTMLElement>);
|
|
111
|
+
private readonly _injector = inject(Injector);
|
|
111
112
|
|
|
112
113
|
protected readonly context = inject(HOVER_CARD_CONTEXT);
|
|
113
114
|
|
|
114
|
-
protected readonly computedClass = computed(() =>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
bottom: 'top-full mt-2',
|
|
118
|
-
left: 'right-full mr-2',
|
|
119
|
-
right: 'left-full ml-2',
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const alignClasses = {
|
|
123
|
-
start: 'left-0',
|
|
124
|
-
center: 'left-1/2 -translate-x-1/2',
|
|
125
|
-
end: 'right-0',
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
return cn(
|
|
129
|
-
'absolute z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
|
|
115
|
+
protected readonly computedClass = computed(() =>
|
|
116
|
+
cn(
|
|
117
|
+
'fixed z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
|
|
130
118
|
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|
|
131
119
|
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
132
120
|
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
|
|
133
121
|
'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
|
|
134
122
|
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
135
|
-
|
|
136
|
-
this.side() === 'top' || this.side() === 'bottom' ? alignClasses[this.align()] : '',
|
|
123
|
+
!this.isPositioned() && 'pointer-events-none opacity-0',
|
|
137
124
|
this.class(),
|
|
138
|
-
)
|
|
125
|
+
),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
protected readonly positionStyles = signal<Record<string, string>>({
|
|
129
|
+
position: 'fixed',
|
|
130
|
+
top: '-9999px',
|
|
131
|
+
left: '-9999px',
|
|
139
132
|
});
|
|
133
|
+
protected readonly isPositioned = signal(false);
|
|
134
|
+
protected readonly computedSide = signal<Side>('bottom');
|
|
135
|
+
protected readonly computedAlign = signal<Align>('center');
|
|
140
136
|
|
|
141
|
-
private closeTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
142
137
|
/** Current state: open or closed */
|
|
143
138
|
protected readonly state = computed<HoverCardContentState>(() =>
|
|
144
139
|
this.context.open() ? 'open' : 'closed',
|
|
145
140
|
);
|
|
146
141
|
|
|
142
|
+
private closeTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
143
|
+
private positionFrameId: number | null = null;
|
|
144
|
+
|
|
147
145
|
ngOnDestroy(): void {
|
|
148
|
-
this.
|
|
146
|
+
this.clearCloseTimeout();
|
|
147
|
+
this.cancelScheduledPositionUpdate();
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
onMouseEnter(): void {
|
|
152
|
-
this.
|
|
151
|
+
this.clearCloseTimeout();
|
|
153
152
|
}
|
|
154
153
|
onMouseLeave(): void {
|
|
155
154
|
this.closeTimeout = setTimeout(() => {
|
|
156
155
|
this.context.setOpen(false);
|
|
157
|
-
}, this.context.closeDelay);
|
|
156
|
+
}, this.context.closeDelay());
|
|
158
157
|
}
|
|
159
158
|
onFocusIn(): void {
|
|
160
|
-
this.
|
|
159
|
+
this.clearCloseTimeout();
|
|
161
160
|
}
|
|
162
161
|
onFocusOut(event: FocusEvent): void {
|
|
163
162
|
const relatedTarget = event.relatedTarget as HTMLElement | null;
|
|
164
|
-
const trigger = this.
|
|
163
|
+
const trigger = this.context.triggerRef();
|
|
165
164
|
|
|
166
|
-
// Check if focus moved to trigger or stayed within content
|
|
167
165
|
if (relatedTarget && (trigger === relatedTarget || trigger?.contains(relatedTarget))) {
|
|
168
166
|
return;
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
this.closeTimeout = setTimeout(() => {
|
|
172
170
|
this.context.setOpen(false);
|
|
173
|
-
}, this.context.closeDelay);
|
|
171
|
+
}, this.context.closeDelay());
|
|
174
172
|
}
|
|
175
173
|
onEscape(): void {
|
|
176
174
|
this.context.setOpen(false);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
this.context.triggerRef()?.focus();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private schedulePositionUpdate(): void {
|
|
179
|
+
this.cancelScheduledPositionUpdate();
|
|
180
|
+
this.positionFrameId = requestAnimationFrame(() => {
|
|
181
|
+
this.updatePosition();
|
|
182
|
+
this.positionFrameId = requestAnimationFrame(() => {
|
|
183
|
+
this.updatePosition();
|
|
184
|
+
this.positionFrameId = null;
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
private cancelScheduledPositionUpdate(): void {
|
|
189
|
+
if (this.positionFrameId !== null) {
|
|
190
|
+
cancelAnimationFrame(this.positionFrameId);
|
|
191
|
+
this.positionFrameId = null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
private updatePosition(): void {
|
|
195
|
+
const triggerElement = this.context.triggerRef();
|
|
196
|
+
const contentElement = this._elementRef.nativeElement.querySelector(
|
|
197
|
+
'[role="dialog"]',
|
|
180
198
|
) as HTMLElement;
|
|
181
|
-
|
|
199
|
+
|
|
200
|
+
if (!triggerElement || !contentElement) return;
|
|
201
|
+
|
|
202
|
+
const triggerRect = triggerElement.getBoundingClientRect();
|
|
203
|
+
const contentRect = contentElement.getBoundingClientRect();
|
|
204
|
+
const overlayWidth = Math.round(contentRect.width || 256);
|
|
205
|
+
const overlayHeight = Math.round(contentRect.height || 100);
|
|
206
|
+
|
|
207
|
+
const result = computePosition(
|
|
208
|
+
triggerRect,
|
|
209
|
+
{ width: overlayWidth, height: overlayHeight },
|
|
210
|
+
{
|
|
211
|
+
side: this.side(),
|
|
212
|
+
align: this.align(),
|
|
213
|
+
sideOffset: this.sideOffset(),
|
|
214
|
+
alignOffset: 0,
|
|
215
|
+
avoidCollisions: true,
|
|
216
|
+
collisionPadding: 8,
|
|
217
|
+
},
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
this.computedSide.set(result.side);
|
|
221
|
+
this.computedAlign.set(result.align);
|
|
222
|
+
|
|
223
|
+
const transformOrigin = getTransformOrigin(result.side, result.align);
|
|
224
|
+
this.positionStyles.set({
|
|
225
|
+
position: 'fixed',
|
|
226
|
+
top: result.styles.top || '',
|
|
227
|
+
left: result.styles.left || '',
|
|
228
|
+
'--radix-hover-card-content-transform-origin': transformOrigin,
|
|
229
|
+
});
|
|
230
|
+
this.isPositioned.set(true);
|
|
182
231
|
}
|
|
183
232
|
|
|
184
|
-
private
|
|
233
|
+
private clearCloseTimeout(): void {
|
|
185
234
|
if (this.closeTimeout) {
|
|
186
235
|
clearTimeout(this.closeTimeout);
|
|
187
236
|
this.closeTimeout = null;
|
|
@@ -9,9 +9,11 @@ export interface HoverCardContextValue {
|
|
|
9
9
|
/** Set open state */
|
|
10
10
|
setOpen: (open: boolean) => void;
|
|
11
11
|
/** The duration from when the pointer enters the trigger until the hover card opens (ms) */
|
|
12
|
-
openDelay: number;
|
|
12
|
+
openDelay: () => number;
|
|
13
13
|
/** The duration from when the pointer leaves the trigger/content until the hover card closes (ms) */
|
|
14
|
-
closeDelay: number;
|
|
14
|
+
closeDelay: () => number;
|
|
15
|
+
/** Reference to the trigger element for fixed positioning */
|
|
16
|
+
triggerRef: WritableSignal<HTMLElement | null>;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export const HOVER_CARD_CONTEXT = new InjectionToken<HoverCardContextValue>('HOVER_CARD_CONTEXT');
|
|
@@ -64,6 +64,7 @@ export interface HoverCardTriggerProps {
|
|
|
64
64
|
selector: 'HoverCardTrigger',
|
|
65
65
|
template: `<ng-content />`,
|
|
66
66
|
host: {
|
|
67
|
+
'attr.data-slot': '"hover-card-trigger"',
|
|
67
68
|
tabindex: '0',
|
|
68
69
|
role: 'button',
|
|
69
70
|
'(mouseenter)': 'onMouseEnter()',
|
|
@@ -95,18 +96,20 @@ export class HoverCardTrigger implements OnDestroy {
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
onMouseEnter(): void {
|
|
99
|
+
this.context.triggerRef.set(this._elementRef.nativeElement);
|
|
98
100
|
this.clearTimeouts();
|
|
99
101
|
this.openTimeout = setTimeout(() => {
|
|
100
102
|
this.context.setOpen(true);
|
|
101
|
-
}, this.context.openDelay);
|
|
103
|
+
}, this.context.openDelay());
|
|
102
104
|
}
|
|
103
105
|
onMouseLeave(): void {
|
|
104
106
|
this.clearTimeouts();
|
|
105
107
|
this.closeTimeout = setTimeout(() => {
|
|
106
108
|
this.context.setOpen(false);
|
|
107
|
-
}, this.context.closeDelay);
|
|
109
|
+
}, this.context.closeDelay());
|
|
108
110
|
}
|
|
109
111
|
onFocus(): void {
|
|
112
|
+
this.context.triggerRef.set(this._elementRef.nativeElement);
|
|
110
113
|
this.clearTimeouts();
|
|
111
114
|
// Open immediately on focus for keyboard users
|
|
112
115
|
this.context.setOpen(true);
|
|
@@ -126,7 +129,7 @@ export class HoverCardTrigger implements OnDestroy {
|
|
|
126
129
|
this.clearTimeouts();
|
|
127
130
|
this.closeTimeout = setTimeout(() => {
|
|
128
131
|
this.context.setOpen(false);
|
|
129
|
-
}, this.context.closeDelay);
|
|
132
|
+
}, this.context.closeDelay());
|
|
130
133
|
}
|
|
131
134
|
onKeyDown(event: Event): void {
|
|
132
135
|
event.preventDefault();
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
input,
|
|
6
6
|
output,
|
|
7
7
|
signal,
|
|
8
|
+
Signal,
|
|
9
|
+
WritableSignal,
|
|
8
10
|
} from '@angular/core';
|
|
9
11
|
import { HOVER_CARD_CONTEXT, type HoverCardContextValue } from './hover-card-context';
|
|
10
12
|
|
|
@@ -92,7 +94,8 @@ export interface HoverCardProps {
|
|
|
92
94
|
selector: 'HoverCard',
|
|
93
95
|
template: `<ng-content />`,
|
|
94
96
|
host: {
|
|
95
|
-
|
|
97
|
+
'attr.data-slot': '"hover-card"',
|
|
98
|
+
class: 'inline-block',
|
|
96
99
|
},
|
|
97
100
|
providers: [
|
|
98
101
|
{
|
|
@@ -119,10 +122,13 @@ export class HoverCard implements HoverCardContextValue {
|
|
|
119
122
|
|
|
120
123
|
readonly open = signal(false);
|
|
121
124
|
|
|
125
|
+
/** Reference to the trigger element for fixed positioning */
|
|
126
|
+
readonly triggerRef: WritableSignal<HTMLElement | null> = signal<HTMLElement | null>(null);
|
|
127
|
+
|
|
122
128
|
/** The duration from when the pointer enters the trigger until the hover card opens (ms) */
|
|
123
|
-
readonly openDelay = 700;
|
|
129
|
+
readonly openDelay = input<number>(700);
|
|
124
130
|
/** The duration from when the pointer leaves the trigger/content until the hover card closes (ms) */
|
|
125
|
-
readonly closeDelay = 300;
|
|
131
|
+
readonly closeDelay = input<number>(300);
|
|
126
132
|
|
|
127
133
|
setOpen(open: boolean): void {
|
|
128
134
|
if (this.controlledOpen() === undefined) {
|
|
@@ -14,6 +14,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
14
14
|
selector: 'InputGroupAddon',
|
|
15
15
|
template: `<ng-content />`,
|
|
16
16
|
host: {
|
|
17
|
+
'attr.data-slot': '"input-group-addon"',
|
|
17
18
|
'[class]': 'computedClass()',
|
|
18
19
|
},
|
|
19
20
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -10,6 +10,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
10
10
|
selector: 'InputGroupInput',
|
|
11
11
|
template: ``,
|
|
12
12
|
host: {
|
|
13
|
+
'attr.data-slot': '"input-group-input"',
|
|
13
14
|
'[class]': 'computedClass()',
|
|
14
15
|
},
|
|
15
16
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -30,6 +30,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
30
30
|
selector: 'InputGroup',
|
|
31
31
|
template: `<ng-content />`,
|
|
32
32
|
host: {
|
|
33
|
+
'attr.data-slot': '"input-group"',
|
|
33
34
|
'[class]': 'computedClass()',
|
|
34
35
|
},
|
|
35
36
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -9,6 +9,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
9
9
|
selector: 'InputOTPGroup',
|
|
10
10
|
template: `<ng-content />`,
|
|
11
11
|
host: {
|
|
12
|
+
'attr.data-slot': '"input-otp-group"',
|
|
12
13
|
'[class]': 'computedClass()',
|
|
13
14
|
},
|
|
14
15
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -27,6 +27,7 @@ import { MENUBAR_CONTEXT, MENUBAR_MENU_CONTEXT } from './menubar-context';
|
|
|
27
27
|
<ng-content />
|
|
28
28
|
`,
|
|
29
29
|
host: {
|
|
30
|
+
'attr.data-slot': '"menubar-checkbox-item"',
|
|
30
31
|
'[class]': 'computedClass()',
|
|
31
32
|
'[attr.role]': '"menuitemcheckbox"',
|
|
32
33
|
'[attr.aria-checked]': 'checked()',
|
|
@@ -35,6 +35,7 @@ import { MENUBAR_CONTEXT, MENUBAR_MENU_CONTEXT } from './menubar-context';
|
|
|
35
35
|
</Presence>
|
|
36
36
|
`,
|
|
37
37
|
host: {
|
|
38
|
+
'attr.data-slot': '"menubar-content"',
|
|
38
39
|
class: 'contents',
|
|
39
40
|
'(document:click)': 'onDocumentClick($event)',
|
|
40
41
|
'(document:keydown.escape)': 'onEscapeKey()',
|
|
@@ -113,7 +114,7 @@ export class MenubarContent implements OnDestroy {
|
|
|
113
114
|
if (content) {
|
|
114
115
|
this.menuItems = Array.from(
|
|
115
116
|
content.querySelectorAll(
|
|
116
|
-
'[role="menuitem"]:not([
|
|
117
|
+
'[role="menuitem"]:not([data-disabled=""]), [role="menuitemcheckbox"]:not([data-disabled=""]), [role="menuitemradio"]:not([data-disabled=""])',
|
|
117
118
|
),
|
|
118
119
|
);
|
|
119
120
|
}
|
|
@@ -11,6 +11,7 @@ import { MENUBAR_CONTEXT, MENUBAR_MENU_CONTEXT } from './menubar-context';
|
|
|
11
11
|
selector: 'MenubarItem',
|
|
12
12
|
template: `<ng-content />`,
|
|
13
13
|
host: {
|
|
14
|
+
'attr.data-slot': '"menubar-item"',
|
|
14
15
|
'[class]': 'computedClass()',
|
|
15
16
|
'[attr.role]': '"menuitem"',
|
|
16
17
|
'[attr.tabindex]': 'disabled() ? -1 : -1',
|
|
@@ -9,6 +9,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
9
9
|
selector: 'MenubarLabel',
|
|
10
10
|
template: `<ng-content />`,
|
|
11
11
|
host: {
|
|
12
|
+
'attr.data-slot': '"menubar-label"',
|
|
12
13
|
'[class]': 'computedClass()',
|
|
13
14
|
},
|
|
14
15
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -19,6 +19,7 @@ import { MENUBAR_RADIO_GROUP_CONTEXT } from './menubar-radio-group.component';
|
|
|
19
19
|
<ng-content />
|
|
20
20
|
`,
|
|
21
21
|
host: {
|
|
22
|
+
'attr.data-slot': '"menubar-radio-item"',
|
|
22
23
|
'[class]': 'computedClass()',
|
|
23
24
|
'[attr.role]': '"menuitemradio"',
|
|
24
25
|
'[attr.aria-checked]': 'isSelected()',
|
|
@@ -9,6 +9,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
9
9
|
selector: 'MenubarShortcut',
|
|
10
10
|
template: `<ng-content />`,
|
|
11
11
|
host: {
|
|
12
|
+
'attr.data-slot': '"menubar-shortcut"',
|
|
12
13
|
'[class]': 'computedClass()',
|
|
13
14
|
},
|
|
14
15
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -15,6 +15,7 @@ import { MENUBAR_SUB_CONTEXT } from './menubar-sub.component';
|
|
|
15
15
|
<lucide-icon [img]="ChevronRightIcon" class="ml-auto h-4 w-4" />
|
|
16
16
|
`,
|
|
17
17
|
host: {
|
|
18
|
+
'attr.data-slot': '"menubar-sub-trigger"',
|
|
18
19
|
'[class]': 'computedClass()',
|
|
19
20
|
'[attr.data-state]': 'subContext.open() ? "open" : "closed"',
|
|
20
21
|
'(mouseenter)': 'onMouseEnter()',
|
|
@@ -19,6 +19,7 @@ import { MENUBAR_CONTEXT, MENUBAR_MENU_CONTEXT } from './menubar-context';
|
|
|
19
19
|
selector: 'MenubarTrigger',
|
|
20
20
|
template: `<ng-content />`,
|
|
21
21
|
host: {
|
|
22
|
+
'attr.data-slot': '"menubar-trigger"',
|
|
22
23
|
'[class]': 'computedClass()',
|
|
23
24
|
'[attr.role]': '"menuitem"',
|
|
24
25
|
'[attr.tabindex]': 'isFocused() ? 0 : -1',
|
|
@@ -42,7 +42,7 @@ import { nativeSelectVariants, type NativeSelectVariants } from './native-select
|
|
|
42
42
|
template: `<ng-content />`,
|
|
43
43
|
host: {
|
|
44
44
|
'[class]': 'computedClass()',
|
|
45
|
-
'data-slot': 'native-select',
|
|
45
|
+
'attr.data-slot': '"native-select"',
|
|
46
46
|
},
|
|
47
47
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
48
48
|
})
|
|
@@ -18,12 +18,19 @@ import { NAVIGATION_MENU_CONTEXT, NAVIGATION_MENU_ITEM_CONTEXT } from './navigat
|
|
|
18
18
|
imports: [Presence],
|
|
19
19
|
template: `
|
|
20
20
|
<Presence [present]="itemContext.open()">
|
|
21
|
-
<div
|
|
21
|
+
<div
|
|
22
|
+
[class]="computedClass()"
|
|
23
|
+
[attr.id]="itemContext.contentId"
|
|
24
|
+
[attr.data-state]="itemContext.open() ? 'open' : 'closed'"
|
|
25
|
+
[attr.aria-labelledby]="itemContext.triggerId"
|
|
26
|
+
role="region"
|
|
27
|
+
>
|
|
22
28
|
<ng-content />
|
|
23
29
|
</div>
|
|
24
30
|
</Presence>
|
|
25
31
|
`,
|
|
26
32
|
host: {
|
|
33
|
+
'attr.data-slot': '"navigation-menu-content"',
|
|
27
34
|
class: 'contents',
|
|
28
35
|
'(document:click)': 'onDocumentClick($event)',
|
|
29
36
|
'(document:keydown.escape)': 'onEscapeKey()',
|
|
@@ -22,6 +22,16 @@ export interface NavigationMenuContextValue {
|
|
|
22
22
|
activeItem: WritableSignal<string | null>;
|
|
23
23
|
/** Layout orientation of the menu */
|
|
24
24
|
orientation: WritableSignal<NavigationMenuOrientation>;
|
|
25
|
+
/** Ordered list of registered trigger element IDs */
|
|
26
|
+
triggerIds: WritableSignal<string[]>;
|
|
27
|
+
/** Register a trigger ID (called by NavigationMenuTrigger on init) */
|
|
28
|
+
registerTrigger: (triggerId: string) => void;
|
|
29
|
+
/** Unregister a trigger ID (called by NavigationMenuTrigger on destroy) */
|
|
30
|
+
unregisterTrigger: (triggerId: string) => void;
|
|
31
|
+
/** Move DOM focus to the next trigger in document order */
|
|
32
|
+
focusNextTrigger: (currentTriggerId: string) => void;
|
|
33
|
+
/** Move DOM focus to the previous trigger in document order */
|
|
34
|
+
focusPreviousTrigger: (currentTriggerId: string) => void;
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
export const NAVIGATION_MENU_CONTEXT = new InjectionToken<NavigationMenuContextValue>(
|
|
@@ -38,6 +48,10 @@ export const NAVIGATION_MENU_CONTEXT = new InjectionToken<NavigationMenuContextV
|
|
|
38
48
|
export interface NavigationMenuItemContextValue {
|
|
39
49
|
/** Unique identifier for this item */
|
|
40
50
|
itemId: string;
|
|
51
|
+
/** DOM id for the trigger element (used for aria-controls / aria-labelledby) */
|
|
52
|
+
triggerId: string;
|
|
53
|
+
/** DOM id for the content element (used for aria-controls) */
|
|
54
|
+
contentId: string;
|
|
41
55
|
/** Whether this item's content is open */
|
|
42
56
|
open: WritableSignal<boolean>;
|
|
43
57
|
}
|
|
@@ -11,6 +11,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/co
|
|
|
11
11
|
<div class="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md"></div>
|
|
12
12
|
`,
|
|
13
13
|
host: {
|
|
14
|
+
'attr.data-slot': '"navigation-menu-indicator"',
|
|
14
15
|
'[class]': 'computedClass()',
|
|
15
16
|
},
|
|
16
17
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -17,13 +17,19 @@ let itemIdCounter = 0;
|
|
|
17
17
|
providers: [
|
|
18
18
|
{
|
|
19
19
|
provide: NAVIGATION_MENU_ITEM_CONTEXT,
|
|
20
|
-
useFactory: (): NavigationMenuItemContextValue =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
useFactory: (): NavigationMenuItemContextValue => {
|
|
21
|
+
const id = itemIdCounter++;
|
|
22
|
+
return {
|
|
23
|
+
itemId: `nav-item-${id}`,
|
|
24
|
+
triggerId: `nav-trigger-${id}`,
|
|
25
|
+
contentId: `nav-content-${id}`,
|
|
26
|
+
open: signal(false),
|
|
27
|
+
};
|
|
28
|
+
},
|
|
24
29
|
},
|
|
25
30
|
],
|
|
26
31
|
host: {
|
|
32
|
+
'attr.data-slot': '"navigation-menu-item"',
|
|
27
33
|
class: 'relative',
|
|
28
34
|
},
|
|
29
35
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -12,6 +12,7 @@ import { navigationMenuTriggerStyle } from './navigation-menu-trigger-style';
|
|
|
12
12
|
selector: 'NavigationMenuLink',
|
|
13
13
|
template: `<ng-content />`,
|
|
14
14
|
host: {
|
|
15
|
+
'attr.data-slot': '"navigation-menu-link"',
|
|
15
16
|
'[class]': 'computedClass()',
|
|
16
17
|
'[attr.aria-current]': 'ariaCurrent()',
|
|
17
18
|
'[attr.data-active]': 'active() || null',
|