Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@vaadin/component-base

Package Overview
Dependencies
Maintainers
12
Versions
597
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/component-base - npm Package Compare versions

Comparing version
25.2.0-alpha9
to
25.2.0-beta1
+44
-10
custom-elements.json

@@ -10,5 +10,18 @@ {

{
"kind": "variable",
"kind": "mixin",
"description": "",
"name": "DelegateStateMixin",
"description": "A mixin to delegate properties and attributes to a target element."
"members": [],
"attributes": [],
"parameters": [
{
"name": "superclass"
}
],
"mixins": [
{
"name": "dedupeMixin",
"package": "@open-wc/dedupe-mixin"
}
]
}

@@ -95,3 +108,3 @@ ],

"kind": "mixin",
"description": "A mixin that allows to set partial I18N properties.",
"description": "A mixin that allows to set partial I18N properties.\n\nSubclasses provide their default values by overriding the\n`defaultI18n` static getter:\n\n```js\nstatic get defaultI18n() {\n return { foo: 'Foo', bar: 'Bar' };\n}\n```",
"name": "I18nMixin",

@@ -122,5 +135,2 @@ "members": [

{
"name": "defaultI18n"
},
{
"name": "superClass"

@@ -229,5 +239,17 @@ }

{
"kind": "variable",
"kind": "mixin",
"description": "A mixin that uses a ResizeObserver to listen to host size changes.",
"name": "ResizeMixin",
"description": "A mixin that uses a ResizeObserver to listen to host size changes."
"members": [],
"parameters": [
{
"name": "superclass"
}
],
"mixins": [
{
"name": "dedupeMixin",
"package": "@open-wc/dedupe-mixin"
}
]
}

@@ -251,5 +273,17 @@ ],

{
"kind": "variable",
"kind": "mixin",
"description": "Mixin to insert styles into the outer scope to handle slotted components.\nThis is useful e.g. to hide native `<input type=\"number\">` controls.",
"name": "SlotStylesMixin",
"description": "Mixin to insert styles into the outer scope to handle slotted components.\nThis is useful e.g. to hide native `<input type=\"number\">` controls."
"members": [],
"parameters": [
{
"name": "superclass"
}
],
"mixins": [
{
"name": "dedupeMixin",
"package": "@open-wc/dedupe-mixin"
}
]
}

@@ -256,0 +290,0 @@ ],

