diff --git a/Makefile b/Makefile index 019294ec..bdeaf233 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ build-html: templ-generate render-showcases # Step 4: Lint HTML output using ESLint lint-html: - npx eslint "out/**/*.html" --ext .html + npx eslint --fix "out/**/*.html" --ext .html # Step 6: Run full pipeline (build + lint) validate-html: build-html lint-html diff --git a/cmd/render-showcases/main.go b/cmd/render-showcases/main.go index ad021343..ae4d59dc 100644 --- a/cmd/render-showcases/main.go +++ b/cmd/render-showcases/main.go @@ -28,6 +28,7 @@ func writeHTML(filename string, c templ.Component) error { func main() { showcases := map[string]templ.Component{ + // Accordion "out/showcase/accordion_default.html": showcase.AccordionDefault(), // Alert @@ -104,6 +105,159 @@ func main() { "out/showcase/chart_pie_legend.html": showcase.ChartPieLegend(), "out/showcase/chart_pie_stacked.html": showcase.ChartPieStacked(), "out/showcase/chart_radar.html": showcase.ChartRadar(), + + // Checkbox + "out/showcase/checkbox_card_default.html": showcase.CheckboxCardDefault(), + "out/showcase/checkbox_checked.html": showcase.CheckboxChecked(), + "out/showcase/checkbox_custom_icon.html": showcase.CheckboxCustomIcon(), + "out/showcase/checkbox_default.html": showcase.CheckboxDefault(), + "out/showcase/checkbox_disabled.html": showcase.CheckboxDisabled(), + "out/showcase/checkbox_form.html": showcase.CheckboxForm(), + "out/showcase/checkbox_with_label.html": showcase.CheckboxWithLabel(), + + // Code + "out/showcase/code_copy_button.html": showcase.CodeCopyButton(), + "out/showcase/code_custom_size.html": showcase.CodeCustomSize(), + "out/showcase/code_default.html": showcase.CodeDefault(), + + // Date Picker + "out/showcase/date_picker_custom_placeholder.html": showcase.DatePickerCustomPlaceholder(), + "out/showcase/date_picker_default.html": showcase.DatePickerDefault(), + "out/showcase/date_picker_disabled.html": showcase.DatePickerDisabled(), + "out/showcase/date_picker_form.html": showcase.DatePickerForm(), + "out/showcase/date_picker_formats.html": showcase.DatePickerFormats(), + "out/showcase/date_picker_selected_date.html": showcase.DatePickerSelectedDate(), + "out/showcase/date_picker_with_label.html": showcase.DatePickerWithLabel(), + + // Drawer + "out/showcase/drawer_default.html": showcase.DrawerDefault(), + "out/showcase/drawer_positions.html": showcase.DrawerPositions(), + + // Dropdown + "out/showcase/dropdown_default.html": showcase.DropdownDefault(), + + // Icon + "out/showcase/icon_colored.html": showcase.IconColored(), + "out/showcase/icon_default.html": showcase.IconDefault(), + "out/showcase/icon_filled.html": showcase.IconFilled(), + "out/showcase/icon_sizes.html": showcase.IconSizes(), + + // Input + "out/showcase/input_default.html": showcase.InputDefault(), + "out/showcase/input_disabled.html": showcase.InputDisabled(), + "out/showcase/input_file.html": showcase.InputFile(), + "out/showcase/input_form.html": showcase.InputForm(), + "out/showcase/input_with_label.html": showcase.InputWithLabel(), + + // Input OTP + "out/showcase/input_otp_custom_length.html": showcase.InputOTPCustomLength(), + "out/showcase/input_otp_custom_styling.html": showcase.InputOTPCustomStyling(), + "out/showcase/input_otp_default.html": showcase.InputOTPDefault(), + "out/showcase/input_otp_form.html": showcase.InputOTPForm(), + "out/showcase/input_otp_password_type.html": showcase.InputOTPPasswordType(), + "out/showcase/input_otp_placeholder.html": showcase.InputOTPPlaceholder(), + "out/showcase/input_otp_with_label.html": showcase.InputOTPWithLabel(), + + // Modal + "out/showcase/modal_default.html": showcase.ModalDefault(), + + // Pagination + "out/showcase/pagination_default.html": showcase.PaginationDefault(), + "out/showcase/pagination_with_helper.html": showcase.PaginationWithHelper(), + + // Popover + "out/showcase/popover_default.html": showcase.PopoverDefault(), + "out/showcase/popover_positions.html": showcase.PopoverPositions(), + "out/showcase/popover_triggers.html": showcase.PopoverTriggers(), + + // Progress + "out/showcase/progress_colors.html": showcase.ProgressColors(), + "out/showcase/progress_default.html": showcase.ProgressDefault(), + "out/showcase/progress_sizes.html": showcase.ProgressSizes(), + + // Radio + "out/showcase/radio_card_default.html": showcase.RadioCardDefault(), + "out/showcase/radio_checked.html": showcase.RadioChecked(), + "out/showcase/radio_default.html": showcase.RadioDefault(), + "out/showcase/radio_disabled.html": showcase.RadioDisabled(), + "out/showcase/radio_form.html": showcase.RadioForm(), + "out/showcase/radio_with_label.html": showcase.RadioWithLabel(), + + // Rating + "out/showcase/rating_default.html": showcase.RatingDefault(), + "out/showcase/rating_form.html": showcase.RatingForm(), + "out/showcase/rating_max_values.html": showcase.RatingMaxValues(), + "out/showcase/rating_precision.html": showcase.RatingPrecision(), + "out/showcase/rating_styles.html": showcase.RatingStyles(), + "out/showcase/rating_with_label.html": showcase.RatingWithLabel(), + + // Select Box + "out/showcase/select_box_default.html": showcase.SelectBoxDefault(), + "out/showcase/select_box_disabled.html": showcase.SelectBoxDisabled(), + "out/showcase/select_box_form.html": showcase.SelectBoxForm(), + "out/showcase/select_box_with_label.html": showcase.SelectBoxWithLabel(), + + // Separator + "out/showcase/separator_decorated.html": showcase.SeparatorDecorated(), + "out/showcase/separator_default.html": showcase.SeparatorDefault(), + "out/showcase/separator_label.html": showcase.SeparatorLabel(), + "out/showcase/separator_vertical.html": showcase.SeparatorVertical(), + + // Skeleton + "out/showcase/skeleton_card.html": showcase.SkeletonCard(), + "out/showcase/skeleton_dashboard.html": showcase.SkeletonDashboard(), + "out/showcase/skeleton_default.html": showcase.SkeletonDefault(), + "out/showcase/skeleton_profile.html": showcase.SkeletonProfile(), + + // Slider + "out/showcase/slider_default.html": showcase.SliderDefault(), + "out/showcase/slider_disabled.html": showcase.SliderDisabled(), + "out/showcase/slider_external_value.html": showcase.SliderExternalValue(), + "out/showcase/slider_steps.html": showcase.SliderSteps(), + "out/showcase/slider_value.html": showcase.SliderValue(), + + // Spinner + "out/showcase/spinner_colors.html": showcase.SpinnerColors(), + "out/showcase/spinner_default.html": showcase.SpinnerDefault(), + "out/showcase/spinner_in_button.html": showcase.SpinnerInButton(), + "out/showcase/spinner_sizes.html": showcase.SpinnerSizes(), + + // Table + "out/showcase/table.html": showcase.Table(), + + // Tabs + "out/showcase/tabs_default.html": showcase.TabsDefault(), + + // Textarea + "out/showcase/textarea_auto_resize.html": showcase.TextareaAutoResize(), + "out/showcase/textarea_custom_rows.html": showcase.TextareaCustomRows(), + "out/showcase/textarea_default.html": showcase.TextareaDefault(), + "out/showcase/textarea_disabled.html": showcase.TextareaDisabled(), + "out/showcase/textarea_form.html": showcase.TextareaForm(), + "out/showcase/textarea_with_label.html": showcase.TextareaWithLabel(), + + // Time Picker + "out/showcase/time_picker_12hour.html": showcase.TimePicker12Hour(), + "out/showcase/time_picker_custom_placeholder.html": showcase.TimePickerCustomPlaceholder(), + "out/showcase/time_picker_default.html": showcase.TimePickerDefault(), + "out/showcase/time_picker_form.html": showcase.TimePickerForm(), + "out/showcase/time_picker_label.html": showcase.TimePickerLabel(), + "out/showcase/time_picker_selected_time.html": showcase.TimePickerSelectedTime(), + + // Toast + "out/showcase/toast_default.html": showcase.ToastDefault(), + "out/showcase/toast_playground.html": showcase.ToastPlayground(), + + // Toggle + "out/showcase/toggle_checked.html": showcase.ToggleChecked(), + "out/showcase/toggle_default.html": showcase.ToggleDefault(), + "out/showcase/toggle_disabled.html": showcase.ToggleDisabled(), + "out/showcase/toggle_form.html": showcase.ToggleForm(), + "out/showcase/toggle_with_label.html": showcase.ToggleWithLabel(), + + // Tooltip + "out/showcase/tooltip_default.html": showcase.TooltipDefault(), + "out/showcase/tooltip_positions.html": showcase.TooltipPositions(), } for path, comp := range showcases { diff --git a/component/drawer/drawer.templ b/component/drawer/drawer.templ index 837c85f1..dececf7c 100644 --- a/component/drawer/drawer.templ +++ b/component/drawer/drawer.templ @@ -117,7 +117,9 @@ templ Content(props ...ContentProps) { x-transition:leave-end="opacity-0" >
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -383,7 +393,7 @@ func Content(props ...ContentProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\" @click.stop>") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -404,7 +414,7 @@ func Content(props ...ContentProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -442,30 +452,30 @@ func Header(props ...HeaderProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -494,7 +504,7 @@ func Header(props ...HeaderProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -532,30 +542,30 @@ func Title(props ...TitleProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -584,7 +594,7 @@ func Title(props ...TitleProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -622,30 +632,30 @@ func Description(props ...DescriptionProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -674,7 +684,7 @@ func Description(props ...DescriptionProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -712,30 +722,30 @@ func Footer(props ...FooterProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -764,7 +774,7 @@ func Footer(props ...FooterProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -810,30 +820,30 @@ func Close(props ...CloseProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -862,7 +872,7 @@ func Close(props ...CloseProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -904,20 +914,20 @@ func Script() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "\">\n document.addEventListener('alpine:init', () => {\n Alpine.data('drawer', () => ({\n isOpen: false,\n open() {\n this.isOpen = true\n document.body.style.overflow = 'hidden'\n },\n close() {\n this.isOpen = false\n document.body.style.overflow = ''\n },\n }))\n })\n ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/component/modal/modal.templ b/component/modal/modal.templ index aa7bd8bb..185480c8 100644 --- a/component/modal/modal.templ +++ b/component/modal/modal.templ @@ -145,17 +145,15 @@ templ Header(props ...HeaderProps) { if len(props) > 0 { {{ p = props[0] }} } -
- -
+ { children... } + } templ Body(props ...BodyProps) { diff --git a/component/modal/modal_templ.go b/component/modal/modal_templ.go index 7b922bed..fec7a18a 100644 --- a/component/modal/modal_templ.go +++ b/component/modal/modal_templ.go @@ -447,12 +447,12 @@ func Header(props ...HeaderProps) templ.Component { if len(props) > 0 { p = props[0] } - var templ_7745c5c3_Var18 = []any{util.TwMerge("px-4 pt-5 pb-4 sm:p-6 sm:pb-4", p.Class)} + var templ_7745c5c3_Var18 = []any{util.TwMerge("px-4 pt-5 pb-4 sm:p-6 sm:pb-4 text-lg leading-6 font-medium text-foreground", p.Class)} templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var18...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, ">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -504,7 +504,7 @@ func Header(props ...HeaderProps) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -554,7 +554,7 @@ func Body(props ...BodyProps) templ.Component { var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(p.ID) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 168, Col: 12} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 166, Col: 12} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { @@ -644,7 +644,7 @@ func Footer(props ...FooterProps) templ.Component { var templ_7745c5c3_Var27 string templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(p.ID) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 184, Col: 12} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 182, Col: 12} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) if templ_7745c5c3_Err != nil { @@ -733,7 +733,7 @@ func Script() templ.Component { var templ_7745c5c3_Var31 string templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(templ.GetNonce(ctx)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 196, Col: 43} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `component/modal/modal.templ`, Line: 194, Col: 43} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { diff --git a/component/popover/popover.templ b/component/popover/popover.templ index 58374242..71ef01ac 100644 --- a/component/popover/popover.templ +++ b/component/popover/popover.templ @@ -60,7 +60,7 @@ templ Popover(props ...Props) { { children... }
} @@ -197,7 +197,7 @@ templ Script() { `; document.head.appendChild(style); - const portalContainer = document.getElementById('popover-portal-container'); + const portalContainer = document.querySelector('[data-popover-portal-container]'); const triggers = document.querySelectorAll('[data-popover-trigger]'); const templates = document.querySelectorAll('[data-popover-content-template]'); diff --git a/component/popover/popover_templ.go b/component/popover/popover_templ.go index 6cdb8ba3..8eba0842 100644 --- a/component/popover/popover_templ.go +++ b/component/popover/popover_templ.go @@ -110,7 +110,7 @@ func Popover(props ...Props) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -571,7 +571,7 @@ func Script() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "\">\n document.addEventListener('DOMContentLoaded', () => {\n // Minimal CSS-Animation for the rubber effect\n const style = document.createElement('style');\n style.textContent = `\n @keyframes popover-in {\n 0% { opacity: 0; transform: scale(0.95); }\n 100% { opacity: 1; transform: scale(1); }\n }\n \n @keyframes popover-out {\n 0% { opacity: 1; transform: scale(1); }\n 100% { opacity: 0; transform: scale(0.95); }\n }\n \n .popover-animate-in {\n animation: popover-in 0.15s cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .popover-animate-out {\n animation: popover-out 0.1s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n `;\n document.head.appendChild(style);\n \n const portalContainer = document.getElementById('popover-portal-container');\n const triggers = document.querySelectorAll('[data-popover-trigger]');\n const templates = document.querySelectorAll('[data-popover-content-template]');\n \n // Active popovers\n const activePopovers = new Map();\n \n // Function to update the arrow based on the position\n const updateArrow = (popoverElement, position) => {\n if (popoverElement.dataset.popoverShowArrow !== 'true') return;\n \n // Initially hide all arrows\n popoverElement.querySelectorAll('[data-arrow]').forEach(arrow => {\n arrow.classList.add('hidden');\n });\n \n // Get the background and border color from the parent element\n const computedStyle = window.getComputedStyle(popoverElement);\n const bgColor = computedStyle.backgroundColor;\n const borderColor = computedStyle.borderColor;\n \n // Arrow direction is always opposite to the position\n let arrowPosition;\n \n if (position.startsWith('top')) {\n arrowPosition = position.replace('top', 'bottom');\n } else if (position.startsWith('bottom')) {\n arrowPosition = position.replace('bottom', 'top');\n } else if (position.startsWith('left')) {\n arrowPosition = position.replace('left', 'right');\n } else if (position.startsWith('right')) {\n arrowPosition = position.replace('right', 'left');\n } else {\n arrowPosition = position;\n }\n \n // Show the correct arrow based on the direction\n const arrow = popoverElement.querySelector(`[data-arrow=\"${arrowPosition}\"]`);\n if (arrow) {\n arrow.classList.remove('hidden');\n arrow.style.backgroundColor = bgColor;\n arrow.style.borderColor = borderColor;\n }\n };\n \n // Positioning function\n const positionPopover = (trigger, popoverElement) => {\n // Find the actual element the popover refers to\n let triggerElement = trigger;\n let largestArea = 0;\n \n // Check all direct children of the trigger\n const children = trigger.children;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const rect = child.getBoundingClientRect();\n const area = rect.width * rect.height;\n \n if (area > largestArea) {\n largestArea = area;\n triggerElement = child;\n }\n }\n \n const triggerRect = triggerElement.getBoundingClientRect();\n const contentRect = popoverElement.getBoundingClientRect();\n const margin = popoverElement.dataset.popoverShowArrow === 'true' ? 8 : 4;\n const scrollY = window.scrollY || window.pageYOffset;\n const scrollX = window.scrollX || window.pageXOffset;\n\n // Position from the dataset\n const requestedPosition = popoverElement.dataset.popoverPosition || 'bottom';\n // We store the final position, which can be adjusted based on viewport space\n let finalPosition = requestedPosition;\n\n // Viewport dimensions\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Get element heights and widths\n const triggerHeight = triggerRect.height;\n const contentHeight = contentRect.height;\n const contentWidth = contentRect.width;\n \n // Define anchor points\n const triggerTop = triggerRect.top + scrollY;\n const triggerBottom = triggerRect.bottom + scrollY;\n const triggerLeft = triggerRect.left + scrollX;\n const triggerRight = triggerRect.right + scrollX;\n \n // Calculate available space in each direction\n const spaceAbove = triggerRect.top;\n const spaceBelow = viewportHeight - triggerRect.bottom;\n const spaceLeft = triggerRect.left;\n const spaceRight = viewportWidth - triggerRect.right;\n\n // Intelligent position adjustment\n // We check the opposite position if there is not enough space\n if (finalPosition.startsWith('top') && spaceAbove < contentHeight + margin) {\n // If there is not enough space above, show below\n finalPosition = finalPosition.replace('top', 'bottom');\n } else if (finalPosition.startsWith('bottom') && spaceBelow < contentHeight + margin) {\n // If there is not enough space below, show above\n finalPosition = finalPosition.replace('bottom', 'top');\n } else if (finalPosition.startsWith('left') && spaceLeft < contentWidth + margin) {\n // If there is not enough space on the left, show on the right\n finalPosition = finalPosition.replace('left', 'right');\n } else if (finalPosition.startsWith('right') && spaceRight < contentWidth + margin) {\n // If there is not enough space on the right, show on the left\n finalPosition = finalPosition.replace('right', 'left');\n }\n\n // Store the current position in the element for CSS adjustments (e.g., arrow position)\n popoverElement.dataset.popoverCurrentPosition = finalPosition;\n \n // Show the correct arrow\n updateArrow(popoverElement, finalPosition);\n \n let top, left;\n \n // Positioning logic with the final position\n switch (finalPosition) {\n case 'top':\n top = triggerTop - contentHeight - margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n break;\n case 'top-start':\n top = triggerTop - contentHeight - margin;\n left = triggerLeft;\n break;\n case 'top-end':\n top = triggerTop - contentHeight - margin;\n left = triggerRight - contentRect.width;\n break;\n case 'right':\n top = triggerTop + (triggerHeight / 2) - (contentHeight / 2);\n left = triggerRight + margin;\n break;\n case 'right-start':\n top = triggerTop;\n left = triggerRight + margin;\n break;\n case 'right-end':\n top = triggerBottom - contentHeight;\n left = triggerRight + margin;\n break;\n case 'bottom':\n top = triggerBottom + margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n break;\n case 'bottom-start':\n top = triggerBottom + margin;\n left = triggerLeft;\n break;\n case 'bottom-end':\n top = triggerBottom + margin;\n left = triggerRight - contentRect.width;\n break;\n case 'left':\n top = triggerTop + (triggerHeight / 2) - (contentHeight / 2);\n left = triggerLeft - contentRect.width - margin;\n break;\n case 'left-start':\n top = triggerTop;\n left = triggerLeft - contentRect.width - margin;\n break;\n case 'left-end':\n top = triggerBottom - contentHeight;\n left = triggerLeft - contentRect.width - margin;\n break;\n default:\n top = triggerBottom + margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n }\n\n // Horizontal boundary - ensures the popover does not overflow the viewport\n if (left < 10) {\n left = 10; // Minimum distance from the left edge\n } else if (left + contentWidth > viewportWidth - 10) {\n left = viewportWidth - contentWidth - 10; // Minimum distance from the right edge\n }\n\n // Vertical boundary - Optional, can be problematic in some cases\n if (top < 10) {\n top = 10; // Minimum distance from the top edge\n } else if (top + contentHeight > viewportHeight - 10) {\n top = viewportHeight - contentHeight - 10; // Minimum distance from the bottom edge\n }\n\n popoverElement.style.top = `${top}px`;\n popoverElement.style.left = `${left}px`;\n };\n \n // Event handler setup\n function setupTrigger(trigger) {\n const popoverId = trigger.dataset.popoverFor\n const template = document.querySelector(`[data-popover-content-template][data-popover-id=\"${popoverId}\"]`);\n \n if (!template) return;\n \n const triggerType = trigger.dataset.popoverType;\n \n // Click handler\n if (triggerType === 'click') {\n trigger.addEventListener('click', () => {\n // If the popover is already active, remove it\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n popover.remove();\n activePopovers.delete(popoverId);\n return;\n }\n \n // Otherwise, create a new popover\n const content = template.content.cloneNode(true).firstElementChild;\n \n // Transfer attributes from the template\n Object.keys(template.dataset).forEach(key => {\n if (key.startsWith('popover')) {\n content.dataset[key] = template.dataset[key];\n }\n });\n \n // Set initial position\n content.dataset.popoverCurrentPosition = content.dataset.popoverPosition;\n \n // Add to the portal container\n portalContainer.appendChild(content);\n \n // Position it\n positionPopover(trigger, content);\n \n // Apply transition effect\n content.classList.remove('popover-transition');\n content.classList.remove('show');\n content.classList.add('popover-animate-in');\n \n // Add to active popovers\n activePopovers.set(popoverId, content);\n \n // Clickaway handler\n if (content.dataset.popoverDisableClickaway !== 'true') {\n const clickHandler = (e) => {\n if (!trigger.contains(e.target) && !content.contains(e.target)) {\n // Apply exit animation\n content.classList.remove('popover-animate-in');\n content.classList.add('popover-animate-out');\n \n // Wait for transition to complete before removing\n setTimeout(() => {\n content.remove();\n activePopovers.delete(popoverId);\n }, 100);\n \n document.removeEventListener('click', clickHandler);\n }\n };\n \n // Delay to prevent immediate closing on the current click\n setTimeout(() => {\n document.addEventListener('click', clickHandler);\n }, 0);\n }\n \n // ESC handler\n if (content.dataset.popoverDisableEsc !== 'true') {\n const keyHandler = (e) => {\n if (e.key === 'Escape') {\n // Apply exit animation\n content.classList.remove('popover-animate-in');\n content.classList.add('popover-animate-out');\n \n // Wait for transition to complete before removing\n setTimeout(() => {\n content.remove();\n activePopovers.delete(popoverId);\n }, 100);\n \n document.removeEventListener('keydown', keyHandler);\n }\n };\n document.addEventListener('keydown', keyHandler);\n }\n });\n } else if (triggerType === 'hover') {\n // Hover handlers\n let hoverTimeout;\n let leaveTimeout;\n \n trigger.addEventListener('mouseenter', () => {\n clearTimeout(leaveTimeout);\n \n // Get hover delay from template or use default\n const hoverDelay = parseInt(template.dataset.popoverHoverDelay) || 100;\n \n // If the popover is already active, do not recreate it\n if (activePopovers.has(popoverId)) return;\n \n // Delay for showing the popover\n hoverTimeout = setTimeout(() => {\n // Create a new popover\n const content = template.content.cloneNode(true).firstElementChild;\n \n // Transfer attributes\n Object.keys(template.dataset).forEach(key => {\n if (key.startsWith('popover')) {\n content.dataset[key] = template.dataset[key];\n }\n });\n \n // Add to the portal container\n portalContainer.appendChild(content);\n \n // Position it\n positionPopover(trigger, content);\n \n // Apply animation\n content.classList.add('popover-animate-in');\n \n // Add to active popovers\n activePopovers.set(popoverId, content);\n \n // Hover handler for the content element\n content.addEventListener('mouseenter', () => {\n clearTimeout(leaveTimeout);\n });\n \n content.addEventListener('mouseleave', () => {\n // Get hover out delay from template or use default\n const hoverOutDelay = parseInt(content.dataset.popoverHoverOutDelay) || 200;\n \n leaveTimeout = setTimeout(() => {\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n \n // Apply exit animation\n popover.classList.remove('popover-animate-in');\n popover.classList.add('popover-animate-out');\n \n // Wait for animation to complete before removing\n setTimeout(() => {\n popover.remove();\n activePopovers.delete(popoverId);\n }, 100);\n }\n }, hoverOutDelay);\n });\n }, hoverDelay);\n });\n \n trigger.addEventListener('mouseleave', (e) => {\n // Clear the show timeout if mouse leaves before popover is shown\n clearTimeout(hoverTimeout);\n \n // Check if we are hovering over the content\n const related = e.relatedTarget;\n const content = activePopovers.get(popoverId);\n \n // If we are directly hovering over the content, do not close\n if (content && content.contains(related)) {\n return;\n }\n \n // Get hover out delay from template or use default\n const hoverOutDelay = content ? \n (parseInt(content.dataset.popoverHoverOutDelay) || 200) : 200;\n \n leaveTimeout = setTimeout(() => {\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n \n // Apply exit animation\n popover.classList.remove('popover-animate-in');\n popover.classList.add('popover-animate-out');\n \n // Wait for animation to complete before removing\n setTimeout(() => {\n popover.remove();\n activePopovers.delete(popoverId);\n }, 100);\n }\n }, hoverOutDelay);\n });\n }\n }\n \n // Set up handlers for each trigger\n triggers.forEach(setupTrigger);\n \n // Scroll handler for all popovers\n window.addEventListener('scroll', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n }, { passive: true });\n \n // Resize handler\n window.addEventListener('resize', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n });\n \n // Find all scrollable parent elements and add scroll handlers\n function setupScrollHandlers() {\n const scrollableElements = new Set();\n \n // Find scrollable parents for each trigger\n triggers.forEach(trigger => {\n let element = trigger.parentElement;\n \n while (element) {\n const style = window.getComputedStyle(element);\n const overflow = style.overflow + style.overflowY + style.overflowX;\n \n if (overflow.includes('scroll') || overflow.includes('auto') || \n element.scrollHeight > element.clientHeight) {\n scrollableElements.add(element);\n }\n \n element = element.parentElement;\n }\n });\n \n // Scroll handler for each scrollable element\n scrollableElements.forEach(element => {\n element.addEventListener('scroll', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n }, { passive: true });\n });\n }\n \n setupScrollHandlers();\n });\n ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "\">\n document.addEventListener('DOMContentLoaded', () => {\n // Minimal CSS-Animation for the rubber effect\n const style = document.createElement('style');\n style.textContent = `\n @keyframes popover-in {\n 0% { opacity: 0; transform: scale(0.95); }\n 100% { opacity: 1; transform: scale(1); }\n }\n \n @keyframes popover-out {\n 0% { opacity: 1; transform: scale(1); }\n 100% { opacity: 0; transform: scale(0.95); }\n }\n \n .popover-animate-in {\n animation: popover-in 0.15s cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n .popover-animate-out {\n animation: popover-out 0.1s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n `;\n document.head.appendChild(style);\n \n const portalContainer = document.querySelector('[data-popover-portal-container]');\n const triggers = document.querySelectorAll('[data-popover-trigger]');\n const templates = document.querySelectorAll('[data-popover-content-template]');\n \n // Active popovers\n const activePopovers = new Map();\n \n // Function to update the arrow based on the position\n const updateArrow = (popoverElement, position) => {\n if (popoverElement.dataset.popoverShowArrow !== 'true') return;\n \n // Initially hide all arrows\n popoverElement.querySelectorAll('[data-arrow]').forEach(arrow => {\n arrow.classList.add('hidden');\n });\n \n // Get the background and border color from the parent element\n const computedStyle = window.getComputedStyle(popoverElement);\n const bgColor = computedStyle.backgroundColor;\n const borderColor = computedStyle.borderColor;\n \n // Arrow direction is always opposite to the position\n let arrowPosition;\n \n if (position.startsWith('top')) {\n arrowPosition = position.replace('top', 'bottom');\n } else if (position.startsWith('bottom')) {\n arrowPosition = position.replace('bottom', 'top');\n } else if (position.startsWith('left')) {\n arrowPosition = position.replace('left', 'right');\n } else if (position.startsWith('right')) {\n arrowPosition = position.replace('right', 'left');\n } else {\n arrowPosition = position;\n }\n \n // Show the correct arrow based on the direction\n const arrow = popoverElement.querySelector(`[data-arrow=\"${arrowPosition}\"]`);\n if (arrow) {\n arrow.classList.remove('hidden');\n arrow.style.backgroundColor = bgColor;\n arrow.style.borderColor = borderColor;\n }\n };\n \n // Positioning function\n const positionPopover = (trigger, popoverElement) => {\n // Find the actual element the popover refers to\n let triggerElement = trigger;\n let largestArea = 0;\n \n // Check all direct children of the trigger\n const children = trigger.children;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const rect = child.getBoundingClientRect();\n const area = rect.width * rect.height;\n \n if (area > largestArea) {\n largestArea = area;\n triggerElement = child;\n }\n }\n \n const triggerRect = triggerElement.getBoundingClientRect();\n const contentRect = popoverElement.getBoundingClientRect();\n const margin = popoverElement.dataset.popoverShowArrow === 'true' ? 8 : 4;\n const scrollY = window.scrollY || window.pageYOffset;\n const scrollX = window.scrollX || window.pageXOffset;\n\n // Position from the dataset\n const requestedPosition = popoverElement.dataset.popoverPosition || 'bottom';\n // We store the final position, which can be adjusted based on viewport space\n let finalPosition = requestedPosition;\n\n // Viewport dimensions\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Get element heights and widths\n const triggerHeight = triggerRect.height;\n const contentHeight = contentRect.height;\n const contentWidth = contentRect.width;\n \n // Define anchor points\n const triggerTop = triggerRect.top + scrollY;\n const triggerBottom = triggerRect.bottom + scrollY;\n const triggerLeft = triggerRect.left + scrollX;\n const triggerRight = triggerRect.right + scrollX;\n \n // Calculate available space in each direction\n const spaceAbove = triggerRect.top;\n const spaceBelow = viewportHeight - triggerRect.bottom;\n const spaceLeft = triggerRect.left;\n const spaceRight = viewportWidth - triggerRect.right;\n\n // Intelligent position adjustment\n // We check the opposite position if there is not enough space\n if (finalPosition.startsWith('top') && spaceAbove < contentHeight + margin) {\n // If there is not enough space above, show below\n finalPosition = finalPosition.replace('top', 'bottom');\n } else if (finalPosition.startsWith('bottom') && spaceBelow < contentHeight + margin) {\n // If there is not enough space below, show above\n finalPosition = finalPosition.replace('bottom', 'top');\n } else if (finalPosition.startsWith('left') && spaceLeft < contentWidth + margin) {\n // If there is not enough space on the left, show on the right\n finalPosition = finalPosition.replace('left', 'right');\n } else if (finalPosition.startsWith('right') && spaceRight < contentWidth + margin) {\n // If there is not enough space on the right, show on the left\n finalPosition = finalPosition.replace('right', 'left');\n }\n\n // Store the current position in the element for CSS adjustments (e.g., arrow position)\n popoverElement.dataset.popoverCurrentPosition = finalPosition;\n \n // Show the correct arrow\n updateArrow(popoverElement, finalPosition);\n \n let top, left;\n \n // Positioning logic with the final position\n switch (finalPosition) {\n case 'top':\n top = triggerTop - contentHeight - margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n break;\n case 'top-start':\n top = triggerTop - contentHeight - margin;\n left = triggerLeft;\n break;\n case 'top-end':\n top = triggerTop - contentHeight - margin;\n left = triggerRight - contentRect.width;\n break;\n case 'right':\n top = triggerTop + (triggerHeight / 2) - (contentHeight / 2);\n left = triggerRight + margin;\n break;\n case 'right-start':\n top = triggerTop;\n left = triggerRight + margin;\n break;\n case 'right-end':\n top = triggerBottom - contentHeight;\n left = triggerRight + margin;\n break;\n case 'bottom':\n top = triggerBottom + margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n break;\n case 'bottom-start':\n top = triggerBottom + margin;\n left = triggerLeft;\n break;\n case 'bottom-end':\n top = triggerBottom + margin;\n left = triggerRight - contentRect.width;\n break;\n case 'left':\n top = triggerTop + (triggerHeight / 2) - (contentHeight / 2);\n left = triggerLeft - contentRect.width - margin;\n break;\n case 'left-start':\n top = triggerTop;\n left = triggerLeft - contentRect.width - margin;\n break;\n case 'left-end':\n top = triggerBottom - contentHeight;\n left = triggerLeft - contentRect.width - margin;\n break;\n default:\n top = triggerBottom + margin;\n left = triggerLeft + (triggerRect.width / 2) - (contentRect.width / 2);\n }\n\n // Horizontal boundary - ensures the popover does not overflow the viewport\n if (left < 10) {\n left = 10; // Minimum distance from the left edge\n } else if (left + contentWidth > viewportWidth - 10) {\n left = viewportWidth - contentWidth - 10; // Minimum distance from the right edge\n }\n\n // Vertical boundary - Optional, can be problematic in some cases\n if (top < 10) {\n top = 10; // Minimum distance from the top edge\n } else if (top + contentHeight > viewportHeight - 10) {\n top = viewportHeight - contentHeight - 10; // Minimum distance from the bottom edge\n }\n\n popoverElement.style.top = `${top}px`;\n popoverElement.style.left = `${left}px`;\n };\n \n // Event handler setup\n function setupTrigger(trigger) {\n const popoverId = trigger.dataset.popoverFor\n const template = document.querySelector(`[data-popover-content-template][data-popover-id=\"${popoverId}\"]`);\n \n if (!template) return;\n \n const triggerType = trigger.dataset.popoverType;\n \n // Click handler\n if (triggerType === 'click') {\n trigger.addEventListener('click', () => {\n // If the popover is already active, remove it\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n popover.remove();\n activePopovers.delete(popoverId);\n return;\n }\n \n // Otherwise, create a new popover\n const content = template.content.cloneNode(true).firstElementChild;\n \n // Transfer attributes from the template\n Object.keys(template.dataset).forEach(key => {\n if (key.startsWith('popover')) {\n content.dataset[key] = template.dataset[key];\n }\n });\n \n // Set initial position\n content.dataset.popoverCurrentPosition = content.dataset.popoverPosition;\n \n // Add to the portal container\n portalContainer.appendChild(content);\n \n // Position it\n positionPopover(trigger, content);\n \n // Apply transition effect\n content.classList.remove('popover-transition');\n content.classList.remove('show');\n content.classList.add('popover-animate-in');\n \n // Add to active popovers\n activePopovers.set(popoverId, content);\n \n // Clickaway handler\n if (content.dataset.popoverDisableClickaway !== 'true') {\n const clickHandler = (e) => {\n if (!trigger.contains(e.target) && !content.contains(e.target)) {\n // Apply exit animation\n content.classList.remove('popover-animate-in');\n content.classList.add('popover-animate-out');\n \n // Wait for transition to complete before removing\n setTimeout(() => {\n content.remove();\n activePopovers.delete(popoverId);\n }, 100);\n \n document.removeEventListener('click', clickHandler);\n }\n };\n \n // Delay to prevent immediate closing on the current click\n setTimeout(() => {\n document.addEventListener('click', clickHandler);\n }, 0);\n }\n \n // ESC handler\n if (content.dataset.popoverDisableEsc !== 'true') {\n const keyHandler = (e) => {\n if (e.key === 'Escape') {\n // Apply exit animation\n content.classList.remove('popover-animate-in');\n content.classList.add('popover-animate-out');\n \n // Wait for transition to complete before removing\n setTimeout(() => {\n content.remove();\n activePopovers.delete(popoverId);\n }, 100);\n \n document.removeEventListener('keydown', keyHandler);\n }\n };\n document.addEventListener('keydown', keyHandler);\n }\n });\n } else if (triggerType === 'hover') {\n // Hover handlers\n let hoverTimeout;\n let leaveTimeout;\n \n trigger.addEventListener('mouseenter', () => {\n clearTimeout(leaveTimeout);\n \n // Get hover delay from template or use default\n const hoverDelay = parseInt(template.dataset.popoverHoverDelay) || 100;\n \n // If the popover is already active, do not recreate it\n if (activePopovers.has(popoverId)) return;\n \n // Delay for showing the popover\n hoverTimeout = setTimeout(() => {\n // Create a new popover\n const content = template.content.cloneNode(true).firstElementChild;\n \n // Transfer attributes\n Object.keys(template.dataset).forEach(key => {\n if (key.startsWith('popover')) {\n content.dataset[key] = template.dataset[key];\n }\n });\n \n // Add to the portal container\n portalContainer.appendChild(content);\n \n // Position it\n positionPopover(trigger, content);\n \n // Apply animation\n content.classList.add('popover-animate-in');\n \n // Add to active popovers\n activePopovers.set(popoverId, content);\n \n // Hover handler for the content element\n content.addEventListener('mouseenter', () => {\n clearTimeout(leaveTimeout);\n });\n \n content.addEventListener('mouseleave', () => {\n // Get hover out delay from template or use default\n const hoverOutDelay = parseInt(content.dataset.popoverHoverOutDelay) || 200;\n \n leaveTimeout = setTimeout(() => {\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n \n // Apply exit animation\n popover.classList.remove('popover-animate-in');\n popover.classList.add('popover-animate-out');\n \n // Wait for animation to complete before removing\n setTimeout(() => {\n popover.remove();\n activePopovers.delete(popoverId);\n }, 100);\n }\n }, hoverOutDelay);\n });\n }, hoverDelay);\n });\n \n trigger.addEventListener('mouseleave', (e) => {\n // Clear the show timeout if mouse leaves before popover is shown\n clearTimeout(hoverTimeout);\n \n // Check if we are hovering over the content\n const related = e.relatedTarget;\n const content = activePopovers.get(popoverId);\n \n // If we are directly hovering over the content, do not close\n if (content && content.contains(related)) {\n return;\n }\n \n // Get hover out delay from template or use default\n const hoverOutDelay = content ? \n (parseInt(content.dataset.popoverHoverOutDelay) || 200) : 200;\n \n leaveTimeout = setTimeout(() => {\n if (activePopovers.has(popoverId)) {\n const popover = activePopovers.get(popoverId);\n \n // Apply exit animation\n popover.classList.remove('popover-animate-in');\n popover.classList.add('popover-animate-out');\n \n // Wait for animation to complete before removing\n setTimeout(() => {\n popover.remove();\n activePopovers.delete(popoverId);\n }, 100);\n }\n }, hoverOutDelay);\n });\n }\n }\n \n // Set up handlers for each trigger\n triggers.forEach(setupTrigger);\n \n // Scroll handler for all popovers\n window.addEventListener('scroll', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n }, { passive: true });\n \n // Resize handler\n window.addEventListener('resize', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n });\n \n // Find all scrollable parent elements and add scroll handlers\n function setupScrollHandlers() {\n const scrollableElements = new Set();\n \n // Find scrollable parents for each trigger\n triggers.forEach(trigger => {\n let element = trigger.parentElement;\n \n while (element) {\n const style = window.getComputedStyle(element);\n const overflow = style.overflow + style.overflowY + style.overflowX;\n \n if (overflow.includes('scroll') || overflow.includes('auto') || \n element.scrollHeight > element.clientHeight) {\n scrollableElements.add(element);\n }\n \n element = element.parentElement;\n }\n });\n \n // Scroll handler for each scrollable element\n scrollableElements.forEach(element => {\n element.addEventListener('scroll', () => {\n activePopovers.forEach((content, popoverId) => {\n const trigger = document.querySelector(`[data-popover-trigger][data-popover-for=\"${popoverId}\"]`);\n if (trigger) {\n positionPopover(trigger, content);\n }\n });\n }, { passive: true });\n });\n }\n \n setupScrollHandlers();\n });\n ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/eslint.config.js b/eslint.config.js index 1ed09a1e..8478e824 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -12,11 +12,6 @@ module.exports = [ }, "rules": { ...htmlPlugin.configs.recommended.rules, - "@html-eslint/element-newline": "off", - "@html-eslint/indent": "off", - "@html-eslint/attrs-newline": "off", - "@html-eslint/attrs-newline": "off", - "@html-eslint/no-extra-spacing-attrs": "off", } }, ] \ No newline at end of file diff --git a/internal/ui/showcase/popover_default.templ b/internal/ui/showcase/popover_default.templ index e39eabf5..40a1d657 100644 --- a/internal/ui/showcase/popover_default.templ +++ b/internal/ui/showcase/popover_default.templ @@ -5,6 +5,7 @@ import ( "github.com/axzilla/templui/component/input" "github.com/axzilla/templui/component/label" "github.com/axzilla/templui/component/popover" + "github.com/axzilla/templui/util" ) templ PopoverDefault() { @@ -27,6 +28,7 @@ templ PopoverDefault() { } templ PopoverContent() { + {{ var id = util.RandomID() }}

Dimensions

@@ -35,12 +37,12 @@ templ PopoverContent() {
@label.Label(label.Props{ - For: "width", + For: "width" + id, }) { Width } @input.Input(input.Props{ - ID: "width", + ID: "width" + id, Placeholder: "Width", Value: "100%", Class: "col-span-2", @@ -48,12 +50,12 @@ templ PopoverContent() {
@label.Label(label.Props{ - For: "height", + For: "height" + id, }) { Height } @input.Input(input.Props{ - ID: "height", + ID: "height" + id, Placeholder: "Height", Value: "100%", Class: "col-span-2",