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,363 +1,686 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity -- the item registry and its index are DOM bookkeeping, not reactive state; `revision` publishes their changes. */
|
|
2
2
|
import { useKeyDown } from './useKeyDown.svelte.js';
|
|
3
3
|
import { on } from 'svelte/events';
|
|
4
4
|
import { onDestroy, untrack } from 'svelte';
|
|
5
5
|
import { usePointerDown } from './usePointerDown.svelte.js';
|
|
6
6
|
import { useDirection } from './useDirection.svelte.js';
|
|
7
|
-
import { createTypeahead } from './typeahead.js';
|
|
7
|
+
import { createTypeahead, isTextEntry } from './typeahead.js';
|
|
8
8
|
import { createId } from './id.js';
|
|
9
|
+
import { prefersReducedMotion } from './motion.svelte.js';
|
|
10
|
+
import { clampRovingKey, createRovingRestoreVersion } from './useRovingRegistry.svelte.js';
|
|
11
|
+
// Every live navigation container, so a list ignores keys that a list nested inside it owns.
|
|
12
|
+
const containers = new WeakSet();
|
|
13
|
+
const byDocumentPosition = (a, b) => {
|
|
14
|
+
const position = a.compareDocumentPosition(b);
|
|
15
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING)
|
|
16
|
+
return -1;
|
|
17
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING)
|
|
18
|
+
return 1;
|
|
19
|
+
return 0;
|
|
20
|
+
};
|
|
21
|
+
// A keyed reorder moves nodes: each moved node is removed and added again in one batch.
|
|
22
|
+
const hasMovedNode = (records) => {
|
|
23
|
+
const removed = new Set();
|
|
24
|
+
for (const record of records)
|
|
25
|
+
record.removedNodes.forEach((node) => removed.add(node));
|
|
26
|
+
if (removed.size === 0)
|
|
27
|
+
return false;
|
|
28
|
+
return records.some((record) => Array.from(record.addedNodes).some((node) => removed.has(node)));
|
|
29
|
+
};
|
|
30
|
+
/** An attribute record whose attribute holds the value it had before the write. */
|
|
31
|
+
const isUnchangedAttribute = (record) => record.type === 'attributes' &&
|
|
32
|
+
record.attributeName !== null &&
|
|
33
|
+
record.target instanceof Element &&
|
|
34
|
+
record.oldValue === record.target.getAttribute(record.attributeName);
|
|
35
|
+
/** Writes an attribute only when its value differs, so unchanged items cost a read, not a write. */
|
|
36
|
+
const setAttribute = (node, name, value) => {
|
|
37
|
+
if (node.getAttribute(name) !== value)
|
|
38
|
+
node.setAttribute(name, value);
|
|
39
|
+
};
|
|
40
|
+
const removeAttribute = (node, name) => {
|
|
41
|
+
if (node.hasAttribute(name))
|
|
42
|
+
node.removeAttribute(name);
|
|
43
|
+
};
|
|
44
|
+
// The caret sits at the start or end of a field with nothing selected, so an arrow pointing past
|
|
45
|
+
// that edge has no text left to move through.
|
|
46
|
+
const isCaretAtEdge = (event, edge) => {
|
|
47
|
+
if (event.shiftKey)
|
|
48
|
+
return false; // Shift+arrow extends a selection.
|
|
49
|
+
const field = event.target;
|
|
50
|
+
if (field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement) {
|
|
51
|
+
const { selectionStart, selectionEnd, value } = field;
|
|
52
|
+
// Fields without a caret API (number, date) keep their arrows.
|
|
53
|
+
if (selectionStart === null || selectionEnd === null || selectionStart !== selectionEnd) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return edge === 'start' ? selectionStart === 0 : selectionEnd === value.length;
|
|
57
|
+
}
|
|
58
|
+
if (!(field instanceof HTMLElement))
|
|
59
|
+
return false;
|
|
60
|
+
const selection = field.ownerDocument.getSelection();
|
|
61
|
+
if (!selection?.isCollapsed || selection.rangeCount === 0)
|
|
62
|
+
return false;
|
|
63
|
+
const caret = selection.getRangeAt(0);
|
|
64
|
+
const rest = field.ownerDocument.createRange();
|
|
65
|
+
rest.selectNodeContents(field);
|
|
66
|
+
if (edge === 'start')
|
|
67
|
+
rest.setEnd(caret.startContainer, caret.startOffset);
|
|
68
|
+
else
|
|
69
|
+
rest.setStart(caret.endContainer, caret.endOffset);
|
|
70
|
+
return rest.toString().length === 0;
|
|
71
|
+
};
|
|
9
72
|
export const useNavigation = (opts) => {
|
|
10
|
-
|
|
73
|
+
// The registered items in document order, and each one's position in that order. Mounting
|
|
74
|
+
// registers in document order, so registration appends; a registration out of order or a node
|
|
75
|
+
// moved inside the container marks the order stale, and the next read checks it with one pass
|
|
76
|
+
// over adjacent pairs, sorting only when that pass finds a pair out of order.
|
|
77
|
+
const registered = [];
|
|
78
|
+
const positions = new Map();
|
|
79
|
+
let orderStale = false;
|
|
80
|
+
let positionsStale = false;
|
|
81
|
+
// Bumped whenever membership, order or an item's disabled/hidden state changes; every
|
|
82
|
+
// reactive read of the list (the focused index, the attribute sync) depends on it.
|
|
83
|
+
let revision = $state(0);
|
|
84
|
+
let sequence = 0;
|
|
11
85
|
let containerRef = $state(null);
|
|
12
|
-
|
|
86
|
+
// The highlighted item: it has DOM focus, or the pointer rests on it, or it is the item the
|
|
87
|
+
// container's aria-activedescendant names. Tracked by element, so it survives insertions,
|
|
88
|
+
// removals and reorders around it.
|
|
89
|
+
let focusedItem = $state.raw(null);
|
|
90
|
+
// Focus sits on the container itself with no item highlighted (a popup opened by pointer).
|
|
91
|
+
let containerHighlighted = $state(false);
|
|
92
|
+
let lastFocusedItem = $state.raw(null);
|
|
13
93
|
let focusSource = $state(null);
|
|
14
94
|
let isHovering = $state(false);
|
|
15
95
|
let isFocused = $state(false);
|
|
16
|
-
|
|
96
|
+
// The item that holds DOM focus, or held it when focus was lost to nothing during this task
|
|
97
|
+
// (the item was removed). Not reactive: only the removal of that item reads it.
|
|
98
|
+
let focusHolder = null;
|
|
99
|
+
const restoreVersion = createRovingRestoreVersion();
|
|
100
|
+
// The attributes this list last wrote, so a highlight move rewrites only the items it leaves
|
|
101
|
+
// and enters (at most four attribute writes) instead of every item.
|
|
102
|
+
let appliedTabStop = null;
|
|
103
|
+
let appliedHighlight = null;
|
|
17
104
|
// Enabled by default — `enabled` is an opt-out, checked at event time so it stays reactive.
|
|
18
105
|
const isEnabled = () => (opts.enabled ? opts.enabled() : true);
|
|
19
|
-
|
|
20
|
-
if (focusedIndex !== null && focusedIndex !== -1) {
|
|
21
|
-
lastFocusedIndex = focusedIndex;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
106
|
+
const keepsDisabledItems = () => opts.disabledItemsFocusable === true || opts.skipDisabled === false;
|
|
24
107
|
// Generate ID if not provided
|
|
25
108
|
const baseId = opts.id ?? createId('nav');
|
|
26
109
|
const getDirection = useDirection(() => containerRef);
|
|
110
|
+
// Get current orientation
|
|
111
|
+
const getOrientation = () => {
|
|
112
|
+
if (typeof opts.orientation === 'function') {
|
|
113
|
+
return opts.orientation();
|
|
114
|
+
}
|
|
115
|
+
return opts.orientation || 'horizontal';
|
|
116
|
+
};
|
|
117
|
+
/** The registered items in document order. */
|
|
118
|
+
const ordered = () => {
|
|
119
|
+
if (orderStale) {
|
|
120
|
+
orderStale = false;
|
|
121
|
+
for (let index = 1; index < registered.length; index += 1) {
|
|
122
|
+
if (byDocumentPosition(registered[index - 1], registered[index]) > 0) {
|
|
123
|
+
registered.sort(byDocumentPosition);
|
|
124
|
+
positionsStale = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (positionsStale) {
|
|
130
|
+
positionsStale = false;
|
|
131
|
+
registered.forEach((item, index) => positions.set(item, index));
|
|
132
|
+
}
|
|
133
|
+
return registered;
|
|
134
|
+
};
|
|
135
|
+
const indexOf = (item) => {
|
|
136
|
+
if (!item)
|
|
137
|
+
return -1;
|
|
138
|
+
ordered();
|
|
139
|
+
return positions.get(item) ?? -1;
|
|
140
|
+
};
|
|
141
|
+
// Natively disabled items (a `disabled` attribute, or inside a disabled fieldset) can never
|
|
142
|
+
// take focus, so they are never targets.
|
|
143
|
+
const isNativelyDisabled = (item) => item.hasAttribute('disabled') || item.matches(':disabled');
|
|
144
|
+
// Announced as disabled while still able to take focus.
|
|
145
|
+
const isSoftDisabled = (item) => {
|
|
146
|
+
const dataDisabled = item.getAttribute('data-disabled');
|
|
147
|
+
return (item.getAttribute('aria-disabled') === 'true' ||
|
|
148
|
+
(dataDisabled !== null && dataDisabled !== 'false'));
|
|
149
|
+
};
|
|
150
|
+
/** Never activated: natively disabled, aria-disabled or data-disabled. */
|
|
151
|
+
const isItemDisabled = (item) => isNativelyDisabled(item) || isSoftDisabled(item);
|
|
152
|
+
/** Cannot hold focus or the tab stop. */
|
|
153
|
+
const isUnfocusable = (item) => isNativelyDisabled(item) || (!keepsDisabledItems() && isSoftDisabled(item));
|
|
154
|
+
// CSS-hidden items (`display: none`, a hidden ancestor, inert content) have no box to focus.
|
|
155
|
+
const isRendered = (item) => item.getClientRects().length > 0 && !item.closest('[inert]');
|
|
156
|
+
/** A target for arrow keys, Home/End and type-ahead. */
|
|
157
|
+
const isNavigable = (item) => !isUnfocusable(item) && isRendered(item);
|
|
158
|
+
// The registered item that is or contains `node`; the container itself is no item.
|
|
159
|
+
const itemOf = (node) => {
|
|
160
|
+
let element = node instanceof Element ? node : node instanceof Node ? node.parentElement : null;
|
|
161
|
+
while (element && element !== containerRef) {
|
|
162
|
+
if (element instanceof HTMLElement && positions.has(element))
|
|
163
|
+
return element;
|
|
164
|
+
element = element.parentElement;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
};
|
|
168
|
+
const itemIndexOf = (node) => indexOf(itemOf(node));
|
|
169
|
+
// A key typed inside a navigation list nested in this one belongs to that list.
|
|
170
|
+
const ownsKeyTarget = (target) => {
|
|
171
|
+
for (let element = target instanceof Element ? target : null; element && element !== containerRef; element = element.parentElement) {
|
|
172
|
+
if (containers.has(element))
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
};
|
|
177
|
+
// The first navigable item from the start (1) or the end (-1). When nothing is rendered yet
|
|
178
|
+
// (the list sits in a hidden panel), the first item that can take focus once it shows.
|
|
179
|
+
const findEdge = (direction) => {
|
|
180
|
+
const items = ordered();
|
|
181
|
+
let fallback = -1;
|
|
182
|
+
for (let step = 0; step < items.length; step += 1) {
|
|
183
|
+
const index = direction === 1 ? step : items.length - 1 - step;
|
|
184
|
+
if (isUnfocusable(items[index]))
|
|
185
|
+
continue;
|
|
186
|
+
if (isRendered(items[index]))
|
|
187
|
+
return index;
|
|
188
|
+
if (fallback === -1)
|
|
189
|
+
fallback = index;
|
|
190
|
+
}
|
|
191
|
+
return fallback;
|
|
192
|
+
};
|
|
193
|
+
// The next navigable item after `from` in `direction`, or -1 when there is none (the end of a
|
|
194
|
+
// list that does not loop). `from: null` enters the list at the edge the key points away from.
|
|
195
|
+
const findFrom = (from, direction) => {
|
|
196
|
+
if (from === null)
|
|
197
|
+
return findEdge(direction);
|
|
198
|
+
const items = ordered();
|
|
199
|
+
const { loop = true } = opts;
|
|
200
|
+
for (let distance = 1; distance <= items.length; distance += 1) {
|
|
201
|
+
let index = from + direction * distance;
|
|
202
|
+
if (loop) {
|
|
203
|
+
index = ((index % items.length) + items.length) % items.length;
|
|
204
|
+
}
|
|
205
|
+
else if (index < 0 || index >= items.length) {
|
|
206
|
+
return -1;
|
|
207
|
+
}
|
|
208
|
+
if (isNavigable(items[index]))
|
|
209
|
+
return index;
|
|
210
|
+
}
|
|
211
|
+
return -1;
|
|
212
|
+
};
|
|
213
|
+
// The single item reachable with Tab: the highlighted item when there is one, otherwise the
|
|
214
|
+
// default/active item, otherwise the first navigable one. This makes Tab land on the
|
|
215
|
+
// meaningful item WITHOUT any element being DOM-focused on mount (which would flash a focus
|
|
216
|
+
// ring). Virtual focus keeps every item out of the tab order.
|
|
217
|
+
const resolveTabStop = () => {
|
|
218
|
+
if (opts.virtualFocus)
|
|
219
|
+
return null;
|
|
220
|
+
if (focusedItem && !isUnfocusable(focusedItem))
|
|
221
|
+
return focusedItem;
|
|
222
|
+
const items = ordered();
|
|
223
|
+
const preferredIndex = opts.defaultFocusedIndex?.();
|
|
224
|
+
const preferred = preferredIndex == null ? undefined : items[preferredIndex];
|
|
225
|
+
if (preferred && isNavigable(preferred))
|
|
226
|
+
return preferred;
|
|
227
|
+
const edge = findEdge(1);
|
|
228
|
+
if (edge !== -1 && isRendered(items[edge]))
|
|
229
|
+
return items[edge];
|
|
230
|
+
// Nothing is rendered yet: keep the stop where it belongs once the list shows.
|
|
231
|
+
if (preferred && !isUnfocusable(preferred))
|
|
232
|
+
return preferred;
|
|
233
|
+
return items[edge] ?? null;
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Brings `tabindex`, `data-highlighted` and the container's `aria-activedescendant` in line
|
|
237
|
+
* with the highlighted item and the tab stop, touching only the items that changed role.
|
|
238
|
+
*/
|
|
239
|
+
const sync = () => {
|
|
240
|
+
const tabStop = resolveTabStop();
|
|
241
|
+
if (appliedTabStop && appliedTabStop !== tabStop && positions.has(appliedTabStop)) {
|
|
242
|
+
setAttribute(appliedTabStop, 'tabindex', '-1');
|
|
243
|
+
}
|
|
244
|
+
if (tabStop)
|
|
245
|
+
setAttribute(tabStop, 'tabindex', '0');
|
|
246
|
+
appliedTabStop = tabStop;
|
|
247
|
+
const highlight = focusedItem;
|
|
248
|
+
if (appliedHighlight && appliedHighlight !== highlight) {
|
|
249
|
+
removeAttribute(appliedHighlight, 'data-highlighted');
|
|
250
|
+
}
|
|
251
|
+
if (highlight)
|
|
252
|
+
setAttribute(highlight, 'data-highlighted', 'true');
|
|
253
|
+
appliedHighlight = highlight;
|
|
254
|
+
if (!containerRef)
|
|
255
|
+
return;
|
|
256
|
+
if (highlight?.id)
|
|
257
|
+
setAttribute(containerRef, 'aria-activedescendant', highlight.id);
|
|
258
|
+
else
|
|
259
|
+
removeAttribute(containerRef, 'aria-activedescendant');
|
|
260
|
+
};
|
|
261
|
+
const setFocused = (item, source) => {
|
|
262
|
+
focusedItem = item;
|
|
263
|
+
focusSource = item ? source : null;
|
|
264
|
+
containerHighlighted = false;
|
|
265
|
+
if (item)
|
|
266
|
+
lastFocusedItem = item;
|
|
267
|
+
};
|
|
27
268
|
const typeahead = opts.typeahead
|
|
28
269
|
? createTypeahead({
|
|
29
|
-
getItems:
|
|
270
|
+
getItems: ordered,
|
|
30
271
|
getText: (item) => typeof opts.typeahead === 'object'
|
|
31
272
|
? opts.typeahead.getText(item)
|
|
32
273
|
: (item.dataset.typeahead ?? item.textContent ?? ''),
|
|
33
|
-
|
|
274
|
+
// Search from the focused item, not from the one the pointer highlighted.
|
|
275
|
+
getCurrentIndex: () => {
|
|
276
|
+
const focused = itemIndexOf(document.activeElement);
|
|
277
|
+
return focused !== -1 ? focused : indexOf(focusedItem);
|
|
278
|
+
},
|
|
279
|
+
isItemDisabled: (item) => !isNavigable(item),
|
|
34
280
|
onMatch: (index) => {
|
|
35
|
-
|
|
36
|
-
|
|
281
|
+
const focused = itemIndexOf(document.activeElement);
|
|
282
|
+
moveFocusTo(index, focused !== -1 ? focused : indexOf(focusedItem));
|
|
37
283
|
}
|
|
38
284
|
})
|
|
39
285
|
: null;
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
if (typeof opts.orientation === 'function') {
|
|
43
|
-
return opts.orientation();
|
|
44
|
-
}
|
|
45
|
-
return opts.orientation || 'horizontal';
|
|
46
|
-
};
|
|
286
|
+
// The focused element, not its index, is what a change reports: an insertion before it moves
|
|
287
|
+
// its index without changing what has focus.
|
|
47
288
|
$effect(() => {
|
|
48
|
-
|
|
289
|
+
const item = focusedItem;
|
|
290
|
+
if (!item)
|
|
49
291
|
return;
|
|
50
|
-
const newFocusedIndex = focusedIndex;
|
|
51
292
|
untrack(() => {
|
|
52
|
-
|
|
293
|
+
const index = indexOf(item);
|
|
294
|
+
if (index !== -1)
|
|
295
|
+
opts.onChange?.(index);
|
|
53
296
|
});
|
|
54
297
|
});
|
|
298
|
+
// Plain functions, not deriveds: a menu switch reads these from sync() while the previous
|
|
299
|
+
// menu's effects are being destroyed, and reading a derived owned by a destroyed effect warns
|
|
300
|
+
// (derived_inert) and may return a stale value. They still track `revision` and the focus
|
|
301
|
+
// state for any reactive caller.
|
|
302
|
+
const readFocusedIndex = () => {
|
|
303
|
+
void revision;
|
|
304
|
+
if (focusedItem) {
|
|
305
|
+
const index = indexOf(focusedItem);
|
|
306
|
+
return index === -1 ? null : index;
|
|
307
|
+
}
|
|
308
|
+
return containerHighlighted ? -1 : null;
|
|
309
|
+
};
|
|
310
|
+
const readLastFocusedIndex = () => {
|
|
311
|
+
void revision;
|
|
312
|
+
const index = indexOf(lastFocusedItem);
|
|
313
|
+
return index === -1 ? null : index;
|
|
314
|
+
};
|
|
315
|
+
let observer = null;
|
|
316
|
+
// A class, style or media-query change can hide an item without touching any watched
|
|
317
|
+
// attribute. Hiding collapses its box, which a ResizeObserver reports; the tab stop then
|
|
318
|
+
// moves to an item that is still rendered. The first report of an item always counts, since an
|
|
319
|
+
// item hidden at mount reports nothing until it shows.
|
|
320
|
+
const renderedItems = new WeakMap();
|
|
321
|
+
let resizeObserver = null;
|
|
322
|
+
const watchRendered = (node) => {
|
|
323
|
+
if (typeof ResizeObserver === 'undefined')
|
|
324
|
+
return;
|
|
325
|
+
resizeObserver ??= new ResizeObserver((entries) => {
|
|
326
|
+
let changed = false;
|
|
327
|
+
for (const { target } of entries) {
|
|
328
|
+
if (!(target instanceof HTMLElement) || !positions.has(target))
|
|
329
|
+
continue;
|
|
330
|
+
const rendered = target.getClientRects().length > 0;
|
|
331
|
+
if (renderedItems.get(target) !== rendered)
|
|
332
|
+
changed = true;
|
|
333
|
+
renderedItems.set(target, rendered);
|
|
334
|
+
}
|
|
335
|
+
if (changed)
|
|
336
|
+
revision += 1;
|
|
337
|
+
});
|
|
338
|
+
resizeObserver.observe(node);
|
|
339
|
+
};
|
|
55
340
|
const cleanUp = () => {
|
|
56
|
-
|
|
341
|
+
registered.length = 0;
|
|
342
|
+
positions.clear();
|
|
343
|
+
observer?.disconnect();
|
|
344
|
+
observer = null;
|
|
345
|
+
resizeObserver?.disconnect();
|
|
346
|
+
resizeObserver = null;
|
|
347
|
+
typeahead?.reset();
|
|
348
|
+
restoreVersion.bump();
|
|
57
349
|
containerRef = null;
|
|
58
|
-
|
|
350
|
+
focusedItem = null;
|
|
59
351
|
focusSource = null;
|
|
352
|
+
containerHighlighted = false;
|
|
60
353
|
isHovering = false;
|
|
61
354
|
isFocused = false;
|
|
62
|
-
|
|
355
|
+
lastFocusedItem = null;
|
|
356
|
+
focusHolder = null;
|
|
357
|
+
appliedTabStop = null;
|
|
358
|
+
appliedHighlight = null;
|
|
63
359
|
};
|
|
64
360
|
onDestroy(() => {
|
|
65
361
|
cleanUp();
|
|
66
362
|
});
|
|
67
363
|
const focusContainer = () => {
|
|
68
364
|
if (containerRef) {
|
|
69
|
-
|
|
365
|
+
setFocused(null, null);
|
|
366
|
+
containerHighlighted = true;
|
|
367
|
+
sync();
|
|
70
368
|
containerRef.focus();
|
|
71
369
|
}
|
|
72
370
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Sort by DOM position using compareDocumentPosition
|
|
81
|
-
return itemsArray.sort((a, b) => {
|
|
82
|
-
const position = a.compareDocumentPosition(b);
|
|
83
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
84
|
-
return -1; // a comes before b
|
|
85
|
-
}
|
|
86
|
-
else if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
87
|
-
return 1; // b comes before a
|
|
88
|
-
}
|
|
89
|
-
return 0;
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
// Check if item is disabled
|
|
93
|
-
const isItemDisabled = (item) => {
|
|
94
|
-
const dataDisabled = item.getAttribute('data-disabled');
|
|
95
|
-
return (item.hasAttribute('disabled') ||
|
|
96
|
-
item.getAttribute('aria-disabled') === 'true' ||
|
|
97
|
-
(dataDisabled !== null && dataDisabled !== 'false'));
|
|
98
|
-
};
|
|
99
|
-
// Find next non-disabled index
|
|
100
|
-
const findNextIndex = (currentIndex, direction) => {
|
|
101
|
-
const { loop = true } = opts;
|
|
102
|
-
const total = items.length;
|
|
103
|
-
for (let distance = 1; distance <= total; distance += 1) {
|
|
104
|
-
let nextIndex = currentIndex + direction * distance;
|
|
105
|
-
if (loop) {
|
|
106
|
-
nextIndex = ((nextIndex % total) + total) % total;
|
|
107
|
-
}
|
|
108
|
-
else if (nextIndex < 0 || nextIndex >= total) {
|
|
109
|
-
return currentIndex;
|
|
110
|
-
}
|
|
111
|
-
if (!isItemDisabled(items[nextIndex]))
|
|
112
|
-
return nextIndex;
|
|
113
|
-
}
|
|
114
|
-
return currentIndex;
|
|
115
|
-
};
|
|
116
|
-
// Find first non-disabled index
|
|
117
|
-
const findFirstIndex = () => {
|
|
118
|
-
for (let i = 0; i < items.length; i++) {
|
|
119
|
-
if (!isItemDisabled(items[i]))
|
|
120
|
-
return i;
|
|
121
|
-
}
|
|
122
|
-
return -1; // No enabled items
|
|
123
|
-
};
|
|
124
|
-
// Find last non-disabled index
|
|
125
|
-
const findLastIndex = () => {
|
|
126
|
-
for (let i = items.length - 1; i >= 0; i--) {
|
|
127
|
-
if (!isItemDisabled(items[i]))
|
|
128
|
-
return i;
|
|
129
|
-
}
|
|
130
|
-
return -1; // No enabled items
|
|
131
|
-
};
|
|
132
|
-
// Update ARIA attributes on all items
|
|
133
|
-
const updateAriaAttributes = (focusIdx) => {
|
|
134
|
-
// The roving tab-stop (the single item reachable with Tab): the focused item
|
|
135
|
-
// when there is one, otherwise the default/active item, otherwise the first
|
|
136
|
-
// enabled one. This makes Tab land on the meaningful item WITHOUT any element
|
|
137
|
-
// being DOM-focused on mount (which would flash a focus ring). Virtual focus
|
|
138
|
-
// keeps every item out of the tab order.
|
|
139
|
-
const preferredTabStop = focusIdx ?? opts.defaultFocusedIndex?.();
|
|
140
|
-
const enabledTabStop = preferredTabStop != null &&
|
|
141
|
-
items[preferredTabStop] &&
|
|
142
|
-
!isItemDisabled(items[preferredTabStop])
|
|
143
|
-
? preferredTabStop
|
|
144
|
-
: findFirstIndex();
|
|
145
|
-
const tabStop = opts.virtualFocus ? -1 : enabledTabStop;
|
|
146
|
-
items.forEach((item, index) => {
|
|
147
|
-
const isFocused = index === focusIdx;
|
|
148
|
-
const itemId = `${baseId}-item-${index}`;
|
|
149
|
-
// Set ID
|
|
150
|
-
if (!item.id) {
|
|
151
|
-
item.id = itemId;
|
|
152
|
-
}
|
|
153
|
-
// Roving tabindex sits on the tab-stop; data-highlighted (below) tracks
|
|
154
|
-
// actual keyboard focus, which is a separate concern.
|
|
155
|
-
item.setAttribute('tabindex', index === tabStop && !isItemDisabled(item) ? '0' : '-1');
|
|
156
|
-
// Set data-highlighted for keyboard focus
|
|
157
|
-
if (isFocused) {
|
|
158
|
-
item.setAttribute('data-highlighted', 'true');
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
item.removeAttribute('data-highlighted');
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
// Update container's aria-activedescendant to focused item
|
|
165
|
-
if (containerRef && focusIdx !== null && items[focusIdx]) {
|
|
166
|
-
containerRef.setAttribute('aria-activedescendant', items[focusIdx].id);
|
|
167
|
-
}
|
|
168
|
-
else if (containerRef) {
|
|
169
|
-
containerRef.removeAttribute('aria-activedescendant');
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
// Move focus to specific index (arrow key navigation)
|
|
173
|
-
const moveFocusTo = (index) => {
|
|
174
|
-
if (items.length === 0)
|
|
371
|
+
/**
|
|
372
|
+
* Moves the highlight and DOM focus to `index`. `from` marks a key-driven move (the index the
|
|
373
|
+
* key started from, `null` when it entered the list), which reports through `onKeyboardMove`.
|
|
374
|
+
*/
|
|
375
|
+
const moveFocusTo = (index, from) => {
|
|
376
|
+
const item = ordered()[index];
|
|
377
|
+
if (!item || isUnfocusable(item))
|
|
175
378
|
return;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
focusedIndex = index;
|
|
182
|
-
updateAriaAttributes(index);
|
|
183
|
-
if (items[index]) {
|
|
184
|
-
const item = items[index];
|
|
185
|
-
// Virtual focus (combobox pattern): DOM focus stays put, only the highlight moves.
|
|
186
|
-
if (!opts.virtualFocus) {
|
|
187
|
-
item.focus();
|
|
188
|
-
}
|
|
189
|
-
// Scroll the item into view if needed
|
|
190
|
-
item.scrollIntoView({
|
|
191
|
-
block: 'nearest',
|
|
192
|
-
inline: 'nearest',
|
|
193
|
-
behavior: 'smooth'
|
|
194
|
-
});
|
|
379
|
+
setFocused(item, 'keyboard');
|
|
380
|
+
sync();
|
|
381
|
+
// Virtual focus (combobox pattern): DOM focus stays put, only the highlight moves.
|
|
382
|
+
if (!opts.virtualFocus) {
|
|
383
|
+
item.focus();
|
|
195
384
|
}
|
|
385
|
+
// Scroll the item into view if needed
|
|
386
|
+
item.scrollIntoView({
|
|
387
|
+
block: 'nearest',
|
|
388
|
+
inline: 'nearest',
|
|
389
|
+
behavior: prefersReducedMotion() ? 'auto' : 'smooth'
|
|
390
|
+
});
|
|
391
|
+
if (from !== undefined && from !== index)
|
|
392
|
+
opts.onKeyboardMove?.(index);
|
|
196
393
|
};
|
|
197
394
|
// Click the currently focused item (Enter/Space key)
|
|
198
395
|
const clickFocused = () => {
|
|
199
|
-
if (
|
|
200
|
-
return;
|
|
201
|
-
if (isItemDisabled(items[focusedIndex]))
|
|
396
|
+
if (!focusedItem || isItemDisabled(focusedItem))
|
|
202
397
|
return;
|
|
203
|
-
|
|
204
|
-
items[focusedIndex].click();
|
|
398
|
+
focusedItem.click();
|
|
205
399
|
};
|
|
206
400
|
// Clear focus state when container loses focus
|
|
207
401
|
const clearFocus = () => {
|
|
208
|
-
|
|
209
|
-
focusSource = null;
|
|
402
|
+
setFocused(null, null);
|
|
210
403
|
// Restore the default roving tab stop while removing the active highlight.
|
|
211
|
-
|
|
404
|
+
sync();
|
|
212
405
|
};
|
|
213
406
|
// Handle item hover - only set visual focus (no DOM focus yet)
|
|
214
|
-
const handleItemHover = (
|
|
215
|
-
|
|
216
|
-
const index = items.findIndex((item) => item === itemElement);
|
|
217
|
-
if (index === -1)
|
|
218
|
-
return;
|
|
219
|
-
if (isItemDisabled(items[index]))
|
|
407
|
+
const handleItemHover = (item) => {
|
|
408
|
+
if (!positions.has(item) || isItemDisabled(item))
|
|
220
409
|
return;
|
|
221
410
|
// Set visual focus on hovered item (don't manipulate DOM focus)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
updateAriaAttributes(index);
|
|
411
|
+
setFocused(item, 'pointer');
|
|
412
|
+
sync();
|
|
225
413
|
};
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
414
|
+
// The navigable item nearest to `from`: `from` itself, then the item before it, the one after,
|
|
415
|
+
// and so on outward (the order a tab list picks the tab that replaces a removed one).
|
|
416
|
+
const findNearest = (from) => {
|
|
417
|
+
const items = ordered();
|
|
418
|
+
for (let distance = 0; distance < items.length; distance += 1) {
|
|
419
|
+
for (const index of [from + distance, from - distance - 1]) {
|
|
420
|
+
if (index >= 0 && index < items.length && isNavigable(items[index]))
|
|
421
|
+
return index;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return -1;
|
|
425
|
+
};
|
|
426
|
+
// Removing the item that had DOM focus would drop focus to <body>. Once the change has settled
|
|
427
|
+
// (replacement items registered), focus moves to the item that took the removed one's place,
|
|
428
|
+
// or the nearest navigable item to it — unless focus has already gone somewhere else.
|
|
429
|
+
const scheduleRestore = (previous, removed) => {
|
|
430
|
+
const version = restoreVersion.bump();
|
|
431
|
+
queueMicrotask(() => {
|
|
432
|
+
if (!restoreVersion.isCurrent(version) || !containerRef)
|
|
433
|
+
return;
|
|
434
|
+
const active = document.activeElement;
|
|
435
|
+
if (active && active !== document.body && active !== document.documentElement)
|
|
436
|
+
return;
|
|
437
|
+
const neighbour = clampRovingKey(previous, removed, ordered());
|
|
438
|
+
const target = neighbour ? findNearest(indexOf(neighbour)) : -1;
|
|
439
|
+
if (target !== -1)
|
|
440
|
+
moveFocusTo(target);
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
const register = (node) => {
|
|
444
|
+
const last = registered.at(-1);
|
|
445
|
+
if (last && (!last.isConnected || byDocumentPosition(last, node) > 0))
|
|
446
|
+
orderStale = true;
|
|
447
|
+
positions.set(node, registered.length);
|
|
448
|
+
registered.push(node);
|
|
449
|
+
// Ids are assigned once, at registration: aria-activedescendant names them.
|
|
450
|
+
if (!node.id)
|
|
451
|
+
node.id = `${baseId}-item-${(sequence += 1)}`;
|
|
452
|
+
setAttribute(node, 'tabindex', '-1');
|
|
453
|
+
watchRendered(node);
|
|
454
|
+
revision += 1;
|
|
455
|
+
};
|
|
456
|
+
const unregister = (node) => {
|
|
457
|
+
if (!positions.has(node))
|
|
458
|
+
return;
|
|
459
|
+
const previous = focusHolder === node ? registered.slice() : null;
|
|
460
|
+
const index = registered.indexOf(node);
|
|
461
|
+
if (index !== -1)
|
|
462
|
+
registered.splice(index, 1);
|
|
463
|
+
positions.delete(node);
|
|
464
|
+
positionsStale = true;
|
|
465
|
+
resizeObserver?.unobserve(node);
|
|
466
|
+
renderedItems.delete(node);
|
|
467
|
+
if (appliedTabStop === node)
|
|
468
|
+
appliedTabStop = null;
|
|
469
|
+
if (appliedHighlight === node)
|
|
470
|
+
appliedHighlight = null;
|
|
471
|
+
if (lastFocusedItem === node)
|
|
472
|
+
lastFocusedItem = null;
|
|
473
|
+
if (focusedItem === node)
|
|
474
|
+
setFocused(null, null);
|
|
475
|
+
if (previous) {
|
|
476
|
+
focusHolder = null;
|
|
477
|
+
scheduleRestore(previous, node);
|
|
231
478
|
}
|
|
479
|
+
revision += 1;
|
|
480
|
+
};
|
|
481
|
+
// Keep the attributes in line after every change to the list, the highlight or the default
|
|
482
|
+
// item. It runs after the DOM updates, so it also wins over a consumer's own `tabindex`.
|
|
483
|
+
$effect(() => {
|
|
484
|
+
void revision;
|
|
485
|
+
sync();
|
|
232
486
|
});
|
|
233
487
|
const pointerDown = usePointerDown({
|
|
234
488
|
isActive: () => true
|
|
235
489
|
});
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
490
|
+
// In RTL the inline arrows are mirrored: in a horizontal list ArrowRight goes to the previous
|
|
491
|
+
// item; in a vertical one ArrowLeft opens a level (onNext) and ArrowRight leaves it (onPrevious).
|
|
492
|
+
const resolveKey = (key) => {
|
|
493
|
+
const mirrored = (opts.rtl ?? true) && getDirection() === 'rtl';
|
|
494
|
+
if (mirrored && key === 'ArrowLeft')
|
|
495
|
+
return 'ArrowRight';
|
|
496
|
+
if (mirrored && key === 'ArrowRight')
|
|
497
|
+
return 'ArrowLeft';
|
|
498
|
+
return key;
|
|
499
|
+
};
|
|
500
|
+
// Move with an arrow along the list's axis; a key with nowhere to go still counts as handled,
|
|
501
|
+
// so the page does not scroll under the list.
|
|
502
|
+
const step = (from, direction) => {
|
|
503
|
+
const index = findFrom(from, direction);
|
|
504
|
+
if (index !== -1)
|
|
505
|
+
moveFocusTo(index, from);
|
|
506
|
+
return true;
|
|
507
|
+
};
|
|
508
|
+
/**
|
|
509
|
+
* Move or activate for one (already mirrored) key, starting from `from`: the index of the item
|
|
510
|
+
* the key acts on, or `null` when it comes from outside the items and enters the list at an
|
|
511
|
+
* edge. Returns whether the key did anything.
|
|
512
|
+
*/
|
|
513
|
+
const navigate = (key, from) => {
|
|
514
|
+
const orientation = getOrientation();
|
|
515
|
+
switch (key) {
|
|
516
|
+
case 'ArrowLeft':
|
|
517
|
+
case 'ArrowRight': {
|
|
518
|
+
const direction = key === 'ArrowRight' ? 1 : -1;
|
|
519
|
+
if (orientation !== 'vertical')
|
|
520
|
+
return step(from, direction);
|
|
521
|
+
// Cross axis of a vertical list: the item may open (onNext) or leave (onPrevious) a level.
|
|
522
|
+
const item = from === null ? undefined : ordered()[from];
|
|
523
|
+
if (!item)
|
|
524
|
+
return false;
|
|
525
|
+
const node = item;
|
|
526
|
+
const handler = direction === 1 ? node.onNext : node.onPrevious;
|
|
527
|
+
if (typeof handler !== 'function')
|
|
528
|
+
return false;
|
|
529
|
+
return handler.call(node) !== false;
|
|
273
530
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
531
|
+
case 'ArrowUp':
|
|
532
|
+
case 'ArrowDown':
|
|
533
|
+
if (orientation === 'horizontal')
|
|
534
|
+
return false;
|
|
535
|
+
return step(from, key === 'ArrowDown' ? 1 : -1);
|
|
536
|
+
case 'Home':
|
|
537
|
+
case 'End': {
|
|
538
|
+
const index = findEdge(key === 'Home' ? 1 : -1);
|
|
539
|
+
if (index === -1)
|
|
540
|
+
return false;
|
|
541
|
+
moveFocusTo(index, from);
|
|
542
|
+
return true;
|
|
277
543
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
? 'ArrowRight'
|
|
282
|
-
: mirrored && event.key === 'ArrowRight'
|
|
283
|
-
? 'ArrowLeft'
|
|
284
|
-
: event.key;
|
|
285
|
-
switch (key) {
|
|
286
|
-
case 'ArrowLeft':
|
|
287
|
-
if (orientation === 'horizontal') {
|
|
288
|
-
const currentIdx = focusedIndex ?? findFirstIndex();
|
|
289
|
-
if (currentIdx !== -1) {
|
|
290
|
-
moveFocusTo(findNextIndex(currentIdx, -1));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
else if (focusedIndex !== null) {
|
|
294
|
-
const node = items[focusedIndex];
|
|
295
|
-
if ('onPrevious' in node && typeof node.onPrevious === 'function') {
|
|
296
|
-
node.onPrevious();
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
break;
|
|
300
|
-
case 'ArrowRight':
|
|
301
|
-
if (orientation === 'horizontal') {
|
|
302
|
-
const currentIdx = focusedIndex ?? findFirstIndex();
|
|
303
|
-
if (currentIdx !== -1) {
|
|
304
|
-
moveFocusTo(findNextIndex(currentIdx, 1));
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
else if (focusedIndex !== null) {
|
|
308
|
-
const node = items[focusedIndex];
|
|
309
|
-
if ('onNext' in node && typeof node.onNext === 'function') {
|
|
310
|
-
node.onNext();
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
break;
|
|
314
|
-
case 'ArrowUp':
|
|
315
|
-
if (orientation === 'vertical') {
|
|
316
|
-
const currentIdx = focusedIndex ?? findFirstIndex();
|
|
317
|
-
if (currentIdx !== -1) {
|
|
318
|
-
moveFocusTo(findNextIndex(currentIdx, -1));
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
moveFocusTo(findLastIndex());
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
break;
|
|
325
|
-
case 'ArrowDown':
|
|
326
|
-
if (orientation === 'vertical') {
|
|
327
|
-
const currentIdx = focusedIndex ?? findFirstIndex();
|
|
328
|
-
if (currentIdx !== -1) {
|
|
329
|
-
moveFocusTo(findNextIndex(currentIdx, 1));
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
moveFocusTo(findFirstIndex());
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
break;
|
|
336
|
-
case 'Home': {
|
|
337
|
-
const firstIndex = findFirstIndex();
|
|
338
|
-
if (firstIndex !== -1) {
|
|
339
|
-
moveFocusTo(firstIndex);
|
|
340
|
-
}
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
case 'End': {
|
|
344
|
-
const lastIndex = findLastIndex();
|
|
345
|
-
if (lastIndex !== -1) {
|
|
346
|
-
moveFocusTo(lastIndex);
|
|
347
|
-
}
|
|
348
|
-
break;
|
|
544
|
+
case 'Escape':
|
|
545
|
+
if (containerRef?.contains(document.activeElement)) {
|
|
546
|
+
clearFocus();
|
|
349
547
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
548
|
+
return true;
|
|
549
|
+
case 'Enter':
|
|
550
|
+
case ' ':
|
|
551
|
+
if (key === 'Enter' && opts.enterActivates === false)
|
|
552
|
+
return false;
|
|
553
|
+
clickFocused();
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
};
|
|
558
|
+
// Keys act where keyboard focus is. Hover moves the highlight without moving DOM focus, so a
|
|
559
|
+
// key typed on a focused item starts from that item, not from the one under the pointer. A key
|
|
560
|
+
// typed on the container itself (a popup menu opened by pointer) keeps the highlighted item,
|
|
561
|
+
// which the container's aria-activedescendant names.
|
|
562
|
+
const syncToKeyTarget = (target) => {
|
|
563
|
+
const item = itemOf(target);
|
|
564
|
+
if (!item || item === focusedItem)
|
|
565
|
+
return;
|
|
566
|
+
setFocused(item, 'keyboard');
|
|
567
|
+
sync();
|
|
568
|
+
};
|
|
569
|
+
// The item a key typed on `target` starts from; null enters the list at an edge.
|
|
570
|
+
const keyOrigin = (target) => {
|
|
571
|
+
const index = itemIndexOf(target);
|
|
572
|
+
if (index !== -1)
|
|
573
|
+
return index;
|
|
574
|
+
if (target !== containerRef)
|
|
575
|
+
return null;
|
|
576
|
+
const highlighted = indexOf(focusedItem);
|
|
577
|
+
return highlighted === -1 ? null : highlighted;
|
|
578
|
+
};
|
|
579
|
+
// A text field keeps its editing keys: Home, End, Space and Enter never leave it. Arrows along
|
|
580
|
+
// the list's axis do, horizontal ones only from the caret edge they point past (a search field
|
|
581
|
+
// in a toolbar), vertical ones from single-line inputs (a filter field above a menu's rows).
|
|
582
|
+
const fieldReleases = (event, key) => {
|
|
583
|
+
const orientation = getOrientation();
|
|
584
|
+
switch (key) {
|
|
585
|
+
case 'ArrowLeft':
|
|
586
|
+
case 'ArrowRight':
|
|
587
|
+
return (orientation !== 'vertical' && isCaretAtEdge(event, key === 'ArrowRight' ? 'end' : 'start'));
|
|
588
|
+
case 'ArrowUp':
|
|
589
|
+
case 'ArrowDown':
|
|
590
|
+
if (orientation === 'horizontal')
|
|
591
|
+
return false;
|
|
592
|
+
return (event.target instanceof HTMLInputElement ||
|
|
593
|
+
isCaretAtEdge(event, key === 'ArrowDown' ? 'end' : 'start'));
|
|
594
|
+
default:
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
// Content inside the container that is no item (a header field or button) keeps Enter, Space
|
|
599
|
+
// and Escape; arrows along the axis and Home/End enter the list at its start or end.
|
|
600
|
+
const contentReleases = (event, key) => {
|
|
601
|
+
if (isTextEntry(event.target))
|
|
602
|
+
return fieldReleases(event, key);
|
|
603
|
+
const orientation = getOrientation();
|
|
604
|
+
switch (key) {
|
|
605
|
+
case 'Home':
|
|
606
|
+
case 'End':
|
|
607
|
+
return true;
|
|
608
|
+
case 'ArrowLeft':
|
|
609
|
+
case 'ArrowRight':
|
|
610
|
+
return orientation !== 'vertical';
|
|
611
|
+
case 'ArrowUp':
|
|
612
|
+
case 'ArrowDown':
|
|
613
|
+
return orientation !== 'horizontal';
|
|
614
|
+
default:
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
// Keys typed while focus is inside the container.
|
|
619
|
+
const handleContainerKey = (event) => {
|
|
620
|
+
const target = event.target;
|
|
621
|
+
if (!ownsKeyTarget(target))
|
|
622
|
+
return;
|
|
623
|
+
const key = resolveKey(event.key);
|
|
624
|
+
if (target !== containerRef && !itemOf(target)) {
|
|
625
|
+
if (!isEnabled() || !contentReleases(event, key))
|
|
626
|
+
return;
|
|
627
|
+
event.preventDefault();
|
|
628
|
+
navigate(key, null);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (isTextEntry(target) && key !== 'Escape' && !fieldReleases(event, key))
|
|
632
|
+
return;
|
|
633
|
+
// `preventKeyboardDefault: false` (menus) lets Escape reach the popup that closes on it;
|
|
634
|
+
// every other consumer keeps all of its keys.
|
|
635
|
+
if (opts.preventKeyboardDefault !== false)
|
|
636
|
+
event.preventDefault();
|
|
637
|
+
if (!isEnabled())
|
|
638
|
+
return;
|
|
639
|
+
if (event.key !== 'Escape')
|
|
640
|
+
event.preventDefault();
|
|
641
|
+
syncToKeyTarget(target);
|
|
642
|
+
navigate(key, keyOrigin(target));
|
|
643
|
+
};
|
|
644
|
+
// Only these keys may pull focus into a container the pointer merely rests on.
|
|
645
|
+
const hoverEntryKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'];
|
|
646
|
+
// No element has focus: the key was typed on the page itself, not in a field or control.
|
|
647
|
+
const isPageLevel = (node) => {
|
|
648
|
+
const pageTargets = [
|
|
649
|
+
null,
|
|
650
|
+
window,
|
|
651
|
+
document,
|
|
652
|
+
document.body,
|
|
653
|
+
document.documentElement
|
|
654
|
+
];
|
|
655
|
+
return pageTargets.includes(node);
|
|
656
|
+
};
|
|
657
|
+
// Hover-to-navigate (`enableHoverFocus`): while the pointer rests on the container and nothing
|
|
658
|
+
// on the page has focus, arrows and Home/End move focus into it, from the item highlighted
|
|
659
|
+
// under the pointer or, with none, at the edge the key points to. A key typed anywhere else (a
|
|
660
|
+
// text field, a button, an open submenu or dialog) belongs to that element, and Enter/Space
|
|
661
|
+
// never activate an item that is only highlighted under the pointer.
|
|
662
|
+
const handleHoverKey = (event) => {
|
|
663
|
+
if (event.defaultPrevented || !hoverEntryKeys.includes(event.key))
|
|
664
|
+
return;
|
|
665
|
+
if (!isPageLevel(document.activeElement) || !isPageLevel(event.target))
|
|
666
|
+
return;
|
|
667
|
+
const highlighted = indexOf(focusedItem);
|
|
668
|
+
if (navigate(resolveKey(event.key), highlighted === -1 ? null : highlighted)) {
|
|
669
|
+
event.preventDefault();
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
// Alt/Ctrl/Meta + a navigation key is a browser or OS shortcut (Alt+← is Back), never a move.
|
|
673
|
+
// useKeyDown leaves those alone; preventDefault is decided per path above.
|
|
674
|
+
const keyDown = useKeyDown({
|
|
675
|
+
isActive: isEnabled,
|
|
676
|
+
preventDefault: false,
|
|
677
|
+
ignoreModifiers: true,
|
|
678
|
+
onWindow: () => isHovering && !isFocused && !!opts.enableHoverFocus,
|
|
679
|
+
callback: (event, source) => {
|
|
680
|
+
if (source === 'window')
|
|
681
|
+
handleHoverKey(event);
|
|
682
|
+
else
|
|
683
|
+
handleContainerKey(event);
|
|
361
684
|
},
|
|
362
685
|
keys: ['Escape', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'Enter', ' ']
|
|
363
686
|
});
|
|
@@ -365,28 +688,64 @@ export const useNavigation = (opts) => {
|
|
|
365
688
|
containerReference: (node) => {
|
|
366
689
|
return untrack(() => {
|
|
367
690
|
containerRef = node;
|
|
368
|
-
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
691
|
+
containers.add(node);
|
|
692
|
+
// Focusable from script (a popup focuses it and names the highlighted item through
|
|
693
|
+
// aria-activedescendant) but never a Tab stop: the roving tab stop is on an item.
|
|
694
|
+
// Virtual focus keeps DOM focus on the consumer's own element (a combobox input).
|
|
695
|
+
if (!node.hasAttribute('tabindex') &&
|
|
696
|
+
!opts.virtualFocus &&
|
|
697
|
+
opts.focusableContainer !== false) {
|
|
698
|
+
node.setAttribute('tabindex', '-1');
|
|
699
|
+
}
|
|
700
|
+
// A keyed reorder moves item nodes without re-running their attachments, and an item can
|
|
701
|
+
// become disabled or hidden without registering again: both re-sync the list. Only a
|
|
702
|
+
// move (a node removed and added again in one batch) can break the order; insertions are
|
|
703
|
+
// placed as they register and removals keep it.
|
|
704
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
705
|
+
observer = new MutationObserver((records) => {
|
|
706
|
+
// Writing an attribute with the value it already has still queues a record (a
|
|
707
|
+
// template re-assigning `button.disabled = true`). Counting it would re-run the
|
|
708
|
+
// attribute sync, which re-runs that template: an endless loop.
|
|
709
|
+
if (records.every(isUnchangedAttribute))
|
|
710
|
+
return;
|
|
711
|
+
if (hasMovedNode(records))
|
|
712
|
+
orderStale = true;
|
|
713
|
+
revision += 1;
|
|
714
|
+
});
|
|
715
|
+
observer.observe(node, {
|
|
716
|
+
childList: true,
|
|
717
|
+
subtree: true,
|
|
718
|
+
attributes: true,
|
|
719
|
+
attributeOldValue: true,
|
|
720
|
+
attributeFilter: ['disabled', 'aria-disabled', 'data-disabled', 'hidden', 'inert']
|
|
721
|
+
});
|
|
372
722
|
}
|
|
373
723
|
// Apply keydown reference
|
|
374
|
-
const keyDownCleanup = keyDown.reference
|
|
724
|
+
const keyDownCleanup = keyDown.reference(node);
|
|
375
725
|
const typeaheadCleanup = typeahead
|
|
376
726
|
? on(node, 'keydown', (event) => {
|
|
377
|
-
if (!isEnabled() || event.defaultPrevented)
|
|
727
|
+
if (!isEnabled() || event.defaultPrevented || !ownsKeyTarget(event.target))
|
|
378
728
|
return;
|
|
379
729
|
if (typeahead.handleKey(event))
|
|
380
730
|
event.preventDefault();
|
|
381
731
|
})
|
|
382
732
|
: null;
|
|
383
|
-
//
|
|
384
|
-
|
|
733
|
+
// The container itself receiving focus (from script, or a click between items) moves
|
|
734
|
+
// focus to the default item, unless the pointer is down or a popup focused it on purpose.
|
|
735
|
+
// Focus that lands on an item, or on other content inside the list, stays there.
|
|
736
|
+
const handleFocus = (event) => {
|
|
385
737
|
isFocused = true;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
738
|
+
focusHolder = itemOf(event.target);
|
|
739
|
+
if (event.target !== node)
|
|
740
|
+
return;
|
|
741
|
+
if (focusedItem === null && !containerHighlighted && !pointerDown.isDown) {
|
|
742
|
+
const preferred = opts.defaultFocusedIndex?.();
|
|
743
|
+
const items = ordered();
|
|
744
|
+
const index = preferred != null && items[preferred] && isNavigable(items[preferred])
|
|
745
|
+
? preferred
|
|
746
|
+
: findEdge(1);
|
|
747
|
+
if (index !== -1) {
|
|
748
|
+
moveFocusTo(index);
|
|
390
749
|
}
|
|
391
750
|
}
|
|
392
751
|
};
|
|
@@ -394,12 +753,25 @@ export const useNavigation = (opts) => {
|
|
|
394
753
|
// Handle blur event - reset focus when container loses focus
|
|
395
754
|
const handleBlur = (event) => {
|
|
396
755
|
isFocused = false;
|
|
397
|
-
// Check if focus moved outside the container
|
|
398
756
|
const relatedTarget = event.relatedTarget;
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
757
|
+
if (relatedTarget instanceof Node && node.contains(relatedTarget))
|
|
758
|
+
return;
|
|
759
|
+
// Focus left the list: the type-ahead buffer starts over next time.
|
|
760
|
+
typeahead?.reset();
|
|
761
|
+
if (relatedTarget === null) {
|
|
762
|
+
// Lost to nothing. Chromium blurs a focused item while removing it (still connected,
|
|
763
|
+
// so this cannot tell yet), and its unregistration later in the same flush restores
|
|
764
|
+
// focus. An item still in the document afterwards lost focus to the page instead.
|
|
765
|
+
const holder = focusHolder;
|
|
766
|
+
queueMicrotask(() => {
|
|
767
|
+
if (focusHolder === holder && holder?.isConnected)
|
|
768
|
+
focusHolder = null;
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
focusHolder = null;
|
|
402
773
|
}
|
|
774
|
+
clearFocus();
|
|
403
775
|
};
|
|
404
776
|
const blurCleanup = on(node, 'focusout', handleBlur);
|
|
405
777
|
// Handle container pointer enter - track hovering state
|
|
@@ -420,12 +792,12 @@ export const useNavigation = (opts) => {
|
|
|
420
792
|
// on mount — a tablist/menu must not steal focus just by existing (it
|
|
421
793
|
// caused a focus-visible ring on the first tab on page load). Consumers
|
|
422
794
|
// that want focus-on-mount opt in explicitly (e.g. Menu's `focusOnMount`
|
|
423
|
-
// via onMount).
|
|
424
|
-
//
|
|
425
|
-
// (updateAriaAttributes) makes the active item directly Tab-reachable.
|
|
795
|
+
// via onMount). The roving tab-stop (sync) makes the active item directly
|
|
796
|
+
// Tab-reachable.
|
|
426
797
|
return () => {
|
|
798
|
+
containers.delete(node);
|
|
427
799
|
cleanUp();
|
|
428
|
-
keyDownCleanup
|
|
800
|
+
keyDownCleanup();
|
|
429
801
|
typeaheadCleanup?.();
|
|
430
802
|
focusCleanup();
|
|
431
803
|
blurCleanup();
|
|
@@ -437,28 +809,23 @@ export const useNavigation = (opts) => {
|
|
|
437
809
|
},
|
|
438
810
|
itemReference: (node) => {
|
|
439
811
|
return untrack(() => {
|
|
440
|
-
|
|
441
|
-
itemsSet.add(node);
|
|
442
|
-
// ARIA attributes are now batch-updated via $effect
|
|
812
|
+
register(node);
|
|
443
813
|
const handleFocus = () => {
|
|
444
|
-
|
|
445
|
-
if (index === -1 || isItemDisabled(node))
|
|
814
|
+
if (!positions.has(node) || isUnfocusable(node))
|
|
446
815
|
return;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
updateAriaAttributes(index);
|
|
816
|
+
setFocused(node, 'keyboard');
|
|
817
|
+
sync();
|
|
450
818
|
};
|
|
451
819
|
const focusCleanup = on(node, 'focus', handleFocus);
|
|
452
820
|
// Handle hover - only move focus if enabled
|
|
453
821
|
const handleHover = () => {
|
|
454
|
-
if (isEnabled() && opts.enableHoverFocus !== false
|
|
822
|
+
if (isEnabled() && opts.enableHoverFocus !== false) {
|
|
455
823
|
handleItemHover(node);
|
|
456
824
|
}
|
|
457
825
|
};
|
|
458
826
|
const hoverCleanup = on(node, 'pointerenter', handleHover);
|
|
459
827
|
return () => {
|
|
460
|
-
|
|
461
|
-
itemsSet.delete(node);
|
|
828
|
+
unregister(node);
|
|
462
829
|
focusCleanup();
|
|
463
830
|
hoverCleanup();
|
|
464
831
|
};
|
|
@@ -466,22 +833,22 @@ export const useNavigation = (opts) => {
|
|
|
466
833
|
},
|
|
467
834
|
// Expose focused index for external use
|
|
468
835
|
get focusedIndex() {
|
|
469
|
-
return
|
|
836
|
+
return readFocusedIndex();
|
|
470
837
|
},
|
|
471
838
|
// Expose control methods
|
|
472
839
|
focusItem: (index) => {
|
|
473
|
-
if (index >= 0 && index <
|
|
840
|
+
if (index >= 0 && index < ordered().length) {
|
|
474
841
|
moveFocusTo(index);
|
|
475
842
|
}
|
|
476
843
|
},
|
|
477
844
|
focusFirst: () => {
|
|
478
|
-
const firstIndex =
|
|
845
|
+
const firstIndex = findEdge(1);
|
|
479
846
|
if (firstIndex !== -1) {
|
|
480
847
|
moveFocusTo(firstIndex);
|
|
481
848
|
}
|
|
482
849
|
},
|
|
483
850
|
focusLast: () => {
|
|
484
|
-
const lastIndex =
|
|
851
|
+
const lastIndex = findEdge(-1);
|
|
485
852
|
if (lastIndex !== -1) {
|
|
486
853
|
moveFocusTo(lastIndex);
|
|
487
854
|
}
|
|
@@ -496,16 +863,16 @@ export const useNavigation = (opts) => {
|
|
|
496
863
|
* any) should be highlighted instead of the stale trigger.
|
|
497
864
|
*/
|
|
498
865
|
syncPointerFocus: () => {
|
|
499
|
-
const hovered =
|
|
500
|
-
if (hovered
|
|
501
|
-
handleItemHover(
|
|
866
|
+
const hovered = ordered().find((item) => item.matches(':hover') && !isItemDisabled(item));
|
|
867
|
+
if (hovered) {
|
|
868
|
+
handleItemHover(hovered);
|
|
502
869
|
}
|
|
503
870
|
else if (focusSource === 'pointer') {
|
|
504
871
|
clearFocus();
|
|
505
872
|
}
|
|
506
873
|
},
|
|
507
874
|
get lastFocusedIndex() {
|
|
508
|
-
return
|
|
875
|
+
return readLastFocusedIndex();
|
|
509
876
|
},
|
|
510
877
|
focusContainer: focusContainer
|
|
511
878
|
};
|