@rimelight/ui 0.0.4 → 0.0.6
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 +36 -6
- package/src/components/BlogPost.astro +181 -0
- package/src/components/DynamicShowcase.astro +681 -0
- package/src/components/ExtendedCarousel.astro +107 -0
- package/src/components/Head.astro +150 -0
- package/src/components/LanguageSwitcher.astro +128 -0
- package/src/components/ProjectPost.astro +183 -0
- package/src/components/RLHead.astro +3 -0
- package/src/components/ThemeToggle.astro +30 -42
- package/src/components/astro/RLAButton.astro +85 -0
- package/src/components/astro/RLAHeader.astro +75 -0
- package/src/components/vue/RLVButton.vue +90 -0
- package/src/components/vue/RLVHeader.vue +78 -0
- package/src/composables/index.ts +1 -0
- package/src/composables/useUi.ts +27 -0
- package/src/config/index.ts +0 -2
- package/src/config/site.config.ts +1 -1
- package/src/env.d.ts +9 -42
- package/src/integrations/index.ts +2 -0
- package/src/integrations/ui.ts +87 -0
- package/src/themes/button.theme.ts +361 -0
- package/src/themes/header.theme.ts +33 -0
- package/src/themes/index.ts +13 -0
- package/src/utils/index.ts +3 -2
- package/i18n-data.json +0 -186
- package/src/components/accordion/Accordion.astro +0 -257
- package/src/components/accordion/AccordionContent.astro +0 -34
- package/src/components/accordion/AccordionItem.astro +0 -29
- package/src/components/accordion/AccordionTrigger.astro +0 -33
- package/src/components/alert/Alert.astro +0 -34
- package/src/components/alert/AlertDescription.astro +0 -15
- package/src/components/alert/AlertTitle.astro +0 -17
- package/src/components/alert-dialog/AlertDialog.astro +0 -275
- package/src/components/alert-dialog/AlertDialogAction.astro +0 -46
- package/src/components/alert-dialog/AlertDialogCancel.astro +0 -46
- package/src/components/alert-dialog/AlertDialogContent.astro +0 -52
- package/src/components/alert-dialog/AlertDialogDescription.astro +0 -18
- package/src/components/alert-dialog/AlertDialogFooter.astro +0 -16
- package/src/components/alert-dialog/AlertDialogHeader.astro +0 -14
- package/src/components/alert-dialog/AlertDialogTitle.astro +0 -20
- package/src/components/alert-dialog/AlertDialogTrigger.astro +0 -47
- package/src/components/aspect-ratio/AspectRatio.astro +0 -32
- package/src/components/avatar/Avatar.astro +0 -29
- package/src/components/avatar/AvatarFallback.astro +0 -18
- package/src/components/avatar/AvatarImage.astro +0 -66
- package/src/components/badge/Badge.astro +0 -57
- package/src/components/breadcrumb/Breadcrumb.astro +0 -12
- package/src/components/breadcrumb/BreadcrumbEllipsis.astro +0 -29
- package/src/components/breadcrumb/BreadcrumbItem.astro +0 -15
- package/src/components/breadcrumb/BreadcrumbLink.astro +0 -24
- package/src/components/breadcrumb/BreadcrumbList.astro +0 -17
- package/src/components/breadcrumb/BreadcrumbPage.astro +0 -22
- package/src/components/breadcrumb/BreadcrumbSeparator.astro +0 -24
- package/src/components/button/Button.astro +0 -58
- package/src/components/button-group/ButtonGroup.astro +0 -64
- package/src/components/button-group/ButtonGroupSeparator.astro +0 -20
- package/src/components/button-group/ButtonGroupText.astro +0 -19
- package/src/components/card/Card.astro +0 -36
- package/src/components/card/CardAction.astro +0 -16
- package/src/components/card/CardContent.astro +0 -16
- package/src/components/card/CardDescription.astro +0 -16
- package/src/components/card/CardFooter.astro +0 -16
- package/src/components/card/CardHeader.astro +0 -19
- package/src/components/card/CardTitle.astro +0 -16
- package/src/components/carousel/Carousel.astro +0 -55
- package/src/components/carousel/CarouselContent.astro +0 -26
- package/src/components/carousel/CarouselItem.astro +0 -26
- package/src/components/carousel/CarouselNext.astro +0 -39
- package/src/components/carousel/CarouselPrevious.astro +0 -41
- package/src/components/carousel/carousel-script.ts +0 -188
- package/src/components/carousel/index.ts +0 -1
- package/src/components/checkbox/Checkbox.astro +0 -133
- package/src/components/collapsible/Collapsible.astro +0 -161
- package/src/components/collapsible/CollapsibleContent.astro +0 -22
- package/src/components/collapsible/CollapsibleTrigger.astro +0 -44
- package/src/components/dialog/Dialog.astro +0 -389
- package/src/components/dialog/DialogClose.astro +0 -35
- package/src/components/dialog/DialogContent.astro +0 -78
- package/src/components/dialog/DialogDescription.astro +0 -14
- package/src/components/dialog/DialogFooter.astro +0 -14
- package/src/components/dialog/DialogHeader.astro +0 -14
- package/src/components/dialog/DialogTitle.astro +0 -18
- package/src/components/dialog/DialogTrigger.astro +0 -47
- package/src/components/dropdown/Dropdown.astro +0 -604
- package/src/components/dropdown/DropdownContent.astro +0 -118
- package/src/components/dropdown/DropdownItem.astro +0 -48
- package/src/components/dropdown/DropdownLabel.astro +0 -29
- package/src/components/dropdown/DropdownSeparator.astro +0 -21
- package/src/components/dropdown/DropdownShortcut.astro +0 -17
- package/src/components/dropdown/DropdownSub.astro +0 -15
- package/src/components/dropdown/DropdownSubContent.astro +0 -39
- package/src/components/dropdown/DropdownSubTrigger.astro +0 -34
- package/src/components/dropdown/DropdownTrigger.astro +0 -52
- package/src/components/dropzone/Dropzone.astro +0 -236
- package/src/components/dropzone/DropzoneFilesList.astro +0 -26
- package/src/components/dropzone/DropzoneLoadingIndicator.astro +0 -10
- package/src/components/dropzone/DropzoneUploadIndicator.astro +0 -10
- package/src/components/embeds/YoutubeEmbed.astro +0 -94
- package/src/components/hero/Hero.astro +0 -166
- package/src/components/icons/Flag.astro +0 -62
- package/src/components/image/ExtendedImage.astro +0 -46
- package/src/components/image/Image.astro +0 -25
- package/src/components/input/Input.astro +0 -27
- package/src/components/input-group/InputGroup.astro +0 -28
- package/src/components/input-group/InputGroupAddon.astro +0 -76
- package/src/components/input-group/InputGroupButton.astro +0 -36
- package/src/components/input-group/InputGroupInput.astro +0 -18
- package/src/components/input-group/InputGroupText.astro +0 -17
- package/src/components/input-group/InputGroupTextarea.astro +0 -22
- package/src/components/input-otp/InputOtp.astro +0 -352
- package/src/components/input-otp/InputOtpGroup.astro +0 -16
- package/src/components/input-otp/InputOtpSeparator.astro +0 -25
- package/src/components/input-otp/InputOtpSlot.astro +0 -50
- package/src/components/input-otp/InputOtpTypes.ts +0 -6
- package/src/components/item/Item.astro +0 -52
- package/src/components/item/ItemActions.astro +0 -16
- package/src/components/item/ItemContent.astro +0 -16
- package/src/components/item/ItemDescription.astro +0 -19
- package/src/components/item/ItemFooter.astro +0 -16
- package/src/components/item/ItemGroup.astro +0 -16
- package/src/components/item/ItemHeader.astro +0 -16
- package/src/components/item/ItemMedia.astro +0 -40
- package/src/components/item/ItemSeparator.astro +0 -23
- package/src/components/item/ItemTitle.astro +0 -16
- package/src/components/kbd/Kbd.astro +0 -21
- package/src/components/kbd/KbdGroup.astro +0 -16
- package/src/components/label/Label.astro +0 -24
- package/src/components/marquee/Marquee.astro +0 -73
- package/src/components/native-select/NativeSelect.astro +0 -68
- package/src/components/native-select/NativeSelectOptGroup.astro +0 -15
- package/src/components/native-select/NativeSelectOption.astro +0 -15
- package/src/components/pagination/Pagination.astro +0 -20
- package/src/components/pagination/PaginationContent.astro +0 -16
- package/src/components/pagination/PaginationEllipsis.astro +0 -37
- package/src/components/pagination/PaginationItem.astro +0 -16
- package/src/components/pagination/PaginationLink.astro +0 -27
- package/src/components/pagination/PaginationNext.astro +0 -33
- package/src/components/pagination/PaginationPrevious.astro +0 -33
- package/src/components/popover/Popover.astro +0 -717
- package/src/components/popover/PopoverContent.astro +0 -102
- package/src/components/popover/PopoverDescription.astro +0 -14
- package/src/components/popover/PopoverHeader.astro +0 -14
- package/src/components/popover/PopoverTitle.astro +0 -14
- package/src/components/popover/PopoverTrigger.astro +0 -51
- package/src/components/progress/Progress.astro +0 -154
- package/src/components/prose/Prose.astro +0 -619
- package/src/components/radio-group/RadioGroup.astro +0 -162
- package/src/components/radio-group/RadioGroupItem.astro +0 -133
- package/src/components/radio-group/RadioGroupTypes.ts +0 -6
- package/src/components/section/Section.astro +0 -167
- package/src/components/select/Select.astro +0 -752
- package/src/components/select/SelectContent.astro +0 -94
- package/src/components/select/SelectGroup.astro +0 -9
- package/src/components/select/SelectItem.astro +0 -51
- package/src/components/select/SelectLabel.astro +0 -14
- package/src/components/select/SelectSearch.astro +0 -49
- package/src/components/select/SelectSeparator.astro +0 -12
- package/src/components/select/SelectTrigger.astro +0 -56
- package/src/components/select/SelectTypes.ts +0 -13
- package/src/components/select/SelectValue.astro +0 -19
- package/src/components/separator/Separator.astro +0 -36
- package/src/components/sheet/Sheet.astro +0 -15
- package/src/components/sheet/SheetClose.astro +0 -15
- package/src/components/sheet/SheetContent.astro +0 -89
- package/src/components/sheet/SheetDescription.astro +0 -16
- package/src/components/sheet/SheetFooter.astro +0 -16
- package/src/components/sheet/SheetHeader.astro +0 -16
- package/src/components/sheet/SheetTitle.astro +0 -16
- package/src/components/sheet/SheetTrigger.astro +0 -15
- package/src/components/sidebar/Sidebar.astro +0 -231
- package/src/components/sidebar/SidebarContent.astro +0 -25
- package/src/components/sidebar/SidebarFooter.astro +0 -22
- package/src/components/sidebar/SidebarGroup.astro +0 -22
- package/src/components/sidebar/SidebarGroupContent.astro +0 -22
- package/src/components/sidebar/SidebarGroupLabel.astro +0 -53
- package/src/components/sidebar/SidebarHeader.astro +0 -22
- package/src/components/sidebar/SidebarInput.astro +0 -24
- package/src/components/sidebar/SidebarInset.astro +0 -22
- package/src/components/sidebar/SidebarMenu.astro +0 -22
- package/src/components/sidebar/SidebarMenuAction.astro +0 -63
- package/src/components/sidebar/SidebarMenuBadge.astro +0 -31
- package/src/components/sidebar/SidebarMenuButton.astro +0 -124
- package/src/components/sidebar/SidebarMenuItem.astro +0 -22
- package/src/components/sidebar/SidebarMenuSkeleton.astro +0 -43
- package/src/components/sidebar/SidebarMenuSub.astro +0 -25
- package/src/components/sidebar/SidebarMenuSubButton.astro +0 -52
- package/src/components/sidebar/SidebarMenuSubItem.astro +0 -17
- package/src/components/sidebar/SidebarProvider.astro +0 -215
- package/src/components/sidebar/SidebarRail.astro +0 -72
- package/src/components/sidebar/SidebarSeparator.astro +0 -25
- package/src/components/sidebar/SidebarTrigger.astro +0 -69
- package/src/components/skeleton/Skeleton.astro +0 -14
- package/src/components/slider/Slider.astro +0 -425
- package/src/components/spinner/Spinner.astro +0 -23
- package/src/components/switch/Switch.astro +0 -192
- package/src/components/switch/SwitchTypes.ts +0 -6
- package/src/components/table/Table.astro +0 -20
- package/src/components/table/TableBody.astro +0 -18
- package/src/components/table/TableCaption.astro +0 -18
- package/src/components/table/TableCell.astro +0 -18
- package/src/components/table/TableFoot.astro +0 -18
- package/src/components/table/TableHead.astro +0 -18
- package/src/components/table/TableHeader.astro +0 -18
- package/src/components/table/TableRow.astro +0 -17
- package/src/components/tabs/Tabs.astro +0 -270
- package/src/components/tabs/TabsContent.astro +0 -28
- package/src/components/tabs/TabsList.astro +0 -23
- package/src/components/tabs/TabsTrigger.astro +0 -34
- package/src/components/textarea/Textarea.astro +0 -31
- package/src/components/toast/ToastDescription.astro +0 -22
- package/src/components/toast/ToastItem.astro +0 -56
- package/src/components/toast/ToastTemplate.astro +0 -27
- package/src/components/toast/ToastTitle.astro +0 -59
- package/src/components/toast/Toaster.astro +0 -981
- package/src/components/toast/index.ts +0 -1
- package/src/components/toast/toast-manager.ts +0 -234
- package/src/components/toggle/Toggle.astro +0 -174
- package/src/components/toggle/ToggleTypes.ts +0 -14
- package/src/components/tooltip/Tooltip.astro +0 -422
- package/src/components/tooltip/TooltipContent.astro +0 -83
- package/src/components/tooltip/TooltipTrigger.astro +0 -13
- package/src/components/video/Video.astro +0 -121
- package/src/config/cookies.ts +0 -5
- package/src/config/links.ts +0 -4
- package/src/domain/cms/index.ts +0 -1
- package/src/domain/cms/types.ts +0 -20
- package/src/domain/i18n/constants.ts +0 -21
- package/src/domain/i18n/cookie-storage.ts +0 -13
- package/src/domain/i18n/country-to-locale-map.ts +0 -67
- package/src/domain/i18n/fallbacks.generated.ts +0 -230
- package/src/domain/i18n/fetcher.ts +0 -278
- package/src/domain/i18n/flags.ts +0 -16
- package/src/domain/i18n/format.ts +0 -90
- package/src/domain/i18n/index.ts +0 -10
- package/src/domain/i18n/middleware/i18n.ts +0 -161
- package/src/domain/i18n/resolve-locale.ts +0 -55
- package/src/domain/i18n/runtime-constants.ts +0 -14
- package/src/domain/i18n/schema.ts +0 -29
- package/src/domain/index.ts +0 -4
- package/src/domain/seo/constants.ts +0 -6
- package/src/domain/seo/index.ts +0 -3
- package/src/domain/seo/services/index.ts +0 -3
- package/src/domain/seo/services/llms.ts +0 -56
- package/src/domain/seo/services/robots.ts +0 -12
- package/src/domain/seo/services/sitemap.ts +0 -56
- package/src/domain/seo/utils.ts +0 -36
- package/src/domain/theme/constants.ts +0 -6
- package/src/domain/theme/index.ts +0 -2
- package/src/domain/theme/schema.ts +0 -10
- package/src/i18n.generated.d.ts +0 -202
- package/src/lib/component-preview.ts +0 -73
- package/src/lib/index.ts +0 -6
- package/src/lib/remark/remark-modified-time.ts +0 -13
- package/src/lib/showcase-preview-elements.ts +0 -408
- package/src/lib/showcase-renderer.ts +0 -218
- package/src/lib/showcase-utils.ts +0 -189
- package/src/lib/turnstile.ts +0 -35
- package/src/lib/utils/starwind/positioning.ts +0 -318
- package/src/locales/de/blog.json +0 -9
- package/src/locales/de/common.json +0 -19
- package/src/locales/de/errors.json +0 -6
- package/src/locales/de/home.json +0 -20
- package/src/locales/de/messages.json +0 -8
- package/src/locales/de/nav.json +0 -13
- package/src/locales/de/projects.json +0 -9
- package/src/locales/de/services.json +0 -43
- package/src/locales/en/blog.json +0 -9
- package/src/locales/en/chat.json +0 -29
- package/src/locales/en/common.json +0 -19
- package/src/locales/en/cookie_notice.json +0 -11
- package/src/locales/en/editor.json +0 -24
- package/src/locales/en/errors.json +0 -6
- package/src/locales/en/home.json +0 -20
- package/src/locales/en/messages.json +0 -8
- package/src/locales/en/nav.json +0 -13
- package/src/locales/en/projects.json +0 -9
- package/src/locales/en/services.json +0 -43
- package/src/locales/es/blog.json +0 -9
- package/src/locales/es/common.json +0 -19
- package/src/locales/es/errors.json +0 -6
- package/src/locales/es/home.json +0 -20
- package/src/locales/es/messages.json +0 -8
- package/src/locales/es/nav.json +0 -13
- package/src/locales/es/projects.json +0 -9
- package/src/locales/es/services.json +0 -43
- package/src/locales/ja/blog.json +0 -9
- package/src/locales/ja/common.json +0 -19
- package/src/locales/ja/errors.json +0 -6
- package/src/locales/ja/home.json +0 -20
- package/src/locales/ja/messages.json +0 -8
- package/src/locales/ja/nav.json +0 -13
- package/src/locales/ja/projects.json +0 -9
- package/src/locales/ja/services.json +0 -43
- package/src/locales/pt/blog.json +0 -9
- package/src/locales/pt/chat.json +0 -29
- package/src/locales/pt/common.json +0 -19
- package/src/locales/pt/cookie_notice.json +0 -11
- package/src/locales/pt/editor.json +0 -24
- package/src/locales/pt/errors.json +0 -6
- package/src/locales/pt/home.json +0 -20
- package/src/locales/pt/messages.json +0 -8
- package/src/locales/pt/nav.json +0 -13
- package/src/locales/pt/projects.json +0 -9
- package/src/locales/pt/services.json +0 -43
- package/src/utils/server/cookies.ts +0 -98
- package/src/utils/server/index.ts +0 -1
- package/src/utils/shared/index.ts +0 -3
- /package/src/utils/{shared/deep-merge.ts → deep-merge.ts} +0 -0
- /package/src/utils/{shared/embed.ts → embed.ts} +0 -0
- /package/src/utils/{shared/parse-boolean.ts → parse-boolean.ts} +0 -0
|
@@ -1,604 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { HTMLAttributes } from "astro/types";
|
|
3
|
-
|
|
4
|
-
type Props = HTMLAttributes<"div"> & {
|
|
5
|
-
/**
|
|
6
|
-
* When true, the dropdown will open on hover in addition to click
|
|
7
|
-
*/
|
|
8
|
-
openOnHover?: boolean;
|
|
9
|
-
/**
|
|
10
|
-
* Time in milliseconds to wait before closing when hover open is enabled
|
|
11
|
-
* @default 200
|
|
12
|
-
*/
|
|
13
|
-
closeDelay?: number;
|
|
14
|
-
|
|
15
|
-
children: any;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Astro.props;
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
<div
|
|
22
|
-
class:list={["starwind-dropdown", "relative", className]}
|
|
23
|
-
data-open-on-hover={openOnHover ? "true" : undefined}
|
|
24
|
-
data-close-delay={closeDelay}
|
|
25
|
-
{...rest}
|
|
26
|
-
data-slot="dropdown"
|
|
27
|
-
>
|
|
28
|
-
<slot />
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<script>
|
|
32
|
-
class DropdownHandler {
|
|
33
|
-
private dropdown: HTMLElement;
|
|
34
|
-
private trigger: HTMLElement | null;
|
|
35
|
-
private content: HTMLElement | null;
|
|
36
|
-
private items: HTMLElement[] = [];
|
|
37
|
-
private currentFocusIndex: number = -1;
|
|
38
|
-
private isOpen: boolean = false;
|
|
39
|
-
private isClosing: boolean = false;
|
|
40
|
-
private animationDuration = 150;
|
|
41
|
-
private openOnHover: boolean;
|
|
42
|
-
private closeDelay: number;
|
|
43
|
-
private closeTimerRef: number | null = null;
|
|
44
|
-
private lastOpenSource: "keyboard" | "mouse" = "keyboard";
|
|
45
|
-
private lastCloseSource: "keyboard" | "mouse" = "keyboard";
|
|
46
|
-
private isSubmenu: boolean;
|
|
47
|
-
private rootDropdown: HTMLElement;
|
|
48
|
-
private contentPlaceholder: Comment | null = null;
|
|
49
|
-
private cleanupAutoUpdate: (() => void) | null = null;
|
|
50
|
-
private openChildCount: number = 0;
|
|
51
|
-
private parentHandler: DropdownHandler | null = null;
|
|
52
|
-
|
|
53
|
-
constructor(dropdown: HTMLElement, dropdownIdx: number) {
|
|
54
|
-
this.dropdown = dropdown;
|
|
55
|
-
this.isSubmenu = dropdown.classList.contains("starwind-dropdown-sub");
|
|
56
|
-
this.openOnHover = dropdown.getAttribute("data-open-on-hover") === "true" || this.isSubmenu;
|
|
57
|
-
this.closeDelay = parseInt(dropdown.getAttribute("data-close-delay") || "200");
|
|
58
|
-
|
|
59
|
-
// Find the trigger and content that belong to this dropdown, avoiding nested ones
|
|
60
|
-
this.trigger = this.findOwnElement('[data-slot="dropdown-trigger"], [data-sub-trigger]');
|
|
61
|
-
|
|
62
|
-
// if trigger is set with asChild, use the first child element for trigger button
|
|
63
|
-
if (this.trigger?.hasAttribute("data-as-child")) {
|
|
64
|
-
this.trigger = this.trigger.firstElementChild as HTMLElement;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.content = this.findOwnElement('[data-slot="dropdown-content"]');
|
|
68
|
-
|
|
69
|
-
// Resolve root dropdown before any portaling (DOM is in original state)
|
|
70
|
-
this.rootDropdown =
|
|
71
|
-
(this.dropdown.closest(".starwind-dropdown") as HTMLElement) || this.dropdown;
|
|
72
|
-
|
|
73
|
-
// Store handler reference and root dropdown on content element for lookups
|
|
74
|
-
if (this.content) {
|
|
75
|
-
(this.content as any).__dropdownHandler = this;
|
|
76
|
-
(this.content as any).__rootDropdown = this.rootDropdown;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!this.trigger || !this.content) return;
|
|
80
|
-
|
|
81
|
-
// Get animation duration from inline styles if available
|
|
82
|
-
const animationDurationString = this.content.style.animationDuration;
|
|
83
|
-
if (animationDurationString.endsWith("ms")) {
|
|
84
|
-
this.animationDuration = parseFloat(animationDurationString);
|
|
85
|
-
} else if (animationDurationString.endsWith("s")) {
|
|
86
|
-
this.animationDuration = parseFloat(animationDurationString) * 1000;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.init(dropdownIdx);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private findOwnElement(selector: string): HTMLElement | null {
|
|
93
|
-
const elements = this.dropdown.querySelectorAll(selector);
|
|
94
|
-
for (const el of elements) {
|
|
95
|
-
if (el.closest(".starwind-dropdown, .starwind-dropdown-sub") === this.dropdown) {
|
|
96
|
-
return el as HTMLElement;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private init(dropdownIdx: number) {
|
|
103
|
-
this.setupAccessibility(dropdownIdx);
|
|
104
|
-
this.setupEvents();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private setupAccessibility(dropdownIdx: number) {
|
|
108
|
-
if (!this.trigger || !this.content) return;
|
|
109
|
-
|
|
110
|
-
// Generate unique IDs for accessibility
|
|
111
|
-
this.trigger.id = `starwind-dropdown${dropdownIdx}-trigger`;
|
|
112
|
-
this.content.id = `starwind-dropdown${dropdownIdx}-content`;
|
|
113
|
-
|
|
114
|
-
// Set up additional ARIA attributes
|
|
115
|
-
this.trigger.setAttribute("aria-controls", this.content.id);
|
|
116
|
-
this.content.setAttribute("aria-labelledby", this.trigger.id);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private setupEvents() {
|
|
120
|
-
if (!this.trigger || !this.content) return;
|
|
121
|
-
|
|
122
|
-
// Handle trigger click
|
|
123
|
-
this.trigger.addEventListener("click", (e) => {
|
|
124
|
-
e.preventDefault();
|
|
125
|
-
this.lastOpenSource = e.detail === 0 ? "keyboard" : "mouse";
|
|
126
|
-
this.toggleDropdown();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Handle keyboard navigation on trigger
|
|
130
|
-
this.trigger.addEventListener("keydown", (e) => {
|
|
131
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
132
|
-
e.preventDefault();
|
|
133
|
-
e.stopPropagation();
|
|
134
|
-
this.lastOpenSource = "keyboard";
|
|
135
|
-
if (this.isSubmenu) {
|
|
136
|
-
this.openDropdown();
|
|
137
|
-
} else {
|
|
138
|
-
this.toggleDropdown();
|
|
139
|
-
}
|
|
140
|
-
} else if (e.key === "Escape" && this.isOpen) {
|
|
141
|
-
e.preventDefault();
|
|
142
|
-
e.stopPropagation();
|
|
143
|
-
this.lastCloseSource = "keyboard";
|
|
144
|
-
// Close all menus in the group, focus root trigger
|
|
145
|
-
this.rootDropdown.dispatchEvent(
|
|
146
|
-
new CustomEvent("starwind-dropdown:close-all", { detail: { focusRoot: true } }),
|
|
147
|
-
);
|
|
148
|
-
} else if (this.isOpen && (e.key === "ArrowDown" || e.key === "ArrowUp")) {
|
|
149
|
-
e.preventDefault();
|
|
150
|
-
e.stopPropagation();
|
|
151
|
-
this.lastOpenSource = "keyboard";
|
|
152
|
-
this.updateDropdownItems();
|
|
153
|
-
if (e.key === "ArrowDown") {
|
|
154
|
-
this.focusItem(0); // Focus first item when opening with arrow down
|
|
155
|
-
} else {
|
|
156
|
-
this.focusItem(this.items.length - 1); // Focus last item when opening with arrow up
|
|
157
|
-
}
|
|
158
|
-
} else if (e.key === "ArrowRight" && this.isSubmenu) {
|
|
159
|
-
e.preventDefault();
|
|
160
|
-
e.stopPropagation();
|
|
161
|
-
if (!this.isOpen) {
|
|
162
|
-
this.lastOpenSource = "keyboard";
|
|
163
|
-
this.openDropdown();
|
|
164
|
-
} else {
|
|
165
|
-
this.updateDropdownItems();
|
|
166
|
-
this.focusItem(0);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Listen for close-all event (routed through rootDropdown to work across portaled content)
|
|
172
|
-
this.rootDropdown.addEventListener("starwind-dropdown:close-all", ((e: CustomEvent) => {
|
|
173
|
-
this.closeDropdown({ skipFocus: !!(e.detail?.focusRoot && this.isSubmenu) });
|
|
174
|
-
}) as EventListener);
|
|
175
|
-
|
|
176
|
-
// Listen for cancel-close event (routed through rootDropdown)
|
|
177
|
-
this.rootDropdown.addEventListener("starwind-dropdown:cancel-close", () => {
|
|
178
|
-
this.clearCloseTimer();
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// Close dropdown when clicking outside for mouse
|
|
182
|
-
document.addEventListener("pointerdown", (e) => {
|
|
183
|
-
if (
|
|
184
|
-
this.isOpen &&
|
|
185
|
-
!this.dropdown.contains(e.target as Node) &&
|
|
186
|
-
!this.content?.contains(e.target as Node) &&
|
|
187
|
-
!this.isTargetInGroup(e.target as Node)
|
|
188
|
-
) {
|
|
189
|
-
if (e.button === 0 && e.ctrlKey === false && e.pointerType === "mouse") {
|
|
190
|
-
this.closeDropdown();
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Handle click outside select content to close for mobile
|
|
196
|
-
document.addEventListener("click", (e) => {
|
|
197
|
-
if (
|
|
198
|
-
this.isOpen &&
|
|
199
|
-
!this.trigger?.contains(e.target as Node) &&
|
|
200
|
-
!this.content?.contains(e.target as Node) &&
|
|
201
|
-
!this.isTargetInGroup(e.target as Node)
|
|
202
|
-
) {
|
|
203
|
-
this.closeDropdown();
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Handle keyboard navigation and item selection within dropdown
|
|
208
|
-
this.content.addEventListener("keydown", (e) => {
|
|
209
|
-
if (e.key === "Escape") {
|
|
210
|
-
e.preventDefault();
|
|
211
|
-
e.stopPropagation();
|
|
212
|
-
// Close all menus in the group, focus root trigger
|
|
213
|
-
this.rootDropdown.dispatchEvent(
|
|
214
|
-
new CustomEvent("starwind-dropdown:close-all", { detail: { focusRoot: true } }),
|
|
215
|
-
);
|
|
216
|
-
} else if (this.isOpen) {
|
|
217
|
-
this.handleMenuKeydown(e);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Handle item selection
|
|
222
|
-
this.content.addEventListener("click", (e) => {
|
|
223
|
-
const target = e.target as HTMLElement;
|
|
224
|
-
const item = target.closest('[role="menuitem"]');
|
|
225
|
-
if (item && !(item as HTMLElement).hasAttribute("data-disabled")) {
|
|
226
|
-
if (item.hasAttribute("aria-haspopup")) return;
|
|
227
|
-
|
|
228
|
-
// Close the dropdown after item selection
|
|
229
|
-
this.closeDropdown();
|
|
230
|
-
|
|
231
|
-
// Dispatch close-all through root to close all menus in the group
|
|
232
|
-
this.rootDropdown.dispatchEvent(new CustomEvent("starwind-dropdown:close-all"));
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Handle hover on dropdown items
|
|
237
|
-
this.content.addEventListener("mouseover", (e) => {
|
|
238
|
-
const target = e.target as HTMLElement;
|
|
239
|
-
const menuItem = target.closest('[role="menuitem"]');
|
|
240
|
-
if (menuItem && menuItem instanceof HTMLElement && this.isOpen === true) {
|
|
241
|
-
// Update items list before focusing to ensure the index is correct
|
|
242
|
-
this.updateDropdownItems();
|
|
243
|
-
|
|
244
|
-
// Focus the item when hovering
|
|
245
|
-
menuItem.focus();
|
|
246
|
-
|
|
247
|
-
// Update the current focus index
|
|
248
|
-
this.currentFocusIndex = this.items.indexOf(menuItem);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
if (this.openOnHover) {
|
|
253
|
-
this.trigger.addEventListener("pointerenter", (e) => {
|
|
254
|
-
if (e.pointerType !== "mouse") return;
|
|
255
|
-
if (this.isClosing) return;
|
|
256
|
-
if (!this.isOpen) {
|
|
257
|
-
this.lastOpenSource = "mouse";
|
|
258
|
-
this.openDropdown();
|
|
259
|
-
} else {
|
|
260
|
-
// If the dropdown is already open, make sure to clear any close timer
|
|
261
|
-
this.clearCloseTimer();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
this.dropdown.addEventListener("pointerleave", (e) => {
|
|
266
|
-
if (e.pointerType !== "mouse") return;
|
|
267
|
-
if (this.openChildCount > 0) return;
|
|
268
|
-
if (this.isOpen) {
|
|
269
|
-
this.lastCloseSource = "mouse";
|
|
270
|
-
this.closeDropdownDelayed();
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
this.content.addEventListener("pointerenter", (e) => {
|
|
275
|
-
if (e.pointerType !== "mouse") return;
|
|
276
|
-
// If the user moves the mouse to the content, cancel the close timer
|
|
277
|
-
this.clearCloseTimer();
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
private handleMenuKeydown(e: KeyboardEvent) {
|
|
283
|
-
// Make sure we've got an updated list of menu items
|
|
284
|
-
this.updateDropdownItems();
|
|
285
|
-
|
|
286
|
-
// Skip if no items
|
|
287
|
-
if (this.items.length === 0) return;
|
|
288
|
-
|
|
289
|
-
const currentIdx = this.currentFocusIndex;
|
|
290
|
-
const currentItem = this.items[currentIdx];
|
|
291
|
-
|
|
292
|
-
switch (e.key) {
|
|
293
|
-
case "ArrowDown":
|
|
294
|
-
e.preventDefault();
|
|
295
|
-
e.stopPropagation();
|
|
296
|
-
this.focusItem(currentIdx === -1 ? 0 : currentIdx + 1);
|
|
297
|
-
break;
|
|
298
|
-
case "ArrowUp":
|
|
299
|
-
e.preventDefault();
|
|
300
|
-
e.stopPropagation();
|
|
301
|
-
this.focusItem(currentIdx === -1 ? this.items.length - 1 : currentIdx - 1);
|
|
302
|
-
break;
|
|
303
|
-
case "ArrowRight":
|
|
304
|
-
if (currentItem?.getAttribute("aria-haspopup") === "true") {
|
|
305
|
-
e.preventDefault();
|
|
306
|
-
e.stopPropagation();
|
|
307
|
-
currentItem.click();
|
|
308
|
-
}
|
|
309
|
-
break;
|
|
310
|
-
case "ArrowLeft":
|
|
311
|
-
if (this.isSubmenu) {
|
|
312
|
-
e.preventDefault();
|
|
313
|
-
e.stopPropagation();
|
|
314
|
-
this.closeDropdown();
|
|
315
|
-
}
|
|
316
|
-
break;
|
|
317
|
-
case "Home":
|
|
318
|
-
e.preventDefault();
|
|
319
|
-
e.stopPropagation();
|
|
320
|
-
this.focusItem(0);
|
|
321
|
-
break;
|
|
322
|
-
case "End":
|
|
323
|
-
e.preventDefault();
|
|
324
|
-
e.stopPropagation();
|
|
325
|
-
this.focusItem(this.items.length - 1);
|
|
326
|
-
break;
|
|
327
|
-
case "Enter":
|
|
328
|
-
case " ":
|
|
329
|
-
if (currentIdx !== -1 && this.items[currentIdx]) {
|
|
330
|
-
e.preventDefault();
|
|
331
|
-
e.stopPropagation();
|
|
332
|
-
this.items[currentIdx]?.click();
|
|
333
|
-
}
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
private isTargetInGroup(target: Node): boolean {
|
|
339
|
-
const el = target instanceof HTMLElement ? target : target.parentElement;
|
|
340
|
-
if (!el) return false;
|
|
341
|
-
const contentEl = el.closest('[data-slot="dropdown-content"]');
|
|
342
|
-
return !!contentEl && (contentEl as any).__rootDropdown === this.rootDropdown;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
private updateDropdownItems() {
|
|
346
|
-
if (!this.content) return;
|
|
347
|
-
// Get all interactive menuitem elements belonging to this menu level only
|
|
348
|
-
this.items = (
|
|
349
|
-
Array.from(
|
|
350
|
-
this.content.querySelectorAll('[role="menuitem"]:not([data-disabled="true"])'),
|
|
351
|
-
) as HTMLElement[]
|
|
352
|
-
).filter((item) => item.closest('[role="menu"]') === this.content);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
private focusItem(idx: number) {
|
|
356
|
-
// Ensure the index wraps around properly
|
|
357
|
-
const targetIdx = (idx + this.items.length) % this.items.length;
|
|
358
|
-
|
|
359
|
-
if (this.items[targetIdx]) {
|
|
360
|
-
this.items[targetIdx].focus();
|
|
361
|
-
this.currentFocusIndex = targetIdx;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
private toggleDropdown() {
|
|
366
|
-
if (this.isOpen) {
|
|
367
|
-
this.closeDropdown();
|
|
368
|
-
} else {
|
|
369
|
-
this.openDropdown();
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
private openDropdown() {
|
|
374
|
-
if (this.isClosing) return;
|
|
375
|
-
if (!this.content || !this.trigger || (this.trigger as any).disabled) return;
|
|
376
|
-
|
|
377
|
-
this.isOpen = true;
|
|
378
|
-
this.trigger.setAttribute("aria-expanded", "true");
|
|
379
|
-
this.content.style.removeProperty("display");
|
|
380
|
-
|
|
381
|
-
// Portal sub-content to body before triggering animation
|
|
382
|
-
if (this.isSubmenu) {
|
|
383
|
-
this.portalContent();
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
this.content.setAttribute("data-state", "open");
|
|
387
|
-
|
|
388
|
-
// Update the list of dropdown items
|
|
389
|
-
this.updateDropdownItems();
|
|
390
|
-
|
|
391
|
-
// Reset focus index when opening
|
|
392
|
-
this.currentFocusIndex = -1;
|
|
393
|
-
|
|
394
|
-
this.positionContent();
|
|
395
|
-
|
|
396
|
-
// For submenus opened by keyboard, focus the first item
|
|
397
|
-
if (this.isSubmenu && this.lastOpenSource === "keyboard") {
|
|
398
|
-
requestAnimationFrame(() => {
|
|
399
|
-
this.focusItem(0);
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private closeDropdown(options?: { skipFocus?: boolean }) {
|
|
405
|
-
if (!this.isOpen) return;
|
|
406
|
-
if (!this.content || !this.trigger) return;
|
|
407
|
-
|
|
408
|
-
this.isClosing = true;
|
|
409
|
-
this.isOpen = false;
|
|
410
|
-
this.content.setAttribute("data-state", "closed");
|
|
411
|
-
|
|
412
|
-
// Set focus back on trigger only if opened or closed by keyboard
|
|
413
|
-
// Skip focus if a close-all with focusRoot is closing this submenu (root will handle focus)
|
|
414
|
-
if (
|
|
415
|
-
!options?.skipFocus &&
|
|
416
|
-
(!this.openOnHover ||
|
|
417
|
-
this.lastOpenSource === "keyboard" ||
|
|
418
|
-
this.lastCloseSource === "keyboard")
|
|
419
|
-
) {
|
|
420
|
-
requestAnimationFrame(() => {
|
|
421
|
-
if (!this.trigger) return;
|
|
422
|
-
this.trigger.focus();
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Give the content time to animate before hiding
|
|
427
|
-
setTimeout(() => {
|
|
428
|
-
if (!this.content) return;
|
|
429
|
-
if (this.isSubmenu) {
|
|
430
|
-
this.unportalContent();
|
|
431
|
-
}
|
|
432
|
-
this.content.style.display = "none";
|
|
433
|
-
this.isClosing = false;
|
|
434
|
-
}, this.animationDuration);
|
|
435
|
-
|
|
436
|
-
this.trigger.setAttribute("aria-expanded", "false");
|
|
437
|
-
|
|
438
|
-
// Reset focus index when closing
|
|
439
|
-
this.currentFocusIndex = -1;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
private closeDropdownDelayed() {
|
|
443
|
-
if (!this.content || !this.trigger) return;
|
|
444
|
-
|
|
445
|
-
// Clear any existing close timer
|
|
446
|
-
this.clearCloseTimer();
|
|
447
|
-
|
|
448
|
-
// Set a new timer to close the dropdown after the delay
|
|
449
|
-
this.closeTimerRef = window.setTimeout(() => {
|
|
450
|
-
if (this.isOpen) {
|
|
451
|
-
this.closeDropdown();
|
|
452
|
-
}
|
|
453
|
-
this.closeTimerRef = null;
|
|
454
|
-
}, this.closeDelay);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
private clearCloseTimer() {
|
|
458
|
-
if (this.closeTimerRef !== null) {
|
|
459
|
-
window.clearTimeout(this.closeTimerRef);
|
|
460
|
-
this.closeTimerRef = null;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
private portalContent() {
|
|
465
|
-
if (!this.content || !this.trigger) return;
|
|
466
|
-
|
|
467
|
-
// Save the original position with a placeholder
|
|
468
|
-
this.contentPlaceholder = document.createComment("dropdown-sub-placeholder");
|
|
469
|
-
this.content.parentNode?.insertBefore(this.contentPlaceholder, this.content);
|
|
470
|
-
|
|
471
|
-
// Move content to body
|
|
472
|
-
document.body.appendChild(this.content);
|
|
473
|
-
|
|
474
|
-
// Apply fixed positioning (overrides the CSS absolute class)
|
|
475
|
-
this.content.style.position = "fixed";
|
|
476
|
-
this.content.style.zIndex = "50";
|
|
477
|
-
|
|
478
|
-
// Position relative to trigger
|
|
479
|
-
this.positionSubContent();
|
|
480
|
-
|
|
481
|
-
// Set up auto-update for scroll/resize
|
|
482
|
-
const updatePosition = () => this.positionSubContent();
|
|
483
|
-
window.addEventListener("scroll", updatePosition, true);
|
|
484
|
-
window.addEventListener("resize", updatePosition);
|
|
485
|
-
|
|
486
|
-
// Find and link to parent handler for child-tracking
|
|
487
|
-
const parentContent = this.trigger.closest('[data-slot="dropdown-content"]');
|
|
488
|
-
if (parentContent) {
|
|
489
|
-
this.parentHandler = (parentContent as any).__dropdownHandler || null;
|
|
490
|
-
if (this.parentHandler) {
|
|
491
|
-
this.parentHandler.openChildCount++;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// Handle hover interactions for portaled content
|
|
496
|
-
const onPointerEnter = (e: PointerEvent) => {
|
|
497
|
-
if (e.pointerType !== "mouse") return;
|
|
498
|
-
this.clearCloseTimer();
|
|
499
|
-
// Cancel close timers for all handlers in the group (parents included)
|
|
500
|
-
this.rootDropdown.dispatchEvent(new CustomEvent("starwind-dropdown:cancel-close"));
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
const onPointerLeave = (e: PointerEvent) => {
|
|
504
|
-
if (e.pointerType !== "mouse") return;
|
|
505
|
-
// Don't close if a child submenu is still open
|
|
506
|
-
if (this.openChildCount > 0) return;
|
|
507
|
-
this.lastCloseSource = "mouse";
|
|
508
|
-
this.closeDropdownDelayed();
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
this.content.addEventListener("pointerenter", onPointerEnter);
|
|
512
|
-
this.content.addEventListener("pointerleave", onPointerLeave);
|
|
513
|
-
|
|
514
|
-
this.cleanupAutoUpdate = () => {
|
|
515
|
-
window.removeEventListener("scroll", updatePosition, true);
|
|
516
|
-
window.removeEventListener("resize", updatePosition);
|
|
517
|
-
this.content?.removeEventListener("pointerenter", onPointerEnter);
|
|
518
|
-
this.content?.removeEventListener("pointerleave", onPointerLeave);
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
private unportalContent() {
|
|
523
|
-
if (!this.content || !this.contentPlaceholder) return;
|
|
524
|
-
|
|
525
|
-
// Decrement parent's open child count
|
|
526
|
-
if (this.parentHandler) {
|
|
527
|
-
this.parentHandler.openChildCount--;
|
|
528
|
-
this.parentHandler = null;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Clean up auto-update and hover listeners
|
|
532
|
-
this.cleanupAutoUpdate?.();
|
|
533
|
-
this.cleanupAutoUpdate = null;
|
|
534
|
-
|
|
535
|
-
// Move content back to its original position
|
|
536
|
-
this.contentPlaceholder.parentNode?.insertBefore(this.content, this.contentPlaceholder);
|
|
537
|
-
this.contentPlaceholder.remove();
|
|
538
|
-
this.contentPlaceholder = null;
|
|
539
|
-
|
|
540
|
-
// Remove fixed positioning styles
|
|
541
|
-
this.content.style.removeProperty("position");
|
|
542
|
-
this.content.style.removeProperty("z-index");
|
|
543
|
-
this.content.style.removeProperty("top");
|
|
544
|
-
this.content.style.removeProperty("left");
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
private positionSubContent() {
|
|
548
|
-
if (!this.content || !this.trigger) return;
|
|
549
|
-
|
|
550
|
-
const triggerRect = this.trigger.getBoundingClientRect();
|
|
551
|
-
|
|
552
|
-
// Position to the right of the trigger by default
|
|
553
|
-
let top = triggerRect.top;
|
|
554
|
-
let left = triggerRect.right;
|
|
555
|
-
|
|
556
|
-
// Measure content dimensions
|
|
557
|
-
const contentWidth = this.content.offsetWidth;
|
|
558
|
-
const contentHeight = this.content.offsetHeight;
|
|
559
|
-
const viewportWidth = window.innerWidth;
|
|
560
|
-
const viewportHeight = window.innerHeight;
|
|
561
|
-
|
|
562
|
-
// If it would overflow on the right, flip to the left
|
|
563
|
-
if (left + contentWidth > viewportWidth) {
|
|
564
|
-
left = triggerRect.left - contentWidth;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// If it would overflow on the bottom, shift up
|
|
568
|
-
if (top + contentHeight > viewportHeight) {
|
|
569
|
-
top = Math.max(0, viewportHeight - contentHeight);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
this.content.style.top = `${top}px`;
|
|
573
|
-
this.content.style.left = `${left}px`;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
private positionContent() {
|
|
577
|
-
if (!this.content || !this.trigger || this.isSubmenu) return;
|
|
578
|
-
|
|
579
|
-
// Set content width to match trigger width
|
|
580
|
-
this.content.style.width = "var(--starwind-dropdown-trigger-width)";
|
|
581
|
-
this.content.style.setProperty(
|
|
582
|
-
"--starwind-dropdown-trigger-width",
|
|
583
|
-
`${this.trigger.offsetWidth}px`,
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Store instances in a WeakMap to avoid memory leaks
|
|
589
|
-
const dropdownInstances = new WeakMap<HTMLElement, DropdownHandler>();
|
|
590
|
-
let dropdownCounter = 0;
|
|
591
|
-
|
|
592
|
-
// Initialize dropdowns
|
|
593
|
-
const initDropdowns = () => {
|
|
594
|
-
document.querySelectorAll(".starwind-dropdown, .starwind-dropdown-sub").forEach((dropdown) => {
|
|
595
|
-
if (dropdown instanceof HTMLElement && !dropdownInstances.has(dropdown)) {
|
|
596
|
-
dropdownInstances.set(dropdown, new DropdownHandler(dropdown, dropdownCounter++));
|
|
597
|
-
}
|
|
598
|
-
});
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
initDropdowns();
|
|
602
|
-
document.addEventListener("astro:after-swap", initDropdowns);
|
|
603
|
-
document.addEventListener("starwind:init", initDropdowns);
|
|
604
|
-
</script>
|