entasis 0.11.0 → 0.12.0
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/README.md +1 -1
- package/dist/attachments/disclosurePanel.svelte.d.ts +84 -0
- package/dist/attachments/disclosurePanel.svelte.js +277 -0
- package/dist/attachments/portal.d.ts +17 -1
- package/dist/attachments/portal.js +39 -2
- package/dist/attachments/spinnerOverlay.svelte.js +12 -0
- package/dist/attachments/transitionSize.d.ts +6 -0
- package/dist/attachments/transitionSize.js +30 -0
- package/dist/components/AIAskUserQuestion/AIAskUserQuestion.svelte +131 -17
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionFileStep.svelte +26 -6
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionFileStep.svelte.d.ts +6 -0
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionFooter.svelte +27 -53
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionFooter.svelte.d.ts +3 -4
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionHeader.svelte +19 -16
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionStep.svelte +180 -21
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionStep.svelte.d.ts +9 -1
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionSummary.svelte +56 -0
- package/dist/components/AIAskUserQuestion/AIAskUserQuestionSummary.svelte.d.ts +4 -0
- package/dist/components/AIAskUserQuestion/aiAskUserQuestion.mcp.d.ts +1 -1
- package/dist/components/AIAskUserQuestion/aiAskUserQuestion.mcp.js +26 -8
- package/dist/components/AIAskUserQuestion/aiAskUserQuestion.props.d.ts +62 -5
- package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.d.ts +42 -0
- package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.js +53 -12
- package/dist/components/AIAskUserQuestion/aiAskUserQuestionAnswers.d.ts +17 -1
- package/dist/components/AIAskUserQuestion/aiAskUserQuestionAnswers.js +56 -8
- package/dist/components/AIAskUserQuestion/index.d.ts +3 -1
- package/dist/components/AIAskUserQuestion/index.js +2 -0
- package/dist/components/AIAskUserQuestion/schemas.d.ts +44 -0
- package/dist/components/AIAskUserQuestion/schemas.js +10 -3
- package/dist/components/AIChat/AIChat.svelte +10 -0
- package/dist/components/AIChat/AIChat.svelte.d.ts +2 -2
- package/dist/components/AIChat/AIChatComposerSurface.svelte +23 -5
- package/dist/components/AIChat/AIChatComposerSurface.svelte.d.ts +5 -0
- package/dist/components/AIChat/AIChatSkeleton.svelte +29 -37
- package/dist/components/AIChat/AIChatSurface.svelte +30 -2
- package/dist/components/AIChat/AIChatSurface.svelte.d.ts +1 -1
- package/dist/components/AIChat/AIChatThreadSurface.svelte +11 -1
- package/dist/components/AIChat/AIChatThreadSurface.svelte.d.ts +3 -1
- package/dist/components/AIChat/aiChat.mcp.d.ts +1 -1
- package/dist/components/AIChat/aiChat.mcp.js +31 -15
- package/dist/components/AIChat/aiChat.props.d.ts +36 -10
- package/dist/components/AIChat/aiChat.theme.d.ts +9 -0
- package/dist/components/AIChat/aiChat.theme.js +21 -4
- package/dist/components/AIChat/aiChatSkeleton.props.d.ts +5 -0
- package/dist/components/AIChat/index.d.ts +1 -1
- package/dist/components/AIComposer/AIComposer.svelte +102 -5
- package/dist/components/AIComposer/AIComposer.svelte.d.ts +1 -0
- package/dist/components/AIComposer/AIComposerFooter.svelte +54 -12
- package/dist/components/AIComposer/AIComposerFooter.svelte.d.ts +2 -0
- package/dist/components/AIComposer/AIComposerQueue.svelte +8 -3
- package/dist/components/AIComposer/aiComposer.editor.theme.js +13 -2
- package/dist/components/AIComposer/aiComposer.mcp.d.ts +1 -1
- package/dist/components/AIComposer/aiComposer.mcp.js +15 -7
- package/dist/components/AIComposer/aiComposer.props.d.ts +27 -7
- package/dist/components/AIComposer/aiComposer.theme.d.ts +42 -3
- package/dist/components/AIComposer/aiComposer.theme.js +37 -5
- package/dist/components/AIComposer/aiComposerFileController.svelte.d.ts +20 -0
- package/dist/components/AIComposer/aiComposerFileController.svelte.js +75 -9
- package/dist/components/AIComposer/aiComposerSourceAdapter.js +22 -4
- package/dist/components/AIComposer/aiComposerSubmitController.svelte.d.ts +12 -0
- package/dist/components/AIComposer/aiComposerSubmitController.svelte.js +16 -6
- package/dist/components/AIContext/AIContext.svelte +7 -3
- package/dist/components/AIContext/aiContext.mcp.d.ts +1 -1
- package/dist/components/AIContext/aiContext.mcp.js +1 -1
- package/dist/components/AIContext/aiContext.props.d.ts +4 -1
- package/dist/components/AIContext/aiContext.theme.d.ts +3 -0
- package/dist/components/AIContext/aiContext.theme.js +7 -2
- package/dist/components/AIConversation/AIConversation.svelte.d.ts +2 -2
- package/dist/components/AIFilePreview/aiFilePreview.theme.js +1 -1
- package/dist/components/AIMarker/AIMarker.svelte +2 -0
- package/dist/components/AIMarker/aiMarker.mcp.d.ts +1 -1
- package/dist/components/AIMarker/aiMarker.mcp.js +2 -0
- package/dist/components/AIMarker/aiMarker.props.d.ts +3 -0
- package/dist/components/AIMarker/aiMarker.theme.js +2 -2
- package/dist/components/AIMessage/AIMessage.svelte +38 -16
- package/dist/components/AIMessage/aiMessage.mcp.d.ts +1 -1
- package/dist/components/AIMessage/aiMessage.mcp.js +20 -6
- package/dist/components/AIMessage/aiMessage.props.d.ts +18 -2
- package/dist/components/AIMessage/aiMessage.theme.d.ts +51 -6
- package/dist/components/AIMessage/aiMessage.theme.js +91 -32
- package/dist/components/AIMessageActions/AIMessageActions.svelte +19 -9
- package/dist/components/AIMessageActions/aiMessageActions.mcp.d.ts +1 -1
- package/dist/components/AIMessageActions/aiMessageActions.mcp.js +11 -3
- package/dist/components/AIMessageActions/aiMessageActions.theme.js +36 -9
- package/dist/components/AIModelSelector/AIModelSelector.svelte +25 -10
- package/dist/components/AIModelSelector/aiModelSelector.mcp.d.ts +1 -1
- package/dist/components/AIModelSelector/aiModelSelector.mcp.js +1 -1
- package/dist/components/AIModelSelector/aiModelSelector.theme.d.ts +3 -0
- package/dist/components/AIModelSelector/aiModelSelector.theme.js +7 -3
- package/dist/components/AIReasoning/AIReasoning.svelte +135 -38
- package/dist/components/AIReasoning/aiReasoning.mcp.d.ts +1 -1
- package/dist/components/AIReasoning/aiReasoning.mcp.js +11 -5
- package/dist/components/AIReasoning/aiReasoning.props.d.ts +15 -4
- package/dist/components/AIReasoning/aiReasoning.theme.d.ts +45 -0
- package/dist/components/AIReasoning/aiReasoning.theme.js +47 -7
- package/dist/components/AISuggestion/AISuggestion.svelte +2 -1
- package/dist/components/AISuggestion/AISuggestions.svelte +2 -1
- package/dist/components/AISuggestion/aiSuggestion.mcp.d.ts +1 -1
- package/dist/components/AISuggestion/aiSuggestion.mcp.js +8 -1
- package/dist/components/AISuggestion/aiSuggestion.props.d.ts +4 -1
- package/dist/components/AISuggestion/aiSuggestion.theme.js +1 -1
- package/dist/components/AISuggestion/aiSuggestions.props.d.ts +7 -0
- package/dist/components/AIThread/AIThread.svelte +378 -95
- package/dist/components/AIThread/AIThreadAskUserQuestion.svelte +1 -0
- package/dist/components/AIThread/AIThreadItems.svelte +266 -64
- package/dist/components/AIThread/AIThreadItems.svelte.d.ts +7 -3
- package/dist/components/AIThread/AIThreadMarker.svelte +8 -1
- package/dist/components/AIThread/AIThreadMarker.svelte.d.ts +1 -0
- package/dist/components/AIThread/aiThread.mcp.d.ts +1 -1
- package/dist/components/AIThread/aiThread.mcp.js +34 -20
- package/dist/components/AIThread/aiThread.props.d.ts +73 -8
- package/dist/components/AIThread/aiThread.theme.d.ts +78 -0
- package/dist/components/AIThread/aiThread.theme.js +108 -9
- package/dist/components/AIThread/index.d.ts +1 -1
- package/dist/components/AIThread/threadAskUserQuestion.d.ts +4 -1
- package/dist/components/AIThread/threadAskUserQuestion.js +8 -4
- package/dist/components/AIThread/threadRenderItems.d.ts +74 -3
- package/dist/components/AIThread/threadRenderItems.js +265 -77
- package/dist/components/AIThread/threadScrollController.d.ts +0 -8
- package/dist/components/AIThread/threadScrollController.js +2 -39
- package/dist/components/AIThread/threadTools.d.ts +11 -0
- package/dist/components/AIThread/threadTools.js +79 -0
- package/dist/components/AIThreadToc/AIThreadToc.svelte +188 -18
- package/dist/components/AIThreadToc/AIThreadTocPreview.svelte +25 -2
- package/dist/components/AIThreadToc/AIThreadTocPreview.svelte.d.ts +3 -0
- package/dist/components/AIThreadToc/aiThreadToc.d.ts +4 -2
- package/dist/components/AIThreadToc/aiThreadToc.js +17 -5
- package/dist/components/AIThreadToc/aiThreadToc.mcp.d.ts +1 -1
- package/dist/components/AIThreadToc/aiThreadToc.mcp.js +13 -3
- package/dist/components/AIThreadToc/aiThreadToc.props.d.ts +11 -0
- package/dist/components/AIThreadToc/aiThreadToc.theme.d.ts +3 -0
- package/dist/components/AIThreadToc/aiThreadToc.theme.js +15 -6
- package/dist/components/AITool/AITool.svelte +56 -21
- package/dist/components/AITool/AIToolCallList.svelte +79 -29
- package/dist/components/AITool/AIToolCallList.svelte.d.ts +6 -2
- package/dist/components/AITool/AIToolStatusMark.svelte +52 -0
- package/dist/components/AITool/AIToolStatusMark.svelte.d.ts +14 -0
- package/dist/components/AITool/AIToolValueSection.svelte +126 -28
- package/dist/components/AITool/AIToolValueSection.svelte.d.ts +6 -2
- package/dist/components/AITool/AIToolValueTree.svelte +11 -16
- package/dist/components/AITool/AIToolValueTree.svelte.d.ts +2 -3
- package/dist/components/AITool/aiTool.mcp.d.ts +1 -1
- package/dist/components/AITool/aiTool.mcp.js +36 -8
- package/dist/components/AITool/aiTool.props.d.ts +52 -6
- package/dist/components/AITool/aiTool.theme.d.ts +117 -39
- package/dist/components/AITool/aiTool.theme.js +144 -140
- package/dist/components/AITool/aiToolClock.svelte.d.ts +18 -0
- package/dist/components/AITool/aiToolClock.svelte.js +62 -0
- package/dist/components/AITool/aiToolPrimitiveThemes.d.ts +0 -2
- package/dist/components/AITool/aiToolPrimitiveThemes.js +0 -10
- package/dist/components/AITool/index.d.ts +2 -1
- package/dist/components/AITool/index.js +1 -0
- package/dist/components/AITool/toolRendering.d.ts +33 -1
- package/dist/components/AITool/toolRendering.js +179 -15
- package/dist/components/AITool/toolValueTree.d.ts +14 -1
- package/dist/components/AITool/toolValueTree.js +126 -27
- package/dist/components/Accordion/Accordion.svelte +109 -109
- package/dist/components/Accordion/Accordion.svelte.d.ts +0 -1
- package/dist/components/Accordion/AccordionPanel.svelte +64 -0
- package/dist/components/Accordion/AccordionPanel.svelte.d.ts +20 -0
- package/dist/components/Accordion/accordion.attributes.d.ts +24 -0
- package/dist/components/Accordion/accordion.attributes.js +20 -0
- package/dist/components/Accordion/accordion.mcp.d.ts +1 -1
- package/dist/components/Accordion/accordion.mcp.js +78 -22
- package/dist/components/Accordion/accordion.props.d.ts +54 -10
- package/dist/components/Accordion/accordion.theme.d.ts +3 -0
- package/dist/components/Accordion/accordion.theme.js +4 -0
- package/dist/components/Accordion/index.d.ts +1 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/AudioPlayer/audioPlayerVolumeControl.slider.theme.d.ts +31 -1
- package/dist/components/Avatar/Avatar.svelte +60 -10
- package/dist/components/Avatar/AvatarGroup.svelte +9 -0
- package/dist/components/Avatar/avatar.mcp.d.ts +1 -1
- package/dist/components/Avatar/avatar.mcp.js +13 -5
- package/dist/components/Avatar/avatar.props.d.ts +28 -1
- package/dist/components/Avatar/avatar.theme.js +3 -3
- package/dist/components/Avatar/index.d.ts +1 -1
- package/dist/components/Breadcrumbs/breadcrumbs.mcp.d.ts +1 -1
- package/dist/components/Breadcrumbs/breadcrumbs.mcp.js +1 -1
- package/dist/components/Button/Button.svelte +35 -15
- package/dist/components/Button/button.mcp.d.ts +1 -1
- package/dist/components/Button/button.mcp.js +8 -4
- package/dist/components/Button/button.props.d.ts +23 -8
- package/dist/components/Button/button.theme.d.ts +12 -0
- package/dist/components/Button/button.theme.js +17 -4
- package/dist/components/ButtonGroup/buttonGroup.mcp.d.ts +1 -1
- package/dist/components/ButtonGroup/buttonGroup.mcp.js +1 -1
- package/dist/components/ButtonGroup/buttonGroup.props.d.ts +4 -1
- package/dist/components/Collapsible/Collapsible.svelte +125 -19
- package/dist/components/Collapsible/collapsible.attributes.d.ts +21 -0
- package/dist/components/Collapsible/collapsible.attributes.js +17 -0
- package/dist/components/Collapsible/collapsible.mcp.d.ts +1 -1
- package/dist/components/Collapsible/collapsible.mcp.js +62 -12
- package/dist/components/Collapsible/collapsible.props.d.ts +39 -8
- package/dist/components/Collapsible/collapsible.theme.js +3 -1
- package/dist/components/Collapsible/index.d.ts +1 -0
- package/dist/components/Collapsible/index.js +1 -0
- package/dist/components/Command/Command.svelte +56 -14
- package/dist/components/Command/command.mcp.d.ts +1 -1
- package/dist/components/Command/command.mcp.js +12 -6
- package/dist/components/Command/command.props.d.ts +39 -6
- package/dist/components/Command/command.state.svelte.d.ts +40 -11
- package/dist/components/Command/command.state.svelte.js +75 -28
- package/dist/components/Command/command.theme.js +4 -3
- package/dist/components/Confirmation/Confirmation.svelte +72 -31
- package/dist/components/Confirmation/confirmation.mcp.d.ts +1 -1
- package/dist/components/Confirmation/confirmation.mcp.js +5 -4
- package/dist/components/ContextMenu/ContextMenu.svelte +126 -16
- package/dist/components/ContextMenu/contextMenu.mcp.d.ts +1 -1
- package/dist/components/ContextMenu/contextMenu.mcp.js +10 -7
- package/dist/components/ContextMenu/contextMenu.props.d.ts +13 -4
- package/dist/components/ContextMenu/contextMenu.theme.d.ts +3 -3
- package/dist/components/ContextMenu/contextMenu.theme.js +3 -2
- package/dist/components/DataTable/DataTable.svelte +4 -9
- package/dist/components/DataTable/DataTableEditor.svelte +5 -0
- package/dist/components/DataTable/DataTableFilter.svelte +1 -0
- package/dist/components/DataTable/DataTableToolbar.svelte +1 -0
- package/dist/components/DataTable/dataTable.mcp.d.ts +1 -1
- package/dist/components/DataTable/dataTable.mcp.js +4 -2
- package/dist/components/DataTable/dataTable.theme.d.ts +0 -3
- package/dist/components/DataTable/dataTable.theme.js +9 -6
- package/dist/components/Dialog/Dialog.svelte +120 -35
- package/dist/components/Dialog/Dialog.svelte.d.ts +1 -1
- package/dist/components/Dialog/DialogBackdrop.svelte +21 -1
- package/dist/components/Dialog/dialog.api.d.ts +65 -0
- package/dist/components/Dialog/dialog.api.js +1 -0
- package/dist/components/Dialog/dialog.attributes.d.ts +23 -0
- package/dist/components/Dialog/dialog.attributes.js +19 -0
- package/dist/components/Dialog/dialog.indent.d.ts +6 -0
- package/dist/components/Dialog/dialog.indent.js +16 -0
- package/dist/components/Dialog/dialog.mcp.d.ts +1 -1
- package/dist/components/Dialog/dialog.mcp.js +195 -22
- package/dist/components/Dialog/dialog.props.d.ts +102 -19
- package/dist/components/Dialog/dialog.snap.d.ts +40 -0
- package/dist/components/Dialog/dialog.snap.js +78 -0
- package/dist/components/Dialog/dialog.state.svelte.d.ts +122 -10
- package/dist/components/Dialog/dialog.state.svelte.js +525 -66
- package/dist/components/Dialog/dialog.theme.d.ts +48 -0
- package/dist/components/Dialog/dialog.theme.js +32 -9
- package/dist/components/Dialog/index.d.ts +4 -1
- package/dist/components/Dialog/index.js +1 -0
- package/dist/components/DocumentViewer/DocumentSearchControl.svelte +5 -3
- package/dist/components/DocumentViewer/documentOutput.js +2 -1
- package/dist/components/FloatingWindow/FloatingWindow.svelte +20 -32
- package/dist/components/FloatingWindow/FloatingWindow.svelte.d.ts +1 -1
- package/dist/components/FloatingWindow/floatingWindow.mcp.d.ts +1 -1
- package/dist/components/FloatingWindow/floatingWindow.mcp.js +3 -3
- package/dist/components/FloatingWindow/floatingWindow.props.d.ts +9 -4
- package/dist/components/FloatingWindow/floatingWindow.state.svelte.d.ts +8 -2
- package/dist/components/FloatingWindow/floatingWindow.state.svelte.js +18 -7
- package/dist/components/Form/Ask/Ask.svelte +9 -13
- package/dist/components/Form/Ask/ask.mcp.d.ts +1 -1
- package/dist/components/Form/Ask/ask.mcp.js +1 -1
- package/dist/components/Form/Ask/ask.props.d.ts +1 -1
- package/dist/components/Form/Autocomplete/Autocomplete.svelte +418 -0
- package/dist/components/Form/Autocomplete/Autocomplete.svelte.d.ts +4 -0
- package/dist/components/Form/Autocomplete/autocomplete.items.d.ts +30 -0
- package/dist/components/Form/Autocomplete/autocomplete.items.js +64 -0
- package/dist/components/Form/Autocomplete/autocomplete.mcp.d.ts +1 -0
- package/dist/components/Form/Autocomplete/autocomplete.mcp.js +134 -0
- package/dist/components/Form/Autocomplete/autocomplete.props.d.ts +146 -0
- package/dist/components/Form/Autocomplete/autocomplete.props.js +1 -0
- package/dist/components/Form/Autocomplete/autocomplete.theme.d.ts +213 -0
- package/dist/components/Form/Autocomplete/autocomplete.theme.js +119 -0
- package/dist/components/Form/Autocomplete/index.d.ts +3 -0
- package/dist/components/Form/Autocomplete/index.js +2 -0
- package/dist/components/Form/Calendar/CalendarInput.svelte +9 -0
- package/dist/components/Form/Calendar/CalendarMonthYearPicker.svelte +3 -0
- package/dist/components/Form/Calendar/CalendarPrimitive.svelte +5 -0
- package/dist/components/Form/Calendar/calendar.mcp.d.ts +1 -1
- package/dist/components/Form/Calendar/calendar.mcp.js +2 -1
- package/dist/components/Form/Calendar/calendarInput.props.d.ts +2 -0
- package/dist/components/Form/Calendar/useCalendar.svelte.d.ts +3 -0
- package/dist/components/Form/Calendar/useCalendar.svelte.js +3 -0
- package/dist/components/Form/Checkbox/Checkbox.svelte +17 -2
- package/dist/components/Form/Checkbox/checkbox.mcp.d.ts +1 -1
- package/dist/components/Form/Checkbox/checkbox.mcp.js +11 -1
- package/dist/components/Form/Checkbox/checkbox.props.d.ts +12 -1
- package/dist/components/Form/CheckboxesInput/CheckboxLine.svelte +69 -32
- package/dist/components/Form/CheckboxesInput/CheckboxLine.svelte.d.ts +10 -2
- package/dist/components/Form/CheckboxesInput/CheckboxesInput.svelte +123 -74
- package/dist/components/Form/CheckboxesInput/CheckboxesInput.svelte.d.ts +12 -12
- package/dist/components/Form/CheckboxesInput/checkboxesInput.mcp.d.ts +1 -1
- package/dist/components/Form/CheckboxesInput/checkboxesInput.mcp.js +11 -7
- package/dist/components/Form/CheckboxesInput/checkboxesInput.props.d.ts +25 -9
- package/dist/components/Form/CheckboxesInput/checkboxesInput.theme.d.ts +12 -0
- package/dist/components/Form/CheckboxesInput/checkboxesInput.theme.js +9 -4
- package/dist/components/Form/CheckboxesInput/choiceEnter.d.ts +11 -0
- package/dist/components/Form/CheckboxesInput/choiceEnter.js +27 -0
- package/dist/components/Form/ColorInput/ColorInput.svelte +12 -3
- package/dist/components/Form/ColorInput/colorInput.mcp.d.ts +1 -1
- package/dist/components/Form/ColorInput/colorInput.mcp.js +1 -0
- package/dist/components/Form/ColorPicker/ColorPicker.svelte +11 -2
- package/dist/components/Form/ColorPicker/ColorPickerInput.svelte +9 -0
- package/dist/components/Form/ColorPicker/colorPicker.mcp.d.ts +1 -1
- package/dist/components/Form/ColorPicker/colorPicker.mcp.js +1 -0
- package/dist/components/Form/ColorPicker/colorPicker.props.d.ts +2 -0
- package/dist/components/Form/ColorPicker/colorPicker.state.svelte.d.ts +4 -0
- package/dist/components/Form/ColorPicker/colorPicker.state.svelte.js +12 -8
- package/dist/components/Form/Combobox/Combobox.svelte +145 -185
- package/dist/components/Form/Combobox/Combobox.svelte.d.ts +1 -1
- package/dist/components/Form/Combobox/ComboboxPopup.svelte +128 -0
- package/dist/components/Form/Combobox/ComboboxPopup.svelte.d.ts +28 -0
- package/dist/components/Form/Combobox/combobox.attributes.d.ts +34 -0
- package/dist/components/Form/Combobox/combobox.attributes.js +25 -0
- package/dist/components/Form/Combobox/combobox.items.d.ts +28 -0
- package/dist/components/Form/Combobox/combobox.items.js +68 -0
- package/dist/components/Form/Combobox/combobox.mcp.d.ts +1 -1
- package/dist/components/Form/Combobox/combobox.mcp.js +104 -13
- package/dist/components/Form/Combobox/combobox.props.d.ts +113 -19
- package/dist/components/Form/Combobox/combobox.state.svelte.d.ts +137 -0
- package/dist/components/Form/Combobox/combobox.state.svelte.js +375 -0
- package/dist/components/Form/Combobox/combobox.theme.d.ts +63 -0
- package/dist/components/Form/Combobox/combobox.theme.js +37 -1
- package/dist/components/Form/Combobox/index.d.ts +2 -1
- package/dist/components/Form/Combobox/index.js +1 -0
- package/dist/components/Form/DateInput/DateInput.svelte +11 -3
- package/dist/components/Form/DateInput/dateInput.mcp.d.ts +1 -1
- package/dist/components/Form/DateInput/dateInput.mcp.js +5 -0
- package/dist/components/Form/DateSelector/DateSelector.svelte +5 -2
- package/dist/components/Form/DateSelector/DateSelectorInput.svelte +9 -0
- package/dist/components/Form/DateSelector/dateSelector.mcp.d.ts +1 -1
- package/dist/components/Form/DateSelector/dateSelector.mcp.js +2 -2
- package/dist/components/Form/DateSelector/dateSelector.props.d.ts +2 -0
- package/dist/components/Form/Field/Field.svelte +256 -30
- package/dist/components/Form/Field/Field.svelte.d.ts +9 -0
- package/dist/components/Form/Field/FieldGroup.svelte +29 -0
- package/dist/components/Form/Field/FieldGroup.svelte.d.ts +11 -0
- package/dist/components/Form/Field/FieldHiddenInputs.svelte +187 -0
- package/dist/components/Form/Field/FieldHiddenInputs.svelte.d.ts +26 -0
- package/dist/components/Form/Field/field.d.ts +64 -8
- package/dist/components/Form/Field/field.mcp.d.ts +1 -1
- package/dist/components/Form/Field/field.mcp.js +158 -18
- package/dist/components/Form/Field/field.messages.d.ts +47 -0
- package/dist/components/Form/Field/field.messages.js +64 -0
- package/dist/components/Form/Field/field.state.svelte.d.ts +109 -3
- package/dist/components/Form/Field/field.state.svelte.js +508 -16
- package/dist/components/Form/Field/field.theme.d.ts +46 -0
- package/dist/components/Form/Field/field.theme.js +33 -0
- package/dist/components/Form/Field/fieldHiddenInputs.props.d.ts +61 -0
- package/dist/components/Form/Field/fieldHiddenInputs.props.js +1 -0
- package/dist/components/Form/Field/fieldNativeForm.svelte.d.ts +14 -0
- package/dist/components/Form/Field/fieldNativeForm.svelte.js +113 -0
- package/dist/components/Form/Field/index.d.ts +5 -2
- package/dist/components/Form/Field/index.js +1 -0
- package/dist/components/Form/Field/schemas.js +7 -2
- package/dist/components/Form/File/FileInput.svelte +24 -3
- package/dist/components/Form/File/fileInput.mcp.d.ts +1 -1
- package/dist/components/Form/File/fileInput.mcp.js +1 -0
- package/dist/components/Form/Form/Form.svelte +47 -14
- package/dist/components/Form/Form/FormActions.svelte +3 -1
- package/dist/components/Form/Form/FormActions.svelte.d.ts +42 -2
- package/dist/components/Form/Form/FormFieldRenderer.svelte +40 -2
- package/dist/components/Form/Form/FormInputRenderer.svelte +7 -0
- package/dist/components/Form/Form/form.d.ts +35 -6
- package/dist/components/Form/Form/form.mcp.d.ts +1 -1
- package/dist/components/Form/Form/form.mcp.js +113 -13
- package/dist/components/Form/Form/form.props.d.ts +32 -1
- package/dist/components/Form/Form/form.registry.d.ts +2 -2
- package/dist/components/Form/Form/form.registry.js +1 -4
- package/dist/components/Form/Form/form.state.svelte.d.ts +1138 -413
- package/dist/components/Form/Form/form.state.svelte.js +319 -26
- package/dist/components/Form/Form/index.d.ts +3 -1
- package/dist/components/Form/Form/visibility.d.ts +3096 -1831
- package/dist/components/Form/KeyValueInput/KeyValueInput.svelte +22 -10
- package/dist/components/Form/KeyValueInput/keyValueInput.mcp.d.ts +1 -1
- package/dist/components/Form/KeyValueInput/keyValueInput.mcp.js +1 -0
- package/dist/components/Form/MultiStepForm/MultiStepForm.svelte +12 -5
- package/dist/components/Form/MultiStepForm/multiStepForm.mcp.d.ts +1 -1
- package/dist/components/Form/MultiStepForm/multiStepForm.mcp.js +5 -3
- package/dist/components/Form/MultiStepForm/multiStepForm.props.d.ts +5 -0
- package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.d.ts +1022 -408
- package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.js +48 -24
- package/dist/components/Form/NumberInput/NumberInput.svelte +365 -46
- package/dist/components/Form/NumberInput/index.d.ts +1 -1
- package/dist/components/Form/NumberInput/numberInput.mcp.d.ts +1 -1
- package/dist/components/Form/NumberInput/numberInput.mcp.js +55 -30
- package/dist/components/Form/NumberInput/numberInput.props.d.ts +64 -4
- package/dist/components/Form/PasswordInput/Password.svelte +28 -1
- package/dist/components/Form/PasswordInput/index.d.ts +1 -1
- package/dist/components/Form/PasswordInput/passwordInput.mcp.d.ts +1 -1
- package/dist/components/Form/PasswordInput/passwordInput.mcp.js +20 -2
- package/dist/components/Form/PasswordInput/passwordInput.props.d.ts +23 -0
- package/dist/components/Form/PhoneInput/PhoneInput.svelte +11 -4
- package/dist/components/Form/PhoneInput/PhoneInputCountryPicker.svelte +47 -21
- package/dist/components/Form/PhoneInput/phoneInput-cdn.js +2 -1
- package/dist/components/Form/PhoneInput/phoneInput.mcp.d.ts +1 -1
- package/dist/components/Form/PhoneInput/phoneInput.mcp.js +6 -2
- package/dist/components/Form/PhoneInput/phoneInputCountry.d.ts +9 -3
- package/dist/components/Form/PhoneInput/phoneInputCountry.js +34 -24
- package/dist/components/Form/PinInput/PinInput.svelte +44 -9
- package/dist/components/Form/PinInput/PinInputCells.svelte +22 -1
- package/dist/components/Form/PinInput/PinInputCells.svelte.d.ts +1 -0
- package/dist/components/Form/PinInput/index.d.ts +1 -1
- package/dist/components/Form/PinInput/pinInput.mcp.d.ts +1 -1
- package/dist/components/Form/PinInput/pinInput.mcp.js +29 -6
- package/dist/components/Form/PinInput/pinInput.props.d.ts +38 -4
- package/dist/components/Form/PinInput/pinInput.state.svelte.d.ts +41 -0
- package/dist/components/Form/PinInput/pinInput.state.svelte.js +227 -24
- package/dist/components/Form/PinInput/pinInput.theme.d.ts +39 -3
- package/dist/components/Form/PinInput/pinInput.theme.js +27 -1
- package/dist/components/Form/RadioInput/RadioInput.svelte +94 -32
- package/dist/components/Form/RadioInput/RadioInput.svelte.d.ts +12 -12
- package/dist/components/Form/RadioInput/radioInput.mcp.d.ts +1 -1
- package/dist/components/Form/RadioInput/radioInput.mcp.js +12 -9
- package/dist/components/Form/RadioInput/radioInput.props.d.ts +22 -6
- package/dist/components/Form/RadioInput/radioInput.theme.d.ts +12 -0
- package/dist/components/Form/RadioInput/radioInput.theme.js +10 -5
- package/dist/components/Form/RatingInput/RatingInput.svelte +13 -4
- package/dist/components/Form/RatingInput/ratingInput.mcp.d.ts +1 -1
- package/dist/components/Form/RatingInput/ratingInput.mcp.js +3 -3
- package/dist/components/Form/RatingInput/ratingInput.props.d.ts +1 -1
- package/dist/components/Form/Select/Select.svelte +186 -48
- package/dist/components/Form/Select/Select.svelte.d.ts +23 -2
- package/dist/components/Form/Select/SelectOptionRow.svelte +69 -0
- package/dist/components/Form/Select/SelectOptionRow.svelte.d.ts +18 -0
- package/dist/components/Form/Select/index.d.ts +2 -1
- package/dist/components/Form/Select/index.js +1 -0
- package/dist/components/Form/Select/select.align.d.ts +5 -0
- package/dist/components/Form/Select/select.align.js +19 -5
- package/dist/components/Form/Select/select.attributes.d.ts +36 -0
- package/dist/components/Form/Select/select.attributes.js +27 -0
- package/dist/components/Form/Select/select.mcp.d.ts +1 -1
- package/dist/components/Form/Select/select.mcp.js +103 -18
- package/dist/components/Form/Select/select.props.d.ts +87 -10
- package/dist/components/Form/Select/select.state.svelte.d.ts +108 -17
- package/dist/components/Form/Select/select.state.svelte.js +354 -59
- package/dist/components/Form/Select/select.theme.d.ts +21 -0
- package/dist/components/Form/Select/select.theme.js +22 -0
- package/dist/components/Form/Slider/Slider.svelte +54 -14
- package/dist/components/Form/Slider/SliderMarks.svelte +1 -1
- package/dist/components/Form/Slider/SliderThumb.svelte +49 -19
- package/dist/components/Form/Slider/SliderThumb.svelte.d.ts +8 -2
- package/dist/components/Form/Slider/SliderTrack.svelte +33 -12
- package/dist/components/Form/Slider/SliderTrack.svelte.d.ts +6 -2
- package/dist/components/Form/Slider/index.d.ts +1 -1
- package/dist/components/Form/Slider/slider.mcp.d.ts +1 -1
- package/dist/components/Form/Slider/slider.mcp.js +55 -11
- package/dist/components/Form/Slider/slider.props.d.ts +35 -2
- package/dist/components/Form/Slider/slider.state.svelte.d.ts +66 -5
- package/dist/components/Form/Slider/slider.state.svelte.js +273 -49
- package/dist/components/Form/Slider/slider.theme.d.ts +36 -0
- package/dist/components/Form/Slider/slider.theme.js +35 -17
- package/dist/components/Form/Switch/Switch.svelte +61 -38
- package/dist/components/Form/Switch/switch.mcp.d.ts +1 -1
- package/dist/components/Form/Switch/switch.mcp.js +25 -5
- package/dist/components/Form/Switch/switch.props.d.ts +14 -1
- package/dist/components/Form/Switch/switch.theme.d.ts +12 -0
- package/dist/components/Form/Switch/switch.theme.js +8 -3
- package/dist/components/Form/TagGroup/TagGroup.svelte +8 -0
- package/dist/components/Form/TagGroup/tagGroup.mcp.d.ts +1 -1
- package/dist/components/Form/TagGroup/tagGroup.mcp.js +1 -0
- package/dist/components/Form/TagsInput/TagsInput.svelte +277 -275
- package/dist/components/Form/TagsInput/TagsInput.svelte.d.ts +1 -1
- package/dist/components/Form/TagsInput/tagsInput.mcp.d.ts +1 -1
- package/dist/components/Form/TagsInput/tagsInput.mcp.js +31 -11
- package/dist/components/Form/TagsInput/tagsInput.props.d.ts +6 -26
- package/dist/components/Form/TagsInput/tagsInput.theme.d.ts +63 -0
- package/dist/components/Form/TagsInput/tagsInput.theme.js +37 -1
- package/dist/components/Form/TextArea/TextArea.svelte +8 -0
- package/dist/components/Form/TextArea/textArea.mcp.d.ts +1 -1
- package/dist/components/Form/TextArea/textArea.mcp.js +1 -0
- package/dist/components/Form/TextInput/TextInput.svelte +8 -1
- package/dist/components/Form/TextInput/textInput.mcp.d.ts +1 -1
- package/dist/components/Form/TextInput/textInput.mcp.js +5 -0
- package/dist/components/Form/TimeInput/TimeInput.svelte +9 -1
- package/dist/components/Form/TimeInput/timeInput.mcp.d.ts +1 -1
- package/dist/components/Form/TimeInput/timeInput.mcp.js +31 -0
- package/dist/components/Form/VoiceInput/VoiceInput.svelte +10 -2
- package/dist/components/Form/VoiceInput/voiceInput.mcp.d.ts +1 -1
- package/dist/components/Form/VoiceInput/voiceInput.mcp.js +1 -0
- package/dist/components/GanttChart/GanttDependencyControl.svelte +4 -4
- package/dist/components/HoverCard/HoverCard.svelte +100 -10
- package/dist/components/HoverCard/hoverCard.attributes.d.ts +33 -0
- package/dist/components/HoverCard/hoverCard.attributes.js +24 -0
- package/dist/components/HoverCard/hoverCard.mcp.d.ts +1 -1
- package/dist/components/HoverCard/hoverCard.mcp.js +61 -2
- package/dist/components/HoverCard/hoverCard.props.d.ts +19 -0
- package/dist/components/HoverCard/hoverCard.theme.d.ts +12 -0
- package/dist/components/HoverCard/hoverCard.theme.js +9 -2
- package/dist/components/HoverCard/index.d.ts +1 -0
- package/dist/components/HoverCard/index.js +1 -0
- package/dist/components/ImageGallery/imageGallery.state.svelte.d.ts +1 -1
- package/dist/components/ImageZoom/imageZoom.lightbox.js +40 -6
- package/dist/components/ImageZoom/imageZoom.mcp.d.ts +1 -1
- package/dist/components/ImageZoom/imageZoom.mcp.js +3 -3
- package/dist/components/ImageZoom/imageZoom.props.d.ts +10 -4
- package/dist/components/ImageZoom/imageZoom.state.svelte.d.ts +16 -4
- package/dist/components/ImageZoom/imageZoom.state.svelte.js +38 -9
- package/dist/components/Kanban/kanban.theme.js +7 -3
- package/dist/components/Layout/layoutSpacing.d.ts +2 -2
- package/dist/components/LinkPreview/LinkPreview.svelte +7 -1
- package/dist/components/LinkPreview/linkPreview.mcp.d.ts +1 -1
- package/dist/components/LinkPreview/linkPreview.mcp.js +4 -1
- package/dist/components/LinkPreview/linkPreview.props.d.ts +15 -0
- package/dist/components/LinkPreview/linkPreview.theme.d.ts +12 -0
- package/dist/components/LinkPreview/linkPreview.theme.js +9 -2
- package/dist/components/Map/maplibre-cdn.js +3 -2
- package/dist/components/Markdown/markdown.mcp.d.ts +1 -1
- package/dist/components/Markdown/markdown.mcp.js +2 -1
- package/dist/components/Markdown/markdown.theme.js +18 -9
- package/dist/components/MediaVolume/MediaVolumeControl.svelte +4 -3
- package/dist/components/Menu/Menu.svelte +3 -3
- package/dist/components/Menu/Menu.svelte.d.ts +1 -1
- package/dist/components/Menu/MenuCheckboxItem.svelte +87 -0
- package/dist/components/Menu/MenuCheckboxItem.svelte.d.ts +16 -0
- package/dist/components/Menu/MenuFloating.svelte +421 -74
- package/dist/components/Menu/MenuFloating.svelte.d.ts +1 -1
- package/dist/components/Menu/MenuMirroredIcon.svelte +9 -0
- package/dist/components/Menu/MenuMirroredIcon.svelte.d.ts +7 -0
- package/dist/components/Menu/MenuRadioGroup.svelte +102 -0
- package/dist/components/Menu/MenuRadioGroup.svelte.d.ts +18 -0
- package/dist/components/Menu/MenuSearchField.svelte +54 -0
- package/dist/components/Menu/MenuSearchField.svelte.d.ts +20 -0
- package/dist/components/Menu/MenuStacked.svelte +404 -158
- package/dist/components/Menu/MenuStacked.svelte.d.ts +1 -1
- package/dist/components/Menu/MenuStackedBackHeader.svelte +6 -1
- package/dist/components/Menu/index.d.ts +2 -1
- package/dist/components/Menu/index.js +1 -0
- package/dist/components/Menu/menu.attributes.d.ts +37 -0
- package/dist/components/Menu/menu.attributes.js +28 -0
- package/dist/components/Menu/menu.filter.svelte.d.ts +52 -0
- package/dist/components/Menu/menu.filter.svelte.js +143 -0
- package/dist/components/Menu/menu.mcp.d.ts +1 -1
- package/dist/components/Menu/menu.mcp.js +227 -17
- package/dist/components/Menu/menu.platform.d.ts +5 -0
- package/dist/components/Menu/menu.platform.js +11 -0
- package/dist/components/Menu/menu.props.d.ts +172 -9
- package/dist/components/Menu/menu.theme.d.ts +147 -0
- package/dist/components/Menu/menu.theme.js +101 -0
- package/dist/components/Menu/menuTree.d.ts +35 -1
- package/dist/components/Menu/menuTree.js +158 -1
- package/dist/components/MenuBar/menuBar.mcp.d.ts +1 -1
- package/dist/components/MenuBar/menuBar.mcp.js +4 -2
- package/dist/components/MenuBar/menuBar.state.svelte.js +28 -10
- package/dist/components/MenuOption/MenuOption.svelte +5 -1
- package/dist/components/MenuOption/menuOption.mcp.d.ts +1 -1
- package/dist/components/MenuOption/menuOption.mcp.js +8 -0
- package/dist/components/MenuOption/menuOption.props.d.ts +12 -0
- package/dist/components/MenuOption/menuOption.theme.d.ts +18 -0
- package/dist/components/MenuOption/menuOption.theme.js +24 -4
- package/dist/components/Mermaid/mermaid.mcp.d.ts +1 -1
- package/dist/components/Mermaid/mermaid.mcp.js +8 -8
- package/dist/components/Mermaid/mermaid.props.d.ts +3 -4
- package/dist/components/Mermaid/mermaid.state.svelte.d.ts +20 -19
- package/dist/components/Mermaid/mermaid.state.svelte.js +80 -243
- package/dist/components/Mermaid/mermaid.theme.js +26 -1
- package/dist/components/MetadataList/MetadataList.svelte.d.ts +1 -1
- package/dist/components/Meter/Meter.svelte +110 -24
- package/dist/components/Meter/Meter.svelte.d.ts +12 -12
- package/dist/components/Meter/meter.mcp.d.ts +1 -1
- package/dist/components/Meter/meter.mcp.js +23 -37
- package/dist/components/Meter/meter.props.d.ts +36 -44
- package/dist/components/NavigationMenu/NavigationMenu.svelte +181 -0
- package/dist/components/NavigationMenu/NavigationMenu.svelte.d.ts +25 -0
- package/dist/components/NavigationMenu/NavigationMenuContent.svelte +141 -0
- package/dist/components/NavigationMenu/NavigationMenuContent.svelte.d.ts +13 -0
- package/dist/components/NavigationMenu/NavigationMenuTrigger.svelte +75 -0
- package/dist/components/NavigationMenu/NavigationMenuTrigger.svelte.d.ts +13 -0
- package/dist/components/NavigationMenu/index.d.ts +4 -0
- package/dist/components/NavigationMenu/index.js +3 -0
- package/dist/components/NavigationMenu/navigationMenu.attributes.d.ts +24 -0
- package/dist/components/NavigationMenu/navigationMenu.attributes.js +21 -0
- package/dist/components/NavigationMenu/navigationMenu.mcp.d.ts +1 -0
- package/dist/components/NavigationMenu/navigationMenu.mcp.js +138 -0
- package/dist/components/NavigationMenu/navigationMenu.props.d.ts +129 -0
- package/dist/components/NavigationMenu/navigationMenu.props.js +1 -0
- package/dist/components/NavigationMenu/navigationMenu.state.svelte.d.ts +163 -0
- package/dist/components/NavigationMenu/navigationMenu.state.svelte.js +721 -0
- package/dist/components/NavigationMenu/navigationMenu.theme.d.ts +326 -0
- package/dist/components/NavigationMenu/navigationMenu.theme.js +239 -0
- package/dist/components/Overlay/Overlay.svelte +19 -30
- package/dist/components/Overlay/index.d.ts +1 -0
- package/dist/components/Overlay/index.js +1 -0
- package/dist/components/Overlay/overlay.attributes.d.ts +16 -0
- package/dist/components/Overlay/overlay.attributes.js +14 -0
- package/dist/components/Overlay/overlay.mcp.d.ts +1 -1
- package/dist/components/Overlay/overlay.mcp.js +21 -3
- package/dist/components/Overlay/overlay.props.d.ts +8 -4
- package/dist/components/Popover/Popover.svelte +163 -52
- package/dist/components/Popover/Popover.svelte.d.ts +23 -2
- package/dist/components/Popover/PopoverSession.svelte +12 -0
- package/dist/components/Popover/PopoverSession.svelte.d.ts +7 -0
- package/dist/components/Popover/index.d.ts +10 -2
- package/dist/components/Popover/index.js +4 -1
- package/dist/components/Popover/popover.api.d.ts +83 -0
- package/dist/components/Popover/popover.api.js +1 -0
- package/dist/components/Popover/popover.attributes.d.ts +32 -0
- package/dist/components/Popover/popover.attributes.js +28 -0
- package/dist/components/Popover/popover.claims.d.ts +19 -0
- package/dist/components/Popover/popover.claims.js +45 -0
- package/dist/components/Popover/popover.mcp.d.ts +1 -1
- package/dist/components/Popover/popover.mcp.js +163 -31
- package/dist/components/Popover/popover.position.d.ts +226 -0
- package/dist/components/Popover/popover.position.js +402 -0
- package/dist/components/Popover/popover.props.d.ts +179 -24
- package/dist/components/Popover/popover.state.svelte.d.ts +169 -37
- package/dist/components/Popover/popover.state.svelte.js +1034 -194
- package/dist/components/Popover/popover.theme.d.ts +15 -0
- package/dist/components/Popover/popover.theme.js +27 -2
- package/dist/components/PopupMenu/PopupMenu.svelte +193 -22
- package/dist/components/PopupMenu/PopupMenu.svelte.d.ts +2 -2
- package/dist/components/PopupMenu/popupMenu.context.d.ts +42 -0
- package/dist/components/PopupMenu/popupMenu.context.js +52 -0
- package/dist/components/PopupMenu/popupMenu.mcp.d.ts +1 -1
- package/dist/components/PopupMenu/popupMenu.mcp.js +46 -6
- package/dist/components/PopupMenu/popupMenu.props.d.ts +29 -2
- package/dist/components/Progress/Progress.svelte +160 -0
- package/dist/components/Progress/Progress.svelte.d.ts +4 -0
- package/dist/components/Progress/index.d.ts +3 -0
- package/dist/components/Progress/index.js +2 -0
- package/dist/components/Progress/progress.mcp.d.ts +1 -0
- package/dist/components/Progress/progress.mcp.js +101 -0
- package/dist/components/Progress/progress.props.d.ts +79 -0
- package/dist/components/Progress/progress.props.js +1 -0
- package/dist/components/Progress/progress.theme.d.ts +129 -0
- package/dist/components/Progress/progress.theme.js +83 -0
- package/dist/components/ProgressCircle/ProgressCircle.svelte +51 -6
- package/dist/components/ProgressCircle/progressCircle.mcp.d.ts +1 -1
- package/dist/components/ProgressCircle/progressCircle.mcp.js +18 -4
- package/dist/components/ProgressCircle/progressCircle.props.d.ts +32 -2
- package/dist/components/ProgressCircle/progressCircle.theme.d.ts +15 -3
- package/dist/components/ProgressCircle/progressCircle.theme.js +7 -2
- package/dist/components/RichTextInput/RichTextInput.svelte +19 -1
- package/dist/components/RichTextInput/RichTextInputChrome.svelte +5 -1
- package/dist/components/RichTextInput/RichTextInputChrome.svelte.d.ts +2 -0
- package/dist/components/RichTextInput/RichTextInputViewport.svelte +3 -1
- package/dist/components/RichTextInput/RichTextInputViewport.svelte.d.ts +1 -0
- package/dist/components/RichTextInput/richTextInput.mcp.d.ts +1 -1
- package/dist/components/RichTextInput/richTextInput.mcp.js +1 -0
- package/dist/components/RichTextInput/suggestions.js +2 -0
- package/dist/components/ScrollArea/ScrollArea.svelte +166 -27
- package/dist/components/ScrollArea/index.d.ts +2 -1
- package/dist/components/ScrollArea/index.js +1 -0
- package/dist/components/ScrollArea/scrollArea.attributes.d.ts +25 -0
- package/dist/components/ScrollArea/scrollArea.attributes.js +21 -0
- package/dist/components/ScrollArea/scrollArea.mcp.d.ts +1 -1
- package/dist/components/ScrollArea/scrollArea.mcp.js +47 -3
- package/dist/components/ScrollArea/scrollArea.props.d.ts +33 -6
- package/dist/components/ScrollArea/scrollArea.svelte.d.ts +56 -12
- package/dist/components/ScrollArea/scrollArea.svelte.js +281 -71
- package/dist/components/ScrollArea/scrollArea.theme.js +5 -2
- package/dist/components/SegmentedControl/SegmentedControl.svelte +4 -3
- package/dist/components/SegmentedControl/segmentedControl.mcp.d.ts +1 -1
- package/dist/components/SegmentedControl/segmentedControl.mcp.js +3 -2
- package/dist/components/SelectionMenu/SelectionMenu.svelte +4 -2
- package/dist/components/Sidebar/SidebarAction.svelte +13 -3
- package/dist/components/Sidebar/SidebarAction.svelte.d.ts +2 -1
- package/dist/components/Sidebar/SidebarActivityBar.svelte +14 -7
- package/dist/components/Sidebar/SidebarFlyout.svelte +97 -0
- package/dist/components/Sidebar/SidebarFlyout.svelte.d.ts +32 -0
- package/dist/components/Sidebar/SidebarGroup.svelte +39 -15
- package/dist/components/Sidebar/SidebarMenuButton.svelte +6 -3
- package/dist/components/Sidebar/SidebarMenuItem.svelte +134 -31
- package/dist/components/Sidebar/SidebarMenuSubItem.svelte +30 -14
- package/dist/components/Sidebar/SidebarTreeNode.svelte +41 -61
- package/dist/components/Sidebar/index.d.ts +1 -0
- package/dist/components/Sidebar/index.js +1 -0
- package/dist/components/Sidebar/sidebar-position.d.ts +37 -2
- package/dist/components/Sidebar/sidebar-position.js +31 -2
- package/dist/components/Sidebar/sidebar.attributes.d.ts +33 -0
- package/dist/components/Sidebar/sidebar.attributes.js +29 -0
- package/dist/components/Sidebar/sidebar.mcp.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.mcp.js +45 -10
- package/dist/components/Sidebar/sidebar.props.d.ts +28 -7
- package/dist/components/Sidebar/sidebar.theme.d.ts +51 -21
- package/dist/components/Sidebar/sidebar.theme.js +113 -62
- package/dist/components/Sidebar/sidebar.views.svelte.js +11 -18
- package/dist/components/Stepper/Stepper.svelte +2 -0
- package/dist/components/Stepper/stepper.mcp.d.ts +1 -1
- package/dist/components/Stepper/stepper.mcp.js +1 -0
- package/dist/components/Stepper/stepper.props.d.ts +5 -0
- package/dist/components/Stepper/stepper.state.svelte.d.ts +2 -0
- package/dist/components/Stepper/stepper.state.svelte.js +31 -12
- package/dist/components/Tabbar/Tabbar.svelte +55 -16
- package/dist/components/Tabbar/index.d.ts +1 -1
- package/dist/components/Tabbar/tabbar.mcp.d.ts +1 -1
- package/dist/components/Tabbar/tabbar.mcp.js +26 -9
- package/dist/components/Tabbar/tabbar.props.d.ts +34 -5
- package/dist/components/Tabbar/tabbar.selection.svelte.d.ts +79 -0
- package/dist/components/Tabbar/tabbar.selection.svelte.js +99 -0
- package/dist/components/TableOfContents/tableOfContents.state.svelte.js +9 -7
- package/dist/components/Tabs/Tabs.svelte +73 -16
- package/dist/components/Tabs/index.d.ts +2 -1
- package/dist/components/Tabs/tabs.direction.svelte.d.ts +25 -0
- package/dist/components/Tabs/tabs.direction.svelte.js +40 -0
- package/dist/components/Tabs/tabs.mcp.d.ts +1 -1
- package/dist/components/Tabs/tabs.mcp.js +22 -4
- package/dist/components/Tabs/tabs.props.d.ts +39 -12
- package/dist/components/Tabs/tabs.theme.js +3 -1
- package/dist/components/Theme/Theme.svelte +44 -27
- package/dist/components/Theme/helper.d.ts +16 -2
- package/dist/components/Theme/helper.js +46 -4
- package/dist/components/Theme/theme.mcp.d.ts +1 -1
- package/dist/components/Theme/theme.mcp.js +103 -0
- package/dist/components/Theme/theme.props.d.ts +16 -0
- package/dist/components/Theme/theme.state.svelte.d.ts +14 -1
- package/dist/components/Theme/theme.state.svelte.js +18 -1
- package/dist/components/Toast/Toast.svelte +184 -39
- package/dist/components/Toast/Toaster.svelte +14 -10
- package/dist/components/Toast/index.d.ts +1 -0
- package/dist/components/Toast/toast.mcp.d.ts +1 -1
- package/dist/components/Toast/toast.mcp.js +47 -6
- package/dist/components/Toast/toast.state.svelte.d.ts +172 -6
- package/dist/components/Toast/toast.state.svelte.js +513 -68
- package/dist/components/Toast/toast.theme.js +1 -1
- package/dist/components/ToggleButton/ToggleButton.svelte +23 -1
- package/dist/components/ToggleButton/toggleButton.mcp.d.ts +1 -1
- package/dist/components/ToggleButton/toggleButton.mcp.js +3 -1
- package/dist/components/ToggleButton/toggleButton.props.d.ts +13 -1
- package/dist/components/ToggleButton/toggleButton.theme.d.ts +12 -0
- package/dist/components/ToggleButton/toggleButton.theme.js +15 -3
- package/dist/components/ToggleButtonGroup/ToggleButtonGroup.svelte +29 -9
- package/dist/components/ToggleButtonGroup/index.d.ts +1 -1
- package/dist/components/ToggleButtonGroup/toggleButtonGroup.mcp.d.ts +1 -1
- package/dist/components/ToggleButtonGroup/toggleButtonGroup.mcp.js +5 -2
- package/dist/components/ToggleButtonGroup/toggleButtonGroup.props.d.ts +19 -1
- package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.d.ts +12 -0
- package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.js +21 -2
- package/dist/components/ToggleMenu/ToggleMenu.svelte +57 -43
- package/dist/components/ToggleMenu/ToggleMenuGroup.svelte +1 -0
- package/dist/components/ToggleMenu/ToggleMenuMenu.svelte +9 -3
- package/dist/components/ToggleMenu/ToggleMenuRadioGroup.svelte +7 -2
- package/dist/components/ToggleMenu/toggleMenu.mcp.d.ts +1 -1
- package/dist/components/ToggleMenu/toggleMenu.mcp.js +3 -2
- package/dist/components/ToggleMenu/toggleMenu.props.d.ts +4 -1
- package/dist/components/Tooltip/Tooltip.svelte +4 -12
- package/dist/components/Tooltip/TooltipHost.svelte +136 -15
- package/dist/components/Tooltip/index.d.ts +1 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/components/Tooltip/tooltip.attachment.svelte.d.ts +5 -0
- package/dist/components/Tooltip/tooltip.attachment.svelte.js +215 -33
- package/dist/components/Tooltip/tooltip.attributes.d.ts +32 -0
- package/dist/components/Tooltip/tooltip.attributes.js +28 -0
- package/dist/components/Tooltip/tooltip.mcp.d.ts +1 -1
- package/dist/components/Tooltip/tooltip.mcp.js +111 -10
- package/dist/components/Tooltip/tooltip.props.d.ts +33 -2
- package/dist/components/Tooltip/tooltip.surface.d.ts +24 -0
- package/dist/components/Tooltip/tooltip.surface.js +42 -0
- package/dist/components/Tree/TreeContextMenuSurface.svelte +16 -3
- package/dist/components/Utils/BeforeHydratation.svelte +14 -3
- package/dist/components/Utils/BeforeHydratation.svelte.d.ts +2 -0
- package/dist/components/VideoPlayer/VideoPlayer.svelte.d.ts +1 -1
- package/dist/components/VideoPlayer/VideoPlayerSettings.svelte +2 -0
- package/dist/generated/componentAliases.d.ts +3 -0
- package/dist/generated/componentAliases.js +3 -0
- package/dist/generated/componentContract.d.ts +79 -34
- package/dist/generated/componentContract.js +225 -6
- package/dist/generated/componentMcpRegistry.js +6 -0
- package/dist/i18n/ar.js +107 -3
- package/dist/i18n/context.svelte.d.ts +6 -0
- package/dist/i18n/context.svelte.js +12 -0
- package/dist/i18n/de.js +101 -3
- package/dist/i18n/en.d.ts +91 -2
- package/dist/i18n/en.js +101 -3
- package/dist/i18n/es.js +101 -3
- package/dist/i18n/fr.js +101 -3
- package/dist/i18n/ja.js +101 -3
- package/dist/i18n/pt.js +101 -3
- package/dist/i18n/zh.js +101 -3
- package/dist/tailwind/geometry.js +7 -0
- package/dist/tailwind/global.js +31 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/types.mcp.d.ts +1 -1
- package/dist/types/types.mcp.js +23 -0
- package/dist/utils/cspNonce.d.ts +16 -0
- package/dist/utils/cspNonce.js +39 -0
- package/dist/utils/cva/merge.d.ts +5 -1
- package/dist/utils/cva/merge.js +6 -4
- package/dist/utils/focus.d.ts +34 -0
- package/dist/utils/focus.js +93 -0
- package/dist/utils/focusHistory.d.ts +21 -0
- package/dist/utils/focusHistory.js +99 -0
- package/dist/utils/handlers.d.ts +7 -0
- package/dist/utils/handlers.js +14 -0
- package/dist/utils/hoverIntent.d.ts +42 -0
- package/dist/utils/hoverIntent.js +57 -0
- package/dist/utils/id.d.ts +7 -0
- package/dist/utils/id.js +15 -0
- package/dist/utils/layers.svelte.d.ts +32 -4
- package/dist/utils/layers.svelte.js +214 -21
- package/dist/utils/listFilter.d.ts +44 -0
- package/dist/utils/listFilter.js +130 -0
- package/dist/utils/match.d.ts +35 -0
- package/dist/utils/match.js +36 -0
- package/dist/utils/number.d.ts +126 -0
- package/dist/utils/number.js +401 -0
- package/dist/utils/openChange.d.ts +88 -0
- package/dist/utils/openChange.js +71 -0
- package/dist/utils/openLifecycle.svelte.d.ts +41 -0
- package/dist/utils/openLifecycle.svelte.js +134 -0
- package/dist/utils/pointerDrag.d.ts +10 -0
- package/dist/utils/pointerDrag.js +37 -2
- package/dist/utils/pragmaticDragAndDrop.d.ts +2 -1
- package/dist/utils/pragmaticDragAndDrop.js +8 -3
- package/dist/utils/range.d.ts +62 -0
- package/dist/utils/range.js +70 -0
- package/dist/utils/requestNativeSubmit.d.ts +17 -0
- package/dist/utils/requestNativeSubmit.js +47 -0
- package/dist/utils/safeArea.svelte.d.ts +10 -1
- package/dist/utils/safeArea.svelte.js +19 -11
- package/dist/utils/stateAttributes.d.ts +108 -0
- package/dist/utils/stateAttributes.js +78 -0
- package/dist/utils/swipeVelocity.d.ts +32 -0
- package/dist/utils/swipeVelocity.js +59 -0
- package/dist/utils/timer.svelte.d.ts +65 -2
- package/dist/utils/timer.svelte.js +159 -25
- package/dist/utils/trigger.d.ts +41 -0
- package/dist/utils/trigger.js +103 -0
- package/dist/utils/typeahead.d.ts +9 -0
- package/dist/utils/typeahead.js +21 -9
- package/dist/utils/useDndList.svelte.d.ts +1 -1
- package/dist/utils/useDndList.svelte.js +6 -23
- package/dist/utils/useFocusScope.svelte.d.ts +29 -0
- package/dist/utils/useFocusScope.svelte.js +189 -27
- package/dist/utils/useHoverAction.svelte.d.ts +44 -4
- package/dist/utils/useHoverAction.svelte.js +161 -51
- package/dist/utils/useKeyDown.svelte.d.ts +19 -2
- package/dist/utils/useKeyDown.svelte.js +19 -12
- package/dist/utils/useListNavigation.svelte.d.ts +94 -13
- package/dist/utils/useListNavigation.svelte.js +261 -35
- package/dist/utils/useLiveAnnouncer.svelte.d.ts +77 -2
- package/dist/utils/useLiveAnnouncer.svelte.js +119 -2
- package/dist/utils/useNavigation.svelte.d.ts +36 -3
- package/dist/utils/useNavigation.svelte.js +699 -332
- package/dist/utils/usePressAndHold.svelte.d.ts +38 -0
- package/dist/utils/usePressAndHold.svelte.js +191 -0
- package/dist/utils/useScrollLock.svelte.d.ts +20 -1
- package/dist/utils/useScrollLock.svelte.js +54 -13
- package/dist/utils/useSlidingIndicator.svelte.d.ts +2 -0
- package/dist/utils/useSlidingIndicator.svelte.js +27 -5
- package/dist/utils/useTabBridge.svelte.d.ts +20 -0
- package/dist/utils/useTabBridge.svelte.js +109 -0
- package/dist/utils/values.d.ts +15 -0
- package/dist/utils/values.js +49 -0
- package/package.json +31 -2
- package/dist/generated/componentMcpRegistry.d.ts +0 -142
- package/dist/utils/useDrag.svelte.d.ts +0 -11
- package/dist/utils/useDrag.svelte.js +0 -55
|
@@ -1,38 +1,104 @@
|
|
|
1
1
|
import { bind } from '../../utils/state.svelte.js';
|
|
2
2
|
import { Registry } from '../../utils/registry.svelte.js';
|
|
3
|
-
import { getContext, hasContext, onMount, setContext, untrack } from 'svelte';
|
|
3
|
+
import { getContext, hasContext, onDestroy, onMount, setContext, untrack } from 'svelte';
|
|
4
|
+
import { on } from 'svelte/events';
|
|
4
5
|
import { useTheme } from '../Theme/theme.state.svelte.js';
|
|
5
|
-
import { computePosition, autoUpdate, hide, offset, shift, flip } from '@floating-ui/dom';
|
|
6
6
|
import { useScrollLock } from '../../utils/useScrollLock.svelte.js';
|
|
7
7
|
import { useFocusScope } from '../../utils/useFocusScope.svelte.js';
|
|
8
|
+
import { useTabBridge } from '../../utils/useTabBridge.svelte.js';
|
|
9
|
+
import { composedContains, getDeepActiveElement, isTextField } from '../../utils/focus.js';
|
|
10
|
+
import { provideLayer, useParentLayer } from '../../utils/layers.svelte.js';
|
|
8
11
|
import { useSafeArea } from '../../utils/safeArea.svelte.js';
|
|
9
12
|
import { useHoverAction } from '../../utils/useHoverAction.svelte.js';
|
|
13
|
+
import { useOpenLifecycle } from '../../utils/openLifecycle.svelte.js';
|
|
14
|
+
import { getInteractionType, isOpenChangeDetails, requestOpenChange, resolveOpenChangeDetails } from '../../utils/openChange.js';
|
|
15
|
+
import { focusedElement, triggerActivation, triggerFocusTarget, writePopupAria } from '../../utils/trigger.js';
|
|
16
|
+
import { useDirection } from '../../utils/useDirection.svelte.js';
|
|
17
|
+
import { applyStateAttributes, openStateAttributes, placementAttributes, popupSideAttributes, transitionStatusAttributes } from '../../utils/stateAttributes.js';
|
|
10
18
|
import { usePopoverMotion } from './popover.theme.js';
|
|
19
|
+
import { applyDirectedOffset, claimPopupOpen, claimPopupSide, createPanelPositioner, directedMotion, releasePanelPosition } from './popover.position.js';
|
|
11
20
|
// `bind(this, options)` installs the option properties on the instance; this type-only base
|
|
12
21
|
// class is what declares them to TypeScript. (Merging an empty `interface` into the class
|
|
13
22
|
// would be unsafe declaration merging: the interface promises members the class never defines.)
|
|
14
23
|
const PopoverOptionsBase = class {
|
|
15
24
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/** The role a non-dialog popup's content element carries, by `haspopup`. */
|
|
26
|
+
const POPUP_ROLE = {
|
|
27
|
+
menu: 'menu',
|
|
28
|
+
listbox: 'listbox',
|
|
29
|
+
tree: 'tree',
|
|
30
|
+
grid: 'grid'
|
|
31
|
+
};
|
|
32
|
+
/** How the open state was reached, from the change that opened it. */
|
|
33
|
+
const openReasonOf = (details) => {
|
|
34
|
+
if (details.reason === 'trigger-hover')
|
|
35
|
+
return 'hover';
|
|
36
|
+
const fromTrigger = ['trigger-press', 'trigger-focus', 'list-navigation'];
|
|
37
|
+
if (fromTrigger.includes(details.reason)) {
|
|
38
|
+
return details.interaction === 'keyboard' ? 'keyboard' : 'press';
|
|
39
|
+
}
|
|
40
|
+
return 'programmatic';
|
|
41
|
+
};
|
|
42
|
+
/** How close to the viewport's width a touch-opened panel must be to lock page scroll, in px. */
|
|
43
|
+
const TOUCH_LOCK_MARGIN = 20;
|
|
44
|
+
/** A closed popover's safe area: it has none, so no point is inside it. */
|
|
45
|
+
const CLOSED_SAFE_AREA = {
|
|
46
|
+
containsPoint: () => false,
|
|
47
|
+
updateAreas: () => { }
|
|
26
48
|
};
|
|
27
49
|
export class PopoverState extends PopoverOptionsBase {
|
|
28
|
-
|
|
50
|
+
/** The trigger that opened the popover, while it is open; `null` for a programmatic open. */
|
|
51
|
+
activeTrigger = $state(null);
|
|
52
|
+
/** The most recently attached `reference` / `trigger` element. */
|
|
53
|
+
#latestTrigger = $state(null);
|
|
54
|
+
/** The id of the role owner inside a non-dialog popup (the `role="menu"` element). */
|
|
55
|
+
#popupOwnerId = $state(null);
|
|
56
|
+
/**
|
|
57
|
+
* The trigger the panel anchors to: the one that opened it, else the most recently attached
|
|
58
|
+
* `reference` / `trigger` element.
|
|
59
|
+
*/
|
|
60
|
+
triggerReference = $derived(this.activeTrigger ?? this.#latestTrigger);
|
|
29
61
|
referenceElement = $derived(this.triggerReference || this.externalRef || null);
|
|
30
62
|
dialogElement = $state(null);
|
|
63
|
+
/** The arrow inside the panel (`arrow`); `null` while there is none. */
|
|
64
|
+
arrowElement = $state(null);
|
|
65
|
+
/** The panel element focus moves into (inside `dialogElement`); `null` while it is not mounted. */
|
|
66
|
+
panelElement = $state(null);
|
|
31
67
|
// Applied to the animated panel (not the portaled positioning wrapper) so the scale/fly
|
|
32
68
|
// transition originates from the edge nearest the trigger.
|
|
33
69
|
transformOrigin = $state('center center');
|
|
34
70
|
// Trigger-matched width (fitTrigger), applied to the panel.
|
|
35
71
|
triggerWidth = $state(null);
|
|
72
|
+
/**
|
|
73
|
+
* How the popover was opened: `hover`, `press` (pointer), `keyboard`, or `programmatic`
|
|
74
|
+
* (`open()` from code, the `open` prop, `defaultOpen`). `null` once closed.
|
|
75
|
+
*/
|
|
76
|
+
openReason = $state(null);
|
|
77
|
+
/** The details of the last change that was applied, kept until the next one. */
|
|
78
|
+
lastOpenChange = $state.raw(null);
|
|
79
|
+
/** The open state `setOpen` last applied, to tell a change made from outside. */
|
|
80
|
+
#appliedOpen;
|
|
81
|
+
/** Whether a finger opened the popover (a programmatic open leaves the last change stale). */
|
|
82
|
+
get #openedByTouch() {
|
|
83
|
+
return this.openReason === 'press' && this.lastOpenChange?.interaction === 'touch';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Where the floating panel was last placed: the side it sits on (logical when a logical side
|
|
87
|
+
* was requested, `none` when `positionPanel` placed it), its alignment, and whether its anchor
|
|
88
|
+
* is scrolled out of view. `null` until the first placement lands and once the panel unmounts.
|
|
89
|
+
*/
|
|
90
|
+
placement = $state(null);
|
|
91
|
+
/**
|
|
92
|
+
* The panel's styling hooks: `data-open` / `data-closed`, `data-entering` / `data-exiting`,
|
|
93
|
+
* `data-side`, `data-align` and `data-anchor-hidden` (see `popoverDataAttributes`).
|
|
94
|
+
*/
|
|
95
|
+
panelAttributes = $derived({
|
|
96
|
+
...openStateAttributes(this.isOpen),
|
|
97
|
+
...transitionStatusAttributes(this.status),
|
|
98
|
+
...placementAttributes(this.placement
|
|
99
|
+
? { side: this.placement.side, align: this.placement.align ?? undefined }
|
|
100
|
+
: undefined, { anchorHidden: this.placement?.anchorHidden })
|
|
101
|
+
});
|
|
36
102
|
parent = getContext('popover');
|
|
37
103
|
// Nested popovers join while they mount and leave when torn down; see `Registry`.
|
|
38
104
|
#children = new Registry();
|
|
@@ -40,24 +106,65 @@ export class PopoverState extends PopoverOptionsBase {
|
|
|
40
106
|
return this.#children.items;
|
|
41
107
|
}
|
|
42
108
|
hasChildOpen = $derived(this.children.some((d) => d.isOpen));
|
|
43
|
-
hasTransitioned = $state(false);
|
|
44
109
|
theme = useTheme();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Open → entering → open → exiting → closed; completes even when no transition plays.
|
|
112
|
+
* Created in the constructor: it reads the options as it starts, after `bind` installs them.
|
|
113
|
+
*/
|
|
114
|
+
lifecycle;
|
|
115
|
+
/** Where the panel is in its open/close lifecycle; see `PopoverApi.status`. */
|
|
116
|
+
get status() {
|
|
117
|
+
return this.lifecycle.status;
|
|
118
|
+
}
|
|
119
|
+
/** @deprecated Read `status === 'open'`; kept for one minor. */
|
|
120
|
+
get hasTransitioned() {
|
|
121
|
+
return this.lifecycle.status === 'open';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* What only an open popover needs, while it is open or closing; see `openSession`. A closed
|
|
125
|
+
* popover (every Select, date input and row menu on a page) builds none of it.
|
|
126
|
+
*/
|
|
127
|
+
#session = $state.raw(null);
|
|
128
|
+
/** `#session` as last written, for teardowns, which must not read `$state`. */
|
|
129
|
+
#currentSession = null;
|
|
130
|
+
/** The layer this popover renders inside (a Dialog, a parent menu), read when it opens. */
|
|
131
|
+
#parentLayer = useParentLayer();
|
|
132
|
+
/** The popover's layer while it is open or closing, else `null`. */
|
|
133
|
+
get layer() {
|
|
134
|
+
return this.#session?.layer ?? null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Whether no open layer sits above this popover, except a tooltip: a tooltip never takes focus
|
|
138
|
+
* or holds a control, so one showing over a button in the panel (or over the trigger) must not
|
|
139
|
+
* count as something that took over from it. `false` while closed.
|
|
140
|
+
*/
|
|
141
|
+
get isTopLayer() {
|
|
142
|
+
return this.#session?.isTopLayer ?? false;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The safe area around the trigger and the panel (menus ask it whether the pointer is on its way
|
|
146
|
+
* to an open submenu). A closed popover has none: no point is inside it.
|
|
147
|
+
*/
|
|
148
|
+
get safeArea() {
|
|
149
|
+
return this.#session?.safeArea ?? CLOSED_SAFE_AREA;
|
|
150
|
+
}
|
|
57
151
|
computedSize = $derived(this.theme.resolveResponsiveProps(this.size, 'normal'));
|
|
58
152
|
// `inline` wins over `mobileSheet`: an in-flow panel never becomes a sheet.
|
|
59
153
|
isMobileSheet = $derived(!this.inline && !!this.mobileSheet && this.theme.isMobile);
|
|
60
154
|
computedMode = $derived(this.inline ? 'inline' : this.isMobileSheet ? 'mobileSheet' : 'floating');
|
|
155
|
+
/**
|
|
156
|
+
* Whether the panel is modal right now: a floating panel with `modal` contains Tab and makes the
|
|
157
|
+
* page behind it `inert`. An inline panel sits in the page and never is; the mobile sheet is a
|
|
158
|
+
* modal Dialog of its own.
|
|
159
|
+
*/
|
|
160
|
+
isModal = $derived(!!this.modal && this.computedMode === 'floating');
|
|
161
|
+
/**
|
|
162
|
+
* Whether the panel holds dialog content. Menus, listboxes, trees and grids render a plain
|
|
163
|
+
* wrapper instead of an unnamed `<dialog>`, and their trigger controls the role owner inside.
|
|
164
|
+
*/
|
|
165
|
+
isDialogPopup = $derived((this.haspopup ?? 'dialog') === 'dialog');
|
|
166
|
+
/** The id of the element `aria-controls` points at while open. */
|
|
167
|
+
controlsId = $derived(this.isDialogPopup ? this.id : (this.#popupOwnerId ?? this.id));
|
|
61
168
|
/**
|
|
62
169
|
* Trigger state in the library's semantic vocabulary: spread on the built-in Button, and
|
|
63
170
|
* written as the matching ARIA attributes by `reference` for a snippet trigger.
|
|
@@ -65,257 +172,990 @@ export class PopoverState extends PopoverOptionsBase {
|
|
|
65
172
|
triggerProps = $derived({
|
|
66
173
|
haspopup: this.haspopup ?? 'dialog',
|
|
67
174
|
expanded: this.isOpen,
|
|
68
|
-
controls: this.isOpen && !this.isMobileSheet ? this.
|
|
69
|
-
});
|
|
70
|
-
// Non-modal: no Tab containment or `inert`; optional initial focus, always restores.
|
|
71
|
-
focusScope = useFocusScope({
|
|
72
|
-
isActive: () => this.isOpen && !this.isMobileSheet && this.layer.isTop,
|
|
73
|
-
trap: () => false,
|
|
74
|
-
initialFocus: () => this.focusOnOpen ?? false,
|
|
75
|
-
returnTo: () => this.triggerReference
|
|
175
|
+
controls: this.isOpen && !this.isMobileSheet ? this.controlsId : undefined
|
|
76
176
|
});
|
|
177
|
+
/**
|
|
178
|
+
* Whether Tab is bridged between the trigger and the portaled panel: a floating dialog popup
|
|
179
|
+
* opened from a trigger, unless `tabBridge` is off. Menus, listboxes and the like manage focus
|
|
180
|
+
* themselves, a modal panel contains Tab on its own, and a panel the pointer merely hovered
|
|
181
|
+
* open is not a Tab destination.
|
|
182
|
+
*/
|
|
183
|
+
get tabBridgeActive() {
|
|
184
|
+
return (this.isOpen &&
|
|
185
|
+
this.tabBridge &&
|
|
186
|
+
!this.isModal &&
|
|
187
|
+
this.computedMode === 'floating' &&
|
|
188
|
+
this.isDialogPopup &&
|
|
189
|
+
this.openReason !== 'hover' &&
|
|
190
|
+
this.isTopLayer &&
|
|
191
|
+
this.placement !== null &&
|
|
192
|
+
this.panelElement !== null &&
|
|
193
|
+
this.#bridgeAnchor() !== null);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Whether focus moving away closes the popover: a floating dialog popup that is not modal (a
|
|
197
|
+
* modal one keeps focus), not opened by the pointer hovering, and `closeOnFocusOut` (by
|
|
198
|
+
* default, `closeOnClickOutside`). Menus and lists steer focus themselves.
|
|
199
|
+
*/
|
|
200
|
+
get closesOnFocusOut() {
|
|
201
|
+
return ((this.closeOnFocusOut ?? this.closeOnClickOutside) &&
|
|
202
|
+
!this.isModal &&
|
|
203
|
+
this.computedMode === 'floating' &&
|
|
204
|
+
this.isDialogPopup &&
|
|
205
|
+
this.openReason !== 'hover');
|
|
206
|
+
}
|
|
77
207
|
// Mode preset from `popoverTheme.motion`, through the override ladder
|
|
78
208
|
// (registry → `setPopoverTheme` → instance `theme.motion` → `transition` prop).
|
|
79
209
|
resolveMotion = usePopoverMotion();
|
|
80
210
|
computedTransition = $derived(this.resolveMotion({ mode: this.computedMode }, { motion: this.motion, transition: this.transition }));
|
|
81
211
|
computedPosition = $derived(this.theme.resolveResponsiveProps(this.position, 'top'));
|
|
82
|
-
// Hook instances
|
|
83
|
-
safeArea = useSafeArea({
|
|
84
|
-
isActive: () => this.isOpen && this.closeOnMouseLeave && this.children.filter((d) => d.isOpen).length === 0,
|
|
85
|
-
callback: () => this.close(),
|
|
86
|
-
offset: 15,
|
|
87
|
-
debug: () => this.debugSafeArea
|
|
88
|
-
});
|
|
89
212
|
hoverAction = useHoverAction({
|
|
90
|
-
isActive: () => this.openOnHover && !this.isOpen,
|
|
91
|
-
onMouseEnter: () => {
|
|
92
|
-
this.
|
|
213
|
+
isActive: () => this.openOnHover && !this.modal && !this.isOpen,
|
|
214
|
+
onMouseEnter: (event) => {
|
|
215
|
+
this.setOpen(true, {
|
|
216
|
+
reason: 'trigger-hover',
|
|
217
|
+
event,
|
|
218
|
+
trigger: this.#hoveredTrigger ?? undefined,
|
|
219
|
+
interaction: 'mouse'
|
|
220
|
+
});
|
|
93
221
|
},
|
|
94
|
-
|
|
222
|
+
// A function, read on each enter: field initialisers run before `bind(this, options)`
|
|
223
|
+
// installs the options, so a plain `this.delay` here would be `undefined` (no delay).
|
|
224
|
+
delay: () => this.delay,
|
|
225
|
+
// Root hover popovers share the warm-up with tooltips and hover cards. Submenus keep their
|
|
226
|
+
// delay: it is what lets the pointer cross sibling rows on the way to an open submenu.
|
|
227
|
+
group: () => (this.openOnHover && !this.parent ? this.theme.hoverIntent : null),
|
|
228
|
+
isOpen: () => this.isOpen,
|
|
229
|
+
contains: (node) => !!this.dialogElement?.contains(node)
|
|
95
230
|
});
|
|
96
231
|
addChild = (child) => () => this.#children.add(child);
|
|
232
|
+
/** The element the panel is anchored to, for its writing direction. */
|
|
233
|
+
#anchorElement = () => {
|
|
234
|
+
const reference = this.referenceElement;
|
|
235
|
+
if (reference instanceof HTMLElement)
|
|
236
|
+
return reference;
|
|
237
|
+
const context = reference?.contextElement;
|
|
238
|
+
return context instanceof HTMLElement ? context : null;
|
|
239
|
+
};
|
|
240
|
+
/** The reading direction logical sides and start/end alignment resolve with. */
|
|
241
|
+
#direction = useDirection(this.#anchorElement);
|
|
97
242
|
constructor(options) {
|
|
98
243
|
super();
|
|
99
244
|
bind(this, options);
|
|
245
|
+
this.lifecycle = useOpenLifecycle({
|
|
246
|
+
isOpen: () => this.isOpen,
|
|
247
|
+
external: () => this.isMobileSheet,
|
|
248
|
+
onAfterOpen: () => this.onAfterOpen?.(this),
|
|
249
|
+
onAfterClose: () => {
|
|
250
|
+
this.#currentSession?.focusScope.restore();
|
|
251
|
+
this.onAfterClose?.(this);
|
|
252
|
+
this.openReason = null;
|
|
253
|
+
this.#setActiveTrigger(null);
|
|
254
|
+
this.#opener = null;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
100
257
|
setContext('popover', this);
|
|
258
|
+
// Layers registered inside the panel (a nested popover, a dialog it opens) sit above this
|
|
259
|
+
// popover's layer, which exists only while it is open.
|
|
260
|
+
provideLayer(() => this.#currentSession?.layer ?? null);
|
|
261
|
+
// The parent registers its children whatever their payload type.
|
|
101
262
|
if (this.parent)
|
|
102
263
|
onMount(this.parent.addChild(this));
|
|
103
|
-
|
|
104
|
-
|
|
264
|
+
// Details describe the change `setOpen` made: an open state moved from outside (the bound
|
|
265
|
+
// `open` prop) leaves none, so a later close does not read the one that opened it.
|
|
266
|
+
$effect.pre(() => {
|
|
267
|
+
const open = this.isOpen;
|
|
268
|
+
untrack(() => {
|
|
269
|
+
if (this.#appliedOpen !== open)
|
|
270
|
+
this.lastOpenChange = null;
|
|
271
|
+
this.#appliedOpen = open;
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
onDestroy(() => {
|
|
275
|
+
this.#destroyed = true;
|
|
105
276
|
});
|
|
277
|
+
// An open state that did not come through `setOpen` (the `open` prop, `defaultOpen`) is a
|
|
278
|
+
// programmatic open: focus returns to whatever had it when it opened.
|
|
279
|
+
$effect.pre(() => {
|
|
280
|
+
const open = this.isOpen;
|
|
281
|
+
untrack(() => {
|
|
282
|
+
const committed = this.#committed;
|
|
283
|
+
this.#committed = null;
|
|
284
|
+
if (committed === open || !open)
|
|
285
|
+
return;
|
|
286
|
+
this.openReason = 'programmatic';
|
|
287
|
+
this.#opener = focusedElement();
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Whether the open-only machinery is needed: while the popover is open, and until its closing
|
|
293
|
+
* transition has finished. `PopoverSession` is rendered while this holds.
|
|
294
|
+
*/
|
|
295
|
+
get sessionActive() {
|
|
296
|
+
return this.isOpen || this.lifecycle.status !== 'closed';
|
|
106
297
|
}
|
|
107
|
-
|
|
108
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Builds what only an open popover needs: its layer, focus scope, safe area, Tab bridge, scroll
|
|
300
|
+
* lock and focus-out watch, and registers the attached triggers with them. `PopoverSession`
|
|
301
|
+
* calls it during its initialisation while `sessionActive` holds; everything it creates goes
|
|
302
|
+
* with that component.
|
|
303
|
+
*/
|
|
304
|
+
openSession = () => {
|
|
305
|
+
// The mobile sheet delegates to a Dialog, which registers its own layer.
|
|
306
|
+
// An inline panel sits in the flow and is not dismissed by an outside press; Escape still
|
|
307
|
+
// reaches it while it is the top layer.
|
|
308
|
+
const layer = this.theme.layers.register({
|
|
309
|
+
kind: 'popover',
|
|
310
|
+
isOpen: () => this.isOpen && !this.isMobileSheet,
|
|
311
|
+
isModal: () => this.isModal,
|
|
312
|
+
dismissOnEscape: () => this.closeOnEscape,
|
|
313
|
+
dismissOnOutside: () => !this.inline && this.closeOnClickOutside,
|
|
314
|
+
onDismiss: (request) => this.setOpen(false, request),
|
|
315
|
+
state: this,
|
|
316
|
+
// Read here, not from the session component's context, which is this popover's own.
|
|
317
|
+
parent: untrack(this.#parentLayer)
|
|
318
|
+
});
|
|
319
|
+
const isTopLayer = $derived.by(() => {
|
|
320
|
+
const open = this.theme.layers.open;
|
|
321
|
+
const index = open.indexOf(layer);
|
|
322
|
+
if (index < 0)
|
|
323
|
+
return false;
|
|
324
|
+
return open.slice(index + 1).every(({ state }) => {
|
|
325
|
+
// The shared tooltip surface is known by id, so it counts before its panel has
|
|
326
|
+
// mounted: the scope would otherwise release and re-apply `inert` around the tooltip.
|
|
327
|
+
return (state instanceof PopoverState &&
|
|
328
|
+
(`${state.id}-tooltip` === this.theme.tooltipId ||
|
|
329
|
+
!!state.panelElement?.querySelector('[role="tooltip"]')));
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
// Non-modal: no Tab containment or `inert`; optional initial focus. Focus goes back when it
|
|
333
|
+
// was inside the panel, or when a trigger opened the popover (Safari does not focus a button
|
|
334
|
+
// on click, so a press and Escape leave focus on <body>). A popover with neither, such as a
|
|
335
|
+
// combobox list, leaves focus alone, even when the control that kept it blurred on purpose.
|
|
336
|
+
// A floating panel is hidden until its first placement lands, and nothing in it can take
|
|
337
|
+
// focus before then, so initial focus waits for that placement.
|
|
338
|
+
const focusScope = useFocusScope({
|
|
339
|
+
isActive: () => this.isOpen &&
|
|
340
|
+
!this.isMobileSheet &&
|
|
341
|
+
isTopLayer &&
|
|
342
|
+
(this.computedMode !== 'floating' || this.placement !== null),
|
|
343
|
+
trap: () => this.isModal,
|
|
344
|
+
inertSiblings: () => this.isModal,
|
|
345
|
+
initialFocus: () => this.focusOnOpen ?? (this.isModal ? 'first' : false),
|
|
346
|
+
restoreFocus: () => this.#focusEntered || this.activeTrigger !== null,
|
|
347
|
+
returnTo: () => this.#returnTarget(),
|
|
348
|
+
// Focus that moved on by itself (Tab past the end of the panel) is not taken back.
|
|
349
|
+
focusOnClose: () => (this.lastOpenChange?.reason === 'focus-out' ? false : this.focusOnClose),
|
|
350
|
+
closeDetails: () => this.lastOpenChange
|
|
351
|
+
});
|
|
352
|
+
// The safe area tracks every open popover (menus ask it whether the pointer is on its way to
|
|
353
|
+
// an open submenu), but leaving it closes only a popover the pointer opened by hovering: one
|
|
354
|
+
// opened by a press, the keyboard or code stays until it is dismissed.
|
|
355
|
+
const safeArea = useSafeArea({
|
|
356
|
+
isActive: () => this.isOpen && this.closeOnMouseLeave && this.children.every((child) => !child.isOpen),
|
|
357
|
+
callback: (event) => {
|
|
358
|
+
if (this.openReason !== 'hover')
|
|
359
|
+
return;
|
|
360
|
+
this.setOpen(false, { reason: 'trigger-hover', event, interaction: 'mouse' });
|
|
361
|
+
},
|
|
362
|
+
offset: 15,
|
|
363
|
+
debug: () => this.debugSafeArea,
|
|
364
|
+
closeDelay: () => this.closeDelay
|
|
365
|
+
});
|
|
366
|
+
// Every attached trigger counts as inside the layer and anchors the safe area.
|
|
367
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
|
|
368
|
+
const triggers = new Map();
|
|
369
|
+
const session = {
|
|
370
|
+
layer,
|
|
371
|
+
focusScope,
|
|
372
|
+
safeArea,
|
|
373
|
+
get isTopLayer() {
|
|
374
|
+
return isTopLayer;
|
|
375
|
+
},
|
|
376
|
+
addTrigger: (node) => {
|
|
377
|
+
if (triggers.has(node))
|
|
378
|
+
return;
|
|
379
|
+
triggers.set(node, [layer.node(node), safeArea.anchorReference(node)]);
|
|
380
|
+
},
|
|
381
|
+
removeTrigger: (node) => {
|
|
382
|
+
triggers.get(node)?.forEach((off) => off?.());
|
|
383
|
+
triggers.delete(node);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
untrack(() => {
|
|
387
|
+
for (const node of this.#triggers.keys())
|
|
388
|
+
session.addTrigger(node);
|
|
389
|
+
this.#currentSession = session;
|
|
390
|
+
this.#session = session;
|
|
391
|
+
});
|
|
392
|
+
onDestroy(() => {
|
|
393
|
+
for (const node of [...triggers.keys()])
|
|
394
|
+
session.removeTrigger(node);
|
|
395
|
+
if (this.#currentSession !== session)
|
|
396
|
+
return;
|
|
397
|
+
this.#currentSession = null;
|
|
398
|
+
this.#session = null;
|
|
399
|
+
});
|
|
400
|
+
useTabBridge({
|
|
401
|
+
isActive: () => this.tabBridgeActive,
|
|
402
|
+
anchor: this.#bridgeAnchor,
|
|
403
|
+
panel: () => this.panelElement,
|
|
404
|
+
// A trigger inside another popover's panel tabs on within that panel.
|
|
405
|
+
boundary: () => {
|
|
406
|
+
const anchor = this.#bridgeAnchor();
|
|
407
|
+
const parentPanel = this.parent?.panelElement;
|
|
408
|
+
return anchor && parentPanel && parentPanel.contains(anchor) ? parentPanel : undefined;
|
|
409
|
+
},
|
|
410
|
+
// The bridge has already moved focus on; whether that closes the panel is the same
|
|
411
|
+
// `closeOnFocusOut` decision the focus listener below makes.
|
|
412
|
+
onLeave: (event) => {
|
|
413
|
+
if (!this.closesOnFocusOut)
|
|
414
|
+
return;
|
|
415
|
+
void this.setOpen(false, { reason: 'focus-out', event, interaction: 'keyboard' });
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
// Focus that was inside the popover (or on its trigger) moving on closes it. A popover whose
|
|
419
|
+
// panel focus never entered is left to outside presses: Tab, a click or a screen reader's
|
|
420
|
+
// virtual cursor elsewhere on the page only counts once focus has been in the tree. Judged
|
|
421
|
+
// in a microtask, where focus has settled and reactive state is safe to read: `focus()`
|
|
422
|
+
// calls made by a closing popup's teardown dispatch this event in the middle of a flush.
|
|
423
|
+
$effect(() => {
|
|
424
|
+
if (!this.isOpen || !this.closesOnFocusOut)
|
|
425
|
+
return;
|
|
426
|
+
const doc = this.dialogElement?.ownerDocument;
|
|
427
|
+
if (!doc)
|
|
428
|
+
return;
|
|
429
|
+
let within = untrack(() => this.#focusInTree(getDeepActiveElement(doc)));
|
|
430
|
+
let scheduled = false;
|
|
431
|
+
return on(doc, 'focusin', (event) => {
|
|
432
|
+
if (scheduled)
|
|
433
|
+
return;
|
|
434
|
+
scheduled = true;
|
|
435
|
+
queueMicrotask(() => {
|
|
436
|
+
scheduled = false;
|
|
437
|
+
if (!this.isOpen || this.#appliedOpen === false || !this.closesOnFocusOut)
|
|
438
|
+
return;
|
|
439
|
+
const active = getDeepActiveElement(doc);
|
|
440
|
+
if (!active || active === doc.body)
|
|
441
|
+
return;
|
|
442
|
+
if (this.#focusInTree(active)) {
|
|
443
|
+
within = true;
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (!within)
|
|
447
|
+
return;
|
|
448
|
+
within = false;
|
|
449
|
+
this.setOpen(false, { reason: 'focus-out', event, interaction: 'keyboard' });
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
// A touch-opened popover is non-modal and a finger scrolls the page under it, so it locks
|
|
454
|
+
// scroll only when its panel spans the viewport, where there is nothing left to scroll to.
|
|
455
|
+
let panelSpansViewport = $state(false);
|
|
456
|
+
$effect(() => {
|
|
457
|
+
const panel = this.dialogElement;
|
|
458
|
+
if (!panel || !this.#openedByTouch) {
|
|
459
|
+
panelSpansViewport = false;
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const measure = () => {
|
|
463
|
+
const view = panel.ownerDocument.defaultView;
|
|
464
|
+
panelSpansViewport =
|
|
465
|
+
!!view && panel.getBoundingClientRect().width >= view.innerWidth - TOUCH_LOCK_MARGIN;
|
|
466
|
+
};
|
|
467
|
+
measure();
|
|
468
|
+
const observer = new ResizeObserver(measure);
|
|
469
|
+
observer.observe(panel);
|
|
470
|
+
return () => observer.disconnect();
|
|
471
|
+
});
|
|
472
|
+
// A hover-opened popover is a preview the pointer can leave: the page keeps scrolling.
|
|
473
|
+
useScrollLock({
|
|
474
|
+
isActive: () => this.lockScroll &&
|
|
475
|
+
!this.inline &&
|
|
476
|
+
!this.isMobileSheet &&
|
|
477
|
+
!this.parent &&
|
|
478
|
+
this.isOpen &&
|
|
479
|
+
this.openReason !== 'hover' &&
|
|
480
|
+
(!this.#openedByTouch || panelSpansViewport)
|
|
481
|
+
});
|
|
482
|
+
// The point the pointer was at belongs to one opening: a later keyboard open must not reuse it.
|
|
483
|
+
$effect(() => {
|
|
484
|
+
if (!this.isOpen)
|
|
485
|
+
return;
|
|
486
|
+
return () => {
|
|
487
|
+
this.#anchorOffset = null;
|
|
488
|
+
};
|
|
489
|
+
});
|
|
490
|
+
// The trigger (or `ref` element) reports the side its placed panel sits on, so a theme can
|
|
491
|
+
// flatten the corner the panel attaches to.
|
|
492
|
+
$effect(() => {
|
|
493
|
+
const anchor = this.referenceElement;
|
|
494
|
+
if (!(anchor instanceof HTMLElement))
|
|
495
|
+
return;
|
|
496
|
+
const { 'data-popup-side': side } = popupSideAttributes(this.placement?.side);
|
|
497
|
+
claimPopupSide(anchor, this, side ?? null);
|
|
498
|
+
return () => claimPopupSide(anchor, this, null);
|
|
499
|
+
});
|
|
500
|
+
// The element the panel is anchored to (the trigger that opened it, or the `ref` element)
|
|
501
|
+
// carries `data-popup-open` while it is open. Claimed like the side: a menu and its tooltip
|
|
502
|
+
// share a trigger, and the tooltip closing leaves the menu's hook in place.
|
|
503
|
+
$effect(() => {
|
|
504
|
+
const anchor = this.referenceElement;
|
|
505
|
+
if (!(anchor instanceof HTMLElement))
|
|
506
|
+
return;
|
|
507
|
+
claimPopupOpen(anchor, this, this.isOpen);
|
|
508
|
+
return () => claimPopupOpen(anchor, this, false);
|
|
509
|
+
});
|
|
510
|
+
// The panel's open state and transition phase, written from here rather than only by the
|
|
511
|
+
// template: Svelte pauses the effects of a block while its out-transition plays, so the
|
|
512
|
+
// panel's own attributes would stay `data-open` until it is gone. The session lives until
|
|
513
|
+
// the exit ends, so `data-closed` and `data-exiting` reach the closing panel.
|
|
514
|
+
$effect(() => {
|
|
515
|
+
const panel = this.panelElement;
|
|
516
|
+
if (!panel)
|
|
517
|
+
return;
|
|
518
|
+
applyStateAttributes(panel, {
|
|
519
|
+
...openStateAttributes(this.isOpen),
|
|
520
|
+
...transitionStatusAttributes(this.lifecycle.status)
|
|
521
|
+
});
|
|
522
|
+
});
|
|
109
523
|
};
|
|
110
|
-
|
|
111
|
-
|
|
524
|
+
/** Toggles the popover. A press on the trigger of a popover the pointer opened by hovering pins it open instead. */
|
|
525
|
+
toggle = (input) => {
|
|
526
|
+
const details = this.#details(input);
|
|
527
|
+
if (this.isOpen && details.reason === 'trigger-press') {
|
|
528
|
+
const anchor = this.triggerReference;
|
|
529
|
+
if (this.openReason === 'hover') {
|
|
530
|
+
// Hovered open, then pressed: the press keeps it open and makes it stay.
|
|
531
|
+
this.#openRequests += 1;
|
|
532
|
+
this.openReason = openReasonOf(details);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
if (details.trigger &&
|
|
536
|
+
anchor &&
|
|
537
|
+
details.trigger !== anchor &&
|
|
538
|
+
this.#triggers.has(details.trigger)) {
|
|
539
|
+
// Another trigger of the same popover: the panel moves to it and stays open.
|
|
540
|
+
this.#openRequests += 1;
|
|
541
|
+
this.#setActiveTrigger(details.trigger);
|
|
542
|
+
this.#opener = triggerFocusTarget(details.trigger, details.event);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
this.setOpen(!this.isOpen, details);
|
|
112
547
|
};
|
|
113
|
-
|
|
114
|
-
this.setOpen(
|
|
548
|
+
open = (input) => {
|
|
549
|
+
this.setOpen(true, input);
|
|
115
550
|
};
|
|
551
|
+
/** Closes the popover. Returns `false` when `onOpenChange` cancelled the change. */
|
|
552
|
+
close = (input) => this.setOpen(false, input);
|
|
116
553
|
/** Calls to `setOpen`, direct or through `open`, `close` and `toggle`, unchanged state included. */
|
|
117
554
|
#openRequests = 0;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
555
|
+
#destroyed = false;
|
|
556
|
+
/** The open state `setOpen` last wrote, until the effect that sees it has run. */
|
|
557
|
+
#committed = null;
|
|
558
|
+
/** Where focus returns when the popover closes; see `#returnTarget`. */
|
|
559
|
+
#opener = null;
|
|
560
|
+
/** Whether focus has been inside the mounted panel. */
|
|
561
|
+
#focusEntered = false;
|
|
562
|
+
// Triggers: every element attached through `reference` (or `trigger`), with the order they
|
|
563
|
+
// attached in. Plain fields, not `$state`: detach teardowns compare against them, and a
|
|
564
|
+
// `$state` read in teardown can return the value from before the change that triggered it.
|
|
565
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
|
|
566
|
+
#triggers = new Map();
|
|
567
|
+
#triggerSequence = 0;
|
|
568
|
+
/** Triggers attached during the current flush: a re-rendered trigger's replacement. */
|
|
569
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
|
|
570
|
+
#recentTriggers = new Set();
|
|
571
|
+
#latestTriggerNode = null;
|
|
572
|
+
#activeTriggerNode = null;
|
|
573
|
+
#hoveredTrigger = null;
|
|
574
|
+
/** The press dispatching right now on a trigger, so `toggle()` from its handler knows it. */
|
|
575
|
+
#press = null;
|
|
576
|
+
/** The pointer type of the last press on a trigger, for clicks that do not carry one. */
|
|
577
|
+
#pointerType = null;
|
|
578
|
+
#setActiveTrigger(node) {
|
|
579
|
+
this.#activeTriggerNode = node;
|
|
580
|
+
this.activeTrigger = node;
|
|
581
|
+
}
|
|
582
|
+
#setLatestTrigger(node) {
|
|
583
|
+
this.#latestTriggerNode = node;
|
|
584
|
+
this.#latestTrigger = node;
|
|
585
|
+
}
|
|
586
|
+
/** Whether the panel still has an anchor in the document: a trigger, else the `ref` prop. */
|
|
587
|
+
#hasAnchor = () => {
|
|
588
|
+
const anchor = this.#activeTriggerNode ?? this.#latestTriggerNode ?? this.externalRef;
|
|
589
|
+
if (!anchor)
|
|
590
|
+
return false;
|
|
591
|
+
// A floating-ui virtual element (a cursor point) has no DOM presence to lose.
|
|
592
|
+
return !(anchor instanceof Element) || anchor.isConnected;
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* Closes an open popover whose anchor left the document, so `onOpenChange` reports it with
|
|
596
|
+
* `reason: 'trigger-unmount'`. Skipped while the component itself is being destroyed.
|
|
597
|
+
*/
|
|
598
|
+
#closeIfAnchorLost = () => {
|
|
599
|
+
if (this.#destroyed || !this.isOpen || this.#hasAnchor())
|
|
121
600
|
return;
|
|
122
|
-
this.
|
|
123
|
-
this.onOpenChange?.(nextOpen);
|
|
601
|
+
this.setOpen(false, { reason: 'trigger-unmount' });
|
|
124
602
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
603
|
+
/**
|
|
604
|
+
* Focus goes back to the trigger that opened the popover (or the control pressed inside it),
|
|
605
|
+
* and after a programmatic open to the element that had focus when it opened. `null` lets the
|
|
606
|
+
* focus scope use the element focused when the panel mounted.
|
|
607
|
+
*/
|
|
608
|
+
#returnTarget = () => {
|
|
609
|
+
if (this.#opener?.isConnected)
|
|
610
|
+
return this.#opener;
|
|
611
|
+
if (this.openReason === 'programmatic' || this.openReason === null)
|
|
612
|
+
return null;
|
|
613
|
+
const trigger = this.activeTrigger ?? this.triggerReference;
|
|
614
|
+
return trigger ? triggerFocusTarget(trigger) : null;
|
|
615
|
+
};
|
|
616
|
+
/**
|
|
617
|
+
* The control Tab starts from and returns to: the one that opened the popover, else the focusable
|
|
618
|
+
* part of the trigger. `null` without a registered trigger (a popover anchored to a `ref`), and
|
|
619
|
+
* for a text field (a date or color input): Tab there moves on to the next field of a form.
|
|
620
|
+
*/
|
|
621
|
+
#bridgeAnchor = () => {
|
|
622
|
+
const trigger = this.triggerReference;
|
|
623
|
+
if (!trigger || !this.#triggers.has(trigger))
|
|
624
|
+
return null;
|
|
625
|
+
const anchor = this.openReason !== 'programmatic' && this.#opener?.isConnected
|
|
626
|
+
? this.#opener
|
|
627
|
+
: triggerFocusTarget(trigger);
|
|
628
|
+
return anchor && !isTextField(anchor) ? anchor : null;
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Whether `target` belongs to this popover: its panel, a trigger, the `ref` element, or a popup
|
|
632
|
+
* opened from any of them (a nested popover, a dialog the panel opened).
|
|
633
|
+
*/
|
|
634
|
+
#focusInTree = (target) => {
|
|
635
|
+
if (!target)
|
|
636
|
+
return false;
|
|
637
|
+
const external = this.externalRef;
|
|
638
|
+
if (external instanceof Node && composedContains(external, target))
|
|
639
|
+
return true;
|
|
640
|
+
// Without a layer (closed) nothing opened from the popover is showing.
|
|
641
|
+
const own = this.layer;
|
|
642
|
+
if (!own)
|
|
643
|
+
return false;
|
|
644
|
+
const open = this.theme.layers.open;
|
|
645
|
+
// A modal layer opened above this popover (a Dialog or confirmation the panel's content
|
|
646
|
+
// opened, rendered elsewhere) holds focus while the popover waits underneath it.
|
|
647
|
+
const above = open.indexOf(own);
|
|
648
|
+
if (above >= 0 &&
|
|
649
|
+
open
|
|
650
|
+
.slice(above + 1)
|
|
651
|
+
.some((layer) => layer.isModal && [...layer.nodes].some((node) => composedContains(node, target))))
|
|
652
|
+
return true;
|
|
653
|
+
return open.some((layer) => {
|
|
654
|
+
for (let current = layer; current; current = current.parent) {
|
|
655
|
+
if (current !== own)
|
|
656
|
+
continue;
|
|
657
|
+
return [...layer.nodes].some((node) => composedContains(node, target));
|
|
658
|
+
}
|
|
659
|
+
return false;
|
|
138
660
|
});
|
|
139
661
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
662
|
+
/** The details for a request, filled in from the trigger press it happens during. */
|
|
663
|
+
#details = (input) => {
|
|
664
|
+
if (isOpenChangeDetails(input))
|
|
665
|
+
return input;
|
|
666
|
+
const event = input instanceof Event ? input : input?.event;
|
|
667
|
+
const press = this.#press && (!event || event === this.#press.event) ? this.#press : null;
|
|
668
|
+
const fallback = press
|
|
669
|
+
? {
|
|
670
|
+
reason: press.reason,
|
|
671
|
+
event: press.event,
|
|
672
|
+
trigger: press.node,
|
|
673
|
+
interaction: getInteractionType(press.event, this.#pointerType)
|
|
674
|
+
}
|
|
675
|
+
: { interaction: getInteractionType(event, this.#pointerType) };
|
|
676
|
+
return resolveOpenChangeDetails(input, fallback);
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Requests an open-state change. `onOpenChange(nextOpen, details)` runs first; when it calls
|
|
680
|
+
* `details.cancel()` nothing changes. Returns `false` when the change was cancelled.
|
|
681
|
+
*/
|
|
682
|
+
setOpen = (nextOpen, input) => {
|
|
683
|
+
this.#openRequests += 1;
|
|
684
|
+
if (this.isOpen === nextOpen) {
|
|
685
|
+
// A press on the trigger of a popover the pointer opened by hovering pins it open, the
|
|
686
|
+
// same as `toggle()` does: a menu's submenu trigger opens its submenu with `open()`.
|
|
687
|
+
if (nextOpen && this.openReason === 'hover') {
|
|
688
|
+
const pressed = this.#details(input);
|
|
689
|
+
if (pressed.reason === 'trigger-press')
|
|
690
|
+
this.openReason = openReasonOf(pressed);
|
|
691
|
+
}
|
|
692
|
+
return true;
|
|
148
693
|
}
|
|
149
|
-
|
|
150
|
-
|
|
694
|
+
const details = this.#details(input);
|
|
695
|
+
if (!requestOpenChange(this.onOpenChange, nextOpen, details))
|
|
696
|
+
return false;
|
|
697
|
+
// A hover open still waiting on its delay belongs to the state before this change: left
|
|
698
|
+
// pending, it would reopen a popover the user just closed by click or Escape.
|
|
699
|
+
this.hoverAction.cancel();
|
|
700
|
+
if (nextOpen) {
|
|
701
|
+
const trigger = details.trigger && this.#triggers.has(details.trigger) ? details.trigger : null;
|
|
702
|
+
this.#setActiveTrigger(trigger);
|
|
703
|
+
this.openReason = openReasonOf(details);
|
|
704
|
+
this.#opener =
|
|
705
|
+
this.openReason === 'programmatic'
|
|
706
|
+
? focusedElement()
|
|
707
|
+
: trigger
|
|
708
|
+
? triggerFocusTarget(trigger, details.event)
|
|
709
|
+
: null;
|
|
151
710
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
711
|
+
this.lastOpenChange = details;
|
|
712
|
+
this.#appliedOpen = nextOpen;
|
|
713
|
+
this.#committed = nextOpen;
|
|
714
|
+
this.isOpen = nextOpen;
|
|
715
|
+
return true;
|
|
716
|
+
};
|
|
717
|
+
/**
|
|
718
|
+
* Points the panel's motion at the side facing the reference, for the resolved placement: the
|
|
719
|
+
* scale origin and the exit follow every placement (a flip included), the entrance only the
|
|
720
|
+
* placement made before it plays.
|
|
721
|
+
*/
|
|
722
|
+
applyDirectedTransition = (placement, { direction = 'ltr', intro = true } = {}) => {
|
|
723
|
+
const motion = directedMotion(placement, direction);
|
|
724
|
+
this.transformOrigin = motion.transformOrigin;
|
|
725
|
+
if (intro)
|
|
726
|
+
applyDirectedOffset(this.computedTransition.in, motion);
|
|
727
|
+
applyDirectedOffset(this.computedTransition.out, motion);
|
|
728
|
+
};
|
|
729
|
+
/** Records a placement, reassigning only what changed so styling hooks don't churn on scroll. */
|
|
730
|
+
#setPlacement = ({ side, align, anchorHidden }) => {
|
|
731
|
+
const current = this.placement;
|
|
732
|
+
if (current?.side === side && current.align === align && current.anchorHidden === anchorHidden)
|
|
163
733
|
return;
|
|
164
|
-
}
|
|
165
|
-
const { x, y, strategy, placement } = await computePosition(this.referenceElement, node, {
|
|
166
|
-
strategy: 'fixed',
|
|
167
|
-
placement: this.computedPosition,
|
|
168
|
-
middleware: [
|
|
169
|
-
offset(this.offset ?? 4),
|
|
170
|
-
flip({
|
|
171
|
-
mainAxis: true,
|
|
172
|
-
crossAxis: true,
|
|
173
|
-
padding: 20
|
|
174
|
-
}),
|
|
175
|
-
shift({
|
|
176
|
-
mainAxis: true,
|
|
177
|
-
crossAxis: true,
|
|
178
|
-
padding: 20
|
|
179
|
-
}),
|
|
180
|
-
hide()
|
|
181
|
-
]
|
|
182
|
-
});
|
|
183
|
-
Object.assign(node.style, {
|
|
184
|
-
position: strategy,
|
|
185
|
-
left: `${x}px`,
|
|
186
|
-
top: `${y}px`,
|
|
187
|
-
// computePosition is async: unhide only once the first placement lands, so the
|
|
188
|
-
// panel never flashes at top-left (0,0) before floating-ui resolves.
|
|
189
|
-
visibility: ''
|
|
190
|
-
});
|
|
191
|
-
this.safeArea.updateAreas();
|
|
192
|
-
if (mount && !this.hasTransitioned && this.directedTransition) {
|
|
193
|
-
this.applyDirectedTransition(node, placement);
|
|
194
|
-
}
|
|
734
|
+
this.placement = { side, align, anchorHidden };
|
|
195
735
|
};
|
|
736
|
+
/**
|
|
737
|
+
* Where the pointer last was over the trigger while the popover was closed, in viewport
|
|
738
|
+
* coordinates. Frozen while open: `anchorTo: 'line'` anchors to the line under it.
|
|
739
|
+
*/
|
|
740
|
+
#anchorOffset = null;
|
|
741
|
+
/**
|
|
742
|
+
* The captured point resolved against where its reference is now: held as an offset from the
|
|
743
|
+
* reference's box, it stays on the same line when the page or a scroll ancestor scrolls.
|
|
744
|
+
*/
|
|
745
|
+
#anchorPoint = () => {
|
|
746
|
+
const offset = this.#anchorOffset;
|
|
747
|
+
if (!offset)
|
|
748
|
+
return null;
|
|
749
|
+
const rect = offset.reference.getBoundingClientRect();
|
|
750
|
+
return { x: rect.left + offset.dx, y: rect.top + offset.dy };
|
|
751
|
+
};
|
|
752
|
+
// floating-ui placement lives in `popover.position.ts`. Its inputs are read when a placement
|
|
753
|
+
// runs: the mount placement runs inside the `dialog` attachment, so a change to any of them
|
|
754
|
+
// re-places an open panel.
|
|
755
|
+
#positioner = createPanelPositioner({
|
|
756
|
+
reference: () => this.referenceElement,
|
|
757
|
+
// Inline panels and mobile sheets are laid out by the document, never by floating-ui.
|
|
758
|
+
floating: () => !this.inline && !this.isMobileSheet,
|
|
759
|
+
// Untracked: floating-ui runs its first observed update synchronously inside the panel
|
|
760
|
+
// attachment, which would otherwise re-run (and re-mount the placement) when the opening
|
|
761
|
+
// transition ends. The catch-up placement in `dialog` covers that moment instead.
|
|
762
|
+
settled: () => untrack(() => this.lifecycle.status === 'open'),
|
|
763
|
+
placement: () => this.computedPosition,
|
|
764
|
+
offset: () => this.offset,
|
|
765
|
+
fitTrigger: () => this.fitTrigger,
|
|
766
|
+
positionPanel: () => this.positionPanel,
|
|
767
|
+
direction: this.#direction,
|
|
768
|
+
collisionBoundary: () => this.collisionBoundary,
|
|
769
|
+
fallbackAxisSide: () => this.fallbackAxisSide,
|
|
770
|
+
anchorTo: () => this.anchorTo,
|
|
771
|
+
anchorPoint: this.#anchorPoint,
|
|
772
|
+
arrow: () => (this.arrow && this.computedMode === 'floating' ? this.arrowElement : null),
|
|
773
|
+
setMinWidth: (width) => {
|
|
774
|
+
this.triggerWidth = width;
|
|
775
|
+
},
|
|
776
|
+
// `positionPanel` places synchronously, inside the panel attachment: nothing read here may
|
|
777
|
+
// become one of its dependencies.
|
|
778
|
+
onPlace: ({ placement, side, align, anchorHidden, direction, mount }) => untrack(() => {
|
|
779
|
+
this.#setPlacement({ side, align, anchorHidden });
|
|
780
|
+
this.safeArea.updateAreas();
|
|
781
|
+
if (placement && this.directedTransition) {
|
|
782
|
+
this.applyDirectedTransition(placement, {
|
|
783
|
+
direction,
|
|
784
|
+
intro: mount && this.lifecycle.status !== 'open'
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
})
|
|
788
|
+
});
|
|
789
|
+
/** Places the floating panel against its reference once; see `PanelPositioner.place`. */
|
|
790
|
+
place = (node, mount = false) => this.#positioner.place(node, mount);
|
|
791
|
+
/** Attachment for the positioning wrapper (`<dialog>`, or a `<div>` for a non-dialog popup). */
|
|
196
792
|
dialog = (node) => {
|
|
197
793
|
this.dialogElement = node;
|
|
198
794
|
if (this.inline) {
|
|
199
795
|
// No portal, no fixed placement: the wrapper stays where the component is rendered.
|
|
200
796
|
this.triggerWidth = null;
|
|
201
|
-
|
|
202
|
-
position: '',
|
|
203
|
-
left: '',
|
|
204
|
-
top: '',
|
|
205
|
-
visibility: ''
|
|
206
|
-
});
|
|
797
|
+
releasePanelPosition(node, true);
|
|
207
798
|
return () => {
|
|
208
799
|
this.dialogElement = null;
|
|
209
800
|
};
|
|
210
801
|
}
|
|
211
802
|
if (this.isMobileSheet) {
|
|
212
803
|
this.triggerWidth = null;
|
|
213
|
-
|
|
214
|
-
position: '',
|
|
215
|
-
left: '',
|
|
216
|
-
top: ''
|
|
217
|
-
});
|
|
804
|
+
releasePanelPosition(node, false);
|
|
218
805
|
return () => {
|
|
219
806
|
this.dialogElement = null;
|
|
220
807
|
};
|
|
221
808
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
809
|
+
const reference = this.referenceElement;
|
|
810
|
+
// The anchor can go while the panel's outro still runs (its trigger unmounted): the panel
|
|
811
|
+
// keeps its last place, since floating-ui cannot observe a missing reference.
|
|
812
|
+
if (!reference) {
|
|
813
|
+
return () => {
|
|
814
|
+
this.dialogElement = null;
|
|
815
|
+
queueMicrotask(this.#closeIfAnchorLost);
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
// A reference that leaves the document closes the popover instead of being placed.
|
|
819
|
+
const cleanup = this.#positioner.track(node, reference, this.#closeIfAnchorLost);
|
|
820
|
+
// Changes observed during the opening transition are not placed; catch up once it ends,
|
|
821
|
+
// so content that resized while opening doesn't leave the panel misplaced.
|
|
822
|
+
$effect(() => {
|
|
823
|
+
if (this.lifecycle.status === 'open')
|
|
824
|
+
untrack(() => void this.place(node));
|
|
825
|
+
});
|
|
226
826
|
return () => {
|
|
227
827
|
cleanup();
|
|
228
828
|
this.dialogElement = null;
|
|
829
|
+
// Forget the placement once the panel is gone, not when it is only placed again (a new
|
|
830
|
+
// `position`), so the styling hooks and the focus gate don't flicker in between.
|
|
831
|
+
queueMicrotask(() => {
|
|
832
|
+
if (!this.dialogElement)
|
|
833
|
+
this.placement = null;
|
|
834
|
+
});
|
|
835
|
+
// The panel also leaves when its `ref` anchor does (`bind:this` resets it to null),
|
|
836
|
+
// and without an outro that happens before the positioner's observers can report the
|
|
837
|
+
// detached node: judge the anchor once the flush settles, so the popover closes
|
|
838
|
+
// instead of staying open and reappearing when the anchor returns. A no-op when the
|
|
839
|
+
// popover closed or was destroyed, or when another anchor took over.
|
|
840
|
+
queueMicrotask(this.#closeIfAnchorLost);
|
|
229
841
|
};
|
|
230
842
|
};
|
|
231
843
|
panel = (node) => {
|
|
232
844
|
return untrack(() => {
|
|
233
845
|
const cleanups = [];
|
|
234
|
-
|
|
235
|
-
cleanups.push(
|
|
236
|
-
|
|
846
|
+
this.panelElement = node;
|
|
847
|
+
cleanups.push(() => {
|
|
848
|
+
if (this.panelElement === node)
|
|
849
|
+
this.panelElement = null;
|
|
850
|
+
});
|
|
851
|
+
this.#focusEntered = node.contains(node.ownerDocument.activeElement);
|
|
852
|
+
cleanups.push(on(node, 'focusin', () => {
|
|
853
|
+
this.#focusEntered = true;
|
|
854
|
+
}));
|
|
855
|
+
// The session exists whenever the panel does: it is rendered first, while open or closing.
|
|
856
|
+
const session = this.#currentSession;
|
|
857
|
+
if (session) {
|
|
858
|
+
cleanups.push(session.layer.node(node));
|
|
859
|
+
cleanups.push(session.focusScope.attachment(node));
|
|
860
|
+
cleanups.push(session.safeArea.floatingReference(node));
|
|
861
|
+
}
|
|
862
|
+
if (!this.isDialogPopup)
|
|
863
|
+
cleanups.push(this.#labelPopupOwner(node));
|
|
237
864
|
return () => {
|
|
238
865
|
cleanups.forEach((cleanup) => cleanup?.());
|
|
239
866
|
};
|
|
240
867
|
});
|
|
241
868
|
};
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
869
|
+
/**
|
|
870
|
+
* A menu, listbox, tree or grid popup: its trigger's `aria-controls` points at the element
|
|
871
|
+
* carrying that role (not the wrapper), and that element is labelled by the trigger unless it
|
|
872
|
+
* has a name of its own. Ids it has to create are removed again when the panel goes.
|
|
873
|
+
*/
|
|
874
|
+
#labelPopupOwner = (panel) => {
|
|
875
|
+
const haspopup = this.haspopup ?? 'dialog';
|
|
876
|
+
const role = haspopup === true ? 'menu' : POPUP_ROLE[haspopup];
|
|
877
|
+
const added = [];
|
|
878
|
+
const created = (element, name) => added.some(([e, n]) => e === element && n === name);
|
|
879
|
+
// Never replaces an attribute the consumer wrote; one this code wrote may be rewritten.
|
|
880
|
+
const set = (element, name, value) => {
|
|
881
|
+
if (element.hasAttribute(name) && !created(element, name))
|
|
882
|
+
return;
|
|
883
|
+
if (!created(element, name))
|
|
884
|
+
added.push([element, name]);
|
|
885
|
+
element.setAttribute(name, value);
|
|
886
|
+
};
|
|
887
|
+
const unset = (element, name) => {
|
|
888
|
+
if (!created(element, name))
|
|
249
889
|
return;
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
890
|
+
element.removeAttribute(name);
|
|
891
|
+
added.splice(added.findIndex(([e, n]) => e === element && n === name), 1);
|
|
892
|
+
};
|
|
893
|
+
let owner = null;
|
|
894
|
+
// Named by the consumer: `label` / `labelledBy` win over the trigger. Read reactively, so a
|
|
895
|
+
// name that changes while the popover is open reaches the role owner.
|
|
896
|
+
const name = () => {
|
|
897
|
+
// Read before the owner check, so the effect tracks them while no owner exists yet.
|
|
898
|
+
const { label, labelledBy } = this;
|
|
899
|
+
if (!owner)
|
|
900
|
+
return;
|
|
901
|
+
unset(owner, 'aria-label');
|
|
902
|
+
unset(owner, 'aria-labelledby');
|
|
903
|
+
if (labelledBy)
|
|
904
|
+
set(owner, 'aria-labelledby', labelledBy);
|
|
905
|
+
if (label)
|
|
906
|
+
set(owner, 'aria-label', label);
|
|
907
|
+
const trigger = this.triggerReference;
|
|
908
|
+
if (trigger && !owner.hasAttribute('aria-label') && !owner.hasAttribute('aria-labelledby')) {
|
|
909
|
+
set(trigger, 'id', `${this.id}-trigger`);
|
|
910
|
+
set(owner, 'aria-labelledby', trigger.id);
|
|
256
911
|
}
|
|
912
|
+
};
|
|
913
|
+
const resolve = () => {
|
|
914
|
+
const next = panel.querySelector(`[role="${role}"]`);
|
|
915
|
+
if (next === owner)
|
|
916
|
+
return;
|
|
917
|
+
if (owner)
|
|
918
|
+
for (const attribute of ['aria-label', 'aria-labelledby'])
|
|
919
|
+
unset(owner, attribute);
|
|
920
|
+
owner = next;
|
|
921
|
+
if (!owner) {
|
|
922
|
+
this.#popupOwnerId = null;
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
set(owner, 'id', `${this.id}-${role}`);
|
|
926
|
+
this.#popupOwnerId = owner.id;
|
|
927
|
+
name();
|
|
928
|
+
};
|
|
929
|
+
$effect(name);
|
|
930
|
+
queueMicrotask(resolve);
|
|
931
|
+
const observer = typeof MutationObserver === 'undefined' ? null : new MutationObserver(resolve);
|
|
932
|
+
observer?.observe(panel, { childList: true, subtree: true });
|
|
933
|
+
return () => {
|
|
934
|
+
observer?.disconnect();
|
|
935
|
+
for (const [element, name] of added.splice(0))
|
|
936
|
+
element.removeAttribute(name);
|
|
937
|
+
this.#popupOwnerId = null;
|
|
938
|
+
};
|
|
939
|
+
};
|
|
940
|
+
/** Remembers a press on a trigger until its event has dispatched. */
|
|
941
|
+
#notePress = (node, event, reason) => {
|
|
942
|
+
const press = { node, event, reason };
|
|
943
|
+
this.#press = press;
|
|
944
|
+
setTimeout(() => {
|
|
945
|
+
if (this.#press === press)
|
|
946
|
+
this.#press = null;
|
|
947
|
+
});
|
|
948
|
+
};
|
|
949
|
+
reference = (node) => {
|
|
950
|
+
// Keep the trigger's ARIA in sync whichever way it was rendered (snippet or Button). With
|
|
951
|
+
// several triggers, only the one the panel is anchored to reads as expanded. Closed, they all
|
|
952
|
+
// read the same: the anchor is not read then, so attaching a trigger (a row of a long list
|
|
953
|
+
// sharing one popover) does not rewrite every other trigger's attributes.
|
|
954
|
+
$effect(() => {
|
|
955
|
+
const props = this.triggerProps;
|
|
956
|
+
const anchored = !props.expanded || this.triggerReference === node || this.triggerReference === null;
|
|
957
|
+
writePopupAria(node, {
|
|
958
|
+
...props,
|
|
959
|
+
expanded: props.expanded && anchored,
|
|
960
|
+
controls: anchored ? props.controls : undefined
|
|
961
|
+
});
|
|
257
962
|
});
|
|
258
963
|
return untrack(() => {
|
|
259
|
-
this.
|
|
964
|
+
this.#triggers.set(node, ++this.#triggerSequence);
|
|
965
|
+
this.#recentTriggers.add(node);
|
|
966
|
+
queueMicrotask(() => this.#recentTriggers.delete(node));
|
|
967
|
+
this.#setLatestTrigger(node);
|
|
260
968
|
// Gather all cleanup callbacks
|
|
261
969
|
const cleanups = [];
|
|
262
|
-
|
|
263
|
-
|
|
970
|
+
// Inside the layer and anchoring the safe area while open; see `openSession`.
|
|
971
|
+
this.#currentSession?.addTrigger(node);
|
|
972
|
+
cleanups.push(() => this.#currentSession?.removeTrigger(node));
|
|
973
|
+
// Before the hover action's own listener, which may open at once (no delay).
|
|
974
|
+
cleanups.push(on(node, 'mouseenter', () => {
|
|
975
|
+
this.#hoveredTrigger = node;
|
|
976
|
+
}));
|
|
264
977
|
cleanups.push(this.hoverAction.reference?.(node));
|
|
978
|
+
// Capture phase: these run before the element's own (delegated) handlers, so a
|
|
979
|
+
// `popover.toggle()` called from `onclick` knows the press it belongs to.
|
|
980
|
+
cleanups.push(on(node, 'pointerdown', (event) => {
|
|
981
|
+
this.#pointerType = event.pointerType;
|
|
982
|
+
}, { capture: true }));
|
|
983
|
+
const notePress = (event) => this.#notePress(node, event, 'trigger-press');
|
|
984
|
+
const noteKey = (event) => {
|
|
985
|
+
if (event.key === 'Enter' || event.key === ' ')
|
|
986
|
+
this.#notePress(node, event, 'trigger-press');
|
|
987
|
+
else if (event.key === 'ArrowDown' || event.key === 'ArrowUp')
|
|
988
|
+
this.#notePress(node, event, 'list-navigation');
|
|
989
|
+
};
|
|
990
|
+
node.addEventListener('click', notePress, true);
|
|
991
|
+
node.addEventListener('keydown', noteKey, true);
|
|
992
|
+
cleanups.push(() => {
|
|
993
|
+
node.removeEventListener('click', notePress, true);
|
|
994
|
+
node.removeEventListener('keydown', noteKey, true);
|
|
995
|
+
});
|
|
996
|
+
cleanups.push(this.#trackAnchorPoint(node));
|
|
265
997
|
// Return combined cleanup function
|
|
266
998
|
return () => {
|
|
267
999
|
cleanups.forEach((cleanup) => cleanup?.());
|
|
1000
|
+
this.#triggers.delete(node);
|
|
1001
|
+
this.#recentTriggers.delete(node);
|
|
1002
|
+
if (this.#hoveredTrigger === node)
|
|
1003
|
+
this.#hoveredTrigger = null;
|
|
1004
|
+
const wasActive = this.#activeTriggerNode === node;
|
|
1005
|
+
const wasAnchor = wasActive || (!this.#activeTriggerNode && this.#latestTriggerNode === node);
|
|
1006
|
+
if (wasActive)
|
|
1007
|
+
this.#setActiveTrigger(null);
|
|
1008
|
+
if (this.#latestTriggerNode === node)
|
|
1009
|
+
this.#setLatestTrigger(this.#newestTrigger());
|
|
1010
|
+
if (!wasAnchor)
|
|
1011
|
+
return;
|
|
1012
|
+
// A trigger re-rendered as a new element (a re-rendered snippet, a responsive
|
|
1013
|
+
// branch) attaches in the same flush: the panel moves to it. Only a trigger that
|
|
1014
|
+
// is gone for good closes the popover instead of leaving it on a detached node.
|
|
1015
|
+
const sequence = this.#triggerSequence;
|
|
1016
|
+
const replacements = [...this.#recentTriggers];
|
|
1017
|
+
queueMicrotask(() => {
|
|
1018
|
+
if (this.#destroyed || !this.isOpen)
|
|
1019
|
+
return;
|
|
1020
|
+
const successor = [...replacements, ...this.#triggersAfter(sequence)].find((candidate) => this.#triggers.has(candidate) && candidate.isConnected);
|
|
1021
|
+
if (successor) {
|
|
1022
|
+
if (wasActive)
|
|
1023
|
+
this.#setActiveTrigger(successor);
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
// The trigger that opened it is gone: another trigger does not inherit it.
|
|
1027
|
+
if (wasActive && !this.externalRef) {
|
|
1028
|
+
this.setOpen(false, { reason: 'trigger-unmount' });
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
this.#closeIfAnchorLost();
|
|
1032
|
+
});
|
|
268
1033
|
};
|
|
269
1034
|
});
|
|
270
1035
|
};
|
|
1036
|
+
#newestTrigger() {
|
|
1037
|
+
let newest = null;
|
|
1038
|
+
let newestSequence = -1;
|
|
1039
|
+
for (const [node, sequence] of this.#triggers) {
|
|
1040
|
+
if (sequence > newestSequence)
|
|
1041
|
+
[newest, newestSequence] = [node, sequence];
|
|
1042
|
+
}
|
|
1043
|
+
return newest;
|
|
1044
|
+
}
|
|
1045
|
+
#triggersAfter(sequence) {
|
|
1046
|
+
return [...this.#triggers].filter(([, at]) => at > sequence).map(([node]) => node);
|
|
1047
|
+
}
|
|
271
1048
|
/**
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* An element that is not already a control also gets \`role="button"\`, \`tabindex="0"\` and
|
|
275
|
-
* Enter/Space activation, so a card or an avatar opens the panel from the keyboard too.
|
|
1049
|
+
* Follows the pointer over the trigger while the popover is closed, so an open anchored to a
|
|
1050
|
+
* line (`anchorTo: 'line'`) uses the line the pointer was on; the point stays put while open.
|
|
276
1051
|
*/
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
if (!nativeControl && !node.hasAttribute('tabindex'))
|
|
283
|
-
node.tabIndex = 0;
|
|
284
|
-
// The element's own handler wins. One that still opens, closes or toggles the popover
|
|
285
|
-
// (`onclick={popover.toggle}` kept from before this attachment existed) has acted by the
|
|
286
|
-
// time the event finishes dispatching, so the default toggle waits until then and runs only
|
|
287
|
-
// if nothing asked for an open state meanwhile; toggling regardless would undo that call.
|
|
288
|
-
let pending;
|
|
289
|
-
const activate = () => {
|
|
290
|
-
if (!this.openOnClick)
|
|
1052
|
+
#trackAnchorPoint = (node) => {
|
|
1053
|
+
const follow = (event) => {
|
|
1054
|
+
const reference = this.referenceElement;
|
|
1055
|
+
if (this.isOpen || !reference)
|
|
291
1056
|
return;
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
1057
|
+
const rect = reference.getBoundingClientRect();
|
|
1058
|
+
this.#anchorOffset = {
|
|
1059
|
+
reference,
|
|
1060
|
+
dx: event.clientX - rect.left,
|
|
1061
|
+
dy: event.clientY - rect.top
|
|
1062
|
+
};
|
|
298
1063
|
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
1064
|
+
// A finger lifts (pointerleave) before the click that opens the popover: keep its point.
|
|
1065
|
+
const forget = (event) => {
|
|
1066
|
+
if (!this.isOpen && event.pointerType !== 'touch')
|
|
1067
|
+
this.#anchorOffset = null;
|
|
1068
|
+
};
|
|
1069
|
+
// A keyboard open has no pointer: it takes the first or last line, not a stale hover point.
|
|
1070
|
+
const forgetOnKey = () => {
|
|
1071
|
+
if (!this.isOpen)
|
|
1072
|
+
this.#anchorOffset = null;
|
|
1073
|
+
};
|
|
1074
|
+
node.addEventListener('pointerenter', follow);
|
|
1075
|
+
node.addEventListener('pointermove', follow);
|
|
1076
|
+
node.addEventListener('pointerdown', follow);
|
|
1077
|
+
node.addEventListener('pointerleave', forget);
|
|
1078
|
+
node.addEventListener('keydown', forgetOnKey);
|
|
1079
|
+
return () => {
|
|
1080
|
+
node.removeEventListener('pointerenter', follow);
|
|
1081
|
+
node.removeEventListener('pointermove', follow);
|
|
1082
|
+
node.removeEventListener('pointerdown', follow);
|
|
1083
|
+
node.removeEventListener('pointerleave', forget);
|
|
1084
|
+
node.removeEventListener('keydown', forgetOnKey);
|
|
1085
|
+
};
|
|
1086
|
+
};
|
|
1087
|
+
/** Attachment for the arrow element inside the panel; see the `arrow` prop. */
|
|
1088
|
+
arrowRef = (node) => {
|
|
1089
|
+
this.arrowElement = node;
|
|
1090
|
+
return () => {
|
|
1091
|
+
if (this.arrowElement === node)
|
|
1092
|
+
this.arrowElement = null;
|
|
1093
|
+
};
|
|
1094
|
+
};
|
|
1095
|
+
/** Payload getters of the triggers made with `triggerFor`. */
|
|
1096
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping; `#payloadVersion` carries the reactivity
|
|
1097
|
+
#payloads = new Map();
|
|
1098
|
+
#payloadVersion = $state(0);
|
|
1099
|
+
/**
|
|
1100
|
+
* The payload of the trigger the panel is anchored to: the one that opened it, else the most
|
|
1101
|
+
* recently attached. `undefined` for a trigger made without one. Several triggers share this one
|
|
1102
|
+
* popup, so a list of rows needs a single popover, not one per row.
|
|
1103
|
+
*/
|
|
1104
|
+
payload = $derived.by(() => {
|
|
1105
|
+
void this.#payloadVersion;
|
|
1106
|
+
const trigger = this.triggerReference;
|
|
1107
|
+
return trigger ? this.#payloads.get(trigger)?.() : undefined;
|
|
1108
|
+
});
|
|
1109
|
+
/**
|
|
1110
|
+
* A complete trigger (see `trigger`) that carries data for the panel: read it back as
|
|
1111
|
+
* `popover.payload` while this trigger is the one the panel is anchored to. Pass a getter, so
|
|
1112
|
+
* the payload follows its source without re-attaching the trigger:
|
|
1113
|
+
* `{@attach popover.triggerFor(() => row)}`.
|
|
1114
|
+
*/
|
|
1115
|
+
triggerFor(payload) {
|
|
1116
|
+
return (node) => {
|
|
1117
|
+
const attached = this.trigger(node);
|
|
1118
|
+
untrack(() => {
|
|
1119
|
+
this.#payloads.set(node, payload);
|
|
1120
|
+
this.#payloadVersion += 1;
|
|
1121
|
+
});
|
|
1122
|
+
return () => {
|
|
1123
|
+
attached?.();
|
|
1124
|
+
untrack(() => {
|
|
1125
|
+
if (this.#payloads.get(node) !== payload)
|
|
1126
|
+
return;
|
|
1127
|
+
this.#payloads.delete(node);
|
|
1128
|
+
this.#payloadVersion += 1;
|
|
1129
|
+
});
|
|
1130
|
+
};
|
|
306
1131
|
};
|
|
307
|
-
|
|
308
|
-
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Makes any element a complete trigger: it anchors the panel (as `reference` does), toggles
|
|
1135
|
+
* it on click when `openOnClick` allows, and keeps `aria-expanded` and friends in sync.
|
|
1136
|
+
* An element that is not already a control also gets `role="button"`, `tabindex="0"` and
|
|
1137
|
+
* Enter/Space activation, so a card or an avatar opens the panel from the keyboard too.
|
|
1138
|
+
* The element's own handler runs first: calling `event.preventDefault()` there, or opening,
|
|
1139
|
+
* closing or toggling the popover itself, stops the default toggle.
|
|
1140
|
+
*/
|
|
1141
|
+
trigger = (node) => {
|
|
1142
|
+
const offActivation = triggerActivation(node, {
|
|
1143
|
+
enabled: () => this.openOnClick,
|
|
1144
|
+
requests: () => this.#openRequests,
|
|
1145
|
+
activate: (event) => this.toggle({ reason: 'trigger-press', event, trigger: node })
|
|
1146
|
+
});
|
|
309
1147
|
const offReference = this.reference(node);
|
|
310
1148
|
return () => {
|
|
311
|
-
|
|
312
|
-
node.removeEventListener('click', activate);
|
|
313
|
-
node.removeEventListener('keydown', onKeydown);
|
|
1149
|
+
offActivation();
|
|
314
1150
|
offReference?.();
|
|
315
1151
|
};
|
|
316
1152
|
};
|
|
317
1153
|
}
|
|
318
|
-
|
|
1154
|
+
/**
|
|
1155
|
+
* The state behind the `PopoverApi` a Popover hands its snippets and callbacks. For library
|
|
1156
|
+
* components that drive a popover's internals (menus, hover cards); consumers get the narrow API.
|
|
1157
|
+
*/
|
|
1158
|
+
export const popoverInternals = (popover) => popover;
|
|
319
1159
|
export const usePopoverContext = () => {
|
|
320
1160
|
const hasPopover = hasContext('popover');
|
|
321
1161
|
if (!hasPopover) {
|