@threadlabs/looma 0.22.8 → 0.22.10
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/components/ui-affordance-scope/ui-affordance-scope.js +2 -2
- package/components/ui-avatar/ui-avatar.js +5 -5
- package/components/ui-avatar-group/ui-avatar-group.js +5 -5
- package/components/ui-badge/ui-badge.html +10 -0
- package/components/ui-button/ui-button.js +1 -1
- package/components/ui-checkbox/ui-checkbox.js +5 -5
- package/components/ui-combobox/ui-combobox.js +61 -61
- package/components/ui-context-menu/ui-context-menu.js +6 -6
- package/components/ui-dialog/ui-dialog.js +9 -9
- package/components/ui-disclosure/ui-disclosure.js +6 -6
- package/components/ui-editable/ui-editable.js +6 -6
- package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.js +4 -4
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.js +8 -8
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.js +6 -6
- package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.js +5 -5
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +4 -4
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +5 -5
- package/components/ui-form-field/ui-form-field.js +4 -4
- package/components/ui-icon-button/ui-icon-button.js +2 -2
- package/components/ui-input/ui-input.js +1 -1
- package/components/ui-input-group/ui-input-group.js +1 -1
- package/components/ui-listbox/ui-listbox.js +12 -12
- package/components/ui-menu/ui-menu.js +7 -7
- package/components/ui-menu-item/ui-menu-item.js +7 -7
- package/components/ui-popover/ui-popover.js +4 -4
- package/components/ui-radio/ui-radio.js +5 -5
- package/components/ui-radio-group/ui-radio-group.js +6 -6
- package/components/ui-scroll-area/ui-scroll-area.js +1 -1
- package/components/ui-search-shell/ui-search-shell.js +6 -6
- package/components/ui-select/ui-select.js +1 -1
- package/components/ui-sidebar/ui-sidebar.js +12 -12
- package/components/ui-switch/ui-switch.js +5 -5
- package/components/ui-switcher/ui-switcher.js +1 -1
- package/components/ui-tabs/ui-tabs.js +5 -5
- package/components/ui-textarea/ui-textarea.js +1 -1
- package/components/ui-toast/ui-toast.js +3 -3
- package/components/ui-toast-region/ui-toast-region.js +1 -1
- package/components/ui-tooltip/ui-tooltip.js +9 -9
- package/components/ui-tree/ui-tree.js +4 -4
- package/components/ui-tree-item/ui-tree-item.js +11 -11
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/styles/ui-action-bar.css +1 -1
- package/styles/ui-affordance-scope.css +1 -1
- package/styles/ui-avatar-group.css +1 -1
- package/styles/ui-avatar.css +1 -1
- package/styles/ui-badge.css +10 -1
- package/styles/ui-breadcrumb-item.css +1 -1
- package/styles/ui-breadcrumbs.css +1 -1
- package/styles/ui-button.css +1 -1
- package/styles/ui-callout.css +1 -1
- package/styles/ui-card.css +1 -1
- package/styles/ui-checkbox.css +1 -1
- package/styles/ui-cluster.css +1 -1
- package/styles/ui-combobox.css +1 -1
- package/styles/ui-container.css +1 -1
- package/styles/ui-context-menu.css +1 -1
- package/styles/ui-cover.css +1 -1
- package/styles/ui-description-item.css +1 -1
- package/styles/ui-description-list.css +1 -1
- package/styles/ui-dialog.css +1 -1
- package/styles/ui-disclosure.css +1 -1
- package/styles/ui-editable.css +1 -1
- package/styles/ui-editor-insert-table-grid.css +1 -1
- package/styles/ui-editor-mention-menu-item.css +1 -1
- package/styles/ui-editor-mention-menu.css +1 -1
- package/styles/ui-editor-slash-menu-group.css +1 -1
- package/styles/ui-editor-slash-menu-item.css +1 -1
- package/styles/ui-editor-slash-menu.css +1 -1
- package/styles/ui-editor-table-context-menu.css +1 -1
- package/styles/ui-editor-table-overlay.css +1 -1
- package/styles/ui-editor-table-toolbar.css +1 -1
- package/styles/ui-editor-toolbar.css +1 -1
- package/styles/ui-floating-action-button.css +1 -1
- package/styles/ui-form-field.css +1 -1
- package/styles/ui-grid.css +1 -1
- package/styles/ui-icon-button.css +1 -1
- package/styles/ui-icon.css +1 -1
- package/styles/ui-input-group.css +1 -1
- package/styles/ui-input.css +1 -1
- package/styles/ui-list-item.css +1 -1
- package/styles/ui-list.css +1 -1
- package/styles/ui-listbox.css +1 -1
- package/styles/ui-menu-group.css +1 -1
- package/styles/ui-menu-item.css +1 -1
- package/styles/ui-menu.css +1 -1
- package/styles/ui-meter.css +1 -1
- package/styles/ui-nav-item.css +1 -1
- package/styles/ui-page-header.css +1 -1
- package/styles/ui-popover.css +1 -1
- package/styles/ui-radio-group.css +1 -1
- package/styles/ui-radio.css +1 -1
- package/styles/ui-reel.css +1 -1
- package/styles/ui-scroll-area.css +1 -1
- package/styles/ui-search-result-row.css +1 -1
- package/styles/ui-search-shell.css +1 -1
- package/styles/ui-section.css +1 -1
- package/styles/ui-select.css +1 -1
- package/styles/ui-separator.css +1 -1
- package/styles/ui-sidebar.css +1 -1
- package/styles/ui-spinner.css +1 -1
- package/styles/ui-stack.css +1 -1
- package/styles/ui-status-message.css +1 -1
- package/styles/ui-switch.css +1 -1
- package/styles/ui-switcher.css +1 -1
- package/styles/ui-table.css +1 -1
- package/styles/ui-tabs.css +1 -1
- package/styles/ui-text.css +1 -1
- package/styles/ui-textarea.css +1 -1
- package/styles/ui-toast-region.css +1 -1
- package/styles/ui-toast.css +1 -1
- package/styles/ui-tooltip.css +1 -1
- package/styles/ui-top-bar.css +1 -1
- package/styles/ui-tree-item.css +1 -1
- package/styles/ui-tree.css +1 -1
- package/vanilla/UiActionBar.d.ts +1 -1
- package/vanilla/UiActionBar.js +1 -1
- package/vanilla/UiAffordanceScope.d.ts +1 -1
- package/vanilla/UiAffordanceScope.js +1 -1
- package/vanilla/UiAvatar.d.ts +1 -1
- package/vanilla/UiAvatar.js +1 -1
- package/vanilla/UiAvatarGroup.d.ts +1 -1
- package/vanilla/UiAvatarGroup.js +1 -1
- package/vanilla/UiBadge.d.ts +2 -1
- package/vanilla/UiBadge.js +5 -3
- package/vanilla/UiBreadcrumbItem.d.ts +1 -1
- package/vanilla/UiBreadcrumbItem.js +1 -1
- package/vanilla/UiBreadcrumbs.d.ts +1 -1
- package/vanilla/UiBreadcrumbs.js +1 -1
- package/vanilla/UiButton.d.ts +1 -1
- package/vanilla/UiButton.js +1 -1
- package/vanilla/UiCallout.d.ts +1 -1
- package/vanilla/UiCallout.js +1 -1
- package/vanilla/UiCard.d.ts +1 -1
- package/vanilla/UiCard.js +1 -1
- package/vanilla/UiCheckbox.d.ts +1 -1
- package/vanilla/UiCheckbox.js +1 -1
- package/vanilla/UiCluster.d.ts +1 -1
- package/vanilla/UiCluster.js +1 -1
- package/vanilla/UiCombobox.d.ts +1 -1
- package/vanilla/UiCombobox.js +1 -1
- package/vanilla/UiContainer.d.ts +1 -1
- package/vanilla/UiContainer.js +1 -1
- package/vanilla/UiContextMenu.d.ts +1 -1
- package/vanilla/UiContextMenu.js +1 -1
- package/vanilla/UiCover.d.ts +1 -1
- package/vanilla/UiCover.js +1 -1
- package/vanilla/UiDescriptionItem.d.ts +1 -1
- package/vanilla/UiDescriptionItem.js +1 -1
- package/vanilla/UiDescriptionList.d.ts +1 -1
- package/vanilla/UiDescriptionList.js +1 -1
- package/vanilla/UiDialog.d.ts +1 -1
- package/vanilla/UiDialog.js +1 -1
- package/vanilla/UiDisclosure.d.ts +1 -1
- package/vanilla/UiDisclosure.js +1 -1
- package/vanilla/UiEditable.d.ts +1 -1
- package/vanilla/UiEditable.js +1 -1
- package/vanilla/UiEditorInsertTableGrid.d.ts +1 -1
- package/vanilla/UiEditorInsertTableGrid.js +1 -1
- package/vanilla/UiEditorMentionMenu.d.ts +1 -1
- package/vanilla/UiEditorMentionMenu.js +1 -1
- package/vanilla/UiEditorMentionMenuItem.d.ts +1 -1
- package/vanilla/UiEditorMentionMenuItem.js +1 -1
- package/vanilla/UiEditorSlashMenu.d.ts +1 -1
- package/vanilla/UiEditorSlashMenu.js +1 -1
- package/vanilla/UiEditorSlashMenuGroup.d.ts +1 -1
- package/vanilla/UiEditorSlashMenuGroup.js +1 -1
- package/vanilla/UiEditorSlashMenuItem.d.ts +1 -1
- package/vanilla/UiEditorSlashMenuItem.js +1 -1
- package/vanilla/UiEditorTableContextMenu.d.ts +1 -1
- package/vanilla/UiEditorTableContextMenu.js +1 -1
- package/vanilla/UiEditorTableOverlay.d.ts +1 -1
- package/vanilla/UiEditorTableOverlay.js +1 -1
- package/vanilla/UiEditorTableToolbar.d.ts +1 -1
- package/vanilla/UiEditorTableToolbar.js +1 -1
- package/vanilla/UiEditorToolbar.d.ts +1 -1
- package/vanilla/UiEditorToolbar.js +1 -1
- package/vanilla/UiFloatingActionButton.d.ts +1 -1
- package/vanilla/UiFloatingActionButton.js +1 -1
- package/vanilla/UiFormField.d.ts +1 -1
- package/vanilla/UiFormField.js +1 -1
- package/vanilla/UiGrid.d.ts +1 -1
- package/vanilla/UiGrid.js +1 -1
- package/vanilla/UiIcon.d.ts +1 -1
- package/vanilla/UiIcon.js +1 -1
- package/vanilla/UiIconButton.d.ts +1 -1
- package/vanilla/UiIconButton.js +1 -1
- package/vanilla/UiInput.d.ts +1 -1
- package/vanilla/UiInput.js +1 -1
- package/vanilla/UiInputGroup.d.ts +1 -1
- package/vanilla/UiInputGroup.js +1 -1
- package/vanilla/UiList.d.ts +1 -1
- package/vanilla/UiList.js +1 -1
- package/vanilla/UiListItem.d.ts +1 -1
- package/vanilla/UiListItem.js +1 -1
- package/vanilla/UiListbox.d.ts +1 -1
- package/vanilla/UiListbox.js +1 -1
- package/vanilla/UiMenu.d.ts +1 -1
- package/vanilla/UiMenu.js +1 -1
- package/vanilla/UiMenuGroup.d.ts +1 -1
- package/vanilla/UiMenuGroup.js +1 -1
- package/vanilla/UiMenuItem.d.ts +1 -1
- package/vanilla/UiMenuItem.js +1 -1
- package/vanilla/UiMeter.d.ts +1 -1
- package/vanilla/UiMeter.js +1 -1
- package/vanilla/UiNavItem.d.ts +1 -1
- package/vanilla/UiNavItem.js +1 -1
- package/vanilla/UiPageHeader.d.ts +1 -1
- package/vanilla/UiPageHeader.js +1 -1
- package/vanilla/UiPopover.d.ts +1 -1
- package/vanilla/UiPopover.js +1 -1
- package/vanilla/UiRadio.d.ts +1 -1
- package/vanilla/UiRadio.js +1 -1
- package/vanilla/UiRadioGroup.d.ts +1 -1
- package/vanilla/UiRadioGroup.js +1 -1
- package/vanilla/UiReel.d.ts +1 -1
- package/vanilla/UiReel.js +1 -1
- package/vanilla/UiScrollArea.d.ts +1 -1
- package/vanilla/UiScrollArea.js +1 -1
- package/vanilla/UiSearchResultRow.d.ts +1 -1
- package/vanilla/UiSearchResultRow.js +1 -1
- package/vanilla/UiSearchShell.d.ts +1 -1
- package/vanilla/UiSearchShell.js +1 -1
- package/vanilla/UiSection.d.ts +1 -1
- package/vanilla/UiSection.js +1 -1
- package/vanilla/UiSelect.d.ts +1 -1
- package/vanilla/UiSelect.js +1 -1
- package/vanilla/UiSeparator.d.ts +1 -1
- package/vanilla/UiSeparator.js +1 -1
- package/vanilla/UiSidebar.d.ts +1 -1
- package/vanilla/UiSidebar.js +1 -1
- package/vanilla/UiSpinner.d.ts +1 -1
- package/vanilla/UiSpinner.js +1 -1
- package/vanilla/UiStack.d.ts +1 -1
- package/vanilla/UiStack.js +1 -1
- package/vanilla/UiStatusMessage.d.ts +1 -1
- package/vanilla/UiStatusMessage.js +1 -1
- package/vanilla/UiSwitch.d.ts +1 -1
- package/vanilla/UiSwitch.js +1 -1
- package/vanilla/UiSwitcher.d.ts +1 -1
- package/vanilla/UiSwitcher.js +1 -1
- package/vanilla/UiTable.d.ts +1 -1
- package/vanilla/UiTable.js +1 -1
- package/vanilla/UiTabs.d.ts +1 -1
- package/vanilla/UiTabs.js +1 -1
- package/vanilla/UiText.d.ts +1 -1
- package/vanilla/UiText.js +1 -1
- package/vanilla/UiTextarea.d.ts +1 -1
- package/vanilla/UiTextarea.js +1 -1
- package/vanilla/UiToast.d.ts +1 -1
- package/vanilla/UiToast.js +1 -1
- package/vanilla/UiToastRegion.d.ts +1 -1
- package/vanilla/UiToastRegion.js +1 -1
- package/vanilla/UiTooltip.d.ts +1 -1
- package/vanilla/UiTooltip.js +1 -1
- package/vanilla/UiTopBar.d.ts +1 -1
- package/vanilla/UiTopBar.js +1 -1
- package/vanilla/UiTree.d.ts +1 -1
- package/vanilla/UiTree.js +1 -1
- package/vanilla/UiTreeItem.d.ts +1 -1
- package/vanilla/UiTreeItem.js +1 -1
- package/vue/UiActionBar.vue +1 -1
- package/vue/UiAffordanceScope.vue +17 -4
- package/vue/UiAvatar.vue +38 -5
- package/vue/UiAvatarGroup.vue +32 -5
- package/vue/UiBadge.d.ts +9 -0
- package/vue/UiBadge.vue +41 -3
- package/vue/UiBreadcrumbItem.vue +5 -3
- package/vue/UiBreadcrumbs.vue +5 -3
- package/vue/UiButton.vue +72 -7
- package/vue/UiCallout.vue +5 -3
- package/vue/UiCard.vue +16 -6
- package/vue/UiCheckbox.vue +41 -4
- package/vue/UiCluster.vue +8 -3
- package/vue/UiCombobox.vue +98 -6
- package/vue/UiContainer.vue +6 -3
- package/vue/UiContextMenu.vue +17 -4
- package/vue/UiCover.vue +5 -3
- package/vue/UiDescriptionItem.vue +5 -3
- package/vue/UiDescriptionList.vue +11 -3
- package/vue/UiDialog.vue +38 -5
- package/vue/UiDisclosure.vue +28 -4
- package/vue/UiEditable.vue +50 -4
- package/vue/UiEditorInsertTableGrid.vue +24 -4
- package/vue/UiEditorMentionMenu.vue +41 -4
- package/vue/UiEditorMentionMenuItem.vue +7 -3
- package/vue/UiEditorSlashMenu.vue +28 -4
- package/vue/UiEditorSlashMenuGroup.vue +5 -3
- package/vue/UiEditorSlashMenuItem.vue +15 -3
- package/vue/UiEditorTableContextMenu.vue +28 -4
- package/vue/UiEditorTableOverlay.vue +17 -4
- package/vue/UiEditorTableToolbar.vue +28 -4
- package/vue/UiEditorToolbar.vue +16 -4
- package/vue/UiFloatingActionButton.vue +7 -3
- package/vue/UiFormField.vue +18 -4
- package/vue/UiGrid.vue +7 -3
- package/vue/UiIcon.vue +5 -3
- package/vue/UiIconButton.vue +47 -5
- package/vue/UiInput.vue +90 -37
- package/vue/UiInputGroup.vue +16 -4
- package/vue/UiList.vue +20 -7
- package/vue/UiListItem.vue +6 -3
- package/vue/UiListbox.vue +38 -5
- package/vue/UiMenu.vue +28 -4
- package/vue/UiMenuGroup.vue +5 -3
- package/vue/UiMenuItem.vue +27 -5
- package/vue/UiMeter.vue +19 -3
- package/vue/UiNavItem.vue +28 -6
- package/vue/UiPageHeader.vue +5 -3
- package/vue/UiPopover.vue +18 -5
- package/vue/UiRadio.vue +28 -4
- package/vue/UiRadioGroup.vue +30 -4
- package/vue/UiReel.vue +7 -3
- package/vue/UiScrollArea.vue +16 -4
- package/vue/UiSearchResultRow.d.ts +1 -1
- package/vue/UiSearchResultRow.vue +6 -3
- package/vue/UiSearchShell.vue +24 -4
- package/vue/UiSection.vue +7 -3
- package/vue/UiSelect.vue +33 -5
- package/vue/UiSeparator.vue +5 -3
- package/vue/UiSidebar.vue +44 -4
- package/vue/UiSpinner.vue +6 -3
- package/vue/UiStack.vue +7 -3
- package/vue/UiStatusMessage.vue +7 -3
- package/vue/UiSwitch.vue +28 -4
- package/vue/UiSwitcher.vue +30 -5
- package/vue/UiTable.vue +17 -4
- package/vue/UiTabs.vue +28 -4
- package/vue/UiText.vue +29 -15
- package/vue/UiTextarea.vue +39 -5
- package/vue/UiToast.vue +17 -4
- package/vue/UiToastRegion.vue +17 -5
- package/vue/UiTooltip.vue +30 -5
- package/vue/UiTopBar.vue +1 -1
- package/vue/UiTree.vue +28 -4
- package/vue/UiTreeItem.d.ts +1 -1
- package/vue/UiTreeItem.vue +59 -4
- package/vue/chunks/UiActionBar.js +1 -1
- package/vue/chunks/UiAffordanceScope.js +19 -5
- package/vue/chunks/UiAvatar.js +40 -11
- package/vue/chunks/UiAvatarGroup.js +31 -8
- package/vue/chunks/UiBadge.js +35 -6
- package/vue/chunks/UiBreadcrumbItem.js +5 -4
- package/vue/chunks/UiBreadcrumbs.js +5 -4
- package/vue/chunks/UiButton.js +60 -19
- package/vue/chunks/UiCallout.js +5 -4
- package/vue/chunks/UiCard.js +16 -10
- package/vue/chunks/UiCheckbox.js +40 -11
- package/vue/chunks/UiCluster.js +13 -7
- package/vue/chunks/UiCombobox.js +85 -26
- package/vue/chunks/UiContainer.js +9 -5
- package/vue/chunks/UiContextMenu.js +19 -5
- package/vue/chunks/UiCover.js +5 -4
- package/vue/chunks/UiDescriptionItem.js +5 -4
- package/vue/chunks/UiDescriptionList.js +11 -6
- package/vue/chunks/UiDialog.js +40 -11
- package/vue/chunks/UiDisclosure.js +34 -9
- package/vue/chunks/UiEditable.js +49 -14
- package/vue/chunks/UiEditorInsertTableGrid.js +28 -7
- package/vue/chunks/UiEditorMentionMenu.js +40 -11
- package/vue/chunks/UiEditorMentionMenuItem.js +11 -6
- package/vue/chunks/UiEditorSlashMenu.js +34 -9
- package/vue/chunks/UiEditorSlashMenuGroup.js +5 -4
- package/vue/chunks/UiEditorSlashMenuItem.js +15 -8
- package/vue/chunks/UiEditorTableContextMenu.js +34 -9
- package/vue/chunks/UiEditorTableOverlay.js +19 -5
- package/vue/chunks/UiEditorTableToolbar.js +34 -9
- package/vue/chunks/UiEditorToolbar.js +15 -4
- package/vue/chunks/UiFloatingActionButton.js +11 -6
- package/vue/chunks/UiFormField.js +26 -7
- package/vue/chunks/UiGrid.js +11 -6
- package/vue/chunks/UiIcon.js +5 -4
- package/vue/chunks/UiIconButton.js +41 -12
- package/vue/chunks/UiInput.js +53 -14
- package/vue/chunks/UiInputGroup.js +16 -5
- package/vue/chunks/UiList.js +14 -8
- package/vue/chunks/UiListItem.js +9 -5
- package/vue/chunks/UiListbox.js +40 -11
- package/vue/chunks/UiMenu.js +34 -9
- package/vue/chunks/UiMenuGroup.js +5 -4
- package/vue/chunks/UiMenuItem.js +32 -9
- package/vue/chunks/UiMeter.js +19 -10
- package/vue/chunks/UiNavItem.js +16 -9
- package/vue/chunks/UiPageHeader.js +5 -4
- package/vue/chunks/UiPopover.js +25 -6
- package/vue/chunks/UiRadio.js +34 -9
- package/vue/chunks/UiRadioGroup.js +37 -10
- package/vue/chunks/UiReel.js +11 -6
- package/vue/chunks/UiScrollArea.js +15 -4
- package/vue/chunks/UiSearchResultRow.js +9 -5
- package/vue/chunks/UiSearchShell.js +28 -7
- package/vue/chunks/UiSection.js +11 -6
- package/vue/chunks/UiSelect.js +33 -10
- package/vue/chunks/UiSeparator.js +5 -4
- package/vue/chunks/UiSidebar.js +43 -12
- package/vue/chunks/UiSpinner.js +9 -5
- package/vue/chunks/UiStack.js +11 -6
- package/vue/chunks/UiStatusMessage.js +11 -6
- package/vue/chunks/UiSwitch.js +34 -9
- package/vue/chunks/UiSwitcher.js +28 -7
- package/vue/chunks/UiTable.js +20 -6
- package/vue/chunks/UiTabs.js +34 -9
- package/vue/chunks/UiText.js +29 -20
- package/vue/chunks/UiTextarea.js +42 -13
- package/vue/chunks/UiToast.js +19 -5
- package/vue/chunks/UiToastRegion.js +19 -5
- package/vue/chunks/UiTooltip.js +37 -10
- package/vue/chunks/UiTopBar.js +1 -1
- package/vue/chunks/UiTree.js +35 -10
- package/vue/chunks/UiTreeItem.js +58 -17
- package/vue/chunks/host.js +22 -4
- package/vue/chunks/props.js +20 -7
- package/vue/components.css +1212 -1204
- package/vue/host.ts +50 -6
|
@@ -11,7 +11,7 @@ export default function controller(host) {
|
|
|
11
11
|
let frame = null;
|
|
12
12
|
let point = null;
|
|
13
13
|
let dirty = false;
|
|
14
|
-
let nearRadius = Number(host.
|
|
14
|
+
let nearRadius = Number(host.props.nearRadius.value ?? 16);
|
|
15
15
|
const clear = () => {
|
|
16
16
|
for (const anchor of anchors) anchor.element.removeAttribute("data-ui-proximity");
|
|
17
17
|
host.state.engaged = false;
|
|
@@ -57,7 +57,7 @@ export default function controller(host) {
|
|
|
57
57
|
owner.visualViewport?.addEventListener("resize", invalidate, { passive: true });
|
|
58
58
|
owner.visualViewport?.addEventListener("scroll", invalidate, { passive: true });
|
|
59
59
|
const stop = host.effect(() => {
|
|
60
|
-
const configured = Number(host.
|
|
60
|
+
const configured = Number(host.props.nearRadius.value ?? 16);
|
|
61
61
|
nearRadius = Number.isFinite(configured) ? Math.max(0, configured) : 16;
|
|
62
62
|
invalidate();
|
|
63
63
|
});
|
|
@@ -29,17 +29,17 @@ export default function controller(host) {
|
|
|
29
29
|
authored.hidden = !host.state.hasImage;
|
|
30
30
|
element.removeAttribute("role");
|
|
31
31
|
element.removeAttribute("aria-label");
|
|
32
|
-
} else if (!host.
|
|
32
|
+
} else if (!host.props.decorative.value) {
|
|
33
33
|
element.setAttribute("role", "img");
|
|
34
|
-
element.setAttribute("aria-label", host.
|
|
34
|
+
element.setAttribute("aria-label", host.props.alt.value || host.props.name.value || "Avatar");
|
|
35
35
|
}
|
|
36
|
-
if (host.
|
|
36
|
+
if (host.props.decorative.value) {
|
|
37
37
|
element.setAttribute("aria-hidden", "true");
|
|
38
38
|
element.removeAttribute("role");
|
|
39
39
|
element.removeAttribute("aria-label");
|
|
40
40
|
} else element.removeAttribute("aria-hidden");
|
|
41
|
-
host.state.initials = host.
|
|
42
|
-
host.state.showGlyph = !String(host.
|
|
41
|
+
host.state.initials = host.props.fallback.value || toInitials(host.props.name.value || host.props.alt.value);
|
|
42
|
+
host.state.showGlyph = !String(host.props.name.value || "").trim() && !String(host.props.alt.value || "").trim() && !String(host.props.fallback.value || "").trim();
|
|
43
43
|
};
|
|
44
44
|
const observer = new MutationObserver(apply);
|
|
45
45
|
observer.observe(element, { childList: true });
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
export default function controller(host) {
|
|
4
4
|
const element = host.element;
|
|
5
5
|
const update = () => {
|
|
6
|
-
const max = Number(host.
|
|
6
|
+
const max = Number(host.props.max.value);
|
|
7
7
|
const visible = Number.isFinite(max) ? Math.max(0, Math.floor(max)) : 0;
|
|
8
8
|
const avatars = Array.from(element.children).filter((child) => child !== host.refs.overflow);
|
|
9
9
|
// Small avatars overlap less, so their initials stay clear of the next one.
|
|
10
|
-
const overlap = { xs: "-0.1875rem", sm: "-0.25rem" }[host.
|
|
10
|
+
const overlap = { xs: "-0.1875rem", sm: "-0.25rem" }[host.props.size.value] ?? "-0.5rem";
|
|
11
11
|
avatars.forEach((avatar, index) => {
|
|
12
12
|
avatar.style.display = index >= visible ? "none" : "";
|
|
13
13
|
avatar.style.marginInlineStart = index === 0 ? "0px" : overlap;
|
|
@@ -17,11 +17,11 @@ export default function controller(host) {
|
|
|
17
17
|
: "var(--ui-avatar-group-overlap-shadow, var(--_overlap-shadow)), var(--ui-avatar-group-edge-ring, 0 0 0 0 transparent)";
|
|
18
18
|
});
|
|
19
19
|
const authoredVisible = Math.min(avatars.length, visible);
|
|
20
|
-
const suppliedTotal = Number(host.
|
|
21
|
-
const total = host.
|
|
20
|
+
const suppliedTotal = Number(host.props.total.value);
|
|
21
|
+
const total = host.props.total.value == null || !Number.isFinite(suppliedTotal) ? avatars.length : Math.max(avatars.length, suppliedTotal);
|
|
22
22
|
const count = Math.max(0, total - authoredVisible);
|
|
23
23
|
host.state.overflowCount = count;
|
|
24
|
-
host.state.overflowAnnouncement = String(host.
|
|
24
|
+
host.state.overflowAnnouncement = String(host.props.overflowLabel.value || "{count} more").replaceAll("{count}", String(count));
|
|
25
25
|
};
|
|
26
26
|
const observer = new MutationObserver(update);
|
|
27
27
|
observer.observe(element, { childList: true });
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
colour, which overrides the tone.</prop>
|
|
10
10
|
<prop name="shape" type="keyword" values="pill, tag" default="pill"
|
|
11
11
|
>Silhouette. pill is rounded at both ends; tag is a label: flat at the start and coming to a point at the end, for a tag or a chosen chip.</prop>
|
|
12
|
+
<prop name="size" type="keyword" values="xs, md" default="md">Scale. xs is a compact count beside small controls; md is the usual text badge.</prop>
|
|
12
13
|
</defs>
|
|
13
14
|
<span><slot></slot></span>
|
|
14
15
|
<style>
|
|
@@ -104,6 +105,15 @@
|
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
:host-state([size="xs"]) {
|
|
109
|
+
box-sizing: border-box;
|
|
110
|
+
min-inline-size: 1rem;
|
|
111
|
+
min-block-size: var(--ui-badge-min-block-size, 1rem);
|
|
112
|
+
padding: var(--ui-badge-padding-block, 0) var(--ui-badge-padding-inline, 0.125rem);
|
|
113
|
+
font-size: var(--ui-badge-font-size, var(--ui-font-size-2xs));
|
|
114
|
+
line-height: var(--ui-badge-line-height, 1);
|
|
115
|
+
}
|
|
116
|
+
|
|
107
117
|
:host-state([tone="accent"]) {
|
|
108
118
|
--_badge-surface: var(--ui-accent-strong-surface, var(--ui-accent-solid));
|
|
109
119
|
--_badge-border: var(--ui-accent-strong-surface, var(--ui-accent-solid));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Loading actions retain focus but cannot activate, navigate, submit, or notify click consumers.
|
|
2
2
|
export default function controller(host) {
|
|
3
3
|
const onClick = (event) => {
|
|
4
|
-
if (!host.
|
|
4
|
+
if (!host.props.loading.value && !host.props.pending.value) return;
|
|
5
5
|
event.preventDefault();
|
|
6
6
|
event.stopImmediatePropagation();
|
|
7
7
|
};
|
|
@@ -9,17 +9,17 @@ export default function controller(host) {
|
|
|
9
9
|
const input = host.refs.input;
|
|
10
10
|
describeInput(input, host.refs.description);
|
|
11
11
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
12
|
-
let external = host.
|
|
12
|
+
let external = host.props.checked.value;
|
|
13
13
|
host.state.internalChecked = Boolean(external);
|
|
14
14
|
const stop = host.effect(() => {
|
|
15
|
-
input.defaultChecked = Boolean(host.
|
|
16
|
-
if (host.
|
|
17
|
-
external = host.
|
|
15
|
+
input.defaultChecked = Boolean(host.props.checked.value);
|
|
16
|
+
if (host.props.checked.value === external) return;
|
|
17
|
+
external = host.props.checked.value;
|
|
18
18
|
host.state.internalChecked = Boolean(external);
|
|
19
19
|
});
|
|
20
20
|
const onChange = () => {
|
|
21
21
|
host.state.internalChecked = input.checked;
|
|
22
|
-
host.dispatch("change", { checked: input.checked, value: String(host.
|
|
22
|
+
host.dispatch("change", { checked: input.checked, value: String(host.props.value.value ?? "on"), trigger: trigger() });
|
|
23
23
|
};
|
|
24
24
|
input.addEventListener("change", onChange);
|
|
25
25
|
const stopReset = afterFormReset(input, () => {
|
|
@@ -47,17 +47,17 @@ export default function controller(host) {
|
|
|
47
47
|
let initialRaw = "";
|
|
48
48
|
let awaitingLabel = null;
|
|
49
49
|
let proposedChange;
|
|
50
|
-
let lastValue = host.
|
|
51
|
-
let lastQuery = host.
|
|
50
|
+
let lastValue = host.props.value.value;
|
|
51
|
+
let lastQuery = host.props.query.value;
|
|
52
52
|
const knownOptions = new Map();
|
|
53
53
|
|
|
54
54
|
// Options come from authored <option>/<optgroup> children; everything else is an attribute.
|
|
55
55
|
const config = () => ({
|
|
56
56
|
options: authoredOptions(authored),
|
|
57
|
-
allowFreeText: Boolean(host.
|
|
58
|
-
allowCreate: Boolean(host.
|
|
57
|
+
allowFreeText: Boolean(host.props.allowFreeText.value),
|
|
58
|
+
allowCreate: Boolean(host.props.allowCreate.value),
|
|
59
59
|
// "none": the consumer already narrowed the options (a server search), so every one is listed.
|
|
60
|
-
filterByLabel: host.
|
|
60
|
+
filterByLabel: host.props.filter.value !== "none",
|
|
61
61
|
});
|
|
62
62
|
const authoredDefaults = () => {
|
|
63
63
|
const values = new Set(Array.from(authored.querySelectorAll("option[selected]"), (option) => option.value));
|
|
@@ -66,19 +66,19 @@ export default function controller(host) {
|
|
|
66
66
|
// Selected items work uncontrolled: the component keeps them and reports every change. A consumer
|
|
67
67
|
// that owns `items` stays in charge, because the prop resyncs whatever it sets. A consumer that sets
|
|
68
68
|
// `selectedValues` controls the selection: the chips follow it, and a user's change is only reported.
|
|
69
|
-
const items = () => host.
|
|
69
|
+
const items = () => host.props.multiple.value && Array.isArray(host.state.internalItems) ? host.state.internalItems : [];
|
|
70
70
|
const selectedSet = () => new Set(items().map((item) => item.value));
|
|
71
|
-
const controlledValues = () => Array.isArray(host.
|
|
71
|
+
const controlledValues = () => Array.isArray(host.props.selectedValues.value);
|
|
72
72
|
// Each controlled value shows its authored option; a value no option describes yet keeps the chip it
|
|
73
73
|
// had, or shows the value itself until its option arrives. A repeated value shows once: the chips and
|
|
74
74
|
// hidden inputs are keyed by value. Array.from, not a spread: a loose transpile turns [...set] into [set].
|
|
75
75
|
const itemsForValues = () => {
|
|
76
76
|
const options = config().options;
|
|
77
|
-
return Array.from(new Set(host.
|
|
77
|
+
return Array.from(new Set(host.props.selectedValues.value)).map((value) => asItem(options.find((option) => option.value === value)
|
|
78
78
|
?? items().find((item) => item.value === value) ?? { id: value, value, label: value }));
|
|
79
79
|
};
|
|
80
80
|
const markSelectedRows = () => {
|
|
81
|
-
if (!host.
|
|
81
|
+
if (!host.props.multiple.value || !host.state.rows?.length) return;
|
|
82
82
|
const selected = selectedSet();
|
|
83
83
|
host.state.rows = host.state.rows.map((row) => ({ ...row, selected: selected.has(row.value) }));
|
|
84
84
|
};
|
|
@@ -126,7 +126,7 @@ export default function controller(host) {
|
|
|
126
126
|
const canCreate = () => {
|
|
127
127
|
const current = config();
|
|
128
128
|
const candidates = current.options ? [...current.options, ...(host.state.rows ?? [])] : (host.state.rows ?? []);
|
|
129
|
-
return Boolean(current.allowCreate && String(host.state.raw).trim() && !host.
|
|
129
|
+
return Boolean(current.allowCreate && String(host.state.raw).trim() && !host.props.loading.value && !host.state.lookupError
|
|
130
130
|
&& !candidates.some((row) => row.label.toLocaleLowerCase() === String(host.state.raw).toLocaleLowerCase()));
|
|
131
131
|
};
|
|
132
132
|
const search = (reason) => {
|
|
@@ -142,14 +142,14 @@ export default function controller(host) {
|
|
|
142
142
|
if (controller.signal.aborted || !alive) return;
|
|
143
143
|
for (const option of options) knownOptions.set(option.value, option);
|
|
144
144
|
const selectedOption = host.state.selected == null ? undefined : knownOptions.get(host.state.selected);
|
|
145
|
-
if (host.
|
|
145
|
+
if (host.props.query.value == null && awaitingLabel === host.state.selected && selectedOption) {
|
|
146
146
|
host.state.raw = selectedOption.label;
|
|
147
147
|
host.state.display = selectedOption.label;
|
|
148
148
|
awaitingLabel = null;
|
|
149
149
|
resetValidation();
|
|
150
150
|
}
|
|
151
151
|
const ids = new Set();
|
|
152
|
-
const selected = host.
|
|
152
|
+
const selected = host.props.multiple.value ? selectedSet() : undefined;
|
|
153
153
|
// Multiple keeps its chosen options in the list, checked. Dropping them hid what was picked
|
|
154
154
|
// from the list and from assistive technology, which only ever heard aria-selected="false".
|
|
155
155
|
const filtered = options.filter((option) => {
|
|
@@ -180,7 +180,7 @@ export default function controller(host) {
|
|
|
180
180
|
applyOptions(current.options);
|
|
181
181
|
};
|
|
182
182
|
const open = (reason = "input") => {
|
|
183
|
-
if (host.
|
|
183
|
+
if (host.props.disabled.value || host.props.readonly.value) return;
|
|
184
184
|
host.state.expanded = true;
|
|
185
185
|
popup.style.minWidth = `${field.getBoundingClientRect().width}px`;
|
|
186
186
|
surface.show();
|
|
@@ -194,8 +194,8 @@ export default function controller(host) {
|
|
|
194
194
|
awaitingLabel = null;
|
|
195
195
|
if (kind === "selection") lastSelection = option;
|
|
196
196
|
const queryChanged = query !== host.state.raw;
|
|
197
|
-
if (host.
|
|
198
|
-
if (host.
|
|
197
|
+
if (host.props.value.value == null) host.state.selected = value;
|
|
198
|
+
if (host.props.query.value == null && queryChanged) {
|
|
199
199
|
host.state.raw = query;
|
|
200
200
|
host.state.display = query;
|
|
201
201
|
}
|
|
@@ -209,8 +209,8 @@ export default function controller(host) {
|
|
|
209
209
|
if (kind === "free-entry") host.dispatch("free-entry", detail);
|
|
210
210
|
queueMicrotask(() => {
|
|
211
211
|
if (proposedChange !== proposal) return;
|
|
212
|
-
if (host.
|
|
213
|
-
if (host.
|
|
212
|
+
if (host.props.value.value != null && host.props.value.value !== proposal.value) syncValue();
|
|
213
|
+
if (host.props.query.value != null && host.props.query.value !== proposal.query) syncQuery();
|
|
214
214
|
proposedChange = undefined;
|
|
215
215
|
});
|
|
216
216
|
};
|
|
@@ -222,7 +222,7 @@ export default function controller(host) {
|
|
|
222
222
|
host.dispatch("selected-values-change", { selectedValues: next.map((item) => item.value), trigger });
|
|
223
223
|
};
|
|
224
224
|
const setMultiQuery = (query, trigger) => {
|
|
225
|
-
if (host.
|
|
225
|
+
if (host.props.query.value == null) {
|
|
226
226
|
host.state.raw = query;
|
|
227
227
|
host.state.display = query;
|
|
228
228
|
}
|
|
@@ -249,7 +249,7 @@ export default function controller(host) {
|
|
|
249
249
|
const choose = (index, trigger) => {
|
|
250
250
|
const option = (host.state.rows ?? [])[index];
|
|
251
251
|
if (option?.disabled) return;
|
|
252
|
-
if (host.
|
|
252
|
+
if (host.props.multiple.value) {
|
|
253
253
|
if (option) {
|
|
254
254
|
// A checked row toggles off: the list is the selection, so it has to work both ways.
|
|
255
255
|
const position = items().findIndex((item) => item.value === option.value);
|
|
@@ -268,7 +268,7 @@ export default function controller(host) {
|
|
|
268
268
|
else return;
|
|
269
269
|
close();
|
|
270
270
|
input.focus();
|
|
271
|
-
if (!host.
|
|
271
|
+
if (!host.props.multiple.value) queueMicrotask(() => void validateCurrent());
|
|
272
272
|
};
|
|
273
273
|
// A strict combobox (single, no free text, no create) behaves like a select: leaving it resolves the
|
|
274
274
|
// typed text to a valid option (the highlighted one, an exact label, the first label it begins, or the
|
|
@@ -276,13 +276,13 @@ export default function controller(host) {
|
|
|
276
276
|
// "none" the remaining options are all of them, whatever their labels, so the only one listed counts.
|
|
277
277
|
const resolveTyped = (trigger) => {
|
|
278
278
|
const current = config();
|
|
279
|
-
if (host.
|
|
279
|
+
if (host.props.multiple.value || current.allowFreeText || current.allowCreate) return;
|
|
280
280
|
const typed = String(host.state.raw ?? "");
|
|
281
281
|
const selectedOption = (current.options ?? []).find((option) => option.value === host.state.selected)
|
|
282
282
|
?? knownOptions.get(host.state.selected) ?? lastSelection;
|
|
283
283
|
if (selectedOption && selectedOption.label === typed) return;
|
|
284
284
|
const restoreDraft = (label) => {
|
|
285
|
-
if (host.
|
|
285
|
+
if (host.props.query.value != null || label === host.state.raw) return;
|
|
286
286
|
host.state.raw = label;
|
|
287
287
|
host.state.display = label;
|
|
288
288
|
resetValidation();
|
|
@@ -319,7 +319,7 @@ export default function controller(host) {
|
|
|
319
319
|
const removeItemAt = (index, trigger) => {
|
|
320
320
|
const current = items();
|
|
321
321
|
const item = current[index];
|
|
322
|
-
if (!item || item.disabled || host.
|
|
322
|
+
if (!item || item.disabled || host.props.disabled.value || host.props.readonly.value) return;
|
|
323
323
|
host.dispatch("remove-item", { item, index, trigger });
|
|
324
324
|
emitItems(current.filter((_, position) => position !== index), trigger);
|
|
325
325
|
requestAnimationFrame(() => itemButtons()[Math.min(index, itemButtons().length - 1)]?.focus?.() ?? input.focus());
|
|
@@ -344,8 +344,8 @@ export default function controller(host) {
|
|
|
344
344
|
// Native constraints and the free-text policy; application validation stays in the form.
|
|
345
345
|
const current = config();
|
|
346
346
|
const result = { output: host.state.raw, issues: [] };
|
|
347
|
-
const empty = host.
|
|
348
|
-
if (host.
|
|
347
|
+
const empty = host.props.multiple.value ? !items().length : !String(host.state.raw).trim();
|
|
348
|
+
if (host.props.required.value && empty) result.issues = [...result.issues, { message: "A value is required." }];
|
|
349
349
|
else if (host.state.raw && host.state.selected === null && !current.allowFreeText && !current.allowCreate) result.issues = [...result.issues, { message: "Choose a suggestion." }];
|
|
350
350
|
if (result.issues.some((issue) => issue.severity !== "warning")) result.output = undefined;
|
|
351
351
|
if (!run.signal.aborted && alive) setValidation(result);
|
|
@@ -353,9 +353,9 @@ export default function controller(host) {
|
|
|
353
353
|
return host.state.validation;
|
|
354
354
|
};
|
|
355
355
|
const syncValue = () => {
|
|
356
|
-
if (host.
|
|
357
|
-
host.state.selected = host.
|
|
358
|
-
if (host.
|
|
356
|
+
if (host.props.multiple.value || host.props.value.value == null) return;
|
|
357
|
+
host.state.selected = host.props.value.value;
|
|
358
|
+
if (host.props.query.value == null) {
|
|
359
359
|
const proposal = proposedChange;
|
|
360
360
|
const option = config().options?.find((row) => row.value === host.state.selected) ?? (host.state.selected == null ? undefined : knownOptions.get(host.state.selected));
|
|
361
361
|
const nextRaw = proposal?.value === host.state.selected ? proposal.query : option?.label ?? host.state.selected ?? "";
|
|
@@ -368,11 +368,11 @@ export default function controller(host) {
|
|
|
368
368
|
resetValidation();
|
|
369
369
|
};
|
|
370
370
|
const syncQuery = () => {
|
|
371
|
-
if (host.
|
|
372
|
-
if (host.
|
|
371
|
+
if (host.props.query.value == null || host.props.query.value === host.state.raw) return;
|
|
372
|
+
if (host.props.value.value == null && proposedChange?.query !== host.props.query.value) host.state.selected = null;
|
|
373
373
|
awaitingLabel = null;
|
|
374
|
-
host.state.raw = host.
|
|
375
|
-
host.state.display = host.
|
|
374
|
+
host.state.raw = host.props.query.value;
|
|
375
|
+
host.state.display = host.props.query.value;
|
|
376
376
|
resetValidation();
|
|
377
377
|
if (host.state.expanded) search("input");
|
|
378
378
|
};
|
|
@@ -396,11 +396,11 @@ export default function controller(host) {
|
|
|
396
396
|
host.state.creatable = canCreate();
|
|
397
397
|
host.state.createIndex = rows.length;
|
|
398
398
|
// What a named combobox submits in single mode: the value, never the label the field shows.
|
|
399
|
-
host.state.submitted = String(host.state.selected ?? (host.
|
|
400
|
-
host.state.message = host.
|
|
399
|
+
host.state.submitted = String(host.state.selected ?? (host.props.allowFreeText.value ? host.state.raw ?? "" : ""));
|
|
400
|
+
host.state.message = host.props.loading.value ? "Loading suggestions…" : host.state.lookupError || "";
|
|
401
401
|
const validation = host.state.validation ?? { status: "pristine", issues: [] };
|
|
402
402
|
host.state.validationStatus = validation.status;
|
|
403
|
-
const status = host.
|
|
403
|
+
const status = host.props.loading.value ? "Loading suggestions…" : host.state.lookupError || (host.state.expanded ? `${rows.length} suggestions available.` : "");
|
|
404
404
|
host.state.statusText = `${status} ${validation.status === "pending" ? "Checking value…" : (validation.issues ?? []).map((issue) => issue.message).join(" ")}`.trim();
|
|
405
405
|
if (host.state.expanded && host.state.active >= 0) input.setAttribute("aria-activedescendant", `${uid}-option-${host.state.active}`);
|
|
406
406
|
else input.removeAttribute("aria-activedescendant");
|
|
@@ -418,11 +418,11 @@ export default function controller(host) {
|
|
|
418
418
|
host.dispatch("query-change", { query: host.state.raw, display: host.state.display, trigger: "keyboard" });
|
|
419
419
|
// A strict combobox keeps its committed selection while the input holds a search draft.
|
|
420
420
|
// Clearing a controlled value here makes the consumer restore its label on every keystroke.
|
|
421
|
-
if (host.state.selected !== null && (host.
|
|
421
|
+
if (host.state.selected !== null && (host.props.allowFreeText.value || host.props.allowCreate.value)) {
|
|
422
422
|
commit(null, host.state.raw, null, "clear", "keyboard");
|
|
423
423
|
}
|
|
424
424
|
open();
|
|
425
|
-
queueMicrotask(() => { if (host.
|
|
425
|
+
queueMicrotask(() => { if (host.props.query.value != null && host.props.query.value !== host.state.raw) syncQuery(); });
|
|
426
426
|
};
|
|
427
427
|
const onKeydown = (event) => {
|
|
428
428
|
const item = event.target.closest?.(".item");
|
|
@@ -434,9 +434,9 @@ export default function controller(host) {
|
|
|
434
434
|
else if (["Backspace", "Delete"].includes(event.key)) { event.preventDefault(); removeItemAt(index, "keyboard"); }
|
|
435
435
|
return;
|
|
436
436
|
}
|
|
437
|
-
if (event.target !== input || composing || event.isComposing || host.
|
|
438
|
-
if (host.
|
|
439
|
-
if ((host.
|
|
437
|
+
if (event.target !== input || composing || event.isComposing || host.props.disabled.value || host.props.readonly.value) return;
|
|
438
|
+
if (host.props.multiple.value && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
|
|
439
|
+
if ((host.props.tokenSeparators.value ?? []).includes(event.key)) { event.preventDefault(); commitQuery("keyboard"); return; }
|
|
440
440
|
if (!host.state.raw && (input.selectionStart ?? 0) === 0 && event.key === "ArrowLeft" && items().length) { event.preventDefault(); itemButtons().at(-1)?.focus(); return; }
|
|
441
441
|
if (!host.state.raw && (input.selectionStart ?? 0) === 0 && event.key === "Backspace" && items().length) { event.preventDefault(); removeItemAt(items().length - 1, "keyboard"); return; }
|
|
442
442
|
}
|
|
@@ -447,7 +447,7 @@ export default function controller(host) {
|
|
|
447
447
|
else if (event.key === "Enter" && host.state.expanded) {
|
|
448
448
|
if (host.state.active >= 0) { event.preventDefault(); choose(host.state.active, "keyboard"); }
|
|
449
449
|
// With nothing highlighted, Enter commits what was typed, as a token separator does.
|
|
450
|
-
else if (host.
|
|
450
|
+
else if (host.props.multiple.value && String(host.state.raw).trim()) { event.preventDefault(); commitQuery("keyboard"); }
|
|
451
451
|
else if (canCreate()) { event.preventDefault(); choose((host.state.rows ?? []).length, "keyboard"); }
|
|
452
452
|
else if (config().allowFreeText) { event.preventDefault(); commit(null, host.state.raw, null, "free-entry", "keyboard"); close(); }
|
|
453
453
|
}
|
|
@@ -456,7 +456,7 @@ export default function controller(host) {
|
|
|
456
456
|
const option = event.target.closest?.('[role="option"][data-index]');
|
|
457
457
|
if (option) { choose(Number(option.dataset.index), "pointer"); return; }
|
|
458
458
|
const action = event.target.closest?.("[data-combobox-action]")?.dataset.comboboxAction;
|
|
459
|
-
if (action && (host.
|
|
459
|
+
if (action && (host.props.disabled.value || host.props.readonly.value)) return;
|
|
460
460
|
if (action === "clear") { lastSelection = null; commit(null, "", null, "clear", "pointer"); close(); input.focus(); }
|
|
461
461
|
else if (action === "disclosure") { host.state.expanded ? close() : open("disclosure"); input.focus(); }
|
|
462
462
|
else if (field.contains(event.target) && !event.target.closest?.("button")) input.focus();
|
|
@@ -467,11 +467,11 @@ export default function controller(host) {
|
|
|
467
467
|
close();
|
|
468
468
|
host.state.validation = { ...host.state.validation, touched: true };
|
|
469
469
|
resolveTyped("pointer");
|
|
470
|
-
if (!host.
|
|
470
|
+
if (!host.props.multiple.value && config().allowFreeText && host.state.selected === null) commit(null, host.state.raw, null, "free-entry", "keyboard");
|
|
471
471
|
void validateCurrent();
|
|
472
472
|
};
|
|
473
473
|
const onFocusin = (event) => {
|
|
474
|
-
if (event.target === input && host.
|
|
474
|
+
if (event.target === input && host.props.openOnFocus.value && !host.state.expanded) open();
|
|
475
475
|
};
|
|
476
476
|
const onCompositionstart = (event) => { if (event.target === input) composing = true; };
|
|
477
477
|
const onCompositionend = (event) => { if (event.target === input) { composing = false; onInput(new InputEvent("input")); } };
|
|
@@ -480,16 +480,16 @@ export default function controller(host) {
|
|
|
480
480
|
|
|
481
481
|
// The selection the props describe: where the combobox starts, and where a form reset returns it.
|
|
482
482
|
const applyDefaults = () => {
|
|
483
|
-
if (host.
|
|
483
|
+
if (host.props.multiple.value) {
|
|
484
484
|
host.state.selected = null;
|
|
485
|
-
host.state.raw = host.
|
|
485
|
+
host.state.raw = host.props.query.value ?? "";
|
|
486
486
|
} else {
|
|
487
|
-
host.state.selected = host.
|
|
488
|
-
host.state.raw = host.
|
|
489
|
-
if (host.
|
|
487
|
+
host.state.selected = host.props.value.value != null ? host.props.value.value : authoredDefaults()[0]?.value ?? null;
|
|
488
|
+
host.state.raw = host.props.query.value ?? "";
|
|
489
|
+
if (host.props.query.value == null && !host.state.raw && host.state.selected !== null) {
|
|
490
490
|
host.state.raw = config().options?.find((row) => row.value === host.state.selected)?.label ?? host.state.selected;
|
|
491
491
|
}
|
|
492
|
-
if (host.
|
|
492
|
+
if (host.props.query.value == null && host.state.selected !== null && host.state.raw === host.state.selected) awaitingLabel = host.state.selected;
|
|
493
493
|
}
|
|
494
494
|
host.state.display = host.state.raw;
|
|
495
495
|
};
|
|
@@ -505,7 +505,7 @@ export default function controller(host) {
|
|
|
505
505
|
// Authored options can change after mount (renamed, replaced, or arriving late). A selected value
|
|
506
506
|
// then shows its current label, unless the user is editing the text.
|
|
507
507
|
const relabel = () => {
|
|
508
|
-
if (host.
|
|
508
|
+
if (host.props.multiple.value || host.props.query.value != null || host.state.selected == null) return;
|
|
509
509
|
if (element.ownerDocument.activeElement === input) return;
|
|
510
510
|
const label = config().options?.find((row) => row.value === host.state.selected)?.label;
|
|
511
511
|
if (label === undefined || label === host.state.raw) return;
|
|
@@ -517,7 +517,7 @@ export default function controller(host) {
|
|
|
517
517
|
const stopReset = afterFormReset(input, () => {
|
|
518
518
|
close();
|
|
519
519
|
lastSelection = null;
|
|
520
|
-
host.state.internalItems = controlledValues() ? itemsForValues() : Array.isArray(host.
|
|
520
|
+
host.state.internalItems = controlledValues() ? itemsForValues() : Array.isArray(host.props.items.value) ? host.props.items.value : authoredDefaults();
|
|
521
521
|
applyDefaults();
|
|
522
522
|
input.value = host.state.display;
|
|
523
523
|
resetValidation();
|
|
@@ -529,31 +529,31 @@ export default function controller(host) {
|
|
|
529
529
|
const observer = new MutationObserver(() => {
|
|
530
530
|
relabel();
|
|
531
531
|
// Controlled chips show their options' current labels, including options that arrive late.
|
|
532
|
-
if (host.
|
|
532
|
+
if (host.props.multiple.value) syncValues();
|
|
533
533
|
const key = optionsKey();
|
|
534
534
|
if (key === lastOptionsKey) return;
|
|
535
535
|
lastOptionsKey = key;
|
|
536
536
|
if (host.state.expanded) search(fullSet ? "disclosure" : "options");
|
|
537
537
|
});
|
|
538
538
|
observer.observe(authored, { childList: true, subtree: true, characterData: true, attributes: true });
|
|
539
|
-
let lastItems = host.
|
|
540
|
-
let lastSelectedValues = host.
|
|
539
|
+
let lastItems = host.props.items.value;
|
|
540
|
+
let lastSelectedValues = host.props.selectedValues.value;
|
|
541
541
|
if (controlledValues()) host.state.internalItems = itemsForValues();
|
|
542
542
|
else if (Array.isArray(lastItems)) host.state.internalItems = lastItems;
|
|
543
543
|
else host.state.internalItems = authoredDefaults();
|
|
544
544
|
const stop = host.effect(() => {
|
|
545
545
|
// A consumer that sets `items` owns them; otherwise the component keeps its own. selectedValues wins.
|
|
546
|
-
if (host.
|
|
547
|
-
lastItems = host.
|
|
546
|
+
if (host.props.items.value !== lastItems) {
|
|
547
|
+
lastItems = host.props.items.value;
|
|
548
548
|
if (Array.isArray(lastItems) && !controlledValues()) host.state.internalItems = lastItems;
|
|
549
549
|
// The list shows the selection; a consumer that adds or removes an item later (after creating
|
|
550
550
|
// it, say) is reflected at once rather than at the next search.
|
|
551
551
|
markSelectedRows();
|
|
552
552
|
}
|
|
553
|
-
if (host.
|
|
554
|
-
if (host.
|
|
555
|
-
if (host.
|
|
556
|
-
if (host.
|
|
553
|
+
if (host.props.selectedValues.value !== lastSelectedValues) { lastSelectedValues = host.props.selectedValues.value; syncValues(); }
|
|
554
|
+
if (host.props.value.value !== lastValue) { lastValue = host.props.value.value; syncValue(); }
|
|
555
|
+
if (host.props.query.value !== lastQuery) { lastQuery = host.props.query.value; syncQuery(); }
|
|
556
|
+
if (host.props.disabled.value || host.props.readonly.value) close();
|
|
557
557
|
updateView();
|
|
558
558
|
});
|
|
559
559
|
|
|
@@ -14,8 +14,8 @@ export default function controller(host) {
|
|
|
14
14
|
let surface = null;
|
|
15
15
|
let point = null;
|
|
16
16
|
let press = null;
|
|
17
|
-
let lastFor = host.
|
|
18
|
-
let lastOpenProp = Boolean(host.
|
|
17
|
+
let lastFor = host.props.for.value;
|
|
18
|
+
let lastOpenProp = Boolean(host.props.open.value);
|
|
19
19
|
host.state.internalOpen = lastOpenProp;
|
|
20
20
|
|
|
21
21
|
const items = () => menuItems(element);
|
|
@@ -27,7 +27,7 @@ export default function controller(host) {
|
|
|
27
27
|
};
|
|
28
28
|
const ids = createIdResolver(document, () => resolveTargets());
|
|
29
29
|
const resolveTargets = () => {
|
|
30
|
-
const next = ids.get(String(host.
|
|
30
|
+
const next = ids.get(String(host.props.for.value ?? ""));
|
|
31
31
|
if (next === target) return;
|
|
32
32
|
detach();
|
|
33
33
|
target = next;
|
|
@@ -43,11 +43,11 @@ export default function controller(host) {
|
|
|
43
43
|
if (returnFocus) target?.focus();
|
|
44
44
|
};
|
|
45
45
|
const apply = () => {
|
|
46
|
-
if (host.
|
|
47
|
-
lastFor = host.
|
|
46
|
+
if (host.props.for.value !== lastFor) {
|
|
47
|
+
lastFor = host.props.for.value;
|
|
48
48
|
resolveTargets();
|
|
49
49
|
}
|
|
50
|
-
const externalOpen = Boolean(host.
|
|
50
|
+
const externalOpen = Boolean(host.props.open.value);
|
|
51
51
|
if (externalOpen !== lastOpenProp) {
|
|
52
52
|
lastOpenProp = externalOpen;
|
|
53
53
|
host.state.internalOpen = externalOpen;
|
|
@@ -12,7 +12,7 @@ export default function controller(host) {
|
|
|
12
12
|
const overlayId = `ui-dialog-${Math.random().toString(36).slice(2, 11)}`;
|
|
13
13
|
let trigger = null;
|
|
14
14
|
let lastFor = "";
|
|
15
|
-
let lastExternalOpen = Boolean(host.
|
|
15
|
+
let lastExternalOpen = Boolean(host.props.open.value);
|
|
16
16
|
let lastOpen;
|
|
17
17
|
host.state.internalOpen = lastExternalOpen;
|
|
18
18
|
|
|
@@ -34,7 +34,7 @@ export default function controller(host) {
|
|
|
34
34
|
apply();
|
|
35
35
|
});
|
|
36
36
|
const syncTrigger = () => {
|
|
37
|
-
const nextFor = String(host.
|
|
37
|
+
const nextFor = String(host.props.for.value ?? "");
|
|
38
38
|
if (nextFor === lastFor) return;
|
|
39
39
|
lastFor = nextFor;
|
|
40
40
|
trigger?.removeEventListener("click", onTriggerClick);
|
|
@@ -47,22 +47,22 @@ export default function controller(host) {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
const apply = () => {
|
|
50
|
-
const externalOpen = Boolean(host.
|
|
50
|
+
const externalOpen = Boolean(host.props.open.value);
|
|
51
51
|
if (externalOpen !== lastExternalOpen) {
|
|
52
52
|
lastExternalOpen = externalOpen;
|
|
53
53
|
host.state.internalOpen = externalOpen;
|
|
54
54
|
}
|
|
55
|
-
host.state.accessibleLabel = inferredLabel(element, host.
|
|
55
|
+
host.state.accessibleLabel = inferredLabel(element, host.props.label.value);
|
|
56
56
|
dialog?.setAttribute("aria-label", String(host.state.accessibleLabel));
|
|
57
|
-
if (host.
|
|
57
|
+
if (host.props.alert.value) dialog?.setAttribute("role", "alertdialog");
|
|
58
58
|
else dialog?.removeAttribute("role");
|
|
59
59
|
syncTrigger();
|
|
60
60
|
const open = Boolean(host.state.internalOpen);
|
|
61
61
|
// `modeless` is a deprecated no-op: non-modal is the default. An alert dialog is always modal (APG alertdialog).
|
|
62
|
-
const modal = Boolean(host.
|
|
62
|
+
const modal = Boolean(host.props.modal.value || host.props.alert.value);
|
|
63
63
|
// An unset or unknown closedby follows native <dialog>'s auto state: closerequest when modal, none otherwise.
|
|
64
|
-
const requestedClosedBy = ["any", "closerequest", "none"].includes(host.
|
|
65
|
-
const closedBy = host.
|
|
64
|
+
const requestedClosedBy = ["any", "closerequest", "none"].includes(host.props.closedby.value) ? host.props.closedby.value : modal ? "closerequest" : "none";
|
|
65
|
+
const closedBy = host.props.alert.value && requestedClosedBy === "any" ? "closerequest" : requestedClosedBy;
|
|
66
66
|
trigger?.setAttribute("aria-expanded", String(open));
|
|
67
67
|
if (!dialog) return;
|
|
68
68
|
dialog.setAttribute("closedby", closedBy);
|
|
@@ -104,7 +104,7 @@ export default function controller(host) {
|
|
|
104
104
|
requestTopOverlayClose(document, "escape", "keyboard");
|
|
105
105
|
};
|
|
106
106
|
const observer = new MutationObserver(() => {
|
|
107
|
-
const label = inferredLabel(element, host.
|
|
107
|
+
const label = inferredLabel(element, host.props.label.value);
|
|
108
108
|
if (label !== host.state.accessibleLabel) host.state.accessibleLabel = label;
|
|
109
109
|
});
|
|
110
110
|
observer.observe(element, { childList: true, subtree: true, characterData: true });
|
|
@@ -16,7 +16,7 @@ export default function controller(host) {
|
|
|
16
16
|
const document = host.element.ownerDocument;
|
|
17
17
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
18
18
|
host.state.contentId = `ui-disclosure-${++disclosures}`;
|
|
19
|
-
let external = host.
|
|
19
|
+
let external = host.props.open.value;
|
|
20
20
|
host.state.internalOpen = Boolean(external);
|
|
21
21
|
let groupName = "";
|
|
22
22
|
const member = {
|
|
@@ -27,7 +27,7 @@ export default function controller(host) {
|
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
29
|
const syncGroup = (reason, how) => {
|
|
30
|
-
const name = String(host.
|
|
30
|
+
const name = String(host.props.name.value || "");
|
|
31
31
|
if (name !== groupName) {
|
|
32
32
|
if (groupName) groupFor(document, groupName).delete(member);
|
|
33
33
|
groupName = name;
|
|
@@ -38,11 +38,11 @@ export default function controller(host) {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
const stop = host.effect(() => {
|
|
41
|
-
if (host.
|
|
42
|
-
external = host.
|
|
41
|
+
if (host.props.open.value !== external) {
|
|
42
|
+
external = host.props.open.value;
|
|
43
43
|
host.state.internalOpen = Boolean(external);
|
|
44
44
|
}
|
|
45
|
-
const level = Number(host.
|
|
45
|
+
const level = Number(host.props.headingLevel.value);
|
|
46
46
|
host.state.headingRole = Number.isInteger(level) && level >= 2 && level <= 6 ? "heading" : null;
|
|
47
47
|
host.state.headingAriaLevel = host.state.headingRole ? level : null;
|
|
48
48
|
syncGroup("programmatic", "programmatic");
|
|
@@ -50,7 +50,7 @@ export default function controller(host) {
|
|
|
50
50
|
else host.refs.panel.setAttribute("hidden", "until-found");
|
|
51
51
|
});
|
|
52
52
|
const onClick = () => {
|
|
53
|
-
if (host.
|
|
53
|
+
if (host.props.disabled.value) return;
|
|
54
54
|
const open = !host.state.internalOpen;
|
|
55
55
|
const how = trigger();
|
|
56
56
|
host.state.internalOpen = open;
|