+4
-4
{
"name": "@vaadin/component-base",
"version": "25.2.0-alpha9",
"version": "25.2.0-beta1",
"publishConfig": {

@@ -41,4 +41,4 @@ "access": "public"

"devDependencies": {
"@vaadin/chai-plugins": "25.2.0-alpha9",
"@vaadin/test-runner-commands": "25.2.0-alpha9",
"@vaadin/chai-plugins": "25.2.0-beta1",
"@vaadin/test-runner-commands": "25.2.0-beta1",
"@vaadin/testing-helpers": "^2.0.0",

@@ -48,3 +48,3 @@ "sinon": "^21.0.2"

"customElements": "custom-elements.json",
"gitHead": "a38a03e8a8be45821f39c14054c63634dafe08d0"
"gitHead": "471a23f60d1eb725f98a33f62cb9664d9c0a4163"
}

@@ -6,3 +6,2 @@ /**

*/
import type { ReactiveController } from 'lit';
import type { Cache } from './cache.js';

@@ -27,6 +26,3 @@ import type { getFlatIndexByPath, getFlatIndexContext, getItemContext } from './helpers.js';

*/
export class DataProviderController<
TItem,
TDataProviderParams extends Record<string, unknown>,
> implements ReactiveController {
export class DataProviderController<TItem, TDataProviderParams extends Record<string, unknown>> extends EventTarget {
/**

@@ -99,6 +95,2 @@ * The controller host element.

hostConnected(): void;
hostDisconnected(): void;
/**

@@ -105,0 +97,0 @@ * Whether the root cache or any of its decendant caches have pending requests.

@@ -108,3 +108,3 @@ /**

const subCache = cache.getSubCache(levelIndex);
if (subCache && subCache.flatSize > 0 && subIndexes.length) {
if (subCache?.flatSize > 0 && subIndexes.length) {
return getFlatIndexByPath(subCache, subIndexes, flatIndex + flatIndexOnLevel + 1);

@@ -111,0 +111,0 @@ }

@@ -16,3 +16,3 @@ /**

export function defineCustomElement(CustomElement, version = '25.2.0-alpha9') {
export function defineCustomElement(CustomElement, version = '25.2.0-beta1') {
Object.defineProperty(CustomElement, 'version', {

@@ -19,0 +19,0 @@ get() {

@@ -10,117 +10,116 @@ /**

* A mixin to delegate properties and attributes to a target element.
*
* @polymerMixin
*/
export const DelegateStateMixin = dedupeMixin(
(superclass) =>
class DelegateStateMixinClass extends superclass {
static get properties() {
return {
/**
* A target element to which attributes and properties are delegated.
* @protected
*/
stateTarget: {
type: Object,
observer: '_stateTargetChanged',
},
};
}
const DelegateStateMixinImplementation = (superclass) => {
return class DelegateStateMixinClass extends superclass {
static get properties() {
return {
/**
* A target element to which attributes and properties are delegated.
* @protected
*/
stateTarget: {
type: Object,
observer: '_stateTargetChanged',
},
};
}
/**
* An array of the host attributes to delegate to the target element.
*/
static get delegateAttrs() {
return [];
}
/**
* An array of the host attributes to delegate to the target element.
*/
static get delegateAttrs() {
return [];
}
/**
* An array of the host properties to delegate to the target element.
*/
static get delegateProps() {
return [];
}
/**
* An array of the host properties to delegate to the target element.
*/
static get delegateProps() {
return [];
}
/** @protected */
ready() {
super.ready();
/** @protected */
ready() {
super.ready();
this._createDelegateAttrsObserver();
this._createDelegatePropsObserver();
}
this._createDelegateAttrsObserver();
this._createDelegatePropsObserver();
}
/** @protected */
_stateTargetChanged(target) {
if (target) {
this._ensureAttrsDelegated();
this._ensurePropsDelegated();
}
/** @protected */
_stateTargetChanged(target) {
if (target) {
this._ensureAttrsDelegated();
this._ensurePropsDelegated();
}
}
/** @protected */
_createDelegateAttrsObserver() {
this._createMethodObserver(`_delegateAttrsChanged(${this.constructor.delegateAttrs.join(', ')})`);
}
/** @protected */
_createDelegateAttrsObserver() {
this._createMethodObserver(`_delegateAttrsChanged(${this.constructor.delegateAttrs.join(', ')})`);
}
/** @protected */
_createDelegatePropsObserver() {
this._createMethodObserver(`_delegatePropsChanged(${this.constructor.delegateProps.join(', ')})`);
}
/** @protected */
_createDelegatePropsObserver() {
this._createMethodObserver(`_delegatePropsChanged(${this.constructor.delegateProps.join(', ')})`);
}
/** @protected */
_ensureAttrsDelegated() {
this.constructor.delegateAttrs.forEach((name) => {
this._delegateAttribute(name, this[name]);
});
}
/** @protected */
_ensureAttrsDelegated() {
this.constructor.delegateAttrs.forEach((name) => {
this._delegateAttribute(name, this[name]);
});
}
/** @protected */
_ensurePropsDelegated() {
this.constructor.delegateProps.forEach((name) => {
this._delegateProperty(name, this[name]);
});
/** @protected */
_ensurePropsDelegated() {
this.constructor.delegateProps.forEach((name) => {
this._delegateProperty(name, this[name]);
});
}
/** @protected */
_delegateAttrsChanged(...values) {
this.constructor.delegateAttrs.forEach((name, index) => {
this._delegateAttribute(name, values[index]);
});
}
/** @protected */
_delegatePropsChanged(...values) {
this.constructor.delegateProps.forEach((name, index) => {
this._delegateProperty(name, values[index]);
});
}
/** @protected */
_delegateAttribute(name, value) {
if (!this.stateTarget) {
return;
}
/** @protected */
_delegateAttrsChanged(...values) {
this.constructor.delegateAttrs.forEach((name, index) => {
this._delegateAttribute(name, values[index]);
});
if (name === 'invalid') {
this._delegateAttribute('aria-invalid', value ? 'true' : false);
}
/** @protected */
_delegatePropsChanged(...values) {
this.constructor.delegateProps.forEach((name, index) => {
this._delegateProperty(name, values[index]);
});
if (typeof value === 'boolean') {
this.stateTarget.toggleAttribute(name, value);
} else if (value) {
this.stateTarget.setAttribute(name, value);
} else {
this.stateTarget.removeAttribute(name);
}
}
/** @protected */
_delegateAttribute(name, value) {
if (!this.stateTarget) {
return;
}
if (name === 'invalid') {
this._delegateAttribute('aria-invalid', value ? 'true' : false);
}
if (typeof value === 'boolean') {
this.stateTarget.toggleAttribute(name, value);
} else if (value) {
this.stateTarget.setAttribute(name, value);
} else {
this.stateTarget.removeAttribute(name);
}
/** @protected */
_delegateProperty(name, value) {
if (!this.stateTarget) {
return;
}
/** @protected */
_delegateProperty(name, value) {
if (!this.stateTarget) {
return;
}
this.stateTarget[name] = value;
}
};
};
this.stateTarget[name] = value;
}
},
);
export const DelegateStateMixin = dedupeMixin(DelegateStateMixinImplementation);

@@ -36,4 +36,2 @@ /**

* A mixin to handle `dir` attribute based on the one set on the `<html>` element.
*
* @polymerMixin
*/

@@ -40,0 +38,0 @@ export const DirMixin = (superClass) =>

@@ -34,6 +34,2 @@ /**

/**
* @polymerMixin
* @mixes DirMixin
*/
export const ElementMixin = (superClass) =>

@@ -40,0 +36,0 @@ class VaadinElementMixin extends DirMixin(superClass) {

@@ -124,3 +124,3 @@ /**

// Allow undefined for testing events
let buttons = ev.buttons === undefined ? 1 : ev.buttons;
let buttons = ev.buttons ?? 1;
if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {

@@ -133,3 +133,3 @@ buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;

// Allow undefined for testing events
const button = ev.button === undefined ? 0 : ev.button;
const button = ev.button ?? 0;
// Ev.button is 0 in mousedown/mouseup/click for left button activation

@@ -237,3 +237,3 @@ return button === 0;

// if there is not a shadowroot, exit the loop
while (next && next.shadowRoot && !window.ShadyDOM) {
while (next?.shadowRoot && !window.ShadyDOM) {
// If there is a node at x/y in the shadowroot, look deeper

@@ -454,3 +454,3 @@ const oldNext = next;

gd = gobj[dep];
if (gd && gd[name]) {
if (gd?.[name]) {
gd[name] = (gd[name] || 1) - 1;

@@ -538,3 +538,3 @@ gd._count = (gd._count || 1) - 1;

const preventer = detail.preventer || detail.sourceEvent;
if (preventer && preventer.preventDefault) {
if (preventer?.preventDefault) {
preventer.preventDefault();

@@ -541,0 +541,0 @@ }

@@ -11,4 +11,3 @@ /**

*/
export declare function I18nMixin<I, T extends Constructor<HTMLElement>>(
defaultI18n: I,
export declare function I18nMixin<T extends Constructor<HTMLElement>, I = unknown>(
superclass: T,

@@ -15,0 +14,0 @@ ): Constructor<I18nMixinClass<I>> & T;

@@ -38,5 +38,12 @@ /**

*
* @polymerMixin
* Subclasses provide their default values by overriding the
* `defaultI18n` static getter:
*
* ```js
* static get defaultI18n() {
* return { foo: 'Foo', bar: 'Bar' };
* }
* ```
*/
export const I18nMixin = (defaultI18n, superClass) =>
export const I18nMixin = (superClass) =>
class I18nMixinClass extends superClass {

@@ -59,6 +66,16 @@ static get properties() {

/**
* Default I18N values. Must be overridden by subclasses with actual defaults.
*
* @protected
* @return {Object}
*/
static get defaultI18n() {
return {};
}
constructor() {
super();
this.i18n = deepMerge({}, defaultI18n);
this.i18n = deepMerge({}, this.constructor.defaultI18n);
}

@@ -85,4 +102,4 @@

this.__customI18n = value;
this.__effectiveI18n = deepMerge({}, defaultI18n, this.__customI18n);
this.__effectiveI18n = deepMerge({}, this.constructor.defaultI18n, this.__customI18n);
}
};

@@ -10,4 +10,2 @@ /**

* by setting the `overlayClass` property or `overlay-class` attribute.
*
* @polymerMixin
*/

@@ -14,0 +12,0 @@ export const OverlayClassMixin = (superclass) =>

@@ -62,3 +62,3 @@ /**

if (options && options.reflectToAttribute) {
if (options?.reflectToAttribute) {
options.reflect = true;

@@ -65,0 +65,0 @@ }

@@ -29,67 +29,65 @@ /**

* A mixin that uses a ResizeObserver to listen to host size changes.
*
* @polymerMixin
*/
export const ResizeMixin = dedupeMixin(
(superclass) =>
class ResizeMixinClass extends superclass {
/**
* When true, the parent element resize will be also observed.
* Override this getter and return `true` to enable this.
*
* @protected
*/
get _observeParent() {
return false;
}
const ResizeMixinImplementation = (superclass) =>
class ResizeMixinClass extends superclass {
/**
* When true, the parent element resize will be also observed.
* Override this getter and return `true` to enable this.
*
* @protected
*/
get _observeParent() {
return false;
}
/** @protected */
connectedCallback() {
super.connectedCallback();
observer.observe(this);
/** @protected */
connectedCallback() {
super.connectedCallback();
observer.observe(this);
if (this._observeParent) {
const parent = this.parentNode instanceof ShadowRoot ? this.parentNode.host : this.parentNode;
if (this._observeParent) {
const parent = this.parentNode instanceof ShadowRoot ? this.parentNode.host : this.parentNode;
if (!parent.resizables) {
parent.resizables = new Set();
observer.observe(parent);
}
if (!parent.resizables) {
parent.resizables = new Set();
observer.observe(parent);
}
parent.resizables.add(this);
this.__parent = parent;
}
parent.resizables.add(this);
this.__parent = parent;
}
}
/** @protected */
disconnectedCallback() {
super.disconnectedCallback();
observer.unobserve(this);
/** @protected */
disconnectedCallback() {
super.disconnectedCallback();
observer.unobserve(this);
const parent = this.__parent;
if (this._observeParent && parent) {
const resizables = parent.resizables;
const parent = this.__parent;
if (this._observeParent && parent) {
const resizables = parent.resizables;
if (resizables) {
resizables.delete(this);
if (resizables) {
resizables.delete(this);
if (resizables.size === 0) {
observer.unobserve(parent);
}
if (resizables.size === 0) {
observer.unobserve(parent);
}
}
this.__parent = null;
}
this.__parent = null;
}
}
/**
* A handler invoked on host resize. By default, it does nothing.
* Override the method to implement your own behavior.
*
* @protected
*/
_onResize(_contentRect) {
// To be implemented.
}
},
);
/**
* A handler invoked on host resize. By default, it does nothing.
* Override the method to implement your own behavior.
*
* @protected
*/
_onResize(_contentRect) {
// To be implemented.
}
};
export const ResizeMixin = dedupeMixin(ResizeMixinImplementation);

@@ -226,3 +226,3 @@ /**

if (newNodes && newNodes.length > 0) {
if (newNodes?.length > 0) {
if (this.multiple) {

@@ -229,0 +229,0 @@ // Remove default node if exists

@@ -8,7 +8,15 @@ /**

/**
* A helper for observing slot changes.
* A helper for observing slot or shadow-root changes.
*
* When `target` is an `HTMLSlotElement`, the observer listens for `slotchange`
* on the slot itself and diffs `target.assignedNodes({ flatten: true })`.
*
* When `target` is a `ShadowRoot`, the observer listens for `slotchange` events
* bubbling to it and diffs the **union** of `assignedNodes({ flatten: true })`
* every descendant `<slot>`. Cross-slot reassignment of the same node does
* not change the union and therefore fires no callback.
*/
export class SlotObserver {
constructor(
slot: HTMLSlotElement,
target: HTMLSlotElement | DocumentFragment,
callback: (info: { addedNodes: Node[]; currentNodes: Node[]; movedNodes: Node[]; removedNodes: Node[] }) => void,

@@ -18,2 +26,4 @@ forceInitial?: boolean,

readonly target: HTMLSlotElement | DocumentFragment;
/**

@@ -20,0 +30,0 @@ * Activates an observer. This method is automatically called when

@@ -8,13 +8,21 @@ /**

/**
* A helper for observing slot changes.
* A helper for observing slot or shadow-root changes.
*
* When `target` is an `HTMLSlotElement`, the observer listens for `slotchange`
* on the slot itself and diffs `target.assignedNodes({ flatten: true })`.
*
* When `target` is a `ShadowRoot`, the observer listens for `slotchange` events
* bubbling to it and diffs the **union** of `assignedNodes({ flatten: true })`
* across every descendant `<slot>`. Cross-slot reassignment of the same node
* does not change the union and therefore fires no callback.
*/
export class SlotObserver {
constructor(slot, callback, forceInitial) {
/** @type HTMLSlotElement */
this.slot = slot;
constructor(target, callback, forceInitial) {
/** @type {HTMLSlotElement | DocumentFragment} */
this.target = target;
/** @type Function */
/** @type {Function} */
this.callback = callback;
/** @type boolean */
/** @type {boolean} */
this.forceInitial = forceInitial;

@@ -25,2 +33,5 @@

/** @type {boolean} */
this._isSlot = target instanceof HTMLSlotElement;
this._connected = false;

@@ -43,3 +54,3 @@ this._scheduled = false;

connect() {
this.slot.addEventListener('slotchange', this._boundSchedule);
this.target.addEventListener('slotchange', this._boundSchedule);
this._connected = true;

@@ -54,3 +65,3 @@ }

disconnect() {
this.slot.removeEventListener('slotchange', this._boundSchedule);
this.target.removeEventListener('slotchange', this._boundSchedule);
this._connected = false;

@@ -84,24 +95,53 @@ }

/** @private */
_processNodes() {
const currentNodes = this.slot.assignedNodes({ flatten: true });
_collectNodes() {
const slots = this._isSlot ? [this.target] : [...this.target.querySelectorAll('slot')];
return [...new Set(slots.flatMap((slot) => slot.assignedNodes({ flatten: true })))];
}
let addedNodes = [];
const removedNodes = [];
/** @private */
_groupNodesBySlot(nodes) {
const map = new Map();
nodes.forEach((node) => {
const slot = node.assignedSlot;
map.set(slot, map.get(slot) ?? []);
map.get(slot).push(node);
});
return map;
}
/**
* Collect moved nodes reordered within its current slot,
* but not those that are assigned to different slot.
*
* @private
*/
_collectMovedNodes(currentNodes) {
const currentPerSlot = this._groupNodesBySlot(currentNodes);
const storedPerSlot = this._groupNodesBySlot(this._storedNodes);
const movedNodes = [];
if (currentNodes.length) {
addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
}
if (this._storedNodes.length) {
this._storedNodes.forEach((node, index) => {
const idx = currentNodes.indexOf(node);
if (idx === -1) {
removedNodes.push(node);
} else if (idx !== index) {
currentPerSlot.forEach((nodes, slot) => {
const stored = storedPerSlot.get(slot) || [];
// Skip slots whose membership changed: nodes entered or left the slot.
if (new Set(stored).difference(new Set(nodes)).size > 0) {
return;
}
stored.forEach((node, storedIndex) => {
if (nodes.indexOf(node) !== storedIndex) {
movedNodes.push(node);
}
});
}
});
return movedNodes;
}
/** @private */
_processNodes() {
const currentNodes = this._collectNodes();
const addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
const removedNodes = this._storedNodes.filter((node) => !currentNodes.includes(node));
const movedNodes = this._collectMovedNodes(currentNodes);
// By default, callback is not invoked if there is no child nodes in the slot.

@@ -108,0 +148,0 @@ // Use `forceInitial` flag if needed to also invoke it for the initial state.

@@ -42,36 +42,34 @@ /**

* This is useful e.g. to hide native `<input type="number">` controls.
*
* @polymerMixin
*/
export const SlotStylesMixin = dedupeMixin(
(superclass) =>
class SlotStylesMixinClass extends superclass {
/**
* List of styles to insert into root.
* @protected
*/
get slotStyles() {
return [];
}
const SlotStylesMixinImplementation = (superclass) =>
class SlotStylesMixinClass extends superclass {
/**
* List of styles to insert into root.
* @protected
*/
get slotStyles() {
return [];
}
/** @protected */
connectedCallback() {
super.connectedCallback();
/** @protected */
connectedCallback() {
super.connectedCallback();
this.__applySlotStyles();
}
this.__applySlotStyles();
}
/** @private */
__applySlotStyles() {
const root = this.getRootNode();
const rootStyles = getRootStyles(root);
/** @private */
__applySlotStyles() {
const root = this.getRootNode();
const rootStyles = getRootStyles(root);
this.slotStyles.forEach((styles) => {
if (!rootStyles.has(styles)) {
insertStyles(styles, root);
rootStyles.add(styles);
}
});
}
},
);
this.slotStyles.forEach((styles) => {
if (!rootStyles.has(styles)) {
insertStyles(styles, root);
rootStyles.add(styles);
}
});
}
};
export const SlotStylesMixin = dedupeMixin(SlotStylesMixinImplementation);

@@ -25,5 +25,3 @@ /**

inherits: true,
// Use this initial value so the color stays visible when the property
// is set to an invalid value to make debugging a bit easier.
initialValue: 'light-dark(black, white)',
initialValue: 'transparent',
});

@@ -90,2 +88,3 @@ });

--_vaadin-icon-chevron-down: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
--_vaadin-icon-chevron-right: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>');
--_vaadin-icon-clock: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 6v6l4 2"/><circle cx="12" cy="12" r="10"/></svg>');

@@ -92,0 +91,0 @@ --_vaadin-icon-cross: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /></svg>');

@@ -26,2 +26,4 @@ /**

export class TooltipController extends SlotController {
constructor(host: HTMLElement);
/**

@@ -47,8 +49,2 @@ * An HTML element for linking with the tooltip overlay

/**
* When true, the tooltip is opened programmatically.
* Only works if `manual` is set to `true`.
*/
opened: boolean;
/**
* Position of the tooltip with respect to its target.

@@ -80,7 +76,2 @@ */

/**
* Toggle opened state on the slotted tooltip.
*/
setOpened(opened: boolean): void;
/**
* Set default position for the slotted tooltip.

@@ -102,2 +93,16 @@ * This can be overridden by setting the position

setTarget(target: HTMLElement): void;
/**
* Schedule opening the slotted tooltip. Respects the tooltip's
* configured `hoverDelay` / `focusDelay` and the shared warm-up state.
* No-op when no tooltip is slotted.
*/
open(options?: { hover?: boolean; focus?: boolean; immediate?: boolean }): void;
/**
* Schedule closing the slotted tooltip. Respects the tooltip's
* configured `hideDelay` unless `immediate` is true.
* No-op when no tooltip is slotted.
*/
close(immediate?: boolean): void;
}

@@ -42,6 +42,2 @@ /**

if (this.opened !== undefined) {
tooltipNode.opened = this.opened;
}
if (this.position !== undefined) {

@@ -118,15 +114,2 @@ tooltipNode._position = this.position;

/**
* Toggle opened state on the slotted tooltip.
* @param {boolean} opened
*/
setOpened(opened) {
this.opened = opened;
const tooltipNode = this.node;
if (tooltipNode) {
tooltipNode.opened = opened;
}
}
/**
* Set default position for the slotted tooltip.

@@ -173,2 +156,30 @@ * This can be overridden by setting the position

/**
* Schedule opening the slotted tooltip. Respects the tooltip's
* configured `hoverDelay` / `focusDelay` and the shared warm-up state.
* No-op when no tooltip is slotted.
*
* @param {{ hover?: boolean, focus?: boolean, immediate?: boolean }} [options]
*/
open(options) {
const tooltipNode = this.node;
if (tooltipNode?.isConnected) {
tooltipNode._stateController.open(options);
}
}
/**
* Schedule closing the slotted tooltip. Respects the tooltip's
* configured `hideDelay` unless `immediate` is true.
* No-op when no tooltip is slotted.
*
* @param {boolean} [immediate]
*/
close(immediate) {
const tooltipNode = this.node;
if (tooltipNode) {
tooltipNode._stateController.close(immediate);
}
}
/** @private */

@@ -175,0 +186,0 @@ __onContentChange(event) {

@@ -518,7 +518,15 @@ /**

__getFocusedElement(visibleElements = this.__getVisibleElements()) {
return visibleElements.find(
(element) =>
element.contains(this.elementsContainer.getRootNode().activeElement) ||
element.contains(this.scrollTarget.getRootNode().activeElement),
);
// `document.activeElement` retargets to the outermost shadow host when
// focus lives in a nested shadow tree. Descend through nested shadow
// roots' `activeElement`s to reach the real focused node, then walk up
// the flattened tree (via `assignedSlot`/`parentNode`/`host`) until a
// visible row is reached.
let node = document.activeElement;
while (node?.shadowRoot?.activeElement) {
node = node.shadowRoot.activeElement;
}
while (node && !visibleElements.includes(node)) {
node = node.assignedSlot || node.parentNode || node.host;
}
return node;
}

@@ -525,0 +533,0 @@