Files
base/build/server/chunks/_layout.svelte-C9R7TwNZ.js
T
eewing ec317eb17c
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m11s
INIT
2026-02-18 15:17:47 -06:00

6251 lines
204 KiB
JavaScript

import { c as bind_props, d as spread_props, h as hasContext, f as getContext, j as setContext, p as props_id, k as derived, l as getAllContexts, m as attributes, n as lifecycle_function_unavailable, o as escape_html } from './index2-DHYCG7Ly.js';
import 'clsx';
import { o as on } from './root-BEb1kut4.js';
import './state.svelte-CsO7NG8X.js';
import { c as cn } from './utils2-B05Dmz_H.js';
import { b as boxWith, c as createBitsAttrs, s as simpleBox, a as styleToString, d as createId, m as mergeProps, e as attachRef, f as boxFrom, g as executeCallbacks, i as isWritableSymbol, B as BoxSymbol, h as isObject, j as boxFlatten, t as toReadonlyBox, k as isBox, l as isWritableBox, n as getDataOpenClosed, o as boolToEmptyStrOrUndef, p as boolToStr, q as cssToStyleObj, L as Label, r as getDataChecked, u as getAriaChecked, v as boolToTrueOrUndef, w as composeHandlers } from './label-CsPa3Fds.js';
import 'tailwind-merge';
/*!
* tabbable 6.4.0
* @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
*/
// NOTE: separate `:not()` selectors has broader browser support than the newer
// `:not([inert], [inert] *)` (Feb 2023)
var candidateSelectors = ['input:not([inert]):not([inert] *)', 'select:not([inert]):not([inert] *)', 'textarea:not([inert]):not([inert] *)', 'a[href]:not([inert]):not([inert] *)', 'button:not([inert]):not([inert] *)', '[tabindex]:not(slot):not([inert]):not([inert] *)', 'audio[controls]:not([inert]):not([inert] *)', 'video[controls]:not([inert]):not([inert] *)', '[contenteditable]:not([contenteditable="false"]):not([inert]):not([inert] *)', 'details>summary:first-of-type:not([inert]):not([inert] *)', 'details:not([inert]):not([inert] *)'];
var candidateSelector = /* #__PURE__ */candidateSelectors.join(',');
var NoElement = typeof Element === 'undefined';
var matches = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {
var _element$getRootNode;
return element === null || element === void 0 ? void 0 : (_element$getRootNode = element.getRootNode) === null || _element$getRootNode === void 0 ? void 0 : _element$getRootNode.call(element);
} : function (element) {
return element === null || element === void 0 ? void 0 : element.ownerDocument;
};
/**
* Determines if a node is inert or in an inert ancestor.
* @param {Node} [node]
* @param {boolean} [lookUp] If true and `node` is not inert, looks up at ancestors to
* see if any of them are inert. If false, only `node` itself is considered.
* @returns {boolean} True if inert itself or by way of being in an inert ancestor.
* False if `node` is falsy.
*/
var _isInert = function isInert(node, lookUp) {
var _node$getAttribute;
if (lookUp === void 0) {
lookUp = true;
}
// CAREFUL: JSDom does not support inert at all, so we can't use the `HTMLElement.inert`
// JS API property; we have to check the attribute, which can either be empty or 'true';
// if it's `null` (not specified) or 'false', it's an active element
var inertAtt = node === null || node === void 0 ? void 0 : (_node$getAttribute = node.getAttribute) === null || _node$getAttribute === void 0 ? void 0 : _node$getAttribute.call(node, 'inert');
var inert = inertAtt === '' || inertAtt === 'true';
// NOTE: this could also be handled with `node.matches('[inert], :is([inert] *)')`
// if it weren't for `matches()` not being a function on shadow roots; the following
// code works for any kind of node
var result = inert || lookUp && node && (
// closest does not exist on shadow roots, so we fall back to a manual
// lookup upward, in case it is not defined.
typeof node.closest === 'function' ? node.closest('[inert]') : _isInert(node.parentNode));
return result;
};
/**
* Determines if a node's content is editable.
* @param {Element} [node]
* @returns True if it's content-editable; false if it's not or `node` is falsy.
*/
var isContentEditable = function isContentEditable(node) {
var _node$getAttribute2;
// CAREFUL: JSDom does not support the `HTMLElement.isContentEditable` API so we have
// to use the attribute directly to check for this, which can either be empty or 'true';
// if it's `null` (not specified) or 'false', it's a non-editable element
var attValue = node === null || node === void 0 ? void 0 : (_node$getAttribute2 = node.getAttribute) === null || _node$getAttribute2 === void 0 ? void 0 : _node$getAttribute2.call(node, 'contenteditable');
return attValue === '' || attValue === 'true';
};
/**
* @param {Element} el container to check in
* @param {boolean} includeContainer add container to check
* @param {(node: Element) => boolean} filter filter candidates
* @returns {Element[]}
*/
var getCandidates = function getCandidates(el, includeContainer, filter) {
// even if `includeContainer=false`, we still have to check it for inertness because
// if it's inert (either by itself or via its parent), then all its children are inert
if (_isInert(el)) {
return [];
}
var candidates = Array.prototype.slice.apply(el.querySelectorAll(candidateSelector));
if (includeContainer && matches.call(el, candidateSelector)) {
candidates.unshift(el);
}
candidates = candidates.filter(filter);
return candidates;
};
/**
* @callback GetShadowRoot
* @param {Element} element to check for shadow root
* @returns {ShadowRoot|boolean} ShadowRoot if available or boolean indicating if a shadowRoot is attached but not available.
*/
/**
* @callback ShadowRootFilter
* @param {Element} shadowHostNode the element which contains shadow content
* @returns {boolean} true if a shadow root could potentially contain valid candidates.
*/
/**
* @typedef {Object} CandidateScope
* @property {Element} scopeParent contains inner candidates
* @property {Element[]} candidates list of candidates found in the scope parent
*/
/**
* @typedef {Object} IterativeOptions
* @property {GetShadowRoot|boolean} getShadowRoot true if shadow support is enabled; falsy if not;
* if a function, implies shadow support is enabled and either returns the shadow root of an element
* or a boolean stating if it has an undisclosed shadow root
* @property {(node: Element) => boolean} filter filter candidates
* @property {boolean} flatten if true then result will flatten any CandidateScope into the returned list
* @property {ShadowRootFilter} shadowRootFilter filter shadow roots;
*/
/**
* @param {Element[]} elements list of element containers to match candidates from
* @param {boolean} includeContainer add container list to check
* @param {IterativeOptions} options
* @returns {Array.<Element|CandidateScope>}
*/
var _getCandidatesIteratively = function getCandidatesIteratively(elements, includeContainer, options) {
var candidates = [];
var elementsToCheck = Array.from(elements);
while (elementsToCheck.length) {
var element = elementsToCheck.shift();
if (_isInert(element, false)) {
// no need to look up since we're drilling down
// anything inside this container will also be inert
continue;
}
if (element.tagName === 'SLOT') {
// add shadow dom slot scope (slot itself cannot be focusable)
var assigned = element.assignedElements();
var content = assigned.length ? assigned : element.children;
var nestedCandidates = _getCandidatesIteratively(content, true, options);
if (options.flatten) {
candidates.push.apply(candidates, nestedCandidates);
} else {
candidates.push({
scopeParent: element,
candidates: nestedCandidates
});
}
} else {
// check candidate element
var validCandidate = matches.call(element, candidateSelector);
if (validCandidate && options.filter(element) && (includeContainer || !elements.includes(element))) {
candidates.push(element);
}
// iterate over shadow content if possible
var shadowRoot = element.shadowRoot ||
// check for an undisclosed shadow
typeof options.getShadowRoot === 'function' && options.getShadowRoot(element);
// no inert look up because we're already drilling down and checking for inertness
// on the way down, so all containers to this root node should have already been
// vetted as non-inert
var validShadowRoot = !_isInert(shadowRoot, false) && (!options.shadowRootFilter || options.shadowRootFilter(element));
if (shadowRoot && validShadowRoot) {
// add shadow dom scope IIF a shadow root node was given; otherwise, an undisclosed
// shadow exists, so look at light dom children as fallback BUT create a scope for any
// child candidates found because they're likely slotted elements (elements that are
// children of the web component element (which has the shadow), in the light dom, but
// slotted somewhere _inside_ the undisclosed shadow) -- the scope is created below,
// _after_ we return from this recursive call
var _nestedCandidates = _getCandidatesIteratively(shadowRoot === true ? element.children : shadowRoot.children, true, options);
if (options.flatten) {
candidates.push.apply(candidates, _nestedCandidates);
} else {
candidates.push({
scopeParent: element,
candidates: _nestedCandidates
});
}
} else {
// there's not shadow so just dig into the element's (light dom) children
// __without__ giving the element special scope treatment
elementsToCheck.unshift.apply(elementsToCheck, element.children);
}
}
}
return candidates;
};
/**
* @private
* Determines if the node has an explicitly specified `tabindex` attribute.
* @param {HTMLElement} node
* @returns {boolean} True if so; false if not.
*/
var hasTabIndex = function hasTabIndex(node) {
return !isNaN(parseInt(node.getAttribute('tabindex'), 10));
};
/**
* Determine the tab index of a given node.
* @param {HTMLElement} node
* @returns {number} Tab order (negative, 0, or positive number).
* @throws {Error} If `node` is falsy.
*/
var getTabIndex = function getTabIndex(node) {
if (!node) {
throw new Error('No node provided');
}
if (node.tabIndex < 0) {
// in Chrome, <details/>, <audio controls/> and <video controls/> elements get a default
// `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,
// yet they are still part of the regular tab order; in FF, they get a default
// `tabIndex` of 0; since Chrome still puts those elements in the regular tab
// order, consider their tab index to be 0.
// Also browsers do not return `tabIndex` correctly for contentEditable nodes;
// so if they don't have a tabindex attribute specifically set, assume it's 0.
if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) {
return 0;
}
}
return node.tabIndex;
};
/**
* Determine the tab index of a given node __for sort order purposes__.
* @param {HTMLElement} node
* @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default,
* has tabIndex -1, but needs to be sorted by document order in order for its content to be
* inserted into the correct sort position.
* @returns {number} Tab order (negative, 0, or positive number).
*/
var getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) {
var tabIndex = getTabIndex(node);
if (tabIndex < 0 && isScope && !hasTabIndex(node)) {
return 0;
}
return tabIndex;
};
var sortOrderedTabbables = function sortOrderedTabbables(a, b) {
return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
};
var isInput = function isInput(node) {
return node.tagName === 'INPUT';
};
var isHiddenInput = function isHiddenInput(node) {
return isInput(node) && node.type === 'hidden';
};
var isDetailsWithSummary = function isDetailsWithSummary(node) {
var r = node.tagName === 'DETAILS' && Array.prototype.slice.apply(node.children).some(function (child) {
return child.tagName === 'SUMMARY';
});
return r;
};
var getCheckedRadio = function getCheckedRadio(nodes, form) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].checked && nodes[i].form === form) {
return nodes[i];
}
}
};
var isTabbableRadio = function isTabbableRadio(node) {
if (!node.name) {
return true;
}
var radioScope = node.form || getRootNode(node);
var queryRadios = function queryRadios(name) {
return radioScope.querySelectorAll('input[type="radio"][name="' + name + '"]');
};
var radioSet;
if (typeof window !== 'undefined' && typeof window.CSS !== 'undefined' && typeof window.CSS.escape === 'function') {
radioSet = queryRadios(window.CSS.escape(node.name));
} else {
try {
radioSet = queryRadios(node.name);
} catch (err) {
// eslint-disable-next-line no-console
console.error('Looks like you have a radio button with a name attribute containing invalid CSS selector characters and need the CSS.escape polyfill: %s', err.message);
return false;
}
}
var checked = getCheckedRadio(radioSet, node.form);
return !checked || checked === node;
};
var isRadio = function isRadio(node) {
return isInput(node) && node.type === 'radio';
};
var isNonTabbableRadio = function isNonTabbableRadio(node) {
return isRadio(node) && !isTabbableRadio(node);
};
// determines if a node is ultimately attached to the window's document
var isNodeAttached = function isNodeAttached(node) {
var _nodeRoot;
// The root node is the shadow root if the node is in a shadow DOM; some document otherwise
// (but NOT _the_ document; see second 'If' comment below for more).
// If rootNode is shadow root, it'll have a host, which is the element to which the shadow
// is attached, and the one we need to check if it's in the document or not (because the
// shadow, and all nodes it contains, is never considered in the document since shadows
// behave like self-contained DOMs; but if the shadow's HOST, which is part of the document,
// is hidden, or is not in the document itself but is detached, it will affect the shadow's
// visibility, including all the nodes it contains). The host could be any normal node,
// or a custom element (i.e. web component). Either way, that's the one that is considered
// part of the document, not the shadow root, nor any of its children (i.e. the node being
// tested).
// To further complicate things, we have to look all the way up until we find a shadow HOST
// that is attached (or find none) because the node might be in nested shadows...
// If rootNode is not a shadow root, it won't have a host, and so rootNode should be the
// document (per the docs) and while it's a Document-type object, that document does not
// appear to be the same as the node's `ownerDocument` for some reason, so it's safer
// to ignore the rootNode at this point, and use `node.ownerDocument`. Otherwise,
// using `rootNode.contains(node)` will _always_ be true we'll get false-positives when
// node is actually detached.
// NOTE: If `nodeRootHost` or `node` happens to be the `document` itself (which is possible
// if a tabbable/focusable node was quickly added to the DOM, focused, and then removed
// from the DOM as in https://github.com/focus-trap/focus-trap-react/issues/905), then
// `ownerDocument` will be `null`, hence the optional chaining on it.
var nodeRoot = node && getRootNode(node);
var nodeRootHost = (_nodeRoot = nodeRoot) === null || _nodeRoot === void 0 ? void 0 : _nodeRoot.host;
// in some cases, a detached node will return itself as the root instead of a document or
// shadow root object, in which case, we shouldn't try to look further up the host chain
var attached = false;
if (nodeRoot && nodeRoot !== node) {
var _nodeRootHost, _nodeRootHost$ownerDo, _node$ownerDocument;
attached = !!((_nodeRootHost = nodeRootHost) !== null && _nodeRootHost !== void 0 && (_nodeRootHost$ownerDo = _nodeRootHost.ownerDocument) !== null && _nodeRootHost$ownerDo !== void 0 && _nodeRootHost$ownerDo.contains(nodeRootHost) || node !== null && node !== void 0 && (_node$ownerDocument = node.ownerDocument) !== null && _node$ownerDocument !== void 0 && _node$ownerDocument.contains(node));
while (!attached && nodeRootHost) {
var _nodeRoot2, _nodeRootHost2, _nodeRootHost2$ownerD;
// since it's not attached and we have a root host, the node MUST be in a nested shadow DOM,
// which means we need to get the host's host and check if that parent host is contained
// in (i.e. attached to) the document
nodeRoot = getRootNode(nodeRootHost);
nodeRootHost = (_nodeRoot2 = nodeRoot) === null || _nodeRoot2 === void 0 ? void 0 : _nodeRoot2.host;
attached = !!((_nodeRootHost2 = nodeRootHost) !== null && _nodeRootHost2 !== void 0 && (_nodeRootHost2$ownerD = _nodeRootHost2.ownerDocument) !== null && _nodeRootHost2$ownerD !== void 0 && _nodeRootHost2$ownerD.contains(nodeRootHost));
}
}
return attached;
};
var isZeroArea = function isZeroArea(node) {
var _node$getBoundingClie = node.getBoundingClientRect(),
width = _node$getBoundingClie.width,
height = _node$getBoundingClie.height;
return width === 0 && height === 0;
};
var isHidden = function isHidden(node, _ref) {
var displayCheck = _ref.displayCheck,
getShadowRoot = _ref.getShadowRoot;
if (displayCheck === 'full-native') {
if ('checkVisibility' in node) {
// Chrome >= 105, Edge >= 105, Firefox >= 106, Safari >= 17.4
// @see https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility#browser_compatibility
var visible = node.checkVisibility({
// Checking opacity might be desirable for some use cases, but natively,
// opacity zero elements _are_ focusable and tabbable.
checkOpacity: false,
opacityProperty: false,
contentVisibilityAuto: true,
visibilityProperty: true,
// This is an alias for `visibilityProperty`. Contemporary browsers
// support both. However, this alias has wider browser support (Chrome
// >= 105 and Firefox >= 106, vs. Chrome >= 121 and Firefox >= 122), so
// we include it anyway.
checkVisibilityCSS: true
});
return !visible;
}
// Fall through to manual visibility checks
}
// NOTE: visibility will be `undefined` if node is detached from the document
// (see notes about this further down), which means we will consider it visible
// (this is legacy behavior from a very long way back)
// NOTE: we check this regardless of `displayCheck="none"` because this is a
// _visibility_ check, not a _display_ check
if (getComputedStyle(node).visibility === 'hidden') {
return true;
}
var isDirectSummary = matches.call(node, 'details>summary:first-of-type');
var nodeUnderDetails = isDirectSummary ? node.parentElement : node;
if (matches.call(nodeUnderDetails, 'details:not([open]) *')) {
return true;
}
if (!displayCheck || displayCheck === 'full' ||
// full-native can run this branch when it falls through in case
// Element#checkVisibility is unsupported
displayCheck === 'full-native' || displayCheck === 'legacy-full') {
if (typeof getShadowRoot === 'function') {
// figure out if we should consider the node to be in an undisclosed shadow and use the
// 'non-zero-area' fallback
var originalNode = node;
while (node) {
var parentElement = node.parentElement;
var rootNode = getRootNode(node);
if (parentElement && !parentElement.shadowRoot && getShadowRoot(parentElement) === true // check if there's an undisclosed shadow
) {
// node has an undisclosed shadow which means we can only treat it as a black box, so we
// fall back to a non-zero-area test
return isZeroArea(node);
} else if (node.assignedSlot) {
// iterate up slot
node = node.assignedSlot;
} else if (!parentElement && rootNode !== node.ownerDocument) {
// cross shadow boundary
node = rootNode.host;
} else {
// iterate up normal dom
node = parentElement;
}
}
node = originalNode;
}
// else, `getShadowRoot` might be true, but all that does is enable shadow DOM support
// (i.e. it does not also presume that all nodes might have undisclosed shadows); or
// it might be a falsy value, which means shadow DOM support is disabled
// Since we didn't find it sitting in an undisclosed shadow (or shadows are disabled)
// now we can just test to see if it would normally be visible or not, provided it's
// attached to the main document.
// NOTE: We must consider case where node is inside a shadow DOM and given directly to
// `isTabbable()` or `isFocusable()` -- regardless of `getShadowRoot` option setting.
if (isNodeAttached(node)) {
// this works wherever the node is: if there's at least one client rect, it's
// somehow displayed; it also covers the CSS 'display: contents' case where the
// node itself is hidden in place of its contents; and there's no need to search
// up the hierarchy either
return !node.getClientRects().length;
}
// Else, the node isn't attached to the document, which means the `getClientRects()`
// API will __always__ return zero rects (this can happen, for example, if React
// is used to render nodes onto a detached tree, as confirmed in this thread:
// https://github.com/facebook/react/issues/9117#issuecomment-284228870)
//
// It also means that even window.getComputedStyle(node).display will return `undefined`
// because styles are only computed for nodes that are in the document.
//
// NOTE: THIS HAS BEEN THE CASE FOR YEARS. It is not new, nor is it caused by tabbable
// somehow. Though it was never stated officially, anyone who has ever used tabbable
// APIs on nodes in detached containers has actually implicitly used tabbable in what
// was later (as of v5.2.0 on Apr 9, 2021) called `displayCheck="none"` mode -- essentially
// considering __everything__ to be visible because of the innability to determine styles.
//
// v6.0.0: As of this major release, the default 'full' option __no longer treats detached
// nodes as visible with the 'none' fallback.__
if (displayCheck !== 'legacy-full') {
return true; // hidden
}
// else, fallback to 'none' mode and consider the node visible
} else if (displayCheck === 'non-zero-area') {
// NOTE: Even though this tests that the node's client rect is non-zero to determine
// whether it's displayed, and that a detached node will __always__ have a zero-area
// client rect, we don't special-case for whether the node is attached or not. In
// this mode, we do want to consider nodes that have a zero area to be hidden at all
// times, and that includes attached or not.
return isZeroArea(node);
}
// visible, as far as we can tell, or per current `displayCheck=none` mode, we assume
// it's visible
return false;
};
// form fields (nested) inside a disabled fieldset are not focusable/tabbable
// unless they are in the _first_ <legend> element of the top-most disabled
// fieldset
var isDisabledFromFieldset = function isDisabledFromFieldset(node) {
if (/^(INPUT|BUTTON|SELECT|TEXTAREA)$/.test(node.tagName)) {
var parentNode = node.parentElement;
// check if `node` is contained in a disabled <fieldset>
while (parentNode) {
if (parentNode.tagName === 'FIELDSET' && parentNode.disabled) {
// look for the first <legend> among the children of the disabled <fieldset>
for (var i = 0; i < parentNode.children.length; i++) {
var child = parentNode.children.item(i);
// when the first <legend> (in document order) is found
if (child.tagName === 'LEGEND') {
// if its parent <fieldset> is not nested in another disabled <fieldset>,
// return whether `node` is a descendant of its first <legend>
return matches.call(parentNode, 'fieldset[disabled] *') ? true : !child.contains(node);
}
}
// the disabled <fieldset> containing `node` has no <legend>
return true;
}
parentNode = parentNode.parentElement;
}
}
// else, node's tabbable/focusable state should not be affected by a fieldset's
// enabled/disabled state
return false;
};
var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(options, node) {
if (node.disabled || isHiddenInput(node) || isHidden(node, options) ||
// For a details element with a summary, the summary element gets the focus
isDetailsWithSummary(node) || isDisabledFromFieldset(node)) {
return false;
}
return true;
};
var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable(options, node) {
if (isNonTabbableRadio(node) || getTabIndex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) {
return false;
}
return true;
};
var isShadowRootTabbable = function isShadowRootTabbable(shadowHostNode) {
var tabIndex = parseInt(shadowHostNode.getAttribute('tabindex'), 10);
if (isNaN(tabIndex) || tabIndex >= 0) {
return true;
}
// If a custom element has an explicit negative tabindex,
// browsers will not allow tab targeting said element's children.
return false;
};
/**
* @param {Array.<Element|CandidateScope>} candidates
* @returns Element[]
*/
var _sortByOrder = function sortByOrder(candidates) {
var regularTabbables = [];
var orderedTabbables = [];
candidates.forEach(function (item, i) {
var isScope = !!item.scopeParent;
var element = isScope ? item.scopeParent : item;
var candidateTabindex = getSortOrderTabIndex(element, isScope);
var elements = isScope ? _sortByOrder(item.candidates) : element;
if (candidateTabindex === 0) {
isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
} else {
orderedTabbables.push({
documentOrder: i,
tabIndex: candidateTabindex,
item: item,
isScope: isScope,
content: elements
});
}
});
return orderedTabbables.sort(sortOrderedTabbables).reduce(function (acc, sortable) {
sortable.isScope ? acc.push.apply(acc, sortable.content) : acc.push(sortable.content);
return acc;
}, []).concat(regularTabbables);
};
var tabbable = function tabbable(container, options) {
options = options || {};
var candidates;
if (options.getShadowRoot) {
candidates = _getCandidatesIteratively([container], options.includeContainer, {
filter: isNodeMatchingSelectorTabbable.bind(null, options),
flatten: false,
getShadowRoot: options.getShadowRoot,
shadowRootFilter: isShadowRootTabbable
});
} else {
candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
}
return _sortByOrder(candidates);
};
var focusable = function focusable(container, options) {
options = options || {};
var candidates;
if (options.getShadowRoot) {
candidates = _getCandidatesIteratively([container], options.includeContainer, {
filter: isNodeMatchingSelectorFocusable.bind(null, options),
flatten: true,
getShadowRoot: options.getShadowRoot
});
} else {
candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
}
return candidates;
};
var isTabbable = function isTabbable(node, options) {
options = options || {};
if (!node) {
throw new Error('No node provided');
}
if (matches.call(node, candidateSelector) === false) {
return false;
}
return isNodeMatchingSelectorTabbable(options, node);
};
var focusableCandidateSelector = /* #__PURE__ */candidateSelectors.concat('iframe:not([inert]):not([inert] *)').join(',');
var isFocusable = function isFocusable(node, options) {
options = options || {};
if (!node) {
throw new Error('No node provided');
}
if (matches.call(node, focusableCandidateSelector) === false) {
return false;
}
return isNodeMatchingSelectorFocusable(options, node);
};
/**
* Custom positioning reference element.
* @see https://floating-ui.com/docs/virtual-elements
*/
const sides = ['top', 'right', 'bottom', 'left'];
const min = Math.min;
const max = Math.max;
const round = Math.round;
const createCoords = v => ({
x: v,
y: v
});
const oppositeSideMap = {
left: 'right',
right: 'left',
bottom: 'top',
top: 'bottom'
};
const oppositeAlignmentMap = {
start: 'end',
end: 'start'
};
function clamp(start, value, end) {
return max(start, min(value, end));
}
function evaluate(value, param) {
return typeof value === 'function' ? value(param) : value;
}
function getSide(placement) {
return placement.split('-')[0];
}
function getAlignment(placement) {
return placement.split('-')[1];
}
function getOppositeAxis(axis) {
return axis === 'x' ? 'y' : 'x';
}
function getAxisLength(axis) {
return axis === 'y' ? 'height' : 'width';
}
const yAxisSides = /*#__PURE__*/new Set(['top', 'bottom']);
function getSideAxis(placement) {
return yAxisSides.has(getSide(placement)) ? 'y' : 'x';
}
function getAlignmentAxis(placement) {
return getOppositeAxis(getSideAxis(placement));
}
function getAlignmentSides(placement, rects, rtl) {
if (rtl === void 0) {
rtl = false;
}
const alignment = getAlignment(placement);
const alignmentAxis = getAlignmentAxis(placement);
const length = getAxisLength(alignmentAxis);
let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';
if (rects.reference[length] > rects.floating[length]) {
mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
}
return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];
}
function getExpandedPlacements(placement) {
const oppositePlacement = getOppositePlacement(placement);
return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
}
function getOppositeAlignmentPlacement(placement) {
return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);
}
const lrPlacement = ['left', 'right'];
const rlPlacement = ['right', 'left'];
const tbPlacement = ['top', 'bottom'];
const btPlacement = ['bottom', 'top'];
function getSideList(side, isStart, rtl) {
switch (side) {
case 'top':
case 'bottom':
if (rtl) return isStart ? rlPlacement : lrPlacement;
return isStart ? lrPlacement : rlPlacement;
case 'left':
case 'right':
return isStart ? tbPlacement : btPlacement;
default:
return [];
}
}
function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {
const alignment = getAlignment(placement);
let list = getSideList(getSide(placement), direction === 'start', rtl);
if (alignment) {
list = list.map(side => side + "-" + alignment);
if (flipAlignment) {
list = list.concat(list.map(getOppositeAlignmentPlacement));
}
}
return list;
}
function getOppositePlacement(placement) {
return placement.replace(/left|right|bottom|top/g, side => oppositeSideMap[side]);
}
function expandPaddingObject(padding) {
return {
top: 0,
right: 0,
bottom: 0,
left: 0,
...padding
};
}
function getPaddingObject(padding) {
return typeof padding !== 'number' ? expandPaddingObject(padding) : {
top: padding,
right: padding,
bottom: padding,
left: padding
};
}
function rectToClientRect(rect) {
const {
x,
y,
width,
height
} = rect;
return {
width,
height,
top: y,
left: x,
right: x + width,
bottom: y + height,
x,
y
};
}
function computeCoordsFromPlacement(_ref, placement, rtl) {
let {
reference,
floating
} = _ref;
const sideAxis = getSideAxis(placement);
const alignmentAxis = getAlignmentAxis(placement);
const alignLength = getAxisLength(alignmentAxis);
const side = getSide(placement);
const isVertical = sideAxis === 'y';
const commonX = reference.x + reference.width / 2 - floating.width / 2;
const commonY = reference.y + reference.height / 2 - floating.height / 2;
const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;
let coords;
switch (side) {
case 'top':
coords = {
x: commonX,
y: reference.y - floating.height
};
break;
case 'bottom':
coords = {
x: commonX,
y: reference.y + reference.height
};
break;
case 'right':
coords = {
x: reference.x + reference.width,
y: commonY
};
break;
case 'left':
coords = {
x: reference.x - floating.width,
y: commonY
};
break;
default:
coords = {
x: reference.x,
y: reference.y
};
}
switch (getAlignment(placement)) {
case 'start':
coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
break;
case 'end':
coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
break;
}
return coords;
}
/**
* Resolves with an object of overflow side offsets that determine how much the
* element is overflowing a given clipping boundary on each side.
* - positive = overflowing the boundary by that number of pixels
* - negative = how many pixels left before it will overflow
* - 0 = lies flush with the boundary
* @see https://floating-ui.com/docs/detectOverflow
*/
async function detectOverflow(state, options) {
var _await$platform$isEle;
if (options === void 0) {
options = {};
}
const {
x,
y,
platform,
rects,
elements,
strategy
} = state;
const {
boundary = 'clippingAncestors',
rootBoundary = 'viewport',
elementContext = 'floating',
altBoundary = false,
padding = 0
} = evaluate(options, state);
const paddingObject = getPaddingObject(padding);
const altContext = elementContext === 'floating' ? 'reference' : 'floating';
const element = elements[altBoundary ? altContext : elementContext];
const clippingClientRect = rectToClientRect(await platform.getClippingRect({
element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
boundary,
rootBoundary,
strategy
}));
const rect = elementContext === 'floating' ? {
x,
y,
width: rects.floating.width,
height: rects.floating.height
} : rects.reference;
const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
x: 1,
y: 1
} : {
x: 1,
y: 1
};
const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
elements,
rect,
offsetParent,
strategy
}) : rect);
return {
top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
};
}
/**
* Computes the `x` and `y` coordinates that will place the floating element
* next to a given reference element.
*
* This export does not have any `platform` interface logic. You will need to
* write one for the platform you are using Floating UI with.
*/
const computePosition$1 = async (reference, floating, config) => {
const {
placement = 'bottom',
strategy = 'absolute',
middleware = [],
platform
} = config;
const validMiddleware = middleware.filter(Boolean);
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
let rects = await platform.getElementRects({
reference,
floating,
strategy
});
let {
x,
y
} = computeCoordsFromPlacement(rects, placement, rtl);
let statefulPlacement = placement;
let middlewareData = {};
let resetCount = 0;
for (let i = 0; i < validMiddleware.length; i++) {
var _platform$detectOverf;
const {
name,
fn
} = validMiddleware[i];
const {
x: nextX,
y: nextY,
data,
reset
} = await fn({
x,
y,
initialPlacement: placement,
placement: statefulPlacement,
strategy,
middlewareData,
rects,
platform: {
...platform,
detectOverflow: (_platform$detectOverf = platform.detectOverflow) != null ? _platform$detectOverf : detectOverflow
},
elements: {
reference,
floating
}
});
x = nextX != null ? nextX : x;
y = nextY != null ? nextY : y;
middlewareData = {
...middlewareData,
[name]: {
...middlewareData[name],
...data
}
};
if (reset && resetCount <= 50) {
resetCount++;
if (typeof reset === 'object') {
if (reset.placement) {
statefulPlacement = reset.placement;
}
if (reset.rects) {
rects = reset.rects === true ? await platform.getElementRects({
reference,
floating,
strategy
}) : reset.rects;
}
({
x,
y
} = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
}
i = -1;
}
}
return {
x,
y,
placement: statefulPlacement,
strategy,
middlewareData
};
};
/**
* Provides data to position an inner element of the floating element so that it
* appears centered to the reference element.
* @see https://floating-ui.com/docs/arrow
*/
const arrow$1 = options => ({
name: 'arrow',
options,
async fn(state) {
const {
x,
y,
placement,
rects,
platform,
elements,
middlewareData
} = state;
// Since `element` is required, we don't Partial<> the type.
const {
element,
padding = 0
} = evaluate(options, state) || {};
if (element == null) {
return {};
}
const paddingObject = getPaddingObject(padding);
const coords = {
x,
y
};
const axis = getAlignmentAxis(placement);
const length = getAxisLength(axis);
const arrowDimensions = await platform.getDimensions(element);
const isYAxis = axis === 'y';
const minProp = isYAxis ? 'top' : 'left';
const maxProp = isYAxis ? 'bottom' : 'right';
const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';
const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
const startDiff = coords[axis] - rects.reference[axis];
const arrowOffsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(element));
let clientSize = arrowOffsetParent ? arrowOffsetParent[clientProp] : 0;
// DOM platform can return `window` as the `offsetParent`.
if (!clientSize || !(await (platform.isElement == null ? void 0 : platform.isElement(arrowOffsetParent)))) {
clientSize = elements.floating[clientProp] || rects.floating[length];
}
const centerToReference = endDiff / 2 - startDiff / 2;
// If the padding is large enough that it causes the arrow to no longer be
// centered, modify the padding so that it is centered.
const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;
const minPadding = min(paddingObject[minProp], largestPossiblePadding);
const maxPadding = min(paddingObject[maxProp], largestPossiblePadding);
// Make sure the arrow doesn't overflow the floating element if the center
// point is outside the floating element's bounds.
const min$1 = minPadding;
const max = clientSize - arrowDimensions[length] - maxPadding;
const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
const offset = clamp(min$1, center, max);
// If the reference is small enough that the arrow's padding causes it to
// to point to nothing for an aligned placement, adjust the offset of the
// floating element itself. To ensure `shift()` continues to take action,
// a single reset is performed when this is true.
const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max : 0;
return {
[axis]: coords[axis] + alignmentOffset,
data: {
[axis]: offset,
centerOffset: center - offset - alignmentOffset,
...(shouldAddOffset && {
alignmentOffset
})
},
reset: shouldAddOffset
};
}
});
/**
* Optimizes the visibility of the floating element by flipping the `placement`
* in order to keep it in view when the preferred placement(s) will overflow the
* clipping boundary. Alternative to `autoPlacement`.
* @see https://floating-ui.com/docs/flip
*/
const flip$1 = function (options) {
if (options === void 0) {
options = {};
}
return {
name: 'flip',
options,
async fn(state) {
var _middlewareData$arrow, _middlewareData$flip;
const {
placement,
middlewareData,
rects,
initialPlacement,
platform,
elements
} = state;
const {
mainAxis: checkMainAxis = true,
crossAxis: checkCrossAxis = true,
fallbackPlacements: specifiedFallbackPlacements,
fallbackStrategy = 'bestFit',
fallbackAxisSideDirection = 'none',
flipAlignment = true,
...detectOverflowOptions
} = evaluate(options, state);
// If a reset by the arrow was caused due to an alignment offset being
// added, we should skip any logic now since `flip()` has already done its
// work.
// https://github.com/floating-ui/floating-ui/issues/2549#issuecomment-1719601643
if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
return {};
}
const side = getSide(placement);
const initialSideAxis = getSideAxis(initialPlacement);
const isBasePlacement = getSide(initialPlacement) === initialPlacement;
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== 'none';
if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {
fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
}
const placements = [initialPlacement, ...fallbackPlacements];
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
const overflows = [];
let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
if (checkMainAxis) {
overflows.push(overflow[side]);
}
if (checkCrossAxis) {
const sides = getAlignmentSides(placement, rects, rtl);
overflows.push(overflow[sides[0]], overflow[sides[1]]);
}
overflowsData = [...overflowsData, {
placement,
overflows
}];
// One or more sides is overflowing.
if (!overflows.every(side => side <= 0)) {
var _middlewareData$flip2, _overflowsData$filter;
const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
const nextPlacement = placements[nextIndex];
if (nextPlacement) {
const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;
if (!ignoreCrossAxisOverflow ||
// We leave the current main axis only if every placement on that axis
// overflows the main axis.
overflowsData.every(d => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {
// Try next placement and re-run the lifecycle.
return {
data: {
index: nextIndex,
overflows: overflowsData
},
reset: {
placement: nextPlacement
}
};
}
}
// First, find the candidates that fit on the mainAxis side of overflow,
// then find the placement that fits the best on the main crossAxis side.
let resetPlacement = (_overflowsData$filter = overflowsData.filter(d => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
// Otherwise fallback.
if (!resetPlacement) {
switch (fallbackStrategy) {
case 'bestFit':
{
var _overflowsData$filter2;
const placement = (_overflowsData$filter2 = overflowsData.filter(d => {
if (hasFallbackAxisSideDirection) {
const currentSideAxis = getSideAxis(d.placement);
return currentSideAxis === initialSideAxis ||
// Create a bias to the `y` side axis due to horizontal
// reading directions favoring greater width.
currentSideAxis === 'y';
}
return true;
}).map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];
if (placement) {
resetPlacement = placement;
}
break;
}
case 'initialPlacement':
resetPlacement = initialPlacement;
break;
}
}
if (placement !== resetPlacement) {
return {
reset: {
placement: resetPlacement
}
};
}
}
return {};
}
};
};
function getSideOffsets(overflow, rect) {
return {
top: overflow.top - rect.height,
right: overflow.right - rect.width,
bottom: overflow.bottom - rect.height,
left: overflow.left - rect.width
};
}
function isAnySideFullyClipped(overflow) {
return sides.some(side => overflow[side] >= 0);
}
/**
* Provides data to hide the floating element in applicable situations, such as
* when it is not in the same clipping context as the reference element.
* @see https://floating-ui.com/docs/hide
*/
const hide$1 = function (options) {
if (options === void 0) {
options = {};
}
return {
name: 'hide',
options,
async fn(state) {
const {
rects,
platform
} = state;
const {
strategy = 'referenceHidden',
...detectOverflowOptions
} = evaluate(options, state);
switch (strategy) {
case 'referenceHidden':
{
const overflow = await platform.detectOverflow(state, {
...detectOverflowOptions,
elementContext: 'reference'
});
const offsets = getSideOffsets(overflow, rects.reference);
return {
data: {
referenceHiddenOffsets: offsets,
referenceHidden: isAnySideFullyClipped(offsets)
}
};
}
case 'escaped':
{
const overflow = await platform.detectOverflow(state, {
...detectOverflowOptions,
altBoundary: true
});
const offsets = getSideOffsets(overflow, rects.floating);
return {
data: {
escapedOffsets: offsets,
escaped: isAnySideFullyClipped(offsets)
}
};
}
default:
{
return {};
}
}
}
};
};
const originSides = /*#__PURE__*/new Set(['left', 'top']);
// For type backwards-compatibility, the `OffsetOptions` type was also
// Derivable.
async function convertValueToCoords(state, options) {
const {
placement,
platform,
elements
} = state;
const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
const side = getSide(placement);
const alignment = getAlignment(placement);
const isVertical = getSideAxis(placement) === 'y';
const mainAxisMulti = originSides.has(side) ? -1 : 1;
const crossAxisMulti = rtl && isVertical ? -1 : 1;
const rawValue = evaluate(options, state);
// eslint-disable-next-line prefer-const
let {
mainAxis,
crossAxis,
alignmentAxis
} = typeof rawValue === 'number' ? {
mainAxis: rawValue,
crossAxis: 0,
alignmentAxis: null
} : {
mainAxis: rawValue.mainAxis || 0,
crossAxis: rawValue.crossAxis || 0,
alignmentAxis: rawValue.alignmentAxis
};
if (alignment && typeof alignmentAxis === 'number') {
crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
}
return isVertical ? {
x: crossAxis * crossAxisMulti,
y: mainAxis * mainAxisMulti
} : {
x: mainAxis * mainAxisMulti,
y: crossAxis * crossAxisMulti
};
}
/**
* Modifies the placement by translating the floating element along the
* specified axes.
* A number (shorthand for `mainAxis` or distance), or an axes configuration
* object may be passed.
* @see https://floating-ui.com/docs/offset
*/
const offset$1 = function (options) {
if (options === void 0) {
options = 0;
}
return {
name: 'offset',
options,
async fn(state) {
var _middlewareData$offse, _middlewareData$arrow;
const {
x,
y,
placement,
middlewareData
} = state;
const diffCoords = await convertValueToCoords(state, options);
// If the placement is the same and the arrow caused an alignment offset
// then we don't need to change the positioning coordinates.
if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {
return {};
}
return {
x: x + diffCoords.x,
y: y + diffCoords.y,
data: {
...diffCoords,
placement
}
};
}
};
};
/**
* Optimizes the visibility of the floating element by shifting it in order to
* keep it in view when it will overflow the clipping boundary.
* @see https://floating-ui.com/docs/shift
*/
const shift$1 = function (options) {
if (options === void 0) {
options = {};
}
return {
name: 'shift',
options,
async fn(state) {
const {
x,
y,
placement,
platform
} = state;
const {
mainAxis: checkMainAxis = true,
crossAxis: checkCrossAxis = false,
limiter = {
fn: _ref => {
let {
x,
y
} = _ref;
return {
x,
y
};
}
},
...detectOverflowOptions
} = evaluate(options, state);
const coords = {
x,
y
};
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
const crossAxis = getSideAxis(getSide(placement));
const mainAxis = getOppositeAxis(crossAxis);
let mainAxisCoord = coords[mainAxis];
let crossAxisCoord = coords[crossAxis];
if (checkMainAxis) {
const minSide = mainAxis === 'y' ? 'top' : 'left';
const maxSide = mainAxis === 'y' ? 'bottom' : 'right';
const min = mainAxisCoord + overflow[minSide];
const max = mainAxisCoord - overflow[maxSide];
mainAxisCoord = clamp(min, mainAxisCoord, max);
}
if (checkCrossAxis) {
const minSide = crossAxis === 'y' ? 'top' : 'left';
const maxSide = crossAxis === 'y' ? 'bottom' : 'right';
const min = crossAxisCoord + overflow[minSide];
const max = crossAxisCoord - overflow[maxSide];
crossAxisCoord = clamp(min, crossAxisCoord, max);
}
const limitedCoords = limiter.fn({
...state,
[mainAxis]: mainAxisCoord,
[crossAxis]: crossAxisCoord
});
return {
...limitedCoords,
data: {
x: limitedCoords.x - x,
y: limitedCoords.y - y,
enabled: {
[mainAxis]: checkMainAxis,
[crossAxis]: checkCrossAxis
}
}
};
}
};
};
/**
* Built-in `limiter` that will stop `shift()` at a certain point.
*/
const limitShift$1 = function (options) {
if (options === void 0) {
options = {};
}
return {
options,
fn(state) {
const {
x,
y,
placement,
rects,
middlewareData
} = state;
const {
offset = 0,
mainAxis: checkMainAxis = true,
crossAxis: checkCrossAxis = true
} = evaluate(options, state);
const coords = {
x,
y
};
const crossAxis = getSideAxis(placement);
const mainAxis = getOppositeAxis(crossAxis);
let mainAxisCoord = coords[mainAxis];
let crossAxisCoord = coords[crossAxis];
const rawOffset = evaluate(offset, state);
const computedOffset = typeof rawOffset === 'number' ? {
mainAxis: rawOffset,
crossAxis: 0
} : {
mainAxis: 0,
crossAxis: 0,
...rawOffset
};
if (checkMainAxis) {
const len = mainAxis === 'y' ? 'height' : 'width';
const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;
const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;
if (mainAxisCoord < limitMin) {
mainAxisCoord = limitMin;
} else if (mainAxisCoord > limitMax) {
mainAxisCoord = limitMax;
}
}
if (checkCrossAxis) {
var _middlewareData$offse, _middlewareData$offse2;
const len = mainAxis === 'y' ? 'width' : 'height';
const isOriginSide = originSides.has(getSide(placement));
const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse[crossAxis]) || 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);
const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : ((_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) || 0) - (isOriginSide ? computedOffset.crossAxis : 0);
if (crossAxisCoord < limitMin) {
crossAxisCoord = limitMin;
} else if (crossAxisCoord > limitMax) {
crossAxisCoord = limitMax;
}
}
return {
[mainAxis]: mainAxisCoord,
[crossAxis]: crossAxisCoord
};
}
};
};
/**
* Provides data that allows you to change the size of the floating element —
* for instance, prevent it from overflowing the clipping boundary or match the
* width of the reference element.
* @see https://floating-ui.com/docs/size
*/
const size$1 = function (options) {
if (options === void 0) {
options = {};
}
return {
name: 'size',
options,
async fn(state) {
var _state$middlewareData, _state$middlewareData2;
const {
placement,
rects,
platform,
elements
} = state;
const {
apply = () => {},
...detectOverflowOptions
} = evaluate(options, state);
const overflow = await platform.detectOverflow(state, detectOverflowOptions);
const side = getSide(placement);
const alignment = getAlignment(placement);
const isYAxis = getSideAxis(placement) === 'y';
const {
width,
height
} = rects.floating;
let heightSide;
let widthSide;
if (side === 'top' || side === 'bottom') {
heightSide = side;
widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';
} else {
widthSide = side;
heightSide = alignment === 'end' ? 'top' : 'bottom';
}
const maximumClippingHeight = height - overflow.top - overflow.bottom;
const maximumClippingWidth = width - overflow.left - overflow.right;
const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);
const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);
const noShift = !state.middlewareData.shift;
let availableHeight = overflowAvailableHeight;
let availableWidth = overflowAvailableWidth;
if ((_state$middlewareData = state.middlewareData.shift) != null && _state$middlewareData.enabled.x) {
availableWidth = maximumClippingWidth;
}
if ((_state$middlewareData2 = state.middlewareData.shift) != null && _state$middlewareData2.enabled.y) {
availableHeight = maximumClippingHeight;
}
if (noShift && !alignment) {
const xMin = max(overflow.left, 0);
const xMax = max(overflow.right, 0);
const yMin = max(overflow.top, 0);
const yMax = max(overflow.bottom, 0);
if (isYAxis) {
availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right));
} else {
availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom));
}
}
await apply({
...state,
availableWidth,
availableHeight
});
const nextDimensions = await platform.getDimensions(elements.floating);
if (width !== nextDimensions.width || height !== nextDimensions.height) {
return {
reset: {
rects: true
}
};
}
return {};
}
};
};
function hasWindow() {
return typeof window !== 'undefined';
}
function getNodeName(node) {
if (isNode$1(node)) {
return (node.nodeName || '').toLowerCase();
}
// Mocked nodes in testing environments may not be instances of Node. By
// returning `#document` an infinite loop won't occur.
// https://github.com/floating-ui/floating-ui/issues/2317
return '#document';
}
function getWindow$1(node) {
var _node$ownerDocument;
return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
}
function getDocumentElement(node) {
var _ref;
return (_ref = (isNode$1(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
}
function isNode$1(value) {
if (!hasWindow()) {
return false;
}
return value instanceof Node || value instanceof getWindow$1(value).Node;
}
function isElement$1(value) {
if (!hasWindow()) {
return false;
}
return value instanceof Element || value instanceof getWindow$1(value).Element;
}
function isHTMLElement$2(value) {
if (!hasWindow()) {
return false;
}
return value instanceof HTMLElement || value instanceof getWindow$1(value).HTMLElement;
}
function isShadowRoot$1(value) {
if (!hasWindow() || typeof ShadowRoot === 'undefined') {
return false;
}
return value instanceof ShadowRoot || value instanceof getWindow$1(value).ShadowRoot;
}
const invalidOverflowDisplayValues = /*#__PURE__*/new Set(['inline', 'contents']);
function isOverflowElement(element) {
const {
overflow,
overflowX,
overflowY,
display
} = getComputedStyle$1(element);
return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !invalidOverflowDisplayValues.has(display);
}
const tableElements = /*#__PURE__*/new Set(['table', 'td', 'th']);
function isTableElement(element) {
return tableElements.has(getNodeName(element));
}
const topLayerSelectors = [':popover-open', ':modal'];
function isTopLayer(element) {
return topLayerSelectors.some(selector => {
try {
return element.matches(selector);
} catch (_e) {
return false;
}
});
}
const transformProperties = ['transform', 'translate', 'scale', 'rotate', 'perspective'];
const willChangeValues = ['transform', 'translate', 'scale', 'rotate', 'perspective', 'filter'];
const containValues = ['paint', 'layout', 'strict', 'content'];
function isContainingBlock(elementOrCss) {
const webkit = isWebKit();
const css = isElement$1(elementOrCss) ? getComputedStyle$1(elementOrCss) : elementOrCss;
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
return transformProperties.some(value => css[value] ? css[value] !== 'none' : false) || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || willChangeValues.some(value => (css.willChange || '').includes(value)) || containValues.some(value => (css.contain || '').includes(value));
}
function getContainingBlock(element) {
let currentNode = getParentNode(element);
while (isHTMLElement$2(currentNode) && !isLastTraversableNode(currentNode)) {
if (isContainingBlock(currentNode)) {
return currentNode;
} else if (isTopLayer(currentNode)) {
return null;
}
currentNode = getParentNode(currentNode);
}
return null;
}
function isWebKit() {
if (typeof CSS === 'undefined' || !CSS.supports) return false;
return CSS.supports('-webkit-backdrop-filter', 'none');
}
const lastTraversableNodeNames = /*#__PURE__*/new Set(['html', 'body', '#document']);
function isLastTraversableNode(node) {
return lastTraversableNodeNames.has(getNodeName(node));
}
function getComputedStyle$1(element) {
return getWindow$1(element).getComputedStyle(element);
}
function getNodeScroll(element) {
if (isElement$1(element)) {
return {
scrollLeft: element.scrollLeft,
scrollTop: element.scrollTop
};
}
return {
scrollLeft: element.scrollX,
scrollTop: element.scrollY
};
}
function getParentNode(node) {
if (getNodeName(node) === 'html') {
return node;
}
const result =
// Step into the shadow DOM of the parent of a slotted node.
node.assignedSlot ||
// DOM Element detected.
node.parentNode ||
// ShadowRoot detected.
isShadowRoot$1(node) && node.host ||
// Fallback.
getDocumentElement(node);
return isShadowRoot$1(result) ? result.host : result;
}
function getNearestOverflowAncestor(node) {
const parentNode = getParentNode(node);
if (isLastTraversableNode(parentNode)) {
return node.ownerDocument ? node.ownerDocument.body : node.body;
}
if (isHTMLElement$2(parentNode) && isOverflowElement(parentNode)) {
return parentNode;
}
return getNearestOverflowAncestor(parentNode);
}
function getOverflowAncestors(node, list, traverseIframes) {
var _node$ownerDocument2;
if (list === void 0) {
list = [];
}
const scrollableAncestor = getNearestOverflowAncestor(node);
const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
const win = getWindow$1(scrollableAncestor);
if (isBody) {
getFrameElement(win);
return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], []);
}
return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, []));
}
function getFrameElement(win) {
return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
}
function getCssDimensions(element) {
const css = getComputedStyle$1(element);
// In testing environments, the `width` and `height` properties are empty
// strings for SVG elements, returning NaN. Fallback to `0` in this case.
let width = parseFloat(css.width) || 0;
let height = parseFloat(css.height) || 0;
const hasOffset = isHTMLElement$2(element);
const offsetWidth = hasOffset ? element.offsetWidth : width;
const offsetHeight = hasOffset ? element.offsetHeight : height;
const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;
if (shouldFallback) {
width = offsetWidth;
height = offsetHeight;
}
return {
width,
height,
$: shouldFallback
};
}
function unwrapElement(element) {
return !isElement$1(element) ? element.contextElement : element;
}
function getScale(element) {
const domElement = unwrapElement(element);
if (!isHTMLElement$2(domElement)) {
return createCoords(1);
}
const rect = domElement.getBoundingClientRect();
const {
width,
height,
$
} = getCssDimensions(domElement);
let x = ($ ? round(rect.width) : rect.width) / width;
let y = ($ ? round(rect.height) : rect.height) / height;
// 0, NaN, or Infinity should always fallback to 1.
if (!x || !Number.isFinite(x)) {
x = 1;
}
if (!y || !Number.isFinite(y)) {
y = 1;
}
return {
x,
y
};
}
const noOffsets = /*#__PURE__*/createCoords(0);
function getVisualOffsets(element) {
const win = getWindow$1(element);
if (!isWebKit() || !win.visualViewport) {
return noOffsets;
}
return {
x: win.visualViewport.offsetLeft,
y: win.visualViewport.offsetTop
};
}
function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {
if (isFixed === void 0) {
isFixed = false;
}
if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow$1(element)) {
return false;
}
return isFixed;
}
function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {
if (includeScale === void 0) {
includeScale = false;
}
if (isFixedStrategy === void 0) {
isFixedStrategy = false;
}
const clientRect = element.getBoundingClientRect();
const domElement = unwrapElement(element);
let scale = createCoords(1);
if (includeScale) {
if (offsetParent) {
if (isElement$1(offsetParent)) {
scale = getScale(offsetParent);
}
} else {
scale = getScale(element);
}
}
const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);
let x = (clientRect.left + visualOffsets.x) / scale.x;
let y = (clientRect.top + visualOffsets.y) / scale.y;
let width = clientRect.width / scale.x;
let height = clientRect.height / scale.y;
if (domElement) {
const win = getWindow$1(domElement);
const offsetWin = offsetParent && isElement$1(offsetParent) ? getWindow$1(offsetParent) : offsetParent;
let currentWin = win;
let currentIFrame = getFrameElement(currentWin);
while (currentIFrame && offsetParent && offsetWin !== currentWin) {
const iframeScale = getScale(currentIFrame);
const iframeRect = currentIFrame.getBoundingClientRect();
const css = getComputedStyle$1(currentIFrame);
const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
x *= iframeScale.x;
y *= iframeScale.y;
width *= iframeScale.x;
height *= iframeScale.y;
x += left;
y += top;
currentWin = getWindow$1(currentIFrame);
currentIFrame = getFrameElement(currentWin);
}
}
return rectToClientRect({
width,
height,
x,
y
});
}
// If <html> has a CSS width greater than the viewport, then this will be
// incorrect for RTL.
function getWindowScrollBarX(element, rect) {
const leftScroll = getNodeScroll(element).scrollLeft;
if (!rect) {
return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;
}
return rect.left + leftScroll;
}
function getHTMLOffset(documentElement, scroll) {
const htmlRect = documentElement.getBoundingClientRect();
const x = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect);
const y = htmlRect.top + scroll.scrollTop;
return {
x,
y
};
}
function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
let {
elements,
rect,
offsetParent,
strategy
} = _ref;
const isFixed = strategy === 'fixed';
const documentElement = getDocumentElement(offsetParent);
const topLayer = elements ? isTopLayer(elements.floating) : false;
if (offsetParent === documentElement || topLayer && isFixed) {
return rect;
}
let scroll = {
scrollLeft: 0,
scrollTop: 0
};
let scale = createCoords(1);
const offsets = createCoords(0);
const isOffsetParentAnElement = isHTMLElement$2(offsetParent);
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isHTMLElement$2(offsetParent)) {
const offsetRect = getBoundingClientRect(offsetParent);
scale = getScale(offsetParent);
offsets.x = offsetRect.x + offsetParent.clientLeft;
offsets.y = offsetRect.y + offsetParent.clientTop;
}
}
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
return {
width: rect.width * scale.x,
height: rect.height * scale.y,
x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,
y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y
};
}
function getClientRects(element) {
return Array.from(element.getClientRects());
}
// Gets the entire size of the scrollable document area, even extending outside
// of the `<html>` and `<body>` rect bounds if horizontally scrollable.
function getDocumentRect(element) {
const html = getDocumentElement(element);
const scroll = getNodeScroll(element);
const body = element.ownerDocument.body;
const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);
const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
let x = -scroll.scrollLeft + getWindowScrollBarX(element);
const y = -scroll.scrollTop;
if (getComputedStyle$1(body).direction === 'rtl') {
x += max(html.clientWidth, body.clientWidth) - width;
}
return {
width,
height,
x,
y
};
}
// Safety check: ensure the scrollbar space is reasonable in case this
// calculation is affected by unusual styles.
// Most scrollbars leave 15-18px of space.
const SCROLLBAR_MAX = 25;
function getViewportRect(element, strategy) {
const win = getWindow$1(element);
const html = getDocumentElement(element);
const visualViewport = win.visualViewport;
let width = html.clientWidth;
let height = html.clientHeight;
let x = 0;
let y = 0;
if (visualViewport) {
width = visualViewport.width;
height = visualViewport.height;
const visualViewportBased = isWebKit();
if (!visualViewportBased || visualViewportBased && strategy === 'fixed') {
x = visualViewport.offsetLeft;
y = visualViewport.offsetTop;
}
}
const windowScrollbarX = getWindowScrollBarX(html);
// <html> `overflow: hidden` + `scrollbar-gutter: stable` reduces the
// visual width of the <html> but this is not considered in the size
// of `html.clientWidth`.
if (windowScrollbarX <= 0) {
const doc = html.ownerDocument;
const body = doc.body;
const bodyStyles = getComputedStyle(body);
const bodyMarginInline = doc.compatMode === 'CSS1Compat' ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;
const clippingStableScrollbarWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);
if (clippingStableScrollbarWidth <= SCROLLBAR_MAX) {
width -= clippingStableScrollbarWidth;
}
} else if (windowScrollbarX <= SCROLLBAR_MAX) {
// If the <body> scrollbar is on the left, the width needs to be extended
// by the scrollbar amount so there isn't extra space on the right.
width += windowScrollbarX;
}
return {
width,
height,
x,
y
};
}
const absoluteOrFixed = /*#__PURE__*/new Set(['absolute', 'fixed']);
// Returns the inner client rect, subtracting scrollbars if present.
function getInnerBoundingClientRect(element, strategy) {
const clientRect = getBoundingClientRect(element, true, strategy === 'fixed');
const top = clientRect.top + element.clientTop;
const left = clientRect.left + element.clientLeft;
const scale = isHTMLElement$2(element) ? getScale(element) : createCoords(1);
const width = element.clientWidth * scale.x;
const height = element.clientHeight * scale.y;
const x = left * scale.x;
const y = top * scale.y;
return {
width,
height,
x,
y
};
}
function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {
let rect;
if (clippingAncestor === 'viewport') {
rect = getViewportRect(element, strategy);
} else if (clippingAncestor === 'document') {
rect = getDocumentRect(getDocumentElement(element));
} else if (isElement$1(clippingAncestor)) {
rect = getInnerBoundingClientRect(clippingAncestor, strategy);
} else {
const visualOffsets = getVisualOffsets(element);
rect = {
x: clippingAncestor.x - visualOffsets.x,
y: clippingAncestor.y - visualOffsets.y,
width: clippingAncestor.width,
height: clippingAncestor.height
};
}
return rectToClientRect(rect);
}
function hasFixedPositionAncestor(element, stopNode) {
const parentNode = getParentNode(element);
if (parentNode === stopNode || !isElement$1(parentNode) || isLastTraversableNode(parentNode)) {
return false;
}
return getComputedStyle$1(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);
}
// A "clipping ancestor" is an `overflow` element with the characteristic of
// clipping (or hiding) child elements. This returns all clipping ancestors
// of the given element up the tree.
function getClippingElementAncestors(element, cache) {
const cachedResult = cache.get(element);
if (cachedResult) {
return cachedResult;
}
let result = getOverflowAncestors(element, []).filter(el => isElement$1(el) && getNodeName(el) !== 'body');
let currentContainingBlockComputedStyle = null;
const elementIsFixed = getComputedStyle$1(element).position === 'fixed';
let currentNode = elementIsFixed ? getParentNode(element) : element;
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
while (isElement$1(currentNode) && !isLastTraversableNode(currentNode)) {
const computedStyle = getComputedStyle$1(currentNode);
const currentNodeIsContaining = isContainingBlock(currentNode);
if (!currentNodeIsContaining && computedStyle.position === 'fixed') {
currentContainingBlockComputedStyle = null;
}
const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && absoluteOrFixed.has(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);
if (shouldDropCurrentNode) {
// Drop non-containing blocks.
result = result.filter(ancestor => ancestor !== currentNode);
} else {
// Record last containing block for next iteration.
currentContainingBlockComputedStyle = computedStyle;
}
currentNode = getParentNode(currentNode);
}
cache.set(element, result);
return result;
}
// Gets the maximum area that the element is visible in due to any number of
// clipping ancestors.
function getClippingRect(_ref) {
let {
element,
boundary,
rootBoundary,
strategy
} = _ref;
const elementClippingAncestors = boundary === 'clippingAncestors' ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary);
const clippingAncestors = [...elementClippingAncestors, rootBoundary];
const firstClippingAncestor = clippingAncestors[0];
const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {
const rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy);
accRect.top = max(rect.top, accRect.top);
accRect.right = min(rect.right, accRect.right);
accRect.bottom = min(rect.bottom, accRect.bottom);
accRect.left = max(rect.left, accRect.left);
return accRect;
}, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy));
return {
width: clippingRect.right - clippingRect.left,
height: clippingRect.bottom - clippingRect.top,
x: clippingRect.left,
y: clippingRect.top
};
}
function getDimensions(element) {
const {
width,
height
} = getCssDimensions(element);
return {
width,
height
};
}
function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
const isOffsetParentAnElement = isHTMLElement$2(offsetParent);
const documentElement = getDocumentElement(offsetParent);
const isFixed = strategy === 'fixed';
const rect = getBoundingClientRect(element, true, isFixed, offsetParent);
let scroll = {
scrollLeft: 0,
scrollTop: 0
};
const offsets = createCoords(0);
// If the <body> scrollbar appears on the left (e.g. RTL systems). Use
// Firefox with layout.scrollbar.side = 3 in about:config to test this.
function setLeftRTLScrollbarOffset() {
offsets.x = getWindowScrollBarX(documentElement);
}
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isOffsetParentAnElement) {
const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);
offsets.x = offsetRect.x + offsetParent.clientLeft;
offsets.y = offsetRect.y + offsetParent.clientTop;
} else if (documentElement) {
setLeftRTLScrollbarOffset();
}
}
if (isFixed && !isOffsetParentAnElement && documentElement) {
setLeftRTLScrollbarOffset();
}
const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;
const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;
return {
x,
y,
width: rect.width,
height: rect.height
};
}
function isStaticPositioned(element) {
return getComputedStyle$1(element).position === 'static';
}
function getTrueOffsetParent(element, polyfill) {
if (!isHTMLElement$2(element) || getComputedStyle$1(element).position === 'fixed') {
return null;
}
if (polyfill) {
return polyfill(element);
}
let rawOffsetParent = element.offsetParent;
// Firefox returns the <html> element as the offsetParent if it's non-static,
// while Chrome and Safari return the <body> element. The <body> element must
// be used to perform the correct calculations even if the <html> element is
// non-static.
if (getDocumentElement(element) === rawOffsetParent) {
rawOffsetParent = rawOffsetParent.ownerDocument.body;
}
return rawOffsetParent;
}
// Gets the closest ancestor positioned element. Handles some edge cases,
// such as table ancestors and cross browser bugs.
function getOffsetParent(element, polyfill) {
const win = getWindow$1(element);
if (isTopLayer(element)) {
return win;
}
if (!isHTMLElement$2(element)) {
let svgOffsetParent = getParentNode(element);
while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) {
if (isElement$1(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) {
return svgOffsetParent;
}
svgOffsetParent = getParentNode(svgOffsetParent);
}
return win;
}
let offsetParent = getTrueOffsetParent(element, polyfill);
while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) {
offsetParent = getTrueOffsetParent(offsetParent, polyfill);
}
if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) {
return win;
}
return offsetParent || getContainingBlock(element) || win;
}
const getElementRects = async function (data) {
const getOffsetParentFn = this.getOffsetParent || getOffsetParent;
const getDimensionsFn = this.getDimensions;
const floatingDimensions = await getDimensionsFn(data.floating);
return {
reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy),
floating: {
x: 0,
y: 0,
width: floatingDimensions.width,
height: floatingDimensions.height
}
};
};
function isRTL(element) {
return getComputedStyle$1(element).direction === 'rtl';
}
const platform = {
convertOffsetParentRelativeRectToViewportRelativeRect,
getDocumentElement,
getClippingRect,
getOffsetParent,
getElementRects,
getClientRects,
getDimensions,
getScale,
isElement: isElement$1,
isRTL
};
/**
* Modifies the placement by translating the floating element along the
* specified axes.
* A number (shorthand for `mainAxis` or distance), or an axes configuration
* object may be passed.
* @see https://floating-ui.com/docs/offset
*/
const offset = offset$1;
/**
* Optimizes the visibility of the floating element by shifting it in order to
* keep it in view when it will overflow the clipping boundary.
* @see https://floating-ui.com/docs/shift
*/
const shift = shift$1;
/**
* Optimizes the visibility of the floating element by flipping the `placement`
* in order to keep it in view when the preferred placement(s) will overflow the
* clipping boundary. Alternative to `autoPlacement`.
* @see https://floating-ui.com/docs/flip
*/
const flip = flip$1;
/**
* Provides data that allows you to change the size of the floating element —
* for instance, prevent it from overflowing the clipping boundary or match the
* width of the reference element.
* @see https://floating-ui.com/docs/size
*/
const size = size$1;
/**
* Provides data to hide the floating element in applicable situations, such as
* when it is not in the same clipping context as the reference element.
* @see https://floating-ui.com/docs/hide
*/
const hide = hide$1;
/**
* Provides data to position an inner element of the floating element so that it
* appears centered to the reference element.
* @see https://floating-ui.com/docs/arrow
*/
const arrow = arrow$1;
/**
* Built-in `limiter` that will stop `shift()` at a certain point.
*/
const limitShift = limitShift$1;
/**
* Computes the `x` and `y` coordinates that will place the floating element
* next to a given reference element.
*/
const computePosition = (reference, floating, options) => {
// This caches the expensive `getClippingElementAncestors` function so that
// multiple lifecycle resets re-use the same result. It only lives for a
// single call. If other functions become expensive, we can add them as well.
const cache = new Map();
const mergedOptions = {
platform,
...options
};
const platformWithCache = {
...mergedOptions.platform,
_c: cache
};
return computePosition$1(reference, floating, {
...mergedOptions,
platform: platformWithCache
});
};
function mount() {
lifecycle_function_unavailable("mount");
}
function unmount() {
lifecycle_function_unavailable("unmount");
}
async function tick() {
}
function box(initialValue) {
let current = initialValue;
return {
[BoxSymbol]: true,
[isWritableSymbol]: true,
get current() {
return current;
},
set current(v) {
current = v;
}
};
}
box.from = boxFrom;
box.with = boxWith;
box.flatten = boxFlatten;
box.readonly = toReadonlyBox;
box.isBox = isBox;
box.isWritableBox = isWritableBox;
const srOnlyStyles = {
position: "absolute",
width: "1px",
height: "1px",
padding: "0",
margin: "-1px",
overflow: "hidden",
clip: "rect(0, 0, 0, 0)",
whiteSpace: "nowrap",
borderWidth: "0",
transform: "translateX(-100%)"
};
const srOnlyStylesString = styleToString(srOnlyStyles);
const defaultWindow = void 0;
function getActiveElement$1(document2) {
let activeElement = document2.activeElement;
while (activeElement?.shadowRoot) {
const node = activeElement.shadowRoot.activeElement;
if (node === activeElement)
break;
else
activeElement = node;
}
return activeElement;
}
const SvelteMap = globalThis.Map;
function createSubscriber(_) {
return () => {
};
}
class ActiveElement {
#document;
#subscribe;
constructor(options = {}) {
const { window: window2 = defaultWindow, document: document2 = window2?.document } = options;
if (window2 === void 0) return;
this.#document = document2;
this.#subscribe = createSubscriber();
}
get current() {
this.#subscribe?.();
if (!this.#document) return null;
return getActiveElement$1(this.#document);
}
}
new ActiveElement();
function isFunction(value) {
return typeof value === "function";
}
class Context {
#name;
#key;
/**
* @param name The name of the context.
* This is used for generating the context key and error messages.
*/
constructor(name) {
this.#name = name;
this.#key = Symbol(name);
}
/**
* The key used to get and set the context.
*
* It is not recommended to use this value directly.
* Instead, use the methods provided by this class.
*/
get key() {
return this.#key;
}
/**
* Checks whether this has been set in the context of a parent component.
*
* Must be called during component initialisation.
*/
exists() {
return hasContext(this.#key);
}
/**
* Retrieves the context that belongs to the closest parent component.
*
* Must be called during component initialisation.
*
* @throws An error if the context does not exist.
*/
get() {
const context = getContext(this.#key);
if (context === void 0) {
throw new Error(`Context "${this.#name}" not found`);
}
return context;
}
/**
* Retrieves the context that belongs to the closest parent component,
* or the given fallback value if the context does not exist.
*
* Must be called during component initialisation.
*/
getOr(fallback) {
const context = getContext(this.#key);
if (context === void 0) {
return fallback;
}
return context;
}
/**
* Associates the given value with the current component and returns it.
*
* Must be called during component initialisation.
*/
set(context) {
return setContext(this.#key, context);
}
}
function runWatcher(sources, flush, effect, options = {}) {
const { lazy = false } = options;
}
function watch(sources, effect, options) {
runWatcher(sources, "post", effect, options);
}
function watchPre(sources, effect, options) {
runWatcher(sources, "pre", effect, options);
}
watch.pre = watchPre;
function get$1(value) {
if (isFunction(value)) {
return value();
}
return value;
}
class ElementSize {
// no need to use `$state` here since we are using createSubscriber
#size = { width: 0, height: 0 };
#observed = false;
#options;
#node;
#window;
// we use a derived here to extract the width so that if the width doesn't change we don't get a state update
// which we would get if we would just use a getter since the version of the subscriber will be changing
#width = derived(() => {
this.#subscribe()?.();
return this.getSize().width;
});
// we use a derived here to extract the height so that if the height doesn't change we don't get a state update
// which we would get if we would just use a getter since the version of the subscriber will be changing
#height = derived(() => {
this.#subscribe()?.();
return this.getSize().height;
});
// we need to use a derived here because the class will be created before the node is bound to the ref
#subscribe = derived(() => {
const node$ = get$1(this.#node);
if (!node$) return;
return createSubscriber();
});
constructor(node, options = { box: "border-box" }) {
this.#window = options.window ?? defaultWindow;
this.#options = options;
this.#node = node;
this.#size = { width: 0, height: 0 };
}
calculateSize() {
const element = get$1(this.#node);
if (!element || !this.#window) {
return;
}
const offsetWidth = element.offsetWidth;
const offsetHeight = element.offsetHeight;
if (this.#options.box === "border-box") {
return { width: offsetWidth, height: offsetHeight };
}
const style = this.#window.getComputedStyle(element);
const paddingWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
const paddingHeight = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
const borderWidth = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);
const borderHeight = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
const contentWidth = offsetWidth - paddingWidth - borderWidth;
const contentHeight = offsetHeight - paddingHeight - borderHeight;
return { width: contentWidth, height: contentHeight };
}
getSize() {
return this.#observed ? this.#size : this.calculateSize() ?? this.#size;
}
get current() {
this.#subscribe()?.();
return this.getSize();
}
get width() {
return this.#width();
}
get height() {
return this.#height();
}
}
function afterSleep(ms, cb) {
return setTimeout(cb, ms);
}
function afterTick(fn) {
tick().then(fn);
}
const ELEMENT_NODE = 1;
const DOCUMENT_NODE = 9;
const DOCUMENT_FRAGMENT_NODE = 11;
function isHTMLElement$1(node) {
return isObject(node) && node.nodeType === ELEMENT_NODE && typeof node.nodeName === "string";
}
function isDocument(node) {
return isObject(node) && node.nodeType === DOCUMENT_NODE;
}
function isWindow(node) {
return isObject(node) && node.constructor?.name === "VisualViewport";
}
function isNode(node) {
return isObject(node) && node.nodeType !== void 0;
}
function isShadowRoot(node) {
return isNode(node) && node.nodeType === DOCUMENT_FRAGMENT_NODE && "host" in node;
}
function contains(parent, child) {
if (!parent || !child)
return false;
if (!isHTMLElement$1(parent) || !isHTMLElement$1(child))
return false;
const rootNode = child.getRootNode?.();
if (parent === child)
return true;
if (parent.contains(child))
return true;
if (rootNode && isShadowRoot(rootNode)) {
let next = child;
while (next) {
if (parent === next)
return true;
next = next.parentNode || next.host;
}
}
return false;
}
function getDocument(node) {
if (isDocument(node))
return node;
if (isWindow(node))
return node.document;
return node?.ownerDocument ?? document;
}
function getWindow(node) {
if (isShadowRoot(node))
return getWindow(node.host);
if (isDocument(node))
return node.defaultView ?? window;
if (isHTMLElement$1(node))
return node.ownerDocument?.defaultView ?? window;
return window;
}
function getActiveElement(rootNode) {
let activeElement = rootNode.activeElement;
while (activeElement?.shadowRoot) {
const el = activeElement.shadowRoot.activeElement;
if (el === activeElement)
break;
else
activeElement = el;
}
return activeElement;
}
class DOMContext {
element;
#root = derived(() => {
if (!this.element.current) return document;
const rootNode = this.element.current.getRootNode() ?? document;
return rootNode;
});
get root() {
return this.#root();
}
set root($$value) {
return this.#root($$value);
}
constructor(element) {
if (typeof element === "function") {
this.element = boxWith(element);
} else {
this.element = element;
}
}
getDocument = () => {
return getDocument(this.root);
};
getWindow = () => {
return this.getDocument().defaultView ?? window;
};
getActiveElement = () => {
return getActiveElement(this.root);
};
isActiveElement = (node) => {
return node === this.getActiveElement();
};
getElementById(id) {
return this.root.getElementById(id);
}
querySelector = (selector) => {
if (!this.root) return null;
return this.root.querySelector(selector);
};
querySelectorAll = (selector) => {
if (!this.root) return [];
return this.root.querySelectorAll(selector);
};
setTimeout = (callback, delay) => {
return this.getWindow().setTimeout(callback, delay);
};
clearTimeout = (timeoutId) => {
return this.getWindow().clearTimeout(timeoutId);
};
}
const ARROW_DOWN = "ArrowDown";
const ARROW_LEFT = "ArrowLeft";
const ARROW_RIGHT = "ArrowRight";
const ARROW_UP = "ArrowUp";
const END = "End";
const ENTER = "Enter";
const ESCAPE = "Escape";
const HOME = "Home";
const PAGE_DOWN = "PageDown";
const PAGE_UP = "PageUp";
const SPACE = " ";
const TAB = "Tab";
function getElemDirection(elem) {
const style = window.getComputedStyle(elem);
const direction = style.getPropertyValue("direction");
return direction;
}
function getNextKey(dir = "ltr", orientation = "horizontal") {
return {
horizontal: dir === "rtl" ? ARROW_LEFT : ARROW_RIGHT,
vertical: ARROW_DOWN
}[orientation];
}
function getPrevKey(dir = "ltr", orientation = "horizontal") {
return {
horizontal: dir === "rtl" ? ARROW_RIGHT : ARROW_LEFT,
vertical: ARROW_UP
}[orientation];
}
function getDirectionalKeys(dir = "ltr", orientation = "horizontal") {
if (!["ltr", "rtl"].includes(dir))
dir = "ltr";
if (!["horizontal", "vertical"].includes(orientation))
orientation = "horizontal";
return {
nextKey: getNextKey(dir, orientation),
prevKey: getPrevKey(dir, orientation)
};
}
const isBrowser = typeof document !== "undefined";
const isIOS = getIsIOS();
function getIsIOS() {
return isBrowser && window?.navigator?.userAgent && (/iP(ad|hone|od)/.test(window.navigator.userAgent) || // The new iPad Pro Gen3 does not identify itself as iPad, but as Macintosh.
window?.navigator?.maxTouchPoints > 2 && /iPad|Macintosh/.test(window?.navigator.userAgent));
}
function isHTMLElement(element) {
return element instanceof HTMLElement;
}
function isElement(element) {
return element instanceof Element;
}
function isElementOrSVGElement(element) {
return element instanceof Element || element instanceof SVGElement;
}
function isNotNull(value) {
return value !== null;
}
function isSelectableInput(element) {
return element instanceof HTMLInputElement && "select" in element;
}
class RovingFocusGroup {
#opts;
#currentTabStopId = box(null);
constructor(opts) {
this.#opts = opts;
}
getCandidateNodes() {
return [];
}
focusFirstCandidate() {
const items = this.getCandidateNodes();
if (!items.length)
return;
items[0]?.focus();
}
handleKeydown(node, e, both = false) {
const rootNode = this.#opts.rootNode.current;
if (!rootNode || !node)
return;
const items = this.getCandidateNodes();
if (!items.length)
return;
const currentIndex = items.indexOf(node);
const dir = getElemDirection(rootNode);
const { nextKey, prevKey } = getDirectionalKeys(dir, this.#opts.orientation.current);
const loop = this.#opts.loop.current;
const keyToIndex = {
[nextKey]: currentIndex + 1,
[prevKey]: currentIndex - 1,
[HOME]: 0,
[END]: items.length - 1
};
if (both) {
const altNextKey = nextKey === ARROW_DOWN ? ARROW_RIGHT : ARROW_DOWN;
const altPrevKey = prevKey === ARROW_UP ? ARROW_LEFT : ARROW_UP;
keyToIndex[altNextKey] = currentIndex + 1;
keyToIndex[altPrevKey] = currentIndex - 1;
}
let itemIndex = keyToIndex[e.key];
if (itemIndex === void 0)
return;
e.preventDefault();
if (itemIndex < 0 && loop) {
itemIndex = items.length - 1;
} else if (itemIndex === items.length && loop) {
itemIndex = 0;
}
const itemToFocus = items[itemIndex];
if (!itemToFocus)
return;
itemToFocus.focus();
this.#currentTabStopId.current = itemToFocus.id;
this.#opts.onCandidateFocus?.(itemToFocus);
return itemToFocus;
}
getTabIndex(node) {
const items = this.getCandidateNodes();
const anyActive = this.#currentTabStopId.current !== null;
if (node && !anyActive && items[0] === node) {
this.#currentTabStopId.current = node.id;
return 0;
} else if (node?.id === this.#currentTabStopId.current) {
return 0;
}
return -1;
}
setCurrentTabStopId(id) {
this.#currentTabStopId.current = id;
}
focusCurrentTabStop() {
const currentTabStopId = this.#currentTabStopId.current;
if (!currentTabStopId)
return;
const currentTabStop = this.#opts.rootNode.current?.querySelector(`#${currentTabStopId}`);
if (!currentTabStop || !isHTMLElement(currentTabStop))
return;
currentTabStop.focus();
}
}
class AnimationsComplete {
#opts;
#currentFrame = null;
constructor(opts) {
this.#opts = opts;
}
#cleanup() {
if (!this.#currentFrame)
return;
window.cancelAnimationFrame(this.#currentFrame);
this.#currentFrame = null;
}
run(fn) {
this.#cleanup();
const node = this.#opts.ref.current;
if (!node)
return;
if (typeof node.getAnimations !== "function") {
this.#executeCallback(fn);
return;
}
this.#currentFrame = window.requestAnimationFrame(() => {
const animations = node.getAnimations();
if (animations.length === 0) {
this.#executeCallback(fn);
return;
}
Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
this.#executeCallback(fn);
});
});
}
#executeCallback(fn) {
const execute = () => {
fn();
};
if (this.#opts.afterTick) {
afterTick(execute);
} else {
execute();
}
}
}
class PresenceManager {
#opts;
#enabled;
#afterAnimations;
#shouldRender = false;
constructor(opts) {
this.#opts = opts;
this.#shouldRender = opts.open.current;
this.#enabled = opts.enabled ?? true;
this.#afterAnimations = new AnimationsComplete({ ref: this.#opts.ref, afterTick: this.#opts.open });
watch(() => this.#opts.open.current, (isOpen) => {
if (isOpen) this.#shouldRender = true;
if (!this.#enabled) return;
this.#afterAnimations.run(() => {
if (isOpen === this.#opts.open.current) {
if (!this.#opts.open.current) {
this.#shouldRender = false;
}
this.#opts.onComplete?.();
}
});
});
}
get shouldRender() {
return this.#shouldRender;
}
}
function noop() {
}
const BitsConfigContext = new Context("BitsConfig");
function getBitsConfig() {
const fallback = new BitsConfigState(null, {});
return BitsConfigContext.getOr(fallback).opts;
}
class BitsConfigState {
opts;
constructor(parent, opts) {
const resolveConfigOption = createConfigResolver(parent, opts);
this.opts = {
defaultPortalTo: resolveConfigOption((config) => config.defaultPortalTo),
defaultLocale: resolveConfigOption((config) => config.defaultLocale)
};
}
}
function createConfigResolver(parent, currentOpts) {
return (getter) => {
const configOption = boxWith(() => {
const value = getter(currentOpts)?.current;
if (value !== void 0)
return value;
if (parent === null)
return void 0;
return getter(parent.opts)?.current;
});
return configOption;
};
}
function createPropResolver(configOption, fallback) {
return (getProp) => {
const config = getBitsConfig();
return boxWith(() => {
const propValue = getProp();
if (propValue !== void 0)
return propValue;
const option = configOption(config).current;
if (option !== void 0)
return option;
return fallback;
});
};
}
const resolvePortalToProp = createPropResolver((config) => config.defaultPortalTo, "body");
function Portal($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { to: toProp, children, disabled } = $$props;
const to = resolvePortalToProp(() => toProp);
getAllContexts();
let target = getTarget();
function getTarget() {
if (!isBrowser || disabled) return null;
let localTarget = null;
if (typeof to.current === "string") {
const target2 = document.querySelector(to.current);
localTarget = target2;
} else {
localTarget = to.current;
}
return localTarget;
}
let instance;
function unmountInstance() {
if (instance) {
unmount();
instance = null;
}
}
watch([() => target, () => disabled], ([target2, disabled2]) => {
if (!target2 || disabled2) {
unmountInstance();
return;
}
instance = mount();
return () => {
unmountInstance();
};
});
if (disabled) {
$$renderer2.push("<!--[-->");
children?.($$renderer2);
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
}
$$renderer2.push(`<!--]-->`);
});
}
class CustomEventDispatcher {
eventName;
options;
constructor(eventName, options = { bubbles: true, cancelable: true }) {
this.eventName = eventName;
this.options = options;
}
createEvent(detail) {
return new CustomEvent(this.eventName, {
...this.options,
detail
});
}
dispatch(element, detail) {
const event = this.createEvent(detail);
element.dispatchEvent(event);
return event;
}
listen(element, callback, options) {
const handler = (event) => {
callback(event);
};
return on(element, this.eventName, handler, options);
}
}
function debounce(fn, wait = 500) {
let timeout = null;
const debounced = (...args) => {
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
fn(...args);
}, wait);
};
debounced.destroy = () => {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
}
};
return debounced;
}
function isOrContainsTarget(node, target) {
return node === target || node.contains(target);
}
function getOwnerDocument(el) {
return el?.ownerDocument ?? document;
}
function isClickTrulyOutside(event, contentNode) {
const { clientX, clientY } = event;
const rect = contentNode.getBoundingClientRect();
return clientX < rect.left || clientX > rect.right || clientY < rect.top || clientY > rect.bottom;
}
const FIRST_KEYS = [ARROW_DOWN, PAGE_UP, HOME];
const LAST_KEYS = [ARROW_UP, PAGE_DOWN, END];
const FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
function focus(element, { select = false } = {}) {
if (!element || !element.focus)
return;
const doc = getDocument(element);
if (doc.activeElement === element)
return;
const previouslyFocusedElement = doc.activeElement;
element.focus({ preventScroll: true });
if (element !== previouslyFocusedElement && isSelectableInput(element) && select) {
element.select();
}
}
function focusFirst(candidates, { select = false } = {}, getActiveElement2) {
const previouslyFocusedElement = getActiveElement2();
for (const candidate of candidates) {
focus(candidate, { select });
if (getActiveElement2() !== previouslyFocusedElement)
return true;
}
}
let isUsingKeyboard = false;
class IsUsingKeyboard {
static _refs = 0;
// Reference counting to avoid multiple listeners.
static _cleanup;
constructor() {
}
get current() {
return isUsingKeyboard;
}
set current(value) {
isUsingKeyboard = value;
}
}
function getTabbableOptions() {
return {
getShadowRoot: true,
displayCheck: (
// JSDOM does not support the `tabbable` library. To solve this we can
// check if `ResizeObserver` is a real function (not polyfilled), which
// determines if the current environment is JSDOM-like.
typeof ResizeObserver === "function" && ResizeObserver.toString().includes("[native code]") ? "full" : "none"
)
};
}
function getTabbableFrom(currentNode, direction) {
if (!isTabbable(currentNode, getTabbableOptions())) {
return getTabbableFromFocusable(currentNode, direction);
}
const doc = getDocument(currentNode);
const allTabbable = tabbable(doc.body, getTabbableOptions());
if (direction === "prev")
allTabbable.reverse();
const activeIndex = allTabbable.indexOf(currentNode);
if (activeIndex === -1)
return doc.body;
const nextTabbableElements = allTabbable.slice(activeIndex + 1);
return nextTabbableElements[0];
}
function getTabbableFromFocusable(currentNode, direction) {
const doc = getDocument(currentNode);
if (!isFocusable(currentNode, getTabbableOptions()))
return doc.body;
const allFocusable = focusable(doc.body, getTabbableOptions());
if (direction === "prev")
allFocusable.reverse();
const activeIndex = allFocusable.indexOf(currentNode);
if (activeIndex === -1)
return doc.body;
const nextFocusableElements = allFocusable.slice(activeIndex + 1);
return nextFocusableElements.find((node) => isTabbable(node, getTabbableOptions())) ?? doc.body;
}
function getNextMatch(values, search, currentMatch) {
const lowerSearch = search.toLowerCase();
if (lowerSearch.endsWith(" ")) {
const searchWithoutSpace = lowerSearch.slice(0, -1);
const matchesWithoutSpace = values.filter((value) => value.toLowerCase().startsWith(searchWithoutSpace));
if (matchesWithoutSpace.length <= 1) {
return getNextMatch(values, searchWithoutSpace, currentMatch);
}
const currentMatchLowercase = currentMatch?.toLowerCase();
if (currentMatchLowercase && currentMatchLowercase.startsWith(searchWithoutSpace) && currentMatchLowercase.charAt(searchWithoutSpace.length) === " " && search.trim() === searchWithoutSpace) {
return currentMatch;
}
const spacedMatches = values.filter((value) => value.toLowerCase().startsWith(lowerSearch));
if (spacedMatches.length > 0) {
const currentMatchIndex2 = currentMatch ? values.indexOf(currentMatch) : -1;
let wrappedMatches = wrapArray(spacedMatches, Math.max(currentMatchIndex2, 0));
const nextMatch2 = wrappedMatches.find((match) => match !== currentMatch);
return nextMatch2 || currentMatch;
}
}
const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
const normalizedSearch = isRepeated ? search[0] : search;
const normalizedLowerSearch = normalizedSearch.toLowerCase();
const currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
const excludeCurrentMatch = normalizedSearch.length === 1;
if (excludeCurrentMatch)
wrappedValues = wrappedValues.filter((v) => v !== currentMatch);
const nextMatch = wrappedValues.find((value) => value?.toLowerCase().startsWith(normalizedLowerSearch));
return nextMatch !== currentMatch ? nextMatch : void 0;
}
function wrapArray(array, startIndex) {
return array.map((_, index) => array[(startIndex + index) % array.length]);
}
const defaultOptions = { afterMs: 1e4, onChange: noop };
function boxAutoReset(defaultValue, options) {
const { afterMs, onChange, getWindow: getWindow2 } = { ...defaultOptions, ...options };
let timeout = null;
let value = defaultValue;
function resetAfter() {
return getWindow2().setTimeout(
() => {
value = defaultValue;
onChange?.(defaultValue);
},
afterMs
);
}
return boxWith(() => value, (v) => {
value = v;
onChange?.(v);
if (timeout) getWindow2().clearTimeout(timeout);
timeout = resetAfter();
});
}
class DOMTypeahead {
#opts;
#search;
#onMatch = derived(() => {
if (this.#opts.onMatch) return this.#opts.onMatch;
return (node) => node.focus();
});
#getCurrentItem = derived(() => {
if (this.#opts.getCurrentItem) return this.#opts.getCurrentItem;
return this.#opts.getActiveElement;
});
constructor(opts) {
this.#opts = opts;
this.#search = boxAutoReset("", { afterMs: 1e3, getWindow: opts.getWindow });
this.handleTypeaheadSearch = this.handleTypeaheadSearch.bind(this);
this.resetTypeahead = this.resetTypeahead.bind(this);
}
handleTypeaheadSearch(key, candidates) {
if (!candidates.length) return;
this.#search.current = this.#search.current + key;
const currentItem = this.#getCurrentItem()();
const currentMatch = candidates.find((item) => item === currentItem)?.textContent?.trim() ?? "";
const values = candidates.map((item) => item.textContent?.trim() ?? "");
const nextMatch = getNextMatch(values, this.#search.current, currentMatch);
const newItem = candidates.find((item) => item.textContent?.trim() === nextMatch);
if (newItem) this.#onMatch()(newItem);
return newItem;
}
resetTypeahead() {
this.#search.current = "";
}
get search() {
return this.#search.current;
}
}
class GraceArea {
#opts;
#enabled;
#isPointerInTransit;
#pointerGraceArea = null;
constructor(opts) {
this.#opts = opts;
this.#enabled = derived(() => this.#opts.enabled());
this.#isPointerInTransit = boxAutoReset(false, {
afterMs: opts.transitTimeout ?? 300,
onChange: (value) => {
if (!this.#enabled()) return;
this.#opts.setIsPointerInTransit?.(value);
},
getWindow: () => getWindow(this.#opts.triggerNode())
});
watch([opts.triggerNode, opts.contentNode, opts.enabled], ([triggerNode, contentNode, enabled]) => {
if (!triggerNode || !contentNode || !enabled) return;
const handleTriggerLeave = (e) => {
this.#createGraceArea(e, contentNode);
};
const handleContentLeave = (e) => {
this.#createGraceArea(e, triggerNode);
};
return executeCallbacks(on(triggerNode, "pointerleave", handleTriggerLeave), on(contentNode, "pointerleave", handleContentLeave));
});
watch(() => this.#pointerGraceArea, () => {
const handleTrackPointerGrace = (e) => {
if (!this.#pointerGraceArea) return;
const target = e.target;
if (!isElement(target)) return;
const pointerPosition = { x: e.clientX, y: e.clientY };
const hasEnteredTarget = opts.triggerNode()?.contains(target) || opts.contentNode()?.contains(target);
const isPointerOutsideGraceArea = !isPointInPolygon(pointerPosition, this.#pointerGraceArea);
if (hasEnteredTarget) {
this.#removeGraceArea();
} else if (isPointerOutsideGraceArea) {
this.#removeGraceArea();
opts.onPointerExit();
}
};
const doc = getDocument(opts.triggerNode() ?? opts.contentNode());
if (!doc) return;
return on(doc, "pointermove", handleTrackPointerGrace);
});
}
#removeGraceArea() {
this.#pointerGraceArea = null;
this.#isPointerInTransit.current = false;
}
#createGraceArea(e, hoverTarget) {
const currentTarget = e.currentTarget;
if (!isHTMLElement(currentTarget)) return;
const exitPoint = { x: e.clientX, y: e.clientY };
const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect());
const paddedExitPoints = getPaddedExitPoints(exitPoint, exitSide);
const hoverTargetPoints = getPointsFromRect(hoverTarget.getBoundingClientRect());
const graceArea = getHull([...paddedExitPoints, ...hoverTargetPoints]);
this.#pointerGraceArea = graceArea;
this.#isPointerInTransit.current = true;
}
}
function getExitSideFromRect(point, rect) {
const top = Math.abs(rect.top - point.y);
const bottom = Math.abs(rect.bottom - point.y);
const right = Math.abs(rect.right - point.x);
const left = Math.abs(rect.left - point.x);
switch (Math.min(top, bottom, right, left)) {
case left:
return "left";
case right:
return "right";
case top:
return "top";
case bottom:
return "bottom";
default:
throw new Error("unreachable");
}
}
function getPaddedExitPoints(exitPoint, exitSide, padding = 5) {
const tipPadding = padding * 1.5;
switch (exitSide) {
case "top":
return [
{ x: exitPoint.x - padding, y: exitPoint.y + padding },
{ x: exitPoint.x, y: exitPoint.y - tipPadding },
{ x: exitPoint.x + padding, y: exitPoint.y + padding }
];
case "bottom":
return [
{ x: exitPoint.x - padding, y: exitPoint.y - padding },
{ x: exitPoint.x, y: exitPoint.y + tipPadding },
{ x: exitPoint.x + padding, y: exitPoint.y - padding }
];
case "left":
return [
{ x: exitPoint.x + padding, y: exitPoint.y - padding },
{ x: exitPoint.x - tipPadding, y: exitPoint.y },
{ x: exitPoint.x + padding, y: exitPoint.y + padding }
];
case "right":
return [
{ x: exitPoint.x - padding, y: exitPoint.y - padding },
{ x: exitPoint.x + tipPadding, y: exitPoint.y },
{ x: exitPoint.x - padding, y: exitPoint.y + padding }
];
}
}
function getPointsFromRect(rect) {
const { top, right, bottom, left } = rect;
return [
{ x: left, y: top },
{ x: right, y: top },
{ x: right, y: bottom },
{ x: left, y: bottom }
];
}
function isPointInPolygon(point, polygon) {
const { x, y } = point;
let inside = false;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].x;
const yi = polygon[i].y;
const xj = polygon[j].x;
const yj = polygon[j].y;
const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
function getHull(points) {
const newPoints = points.slice();
newPoints.sort((a, b) => {
if (a.x < b.x) return -1;
else if (a.x > b.x) return 1;
else if (a.y < b.y) return -1;
else if (a.y > b.y) return 1;
else return 0;
});
return getHullPresorted(newPoints);
}
function getHullPresorted(points) {
if (points.length <= 1) return points.slice();
const upperHull = [];
for (let i = 0; i < points.length; i++) {
const p = points[i];
while (upperHull.length >= 2) {
const q = upperHull[upperHull.length - 1];
const r = upperHull[upperHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) upperHull.pop();
else break;
}
upperHull.push(p);
}
upperHull.pop();
const lowerHull = [];
for (let i = points.length - 1; i >= 0; i--) {
const p = points[i];
while (lowerHull.length >= 2) {
const q = lowerHull[lowerHull.length - 1];
const r = lowerHull[lowerHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) lowerHull.pop();
else break;
}
lowerHull.push(p);
}
lowerHull.pop();
if (upperHull.length === 1 && lowerHull.length === 1 && upperHull[0].x === lowerHull[0].x && upperHull[0].y === lowerHull[0].y) return upperHull;
else return upperHull.concat(lowerHull);
}
const CONTEXT_MENU_TRIGGER_ATTR = "data-context-menu-trigger";
const CONTEXT_MENU_CONTENT_ATTR = "data-context-menu-content";
const MenuRootContext = new Context("Menu.Root");
const MenuMenuContext = new Context("Menu.Root | Menu.Sub");
const MenuContentContext = new Context("Menu.Content");
const MenuOpenEvent = new CustomEventDispatcher("bitsmenuopen", { bubbles: false, cancelable: true });
const menuAttrs = createBitsAttrs({
component: "menu",
parts: [
"trigger",
"content",
"sub-trigger",
"item",
"group",
"group-heading",
"checkbox-group",
"checkbox-item",
"radio-group",
"radio-item",
"separator",
"sub-content",
"arrow"
]
});
class MenuRootState {
static create(opts) {
const root = new MenuRootState(opts);
return MenuRootContext.set(root);
}
opts;
isUsingKeyboard = new IsUsingKeyboard();
ignoreCloseAutoFocus = false;
isPointerInTransit = false;
constructor(opts) {
this.opts = opts;
}
getBitsAttr = (part) => {
return menuAttrs.getAttr(part, this.opts.variant.current);
};
}
class MenuMenuState {
static create(opts, root) {
return MenuMenuContext.set(new MenuMenuState(opts, root, null));
}
opts;
root;
parentMenu;
contentId = boxWith(() => "");
contentNode = null;
contentPresence;
triggerNode = null;
constructor(opts, root, parentMenu) {
this.opts = opts;
this.root = root;
this.parentMenu = parentMenu;
this.contentPresence = new PresenceManager({
ref: boxWith(() => this.contentNode),
open: this.opts.open,
onComplete: () => {
this.opts.onOpenChangeComplete.current(this.opts.open.current);
}
});
if (parentMenu) {
watch(() => parentMenu.opts.open.current, () => {
if (parentMenu.opts.open.current) return;
this.opts.open.current = false;
});
}
}
toggleOpen() {
this.opts.open.current = !this.opts.open.current;
}
onOpen() {
this.opts.open.current = true;
}
onClose() {
this.opts.open.current = false;
}
}
class MenuContentState {
static create(opts) {
return MenuContentContext.set(new MenuContentState(opts, MenuMenuContext.get()));
}
opts;
parentMenu;
rovingFocusGroup;
domContext;
attachment;
search = "";
#timer = 0;
#handleTypeaheadSearch;
mounted = false;
#isSub;
constructor(opts, parentMenu) {
this.opts = opts;
this.parentMenu = parentMenu;
this.domContext = new DOMContext(opts.ref);
this.attachment = attachRef(this.opts.ref, (v) => {
if (this.parentMenu.contentNode !== v) {
this.parentMenu.contentNode = v;
}
});
parentMenu.contentId = opts.id;
this.#isSub = opts.isSub ?? false;
this.onkeydown = this.onkeydown.bind(this);
this.onblur = this.onblur.bind(this);
this.onfocus = this.onfocus.bind(this);
this.handleInteractOutside = this.handleInteractOutside.bind(this);
new GraceArea({
contentNode: () => this.parentMenu.contentNode,
triggerNode: () => this.parentMenu.triggerNode,
enabled: () => this.parentMenu.opts.open.current && Boolean(this.parentMenu.triggerNode?.hasAttribute(this.parentMenu.root.getBitsAttr("sub-trigger"))),
onPointerExit: () => {
this.parentMenu.opts.open.current = false;
},
setIsPointerInTransit: (value) => {
this.parentMenu.root.isPointerInTransit = value;
}
});
this.#handleTypeaheadSearch = new DOMTypeahead({
getActiveElement: () => this.domContext.getActiveElement(),
getWindow: () => this.domContext.getWindow()
}).handleTypeaheadSearch;
this.rovingFocusGroup = new RovingFocusGroup({
rootNode: boxWith(() => this.parentMenu.contentNode),
candidateAttr: this.parentMenu.root.getBitsAttr("item"),
loop: this.opts.loop,
orientation: boxWith(() => "vertical")
});
watch(() => this.parentMenu.contentNode, (contentNode) => {
if (!contentNode) return;
const handler = () => {
afterTick(() => {
if (!this.parentMenu.root.isUsingKeyboard.current) return;
this.rovingFocusGroup.focusFirstCandidate();
});
};
return MenuOpenEvent.listen(contentNode, handler);
});
}
#getCandidateNodes() {
const node = this.parentMenu.contentNode;
if (!node) return [];
const candidates = Array.from(node.querySelectorAll(`[${this.parentMenu.root.getBitsAttr("item")}]:not([data-disabled])`));
return candidates;
}
#isPointerMovingToSubmenu() {
return this.parentMenu.root.isPointerInTransit;
}
onCloseAutoFocus = (e) => {
this.opts.onCloseAutoFocus.current?.(e);
if (e.defaultPrevented || this.#isSub) return;
if (this.parentMenu.triggerNode && isTabbable(this.parentMenu.triggerNode)) {
e.preventDefault();
this.parentMenu.triggerNode.focus();
}
};
handleTabKeyDown(e) {
let rootMenu = this.parentMenu;
while (rootMenu.parentMenu !== null) {
rootMenu = rootMenu.parentMenu;
}
if (!rootMenu.triggerNode) return;
e.preventDefault();
const nodeToFocus = getTabbableFrom(rootMenu.triggerNode, e.shiftKey ? "prev" : "next");
if (nodeToFocus) {
this.parentMenu.root.ignoreCloseAutoFocus = true;
rootMenu.onClose();
afterTick(() => {
nodeToFocus.focus();
afterTick(() => {
this.parentMenu.root.ignoreCloseAutoFocus = false;
});
});
} else {
this.domContext.getDocument().body.focus();
}
}
onkeydown(e) {
if (e.defaultPrevented) return;
if (e.key === TAB) {
this.handleTabKeyDown(e);
return;
}
const target = e.target;
const currentTarget = e.currentTarget;
if (!isHTMLElement(target) || !isHTMLElement(currentTarget)) return;
const isKeydownInside = target.closest(`[${this.parentMenu.root.getBitsAttr("content")}]`)?.id === this.parentMenu.contentId.current;
const isModifierKey = e.ctrlKey || e.altKey || e.metaKey;
const isCharacterKey = e.key.length === 1;
const kbdFocusedEl = this.rovingFocusGroup.handleKeydown(target, e);
if (kbdFocusedEl) return;
if (e.code === "Space") return;
const candidateNodes = this.#getCandidateNodes();
if (isKeydownInside) {
if (!isModifierKey && isCharacterKey) {
this.#handleTypeaheadSearch(e.key, candidateNodes);
}
}
if (e.target?.id !== this.parentMenu.contentId.current) return;
if (!FIRST_LAST_KEYS.includes(e.key)) return;
e.preventDefault();
if (LAST_KEYS.includes(e.key)) {
candidateNodes.reverse();
}
focusFirst(candidateNodes, { select: false }, () => this.domContext.getActiveElement());
}
onblur(e) {
if (!isElement(e.currentTarget)) return;
if (!isElement(e.target)) return;
if (!e.currentTarget.contains?.(e.target)) {
this.domContext.getWindow().clearTimeout(this.#timer);
this.search = "";
}
}
onfocus(_) {
if (!this.parentMenu.root.isUsingKeyboard.current) return;
afterTick(() => this.rovingFocusGroup.focusFirstCandidate());
}
onItemEnter() {
return this.#isPointerMovingToSubmenu();
}
onItemLeave(e) {
if (e.currentTarget.hasAttribute(this.parentMenu.root.getBitsAttr("sub-trigger"))) return;
if (this.#isPointerMovingToSubmenu() || this.parentMenu.root.isUsingKeyboard.current) return;
const contentNode = this.parentMenu.contentNode;
contentNode?.focus();
this.rovingFocusGroup.setCurrentTabStopId("");
}
onTriggerLeave() {
if (this.#isPointerMovingToSubmenu()) return true;
return false;
}
handleInteractOutside(e) {
if (!isElementOrSVGElement(e.target)) return;
const triggerId = this.parentMenu.triggerNode?.id;
if (e.target.id === triggerId) {
e.preventDefault();
return;
}
if (e.target.closest(`#${triggerId}`)) {
e.preventDefault();
}
}
get shouldRender() {
return this.parentMenu.contentPresence.shouldRender;
}
#snippetProps = derived(() => ({ open: this.parentMenu.opts.open.current }));
get snippetProps() {
return this.#snippetProps();
}
set snippetProps($$value) {
return this.#snippetProps($$value);
}
#props = derived(() => ({
id: this.opts.id.current,
role: "menu",
"aria-orientation": "vertical",
[this.parentMenu.root.getBitsAttr("content")]: "",
"data-state": getDataOpenClosed(this.parentMenu.opts.open.current),
onkeydown: this.onkeydown,
onblur: this.onblur,
onfocus: this.onfocus,
dir: this.parentMenu.root.opts.dir.current,
style: { pointerEvents: "auto", contain: "layout style" },
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
popperProps = { onCloseAutoFocus: (e) => this.onCloseAutoFocus(e) };
}
class MenuSeparatorState {
static create(opts) {
return new MenuSeparatorState(opts, MenuRootContext.get());
}
opts;
root;
attachment;
constructor(opts, root) {
this.opts = opts;
this.root = root;
this.attachment = attachRef(this.opts.ref);
}
#props = derived(() => ({
id: this.opts.id.current,
role: "group",
[this.root.getBitsAttr("separator")]: "",
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
class DropdownMenuTriggerState {
static create(opts) {
return new DropdownMenuTriggerState(opts, MenuMenuContext.get());
}
opts;
parentMenu;
attachment;
constructor(opts, parentMenu) {
this.opts = opts;
this.parentMenu = parentMenu;
this.attachment = attachRef(this.opts.ref, (v) => this.parentMenu.triggerNode = v);
}
onclick = (e) => {
if (this.opts.disabled.current || e.detail !== 0) return;
this.parentMenu.toggleOpen();
e.preventDefault();
};
onpointerdown = (e) => {
if (this.opts.disabled.current) return;
if (e.pointerType === "touch") return e.preventDefault();
if (e.button === 0 && e.ctrlKey === false) {
this.parentMenu.toggleOpen();
if (!this.parentMenu.opts.open.current) e.preventDefault();
}
};
onpointerup = (e) => {
if (this.opts.disabled.current) return;
if (e.pointerType === "touch") {
e.preventDefault();
this.parentMenu.toggleOpen();
}
};
onkeydown = (e) => {
if (this.opts.disabled.current) return;
if (e.key === SPACE || e.key === ENTER) {
this.parentMenu.toggleOpen();
e.preventDefault();
return;
}
if (e.key === ARROW_DOWN) {
this.parentMenu.onOpen();
e.preventDefault();
}
};
#ariaControls = derived(() => {
if (this.parentMenu.opts.open.current && this.parentMenu.contentId.current) return this.parentMenu.contentId.current;
return void 0;
});
#props = derived(() => ({
id: this.opts.id.current,
disabled: this.opts.disabled.current,
"aria-haspopup": "menu",
"aria-expanded": boolToStr(this.parentMenu.opts.open.current),
"aria-controls": this.#ariaControls(),
"data-disabled": boolToEmptyStrOrUndef(this.opts.disabled.current),
"data-state": getDataOpenClosed(this.parentMenu.opts.open.current),
[this.parentMenu.root.getBitsAttr("trigger")]: "",
//
onclick: this.onclick,
onpointerdown: this.onpointerdown,
onpointerup: this.onpointerup,
onkeydown: this.onkeydown,
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
globalThis.bitsDismissableLayers ??= /* @__PURE__ */ new Map();
class DismissibleLayerState {
static create(opts) {
return new DismissibleLayerState(opts);
}
opts;
#interactOutsideProp;
#behaviorType;
#interceptedEvents = { pointerdown: false };
#isResponsibleLayer = false;
#isFocusInsideDOMTree = false;
#documentObj = void 0;
#onFocusOutside;
#unsubClickListener = noop;
constructor(opts) {
this.opts = opts;
this.#behaviorType = opts.interactOutsideBehavior;
this.#interactOutsideProp = opts.onInteractOutside;
this.#onFocusOutside = opts.onFocusOutside;
let unsubEvents = noop;
const cleanup = () => {
this.#resetState();
globalThis.bitsDismissableLayers.delete(this);
this.#handleInteractOutside.destroy();
unsubEvents();
};
watch([() => this.opts.enabled.current, () => this.opts.ref.current], () => {
if (!this.opts.enabled.current || !this.opts.ref.current) return;
afterSleep(1, () => {
if (!this.opts.ref.current) return;
globalThis.bitsDismissableLayers.set(this, this.#behaviorType);
unsubEvents();
unsubEvents = this.#addEventListeners();
});
return cleanup;
});
}
#handleFocus = (event) => {
if (event.defaultPrevented) return;
if (!this.opts.ref.current) return;
afterTick(() => {
if (!this.opts.ref.current || this.#isTargetWithinLayer(event.target)) return;
if (event.target && !this.#isFocusInsideDOMTree) {
this.#onFocusOutside.current?.(event);
}
});
};
#addEventListeners() {
return executeCallbacks(
/**
* CAPTURE INTERACTION START
* mark interaction-start event as intercepted.
* mark responsible layer during interaction start
* to avoid checking if is responsible layer during interaction end
* when a new floating element may have been opened.
*/
on(this.#documentObj, "pointerdown", executeCallbacks(this.#markInterceptedEvent, this.#markResponsibleLayer), { capture: true }),
/**
* BUBBLE INTERACTION START
* Mark interaction-start event as non-intercepted. Debounce `onInteractOutsideStart`
* to avoid prematurely checking if other events were intercepted.
*/
on(this.#documentObj, "pointerdown", executeCallbacks(this.#markNonInterceptedEvent, this.#handleInteractOutside)),
/**
* HANDLE FOCUS OUTSIDE
*/
on(this.#documentObj, "focusin", this.#handleFocus)
);
}
#handleDismiss = (e) => {
let event = e;
if (event.defaultPrevented) {
event = createWrappedEvent(e);
}
this.#interactOutsideProp.current(e);
};
#handleInteractOutside = debounce(
(e) => {
if (!this.opts.ref.current) {
this.#unsubClickListener();
return;
}
const isEventValid = this.opts.isValidEvent.current(e, this.opts.ref.current) || isValidEvent(e, this.opts.ref.current);
if (!this.#isResponsibleLayer || this.#isAnyEventIntercepted() || !isEventValid) {
this.#unsubClickListener();
return;
}
let event = e;
if (event.defaultPrevented) {
event = createWrappedEvent(event);
}
if (this.#behaviorType.current !== "close" && this.#behaviorType.current !== "defer-otherwise-close") {
this.#unsubClickListener();
return;
}
if (e.pointerType === "touch") {
this.#unsubClickListener();
this.#unsubClickListener = on(this.#documentObj, "click", this.#handleDismiss, { once: true });
} else {
this.#interactOutsideProp.current(event);
}
},
10
);
#markInterceptedEvent = (e) => {
this.#interceptedEvents[e.type] = true;
};
#markNonInterceptedEvent = (e) => {
this.#interceptedEvents[e.type] = false;
};
#markResponsibleLayer = () => {
if (!this.opts.ref.current) return;
this.#isResponsibleLayer = isResponsibleLayer(this.opts.ref.current);
};
#isTargetWithinLayer = (target) => {
if (!this.opts.ref.current) return false;
return isOrContainsTarget(this.opts.ref.current, target);
};
#resetState = debounce(
() => {
for (const eventType in this.#interceptedEvents) {
this.#interceptedEvents[eventType] = false;
}
this.#isResponsibleLayer = false;
},
20
);
#isAnyEventIntercepted() {
const i = Object.values(this.#interceptedEvents).some(Boolean);
return i;
}
#onfocuscapture = () => {
this.#isFocusInsideDOMTree = true;
};
#onblurcapture = () => {
this.#isFocusInsideDOMTree = false;
};
props = {
onfocuscapture: this.#onfocuscapture,
onblurcapture: this.#onblurcapture
};
}
function getTopMostDismissableLayer(layersArr = [...globalThis.bitsDismissableLayers]) {
return layersArr.findLast(([_, { current: behaviorType }]) => behaviorType === "close" || behaviorType === "ignore");
}
function isResponsibleLayer(node) {
const layersArr = [...globalThis.bitsDismissableLayers];
const topMostLayer = getTopMostDismissableLayer(layersArr);
if (topMostLayer) return topMostLayer[0].opts.ref.current === node;
const [firstLayerNode] = layersArr[0];
return firstLayerNode.opts.ref.current === node;
}
function isValidEvent(e, node) {
const target = e.target;
if (!isElementOrSVGElement(target)) return false;
const targetIsContextMenuTrigger = Boolean(target.closest(`[${CONTEXT_MENU_TRIGGER_ATTR}]`));
if ("button" in e && e.button > 0 && !targetIsContextMenuTrigger) return false;
if ("button" in e && e.button === 0 && targetIsContextMenuTrigger) return true;
const nodeIsContextMenu = Boolean(node.closest(`[${CONTEXT_MENU_CONTENT_ATTR}]`));
if (targetIsContextMenuTrigger && nodeIsContextMenu) return false;
const ownerDocument = getOwnerDocument(target);
const isValid = ownerDocument.documentElement.contains(target) && !isOrContainsTarget(node, target) && isClickTrulyOutside(e, node);
return isValid;
}
function createWrappedEvent(e) {
const capturedCurrentTarget = e.currentTarget;
const capturedTarget = e.target;
let newEvent;
if (e instanceof PointerEvent) {
newEvent = new PointerEvent(e.type, e);
} else {
newEvent = new PointerEvent("pointerdown", e);
}
let isPrevented = false;
const wrappedEvent = new Proxy(newEvent, {
get: (target, prop) => {
if (prop === "currentTarget") {
return capturedCurrentTarget;
}
if (prop === "target") {
return capturedTarget;
}
if (prop === "preventDefault") {
return () => {
isPrevented = true;
if (typeof target.preventDefault === "function") {
target.preventDefault();
}
};
}
if (prop === "defaultPrevented") {
return isPrevented;
}
if (prop in target) {
return target[prop];
}
return e[prop];
}
});
return wrappedEvent;
}
function Dismissible_layer($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
interactOutsideBehavior = "close",
onInteractOutside = noop,
onFocusOutside = noop,
id,
children,
enabled,
isValidEvent: isValidEvent2 = () => false,
ref
} = $$props;
const dismissibleLayerState = DismissibleLayerState.create({
id: boxWith(() => id),
interactOutsideBehavior: boxWith(() => interactOutsideBehavior),
onInteractOutside: boxWith(() => onInteractOutside),
enabled: boxWith(() => enabled),
onFocusOutside: boxWith(() => onFocusOutside),
isValidEvent: boxWith(() => isValidEvent2),
ref
});
children?.($$renderer2, { props: dismissibleLayerState.props });
$$renderer2.push(`<!---->`);
});
}
globalThis.bitsEscapeLayers ??= /* @__PURE__ */ new Map();
class EscapeLayerState {
static create(opts) {
return new EscapeLayerState(opts);
}
opts;
domContext;
constructor(opts) {
this.opts = opts;
this.domContext = new DOMContext(this.opts.ref);
let unsubEvents = noop;
watch(() => opts.enabled.current, (enabled) => {
if (enabled) {
globalThis.bitsEscapeLayers.set(this, opts.escapeKeydownBehavior);
unsubEvents = this.#addEventListener();
}
return () => {
unsubEvents();
globalThis.bitsEscapeLayers.delete(this);
};
});
}
#addEventListener = () => {
return on(this.domContext.getDocument(), "keydown", this.#onkeydown, { passive: false });
};
#onkeydown = (e) => {
if (e.key !== ESCAPE || !isResponsibleEscapeLayer(this)) return;
const clonedEvent = new KeyboardEvent(e.type, e);
e.preventDefault();
const behaviorType = this.opts.escapeKeydownBehavior.current;
if (behaviorType !== "close" && behaviorType !== "defer-otherwise-close") return;
this.opts.onEscapeKeydown.current(clonedEvent);
};
}
function isResponsibleEscapeLayer(instance) {
const layersArr = [...globalThis.bitsEscapeLayers];
const topMostLayer = layersArr.findLast(([_, { current: behaviorType }]) => behaviorType === "close" || behaviorType === "ignore");
if (topMostLayer) return topMostLayer[0] === instance;
const [firstLayerNode] = layersArr[0];
return firstLayerNode === instance;
}
function Escape_layer($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
escapeKeydownBehavior = "close",
onEscapeKeydown = noop,
children,
enabled,
ref
} = $$props;
EscapeLayerState.create({
escapeKeydownBehavior: boxWith(() => escapeKeydownBehavior),
onEscapeKeydown: boxWith(() => onEscapeKeydown),
enabled: boxWith(() => enabled),
ref
});
children?.($$renderer2);
$$renderer2.push(`<!---->`);
});
}
class FocusScopeManager {
static instance;
#scopeStack = simpleBox([]);
#focusHistory = /* @__PURE__ */ new WeakMap();
#preFocusHistory = /* @__PURE__ */ new WeakMap();
static getInstance() {
if (!this.instance) {
this.instance = new FocusScopeManager();
}
return this.instance;
}
register(scope) {
const current = this.getActive();
if (current && current !== scope) {
current.pause();
}
const activeElement = document.activeElement;
if (activeElement && activeElement !== document.body) {
this.#preFocusHistory.set(scope, activeElement);
}
this.#scopeStack.current = this.#scopeStack.current.filter((s) => s !== scope);
this.#scopeStack.current.unshift(scope);
}
unregister(scope) {
this.#scopeStack.current = this.#scopeStack.current.filter((s) => s !== scope);
const next = this.getActive();
if (next) {
next.resume();
}
}
getActive() {
return this.#scopeStack.current[0];
}
setFocusMemory(scope, element) {
this.#focusHistory.set(scope, element);
}
getFocusMemory(scope) {
return this.#focusHistory.get(scope);
}
isActiveScope(scope) {
return this.getActive() === scope;
}
setPreFocusMemory(scope, element) {
this.#preFocusHistory.set(scope, element);
}
getPreFocusMemory(scope) {
return this.#preFocusHistory.get(scope);
}
clearPreFocusMemory(scope) {
this.#preFocusHistory.delete(scope);
}
}
class FocusScope {
#paused = false;
#container = null;
#manager = FocusScopeManager.getInstance();
#cleanupFns = [];
#opts;
constructor(opts) {
this.#opts = opts;
}
get paused() {
return this.#paused;
}
pause() {
this.#paused = true;
}
resume() {
this.#paused = false;
}
#cleanup() {
for (const fn of this.#cleanupFns) {
fn();
}
this.#cleanupFns = [];
}
mount(container) {
if (this.#container) {
this.unmount();
}
this.#container = container;
this.#manager.register(this);
this.#setupEventListeners();
this.#handleOpenAutoFocus();
}
unmount() {
if (!this.#container) return;
this.#cleanup();
this.#handleCloseAutoFocus();
this.#manager.unregister(this);
this.#manager.clearPreFocusMemory(this);
this.#container = null;
}
#handleOpenAutoFocus() {
if (!this.#container) return;
const event = new CustomEvent("focusScope.onOpenAutoFocus", { bubbles: false, cancelable: true });
this.#opts.onOpenAutoFocus.current(event);
if (!event.defaultPrevented) {
requestAnimationFrame(() => {
if (!this.#container) return;
const firstTabbable = this.#getFirstTabbable();
if (firstTabbable) {
firstTabbable.focus();
this.#manager.setFocusMemory(this, firstTabbable);
} else {
this.#container.focus();
}
});
}
}
#handleCloseAutoFocus() {
const event = new CustomEvent("focusScope.onCloseAutoFocus", { bubbles: false, cancelable: true });
this.#opts.onCloseAutoFocus.current?.(event);
if (!event.defaultPrevented) {
const preFocusedElement = this.#manager.getPreFocusMemory(this);
if (preFocusedElement && document.contains(preFocusedElement)) {
try {
preFocusedElement.focus();
} catch {
document.body.focus();
}
}
}
}
#setupEventListeners() {
if (!this.#container || !this.#opts.trap.current) return;
const container = this.#container;
const doc = container.ownerDocument;
const handleFocus = (e) => {
if (this.#paused || !this.#manager.isActiveScope(this)) return;
const target = e.target;
if (!target) return;
const isInside = container.contains(target);
if (isInside) {
this.#manager.setFocusMemory(this, target);
} else {
const lastFocused = this.#manager.getFocusMemory(this);
if (lastFocused && container.contains(lastFocused) && isFocusable(lastFocused)) {
e.preventDefault();
lastFocused.focus();
} else {
const firstTabbable = this.#getFirstTabbable();
const firstFocusable = this.#getAllFocusables()[0];
(firstTabbable || firstFocusable || container).focus();
}
}
};
const handleKeydown = (e) => {
if (!this.#opts.loop || this.#paused || e.key !== "Tab") return;
if (!this.#manager.isActiveScope(this)) return;
const tabbables = this.#getTabbables();
if (tabbables.length === 0) return;
const first = tabbables[0];
const last = tabbables[tabbables.length - 1];
if (!e.shiftKey && doc.activeElement === last) {
e.preventDefault();
first.focus();
} else if (e.shiftKey && doc.activeElement === first) {
e.preventDefault();
last.focus();
}
};
this.#cleanupFns.push(on(doc, "focusin", handleFocus, { capture: true }), on(container, "keydown", handleKeydown));
const observer = new MutationObserver(() => {
const lastFocused = this.#manager.getFocusMemory(this);
if (lastFocused && !container.contains(lastFocused)) {
const firstTabbable = this.#getFirstTabbable();
const firstFocusable = this.#getAllFocusables()[0];
const elementToFocus = firstTabbable || firstFocusable;
if (elementToFocus) {
elementToFocus.focus();
this.#manager.setFocusMemory(this, elementToFocus);
} else {
container.focus();
}
}
});
observer.observe(container, { childList: true, subtree: true });
this.#cleanupFns.push(() => observer.disconnect());
}
#getTabbables() {
if (!this.#container) return [];
return tabbable(this.#container, { includeContainer: false, getShadowRoot: true });
}
#getFirstTabbable() {
const tabbables = this.#getTabbables();
return tabbables[0] || null;
}
#getAllFocusables() {
if (!this.#container) return [];
return focusable(this.#container, { includeContainer: false, getShadowRoot: true });
}
static use(opts) {
let scope = null;
watch([() => opts.ref.current, () => opts.enabled.current], ([ref, enabled]) => {
if (ref && enabled) {
if (!scope) {
scope = new FocusScope(opts);
}
scope.mount(ref);
} else if (scope) {
scope.unmount();
scope = null;
}
});
return {
get props() {
return { tabindex: -1 };
}
};
}
}
function Focus_scope($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
enabled = false,
trapFocus = false,
loop = false,
onCloseAutoFocus = noop,
onOpenAutoFocus = noop,
focusScope,
ref
} = $$props;
const focusScopeState = FocusScope.use({
enabled: boxWith(() => enabled),
trap: boxWith(() => trapFocus),
loop,
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
onOpenAutoFocus: boxWith(() => onOpenAutoFocus),
ref
});
focusScope?.($$renderer2, { props: focusScopeState.props });
$$renderer2.push(`<!---->`);
});
}
globalThis.bitsTextSelectionLayers ??= /* @__PURE__ */ new Map();
class TextSelectionLayerState {
static create(opts) {
return new TextSelectionLayerState(opts);
}
opts;
domContext;
#unsubSelectionLock = noop;
constructor(opts) {
this.opts = opts;
this.domContext = new DOMContext(opts.ref);
let unsubEvents = noop;
watch(() => this.opts.enabled.current, (isEnabled) => {
if (isEnabled) {
globalThis.bitsTextSelectionLayers.set(this, this.opts.enabled);
unsubEvents();
unsubEvents = this.#addEventListeners();
}
return () => {
unsubEvents();
this.#resetSelectionLock();
globalThis.bitsTextSelectionLayers.delete(this);
};
});
}
#addEventListeners() {
return executeCallbacks(on(this.domContext.getDocument(), "pointerdown", this.#pointerdown), on(this.domContext.getDocument(), "pointerup", composeHandlers(this.#resetSelectionLock, this.opts.onPointerUp.current)));
}
#pointerdown = (e) => {
const node = this.opts.ref.current;
const target = e.target;
if (!isHTMLElement(node) || !isHTMLElement(target) || !this.opts.enabled.current) return;
if (!isHighestLayer(this) || !contains(node, target)) return;
this.opts.onPointerDown.current(e);
if (e.defaultPrevented) return;
this.#unsubSelectionLock = preventTextSelectionOverflow(node, this.domContext.getDocument().body);
};
#resetSelectionLock = () => {
this.#unsubSelectionLock();
this.#unsubSelectionLock = noop;
};
}
const getUserSelect = (node) => node.style.userSelect || node.style.webkitUserSelect;
function preventTextSelectionOverflow(node, body) {
const originalBodyUserSelect = getUserSelect(body);
const originalNodeUserSelect = getUserSelect(node);
setUserSelect(body, "none");
setUserSelect(node, "text");
return () => {
setUserSelect(body, originalBodyUserSelect);
setUserSelect(node, originalNodeUserSelect);
};
}
function setUserSelect(node, value) {
node.style.userSelect = value;
node.style.webkitUserSelect = value;
}
function isHighestLayer(instance) {
const layersArr = [...globalThis.bitsTextSelectionLayers];
if (!layersArr.length) return false;
const highestLayer = layersArr.at(-1);
if (!highestLayer) return false;
return highestLayer[0] === instance;
}
function Text_selection_layer($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
preventOverflowTextSelection = true,
onPointerDown = noop,
onPointerUp = noop,
id,
children,
enabled,
ref
} = $$props;
TextSelectionLayerState.create({
id: boxWith(() => id),
onPointerDown: boxWith(() => onPointerDown),
onPointerUp: boxWith(() => onPointerUp),
enabled: boxWith(() => enabled && preventOverflowTextSelection),
ref
});
children?.($$renderer2);
$$renderer2.push(`<!---->`);
});
}
globalThis.bitsIdCounter ??= { current: 0 };
function useId(prefix = "bits") {
globalThis.bitsIdCounter.current++;
return `${prefix}-${globalThis.bitsIdCounter.current}`;
}
class SharedState {
#factory;
#subscribers = 0;
#state;
#scope;
constructor(factory) {
this.#factory = factory;
}
#dispose() {
this.#subscribers -= 1;
if (this.#scope && this.#subscribers <= 0) {
this.#scope();
this.#state = void 0;
this.#scope = void 0;
}
}
get(...args) {
this.#subscribers += 1;
if (this.#state === void 0) {
this.#scope = () => {
};
}
return this.#state;
}
}
const lockMap = new SvelteMap();
let initialBodyStyle = null;
let cleanupTimeoutId = null;
let isInCleanupTransition = false;
const anyLocked = boxWith(() => {
for (const value of lockMap.values()) {
if (value) return true;
}
return false;
});
let cleanupScheduledAt = null;
const bodyLockStackCount = new SharedState(() => {
function resetBodyStyle() {
return;
}
function cancelPendingCleanup() {
if (cleanupTimeoutId === null) return;
window.clearTimeout(cleanupTimeoutId);
cleanupTimeoutId = null;
}
function scheduleCleanupIfNoNewLocks(delay, callback) {
cancelPendingCleanup();
isInCleanupTransition = true;
cleanupScheduledAt = Date.now();
const currentCleanupId = cleanupScheduledAt;
const cleanupFn = () => {
cleanupTimeoutId = null;
if (cleanupScheduledAt !== currentCleanupId) return;
if (!isAnyLocked(lockMap)) {
isInCleanupTransition = false;
callback();
} else {
isInCleanupTransition = false;
}
};
const actualDelay = delay === null ? 24 : delay;
cleanupTimeoutId = window.setTimeout(cleanupFn, actualDelay);
}
function ensureInitialStyleCaptured() {
if (initialBodyStyle === null && lockMap.size === 0 && !isInCleanupTransition) {
initialBodyStyle = document.body.getAttribute("style");
}
}
watch(() => anyLocked.current, () => {
if (!anyLocked.current) return;
ensureInitialStyleCaptured();
isInCleanupTransition = false;
const htmlStyle = getComputedStyle(document.documentElement);
const bodyStyle = getComputedStyle(document.body);
const hasStableGutter = htmlStyle.scrollbarGutter?.includes("stable") || bodyStyle.scrollbarGutter?.includes("stable");
const verticalScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
const paddingRight = Number.parseInt(bodyStyle.paddingRight ?? "0", 10);
const config = {
padding: paddingRight + verticalScrollbarWidth,
margin: Number.parseInt(bodyStyle.marginRight ?? "0", 10)
};
if (verticalScrollbarWidth > 0 && !hasStableGutter) {
document.body.style.paddingRight = `${config.padding}px`;
document.body.style.marginRight = `${config.margin}px`;
document.body.style.setProperty("--scrollbar-width", `${verticalScrollbarWidth}px`);
}
document.body.style.overflow = "hidden";
if (isIOS) {
on(
document,
"touchmove",
(e) => {
if (e.target !== document.documentElement) return;
if (e.touches.length > 1) return;
e.preventDefault();
},
{ passive: false }
);
}
afterTick(() => {
document.body.style.pointerEvents = "none";
document.body.style.overflow = "hidden";
});
});
return {
get lockMap() {
return lockMap;
},
resetBodyStyle,
scheduleCleanupIfNoNewLocks,
cancelPendingCleanup,
ensureInitialStyleCaptured
};
});
class BodyScrollLock {
#id = useId();
#initialState;
#restoreScrollDelay = () => null;
#countState;
locked;
constructor(initialState, restoreScrollDelay = () => null) {
this.#initialState = initialState;
this.#restoreScrollDelay = restoreScrollDelay;
this.#countState = bodyLockStackCount.get();
if (!this.#countState) return;
this.#countState.cancelPendingCleanup();
this.#countState.ensureInitialStyleCaptured();
this.#countState.lockMap.set(this.#id, this.#initialState ?? false);
this.locked = boxWith(() => this.#countState.lockMap.get(this.#id) ?? false, (v) => this.#countState.lockMap.set(this.#id, v));
}
}
function isAnyLocked(map) {
for (const [_, value] of map) {
if (value) return true;
}
return false;
}
function Scroll_lock($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { preventScroll = true, restoreScrollDelay = null } = $$props;
if (preventScroll) {
new BodyScrollLock(preventScroll, () => restoreScrollDelay);
}
});
}
const avatarAttrs = createBitsAttrs({ component: "avatar", parts: ["root", "image", "fallback"] });
const AvatarRootContext = new Context("Avatar.Root");
class AvatarRootState {
static create(opts) {
return AvatarRootContext.set(new AvatarRootState(opts));
}
opts;
domContext;
attachment;
constructor(opts) {
this.opts = opts;
this.domContext = new DOMContext(this.opts.ref);
this.loadImage = this.loadImage.bind(this);
this.attachment = attachRef(this.opts.ref);
}
loadImage(src, crossorigin, referrerPolicy) {
if (this.opts.loadingStatus.current === "loaded") return;
let imageTimerId;
const image = new Image();
image.src = src;
if (crossorigin !== void 0) image.crossOrigin = crossorigin;
if (referrerPolicy) image.referrerPolicy = referrerPolicy;
this.opts.loadingStatus.current = "loading";
image.onload = () => {
imageTimerId = this.domContext.setTimeout(
() => {
this.opts.loadingStatus.current = "loaded";
},
this.opts.delayMs.current
);
};
image.onerror = () => {
this.opts.loadingStatus.current = "error";
};
return () => {
if (!imageTimerId) return;
this.domContext.clearTimeout(imageTimerId);
};
}
#props = derived(() => ({
id: this.opts.id.current,
[avatarAttrs.root]: "",
"data-status": this.opts.loadingStatus.current,
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
class AvatarFallbackState {
static create(opts) {
return new AvatarFallbackState(opts, AvatarRootContext.get());
}
opts;
root;
attachment;
constructor(opts, root) {
this.opts = opts;
this.root = root;
this.attachment = attachRef(this.opts.ref);
}
#style = derived(() => this.root.opts.loadingStatus.current === "loaded" ? { display: "none" } : void 0);
get style() {
return this.#style();
}
set style($$value) {
return this.#style($$value);
}
#props = derived(() => ({
style: this.style,
"data-status": this.root.opts.loadingStatus.current,
[avatarAttrs.fallback]: "",
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
function Avatar$1($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
delayMs = 0,
loadingStatus = "loading",
onLoadingStatusChange,
child,
children,
id = createId(uid),
ref = null,
$$slots,
$$events,
...restProps
} = $$props;
const rootState = AvatarRootState.create({
delayMs: boxWith(() => delayMs),
loadingStatus: boxWith(() => loadingStatus, (v) => {
if (loadingStatus !== v) {
loadingStatus = v;
onLoadingStatusChange?.(v);
}
}),
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, rootState.props);
if (child) {
$$renderer2.push("<!--[-->");
child($$renderer2, { props: mergedProps });
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<div${attributes({ ...mergedProps })}>`);
children?.($$renderer2);
$$renderer2.push(`<!----></div>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { loadingStatus, ref });
});
}
function Avatar_fallback$1($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
children,
child,
id = createId(uid),
ref = null,
$$slots,
$$events,
...restProps
} = $$props;
const fallbackState = AvatarFallbackState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, fallbackState.props);
if (child) {
$$renderer2.push("<!--[-->");
child($$renderer2, { props: mergedProps });
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<span${attributes({ ...mergedProps })}>`);
children?.($$renderer2);
$$renderer2.push(`<!----></span>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { ref });
});
}
function Hidden_input($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { value = void 0, $$slots, $$events, ...restProps } = $$props;
const mergedProps = mergeProps(restProps, {
"aria-hidden": "true",
tabindex: -1,
style: srOnlyStylesString
});
if (mergedProps.type === "checkbox") {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<input${attributes({ ...mergedProps, value }, void 0, void 0, void 0, 4)}/>`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<input${attributes({ value, ...mergedProps }, void 0, void 0, void 0, 4)}/>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { value });
});
}
function get(valueOrGetValue) {
return typeof valueOrGetValue === "function" ? valueOrGetValue() : valueOrGetValue;
}
function getDPR(element) {
if (typeof window === "undefined") return 1;
const win = element.ownerDocument.defaultView || window;
return win.devicePixelRatio || 1;
}
function roundByDPR(element, value) {
const dpr = getDPR(element);
return Math.round(value * dpr) / dpr;
}
function getFloatingContentCSSVars(name) {
return {
[`--bits-${name}-content-transform-origin`]: `var(--bits-floating-transform-origin)`,
[`--bits-${name}-content-available-width`]: `var(--bits-floating-available-width)`,
[`--bits-${name}-content-available-height`]: `var(--bits-floating-available-height)`,
[`--bits-${name}-anchor-width`]: `var(--bits-floating-anchor-width)`,
[`--bits-${name}-anchor-height`]: `var(--bits-floating-anchor-height)`
};
}
function useFloating(options) {
const openOption = get(options.open) ?? true;
const middlewareOption = get(options.middleware);
const transformOption = get(options.transform) ?? true;
const placementOption = get(options.placement) ?? "bottom";
const strategyOption = get(options.strategy) ?? "absolute";
const sideOffsetOption = get(options.sideOffset) ?? 0;
const alignOffsetOption = get(options.alignOffset) ?? 0;
const reference = options.reference;
let x = 0;
let y = 0;
const floating = simpleBox(null);
let strategy = strategyOption;
let placement = placementOption;
let middlewareData = {};
let isPositioned = false;
const floatingStyles = (() => {
const xVal = floating.current ? roundByDPR(floating.current, x) : x;
const yVal = floating.current ? roundByDPR(floating.current, y) : y;
if (transformOption) {
return {
position: strategy,
left: "0",
top: "0",
transform: `translate(${xVal}px, ${yVal}px)`,
...floating.current && getDPR(floating.current) >= 1.5 && { willChange: "transform" }
};
}
return { position: strategy, left: `${xVal}px`, top: `${yVal}px` };
})();
function update() {
if (reference.current === null || floating.current === null) return;
computePosition(reference.current, floating.current, {
middleware: middlewareOption,
placement: placementOption,
strategy: strategyOption
}).then((position) => {
if (!openOption && x !== 0 && y !== 0) {
const maxExpectedOffset = Math.max(Math.abs(sideOffsetOption), Math.abs(alignOffsetOption), 15);
if (position.x <= maxExpectedOffset && position.y <= maxExpectedOffset) return;
}
x = position.x;
y = position.y;
strategy = position.strategy;
placement = position.placement;
middlewareData = position.middlewareData;
isPositioned = true;
});
}
return {
floating,
reference,
get strategy() {
return strategy;
},
get placement() {
return placement;
},
get middlewareData() {
return middlewareData;
},
get isPositioned() {
return isPositioned;
},
get floatingStyles() {
return floatingStyles;
},
get update() {
return update;
}
};
}
const OPPOSITE_SIDE = { top: "bottom", right: "left", bottom: "top", left: "right" };
const FloatingRootContext = new Context("Floating.Root");
const FloatingContentContext = new Context("Floating.Content");
const FloatingTooltipRootContext = new Context("Floating.Root");
class FloatingRootState {
static create(tooltip = false) {
return tooltip ? FloatingTooltipRootContext.set(new FloatingRootState()) : FloatingRootContext.set(new FloatingRootState());
}
anchorNode = simpleBox(null);
customAnchorNode = simpleBox(null);
triggerNode = simpleBox(null);
constructor() {
}
}
class FloatingContentState {
static create(opts, tooltip = false) {
return tooltip ? FloatingContentContext.set(new FloatingContentState(opts, FloatingTooltipRootContext.get())) : FloatingContentContext.set(new FloatingContentState(opts, FloatingRootContext.get()));
}
opts;
root;
// nodes
contentRef = simpleBox(null);
wrapperRef = simpleBox(null);
arrowRef = simpleBox(null);
contentAttachment = attachRef(this.contentRef);
wrapperAttachment = attachRef(this.wrapperRef);
arrowAttachment = attachRef(this.arrowRef);
// ids
arrowId = simpleBox(useId());
#transformedStyle = derived(() => {
if (typeof this.opts.style === "string") return cssToStyleObj(this.opts.style);
if (!this.opts.style) return {};
});
#updatePositionStrategy = void 0;
#arrowSize = new ElementSize(() => this.arrowRef.current ?? void 0);
#arrowWidth = derived(() => this.#arrowSize?.width ?? 0);
#arrowHeight = derived(() => this.#arrowSize?.height ?? 0);
#desiredPlacement = derived(() => this.opts.side?.current + (this.opts.align.current !== "center" ? `-${this.opts.align.current}` : ""));
#boundary = derived(() => Array.isArray(this.opts.collisionBoundary.current) ? this.opts.collisionBoundary.current : [this.opts.collisionBoundary.current]);
#hasExplicitBoundaries = derived(() => this.#boundary().length > 0);
get hasExplicitBoundaries() {
return this.#hasExplicitBoundaries();
}
set hasExplicitBoundaries($$value) {
return this.#hasExplicitBoundaries($$value);
}
#detectOverflowOptions = derived(() => ({
padding: this.opts.collisionPadding.current,
boundary: this.#boundary().filter(isNotNull),
altBoundary: this.hasExplicitBoundaries
}));
get detectOverflowOptions() {
return this.#detectOverflowOptions();
}
set detectOverflowOptions($$value) {
return this.#detectOverflowOptions($$value);
}
#availableWidth = void 0;
#availableHeight = void 0;
#anchorWidth = void 0;
#anchorHeight = void 0;
#middleware = derived(() => [
offset({
mainAxis: this.opts.sideOffset.current + this.#arrowHeight(),
alignmentAxis: this.opts.alignOffset.current
}),
this.opts.avoidCollisions.current && shift({
mainAxis: true,
crossAxis: false,
limiter: this.opts.sticky.current === "partial" ? limitShift() : void 0,
...this.detectOverflowOptions
}),
this.opts.avoidCollisions.current && flip({ ...this.detectOverflowOptions }),
size({
...this.detectOverflowOptions,
apply: ({ rects, availableWidth, availableHeight }) => {
const { width: anchorWidth, height: anchorHeight } = rects.reference;
this.#availableWidth = availableWidth;
this.#availableHeight = availableHeight;
this.#anchorWidth = anchorWidth;
this.#anchorHeight = anchorHeight;
}
}),
this.arrowRef.current && arrow({
element: this.arrowRef.current,
padding: this.opts.arrowPadding.current
}),
transformOrigin({
arrowWidth: this.#arrowWidth(),
arrowHeight: this.#arrowHeight()
}),
this.opts.hideWhenDetached.current && hide({ strategy: "referenceHidden", ...this.detectOverflowOptions })
].filter(Boolean));
get middleware() {
return this.#middleware();
}
set middleware($$value) {
return this.#middleware($$value);
}
floating;
#placedSide = derived(() => getSideFromPlacement(this.floating.placement));
get placedSide() {
return this.#placedSide();
}
set placedSide($$value) {
return this.#placedSide($$value);
}
#placedAlign = derived(() => getAlignFromPlacement(this.floating.placement));
get placedAlign() {
return this.#placedAlign();
}
set placedAlign($$value) {
return this.#placedAlign($$value);
}
#arrowX = derived(() => this.floating.middlewareData.arrow?.x ?? 0);
get arrowX() {
return this.#arrowX();
}
set arrowX($$value) {
return this.#arrowX($$value);
}
#arrowY = derived(() => this.floating.middlewareData.arrow?.y ?? 0);
get arrowY() {
return this.#arrowY();
}
set arrowY($$value) {
return this.#arrowY($$value);
}
#cannotCenterArrow = derived(() => this.floating.middlewareData.arrow?.centerOffset !== 0);
get cannotCenterArrow() {
return this.#cannotCenterArrow();
}
set cannotCenterArrow($$value) {
return this.#cannotCenterArrow($$value);
}
contentZIndex;
#arrowBaseSide = derived(() => OPPOSITE_SIDE[this.placedSide]);
get arrowBaseSide() {
return this.#arrowBaseSide();
}
set arrowBaseSide($$value) {
return this.#arrowBaseSide($$value);
}
#wrapperProps = derived(() => ({
id: this.opts.wrapperId.current,
"data-bits-floating-content-wrapper": "",
style: {
...this.floating.floatingStyles,
transform: this.floating.isPositioned ? this.floating.floatingStyles.transform : "translate(0, -200%)",
minWidth: "max-content",
zIndex: this.contentZIndex,
"--bits-floating-transform-origin": `${this.floating.middlewareData.transformOrigin?.x} ${this.floating.middlewareData.transformOrigin?.y}`,
"--bits-floating-available-width": `${this.#availableWidth}px`,
"--bits-floating-available-height": `${this.#availableHeight}px`,
"--bits-floating-anchor-width": `${this.#anchorWidth}px`,
"--bits-floating-anchor-height": `${this.#anchorHeight}px`,
...this.floating.middlewareData.hide?.referenceHidden && { visibility: "hidden", "pointer-events": "none" },
...this.#transformedStyle()
},
dir: this.opts.dir.current,
...this.wrapperAttachment
}));
get wrapperProps() {
return this.#wrapperProps();
}
set wrapperProps($$value) {
return this.#wrapperProps($$value);
}
#props = derived(() => ({
"data-side": this.placedSide,
"data-align": this.placedAlign,
style: styleToString({ ...this.#transformedStyle() }),
...this.contentAttachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
#arrowStyle = derived(() => ({
position: "absolute",
left: this.arrowX ? `${this.arrowX}px` : void 0,
top: this.arrowY ? `${this.arrowY}px` : void 0,
[this.arrowBaseSide]: 0,
"transform-origin": { top: "", right: "0 0", bottom: "center 0", left: "100% 0" }[this.placedSide],
transform: {
top: "translateY(100%)",
right: "translateY(50%) rotate(90deg) translateX(-50%)",
bottom: "rotate(180deg)",
left: "translateY(50%) rotate(-90deg) translateX(50%)"
}[this.placedSide],
visibility: this.cannotCenterArrow ? "hidden" : void 0
}));
get arrowStyle() {
return this.#arrowStyle();
}
set arrowStyle($$value) {
return this.#arrowStyle($$value);
}
constructor(opts, root) {
this.opts = opts;
this.root = root;
this.#updatePositionStrategy = opts.updatePositionStrategy;
if (opts.customAnchor) {
this.root.customAnchorNode.current = opts.customAnchor.current;
}
watch(() => opts.customAnchor.current, (customAnchor) => {
this.root.customAnchorNode.current = customAnchor;
});
this.floating = useFloating({
strategy: () => this.opts.strategy.current,
placement: () => this.#desiredPlacement(),
middleware: () => this.middleware,
reference: this.root.anchorNode,
open: () => this.opts.enabled.current,
sideOffset: () => this.opts.sideOffset.current,
alignOffset: () => this.opts.alignOffset.current
});
watch(() => this.contentRef.current, (contentNode) => {
if (!contentNode || !this.opts.enabled.current) return;
const win = getWindow(contentNode);
const rafId = win.requestAnimationFrame(() => {
if (this.contentRef.current !== contentNode || !this.opts.enabled.current) return;
const zIndex = win.getComputedStyle(contentNode).zIndex;
if (zIndex !== this.contentZIndex) {
this.contentZIndex = zIndex;
}
});
return () => {
win.cancelAnimationFrame(rafId);
};
});
}
}
class FloatingAnchorState {
static create(opts, tooltip = false) {
return tooltip ? new FloatingAnchorState(opts, FloatingTooltipRootContext.get()) : new FloatingAnchorState(opts, FloatingRootContext.get());
}
opts;
root;
constructor(opts, root) {
this.opts = opts;
this.root = root;
if (opts.virtualEl && opts.virtualEl.current) {
root.triggerNode = boxFrom(opts.virtualEl.current);
} else {
root.triggerNode = opts.ref;
}
}
}
function transformOrigin(options) {
return {
name: "transformOrigin",
options,
fn(data) {
const { placement, rects, middlewareData } = data;
const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;
const isArrowHidden = cannotCenterArrow;
const arrowWidth = isArrowHidden ? 0 : options.arrowWidth;
const arrowHeight = isArrowHidden ? 0 : options.arrowHeight;
const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
const noArrowAlign = { start: "0%", center: "50%", end: "100%" }[placedAlign];
const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2;
const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2;
let x = "";
let y = "";
if (placedSide === "bottom") {
x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
y = `${-arrowHeight}px`;
} else if (placedSide === "top") {
x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
y = `${rects.floating.height + arrowHeight}px`;
} else if (placedSide === "right") {
x = `${-arrowHeight}px`;
y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
} else if (placedSide === "left") {
x = `${rects.floating.width + arrowHeight}px`;
y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
}
return { data: { x, y } };
}
};
}
function getSideAndAlignFromPlacement(placement) {
const [side, align = "center"] = placement.split("-");
return [side, align];
}
function getSideFromPlacement(placement) {
return getSideAndAlignFromPlacement(placement)[0];
}
function getAlignFromPlacement(placement) {
return getSideAndAlignFromPlacement(placement)[1];
}
function Floating_layer($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { children, tooltip = false } = $$props;
FloatingRootState.create(tooltip);
children?.($$renderer2);
$$renderer2.push(`<!---->`);
});
}
function Floating_layer_anchor($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { id, children, virtualEl, ref, tooltip = false } = $$props;
FloatingAnchorState.create(
{
id: boxWith(() => id),
virtualEl: boxWith(() => virtualEl),
ref
},
tooltip
);
children?.($$renderer2);
$$renderer2.push(`<!---->`);
});
}
function Floating_layer_content($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
content,
side = "bottom",
sideOffset = 0,
align = "center",
alignOffset = 0,
id,
arrowPadding = 0,
avoidCollisions = true,
collisionBoundary = [],
collisionPadding = 0,
hideWhenDetached = false,
onPlaced = () => {
},
sticky = "partial",
updatePositionStrategy = "optimized",
strategy = "fixed",
dir = "ltr",
style = {},
wrapperId = useId(),
customAnchor = null,
enabled,
tooltip = false
} = $$props;
const contentState = FloatingContentState.create(
{
side: boxWith(() => side),
sideOffset: boxWith(() => sideOffset),
align: boxWith(() => align),
alignOffset: boxWith(() => alignOffset),
id: boxWith(() => id),
arrowPadding: boxWith(() => arrowPadding),
avoidCollisions: boxWith(() => avoidCollisions),
collisionBoundary: boxWith(() => collisionBoundary),
collisionPadding: boxWith(() => collisionPadding),
hideWhenDetached: boxWith(() => hideWhenDetached),
onPlaced: boxWith(() => onPlaced),
sticky: boxWith(() => sticky),
updatePositionStrategy: boxWith(() => updatePositionStrategy),
strategy: boxWith(() => strategy),
dir: boxWith(() => dir),
style: boxWith(() => style),
enabled: boxWith(() => enabled),
wrapperId: boxWith(() => wrapperId),
customAnchor: boxWith(() => customAnchor)
},
tooltip
);
const mergedProps = mergeProps(contentState.wrapperProps, { style: { pointerEvents: "auto" } });
content?.($$renderer2, { props: contentState.props, wrapperProps: mergedProps });
$$renderer2.push(`<!---->`);
});
}
function Floating_layer_content_static($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { content } = $$props;
content?.($$renderer2, { props: {}, wrapperProps: {} });
$$renderer2.push(`<!---->`);
});
}
function Popper_content($$renderer, $$props) {
let {
content,
isStatic = false,
onPlaced,
$$slots,
$$events,
...restProps
} = $$props;
if (isStatic) {
$$renderer.push("<!--[-->");
Floating_layer_content_static($$renderer, { content });
} else {
$$renderer.push("<!--[!-->");
Floating_layer_content($$renderer, spread_props([{ content, onPlaced }, restProps]));
}
$$renderer.push(`<!--]-->`);
}
function Popper_layer_inner($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
popper,
onEscapeKeydown,
escapeKeydownBehavior,
preventOverflowTextSelection,
id,
onPointerDown,
onPointerUp,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
preventScroll,
wrapperId,
style,
onPlaced,
onInteractOutside,
onCloseAutoFocus,
onOpenAutoFocus,
onFocusOutside,
interactOutsideBehavior = "close",
loop,
trapFocus = true,
isValidEvent: isValidEvent2 = () => false,
customAnchor = null,
isStatic = false,
enabled,
ref,
tooltip = false,
contentPointerEvents = "auto",
$$slots,
$$events,
...restProps
} = $$props;
{
let content = function($$renderer3, { props: floatingProps, wrapperProps }) {
if (restProps.forceMount && enabled) {
$$renderer3.push("<!--[-->");
Scroll_lock($$renderer3, { preventScroll });
} else if (!restProps.forceMount) {
$$renderer3.push("<!--[1-->");
Scroll_lock($$renderer3, { preventScroll });
} else {
$$renderer3.push("<!--[!-->");
}
$$renderer3.push(`<!--]--> `);
{
let focusScope = function($$renderer4, { props: focusScopeProps }) {
Escape_layer($$renderer4, {
onEscapeKeydown,
escapeKeydownBehavior,
enabled,
ref,
children: ($$renderer5) => {
{
let children = function($$renderer6, { props: dismissibleProps }) {
Text_selection_layer($$renderer6, {
id,
preventOverflowTextSelection,
onPointerDown,
onPointerUp,
enabled,
ref,
children: ($$renderer7) => {
popper?.($$renderer7, {
props: mergeProps(restProps, floatingProps, dismissibleProps, focusScopeProps, { style: { pointerEvents: contentPointerEvents } }),
wrapperProps
});
$$renderer7.push(`<!---->`);
}
});
};
Dismissible_layer($$renderer5, {
id,
onInteractOutside,
onFocusOutside,
interactOutsideBehavior,
isValidEvent: isValidEvent2,
enabled,
ref,
children
});
}
}
});
};
Focus_scope($$renderer3, {
onOpenAutoFocus,
onCloseAutoFocus,
loop,
enabled,
trapFocus,
forceMount: restProps.forceMount,
ref,
focusScope
});
}
$$renderer3.push(`<!---->`);
};
Popper_content($$renderer2, {
isStatic,
id,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
wrapperId,
style,
onPlaced,
customAnchor,
enabled,
tooltip,
content,
$$slots: { content: true }
});
}
});
}
function Popper_layer($$renderer, $$props) {
let {
popper,
open,
onEscapeKeydown,
escapeKeydownBehavior,
preventOverflowTextSelection,
id,
onPointerDown,
onPointerUp,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
preventScroll,
wrapperId,
style,
onPlaced,
onInteractOutside,
onCloseAutoFocus,
onOpenAutoFocus,
onFocusOutside,
interactOutsideBehavior = "close",
loop,
trapFocus = true,
isValidEvent: isValidEvent2 = () => false,
customAnchor = null,
isStatic = false,
ref,
shouldRender,
$$slots,
$$events,
...restProps
} = $$props;
if (shouldRender) {
$$renderer.push("<!--[-->");
Popper_layer_inner($$renderer, spread_props([
{
popper,
onEscapeKeydown,
escapeKeydownBehavior,
preventOverflowTextSelection,
id,
onPointerDown,
onPointerUp,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
preventScroll,
wrapperId,
style,
onPlaced,
customAnchor,
isStatic,
enabled: open,
onInteractOutside,
onCloseAutoFocus,
onOpenAutoFocus,
interactOutsideBehavior,
loop,
trapFocus,
isValidEvent: isValidEvent2,
onFocusOutside,
forceMount: false,
ref
},
restProps
]));
} else {
$$renderer.push("<!--[!-->");
}
$$renderer.push(`<!--]-->`);
}
function Popper_layer_force_mount($$renderer, $$props) {
let {
popper,
onEscapeKeydown,
escapeKeydownBehavior,
preventOverflowTextSelection,
id,
onPointerDown,
onPointerUp,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
preventScroll,
wrapperId,
style,
onPlaced,
onInteractOutside,
onCloseAutoFocus,
onOpenAutoFocus,
onFocusOutside,
interactOutsideBehavior = "close",
loop,
trapFocus = true,
isValidEvent: isValidEvent2 = () => false,
customAnchor = null,
isStatic = false,
enabled,
$$slots,
$$events,
...restProps
} = $$props;
Popper_layer_inner($$renderer, spread_props([
{
popper,
onEscapeKeydown,
escapeKeydownBehavior,
preventOverflowTextSelection,
id,
onPointerDown,
onPointerUp,
side,
sideOffset,
align,
alignOffset,
arrowPadding,
avoidCollisions,
collisionBoundary,
collisionPadding,
sticky,
hideWhenDetached,
updatePositionStrategy,
strategy,
dir,
preventScroll,
wrapperId,
style,
onPlaced,
customAnchor,
isStatic,
enabled,
onInteractOutside,
onCloseAutoFocus,
onOpenAutoFocus,
interactOutsideBehavior,
loop,
trapFocus,
isValidEvent: isValidEvent2,
onFocusOutside
},
restProps,
{ forceMount: true }
]));
}
function Menu_separator($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
ref = null,
id = createId(uid),
child,
children,
$$slots,
$$events,
...restProps
} = $$props;
const separatorState = MenuSeparatorState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, separatorState.props);
if (child) {
$$renderer2.push("<!--[-->");
child($$renderer2, { props: mergedProps });
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<div${attributes({ ...mergedProps })}>`);
children?.($$renderer2);
$$renderer2.push(`<!----></div>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { ref });
});
}
function Menu($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
open = false,
dir = "ltr",
onOpenChange = noop,
onOpenChangeComplete = noop,
_internal_variant: variant = "dropdown-menu",
children
} = $$props;
const root = MenuRootState.create({
variant: boxWith(() => variant),
dir: boxWith(() => dir),
onClose: () => {
open = false;
onOpenChange(false);
}
});
MenuMenuState.create(
{
open: boxWith(() => open, (v) => {
open = v;
onOpenChange(v);
}),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete)
},
root
);
Floating_layer($$renderer2, {
children: ($$renderer3) => {
children?.($$renderer3);
$$renderer3.push(`<!---->`);
}
});
bind_props($$props, { open });
});
}
function Dropdown_menu_content$1($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
id = createId(uid),
child,
children,
ref = null,
loop = true,
onInteractOutside = noop,
onEscapeKeydown = noop,
onCloseAutoFocus = noop,
forceMount = false,
trapFocus = false,
style,
$$slots,
$$events,
...restProps
} = $$props;
const contentState = MenuContentState.create({
id: boxWith(() => id),
loop: boxWith(() => loop),
ref: boxWith(() => ref, (v) => ref = v),
onCloseAutoFocus: boxWith(() => onCloseAutoFocus)
});
const mergedProps = mergeProps(restProps, contentState.props);
function handleInteractOutside(e) {
contentState.handleInteractOutside(e);
if (e.defaultPrevented) return;
onInteractOutside(e);
if (e.defaultPrevented) return;
if (e.target && e.target instanceof Element) {
const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr("sub-content")}]`;
if (e.target.closest(subContentSelector)) return;
}
contentState.parentMenu.onClose();
}
function handleEscapeKeydown(e) {
onEscapeKeydown(e);
if (e.defaultPrevented) return;
contentState.parentMenu.onClose();
}
if (forceMount) {
$$renderer2.push("<!--[-->");
{
let popper = function($$renderer3, { props, wrapperProps }) {
const finalProps = mergeProps(props, { style: getFloatingContentCSSVars("dropdown-menu") }, { style });
if (child) {
$$renderer3.push("<!--[-->");
child($$renderer3, {
props: finalProps,
wrapperProps,
...contentState.snippetProps
});
$$renderer3.push(`<!---->`);
} else {
$$renderer3.push("<!--[!-->");
$$renderer3.push(`<div${attributes({ ...wrapperProps })}><div${attributes({ ...finalProps })}>`);
children?.($$renderer3);
$$renderer3.push(`<!----></div></div>`);
}
$$renderer3.push(`<!--]-->`);
};
Popper_layer_force_mount($$renderer2, spread_props([
mergedProps,
contentState.popperProps,
{
ref: contentState.opts.ref,
enabled: contentState.parentMenu.opts.open.current,
onInteractOutside: handleInteractOutside,
onEscapeKeydown: handleEscapeKeydown,
trapFocus,
loop,
forceMount: true,
id,
shouldRender: contentState.shouldRender,
popper,
$$slots: { popper: true }
}
]));
}
} else if (!forceMount) {
$$renderer2.push("<!--[1-->");
{
let popper = function($$renderer3, { props, wrapperProps }) {
const finalProps = mergeProps(props, { style: getFloatingContentCSSVars("dropdown-menu") }, { style });
if (child) {
$$renderer3.push("<!--[-->");
child($$renderer3, {
props: finalProps,
wrapperProps,
...contentState.snippetProps
});
$$renderer3.push(`<!---->`);
} else {
$$renderer3.push("<!--[!-->");
$$renderer3.push(`<div${attributes({ ...wrapperProps })}><div${attributes({ ...finalProps })}>`);
children?.($$renderer3);
$$renderer3.push(`<!----></div></div>`);
}
$$renderer3.push(`<!--]-->`);
};
Popper_layer($$renderer2, spread_props([
mergedProps,
contentState.popperProps,
{
ref: contentState.opts.ref,
open: contentState.parentMenu.opts.open.current,
onInteractOutside: handleInteractOutside,
onEscapeKeydown: handleEscapeKeydown,
trapFocus,
loop,
forceMount: false,
id,
shouldRender: contentState.shouldRender,
popper,
$$slots: { popper: true }
}
]));
}
} else {
$$renderer2.push("<!--[!-->");
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { ref });
});
}
function Menu_trigger($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
id = createId(uid),
ref = null,
child,
children,
disabled = false,
type = "button",
$$slots,
$$events,
...restProps
} = $$props;
const triggerState = DropdownMenuTriggerState.create({
id: boxWith(() => id),
disabled: boxWith(() => disabled ?? false),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, triggerState.props, { type });
Floating_layer_anchor($$renderer2, {
id,
ref: triggerState.opts.ref,
children: ($$renderer3) => {
if (child) {
$$renderer3.push("<!--[-->");
child($$renderer3, { props: mergedProps });
$$renderer3.push(`<!---->`);
} else {
$$renderer3.push("<!--[!-->");
$$renderer3.push(`<button${attributes({ ...mergedProps })}>`);
children?.($$renderer3);
$$renderer3.push(`<!----></button>`);
}
$$renderer3.push(`<!--]-->`);
}
});
bind_props($$props, { ref });
});
}
const switchAttrs = createBitsAttrs({ component: "switch", parts: ["root", "thumb"] });
const SwitchRootContext = new Context("Switch.Root");
class SwitchRootState {
static create(opts) {
return SwitchRootContext.set(new SwitchRootState(opts));
}
opts;
attachment;
constructor(opts) {
this.opts = opts;
this.attachment = attachRef(opts.ref);
this.onkeydown = this.onkeydown.bind(this);
this.onclick = this.onclick.bind(this);
}
#toggle() {
this.opts.checked.current = !this.opts.checked.current;
}
onkeydown(e) {
if (!(e.key === ENTER || e.key === SPACE) || this.opts.disabled.current) return;
e.preventDefault();
this.#toggle();
}
onclick(_) {
if (this.opts.disabled.current) return;
this.#toggle();
}
#sharedProps = derived(() => ({
"data-disabled": boolToEmptyStrOrUndef(this.opts.disabled.current),
"data-state": getDataChecked(this.opts.checked.current),
"data-required": boolToEmptyStrOrUndef(this.opts.required.current)
}));
get sharedProps() {
return this.#sharedProps();
}
set sharedProps($$value) {
return this.#sharedProps($$value);
}
#snippetProps = derived(() => ({ checked: this.opts.checked.current }));
get snippetProps() {
return this.#snippetProps();
}
set snippetProps($$value) {
return this.#snippetProps($$value);
}
#props = derived(() => ({
...this.sharedProps,
id: this.opts.id.current,
role: "switch",
disabled: boolToTrueOrUndef(this.opts.disabled.current),
"aria-checked": getAriaChecked(this.opts.checked.current),
"aria-required": boolToStr(this.opts.required.current),
[switchAttrs.root]: "",
onclick: this.onclick,
onkeydown: this.onkeydown,
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
class SwitchInputState {
static create() {
return new SwitchInputState(SwitchRootContext.get());
}
root;
#shouldRender = derived(() => this.root.opts.name.current !== void 0);
get shouldRender() {
return this.#shouldRender();
}
set shouldRender($$value) {
return this.#shouldRender($$value);
}
constructor(root) {
this.root = root;
}
#props = derived(() => ({
type: "checkbox",
name: this.root.opts.name.current,
value: this.root.opts.value.current,
checked: this.root.opts.checked.current,
disabled: this.root.opts.disabled.current,
required: this.root.opts.required.current
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
class SwitchThumbState {
static create(opts) {
return new SwitchThumbState(opts, SwitchRootContext.get());
}
opts;
root;
attachment;
constructor(opts, root) {
this.opts = opts;
this.root = root;
this.attachment = attachRef(opts.ref);
}
#snippetProps = derived(() => ({ checked: this.root.opts.checked.current }));
get snippetProps() {
return this.#snippetProps();
}
set snippetProps($$value) {
return this.#snippetProps($$value);
}
#props = derived(() => ({
...this.root.sharedProps,
id: this.opts.id.current,
[switchAttrs.thumb]: "",
...this.attachment
}));
get props() {
return this.#props();
}
set props($$value) {
return this.#props($$value);
}
}
function Switch_input($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const inputState = SwitchInputState.create();
if (inputState.shouldRender) {
$$renderer2.push("<!--[-->");
Hidden_input($$renderer2, spread_props([inputState.props]));
} else {
$$renderer2.push("<!--[!-->");
}
$$renderer2.push(`<!--]-->`);
});
}
function Switch$1($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
child,
children,
ref = null,
id = createId(uid),
disabled = false,
required = false,
checked = false,
value = "on",
name = void 0,
type = "button",
onCheckedChange = noop,
$$slots,
$$events,
...restProps
} = $$props;
const rootState = SwitchRootState.create({
checked: boxWith(() => checked, (v) => {
checked = v;
onCheckedChange?.(v);
}),
disabled: boxWith(() => disabled ?? false),
required: boxWith(() => required),
value: boxWith(() => value),
name: boxWith(() => name),
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, rootState.props, { type });
if (child) {
$$renderer2.push("<!--[-->");
child($$renderer2, { props: mergedProps, ...rootState.snippetProps });
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<button${attributes({ ...mergedProps })}>`);
children?.($$renderer2, rootState.snippetProps);
$$renderer2.push(`<!----></button>`);
}
$$renderer2.push(`<!--]--> `);
Switch_input($$renderer2);
$$renderer2.push(`<!---->`);
bind_props($$props, { ref, checked });
});
}
function Switch_thumb($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
const uid = props_id($$renderer2);
let {
child,
children,
ref = null,
id = createId(uid),
$$slots,
$$events,
...restProps
} = $$props;
const thumbState = SwitchThumbState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => ref = v)
});
const mergedProps = mergeProps(restProps, thumbState.props);
if (child) {
$$renderer2.push("<!--[-->");
child($$renderer2, { props: mergedProps, ...thumbState.snippetProps });
$$renderer2.push(`<!---->`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<span${attributes({ ...mergedProps })}>`);
children?.($$renderer2, thumbState.snippetProps);
$$renderer2.push(`<!----></span>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { ref });
});
}
function Avatar($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
loadingStatus = "loading",
class: className,
$$slots,
$$events,
...restProps
} = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Avatar$1?.($$renderer3, spread_props([
{
"data-slot": "avatar",
class: cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)
},
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
},
get loadingStatus() {
return loadingStatus;
},
set loadingStatus($$value) {
loadingStatus = $$value;
$$settled = false;
}
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref, loadingStatus });
});
}
function Avatar_fallback($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
class: className,
$$slots,
$$events,
...restProps
} = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Avatar_fallback$1?.($$renderer3, spread_props([
{
"data-slot": "avatar-fallback",
class: cn("bg-muted flex size-full items-center justify-center rounded-full", className)
},
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
}
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref });
});
}
function Dropdown_menu($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { open = false, $$slots, $$events, ...restProps } = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Menu?.($$renderer3, spread_props([
restProps,
{
get open() {
return open;
},
set open($$value) {
open = $$value;
$$settled = false;
}
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { open });
});
}
function Dropdown_menu_portal($$renderer, $$props) {
let { $$slots, $$events, ...restProps } = $$props;
$$renderer.push("<!---->");
Portal?.($$renderer, spread_props([restProps]));
$$renderer.push(`<!---->`);
}
function Dropdown_menu_content($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
sideOffset = 4,
portalProps,
class: className,
$$slots,
$$events,
...restProps
} = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
Dropdown_menu_portal($$renderer3, spread_props([
portalProps,
{
children: ($$renderer4) => {
$$renderer4.push("<!---->");
Dropdown_menu_content$1?.($$renderer4, spread_props([
{
"data-slot": "dropdown-menu-content",
sideOffset,
class: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--bits-dropdown-menu-content-available-height) min-w-[8rem] origin-(--bits-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md outline-none", className)
},
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
}
}
]));
$$renderer4.push(`<!---->`);
},
$$slots: { default: true }
}
]));
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref });
});
}
function Dropdown_menu_separator($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
class: className,
$$slots,
$$events,
...restProps
} = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Menu_separator?.($$renderer3, spread_props([
{
"data-slot": "dropdown-menu-separator",
class: cn("bg-border -mx-1 my-1 h-px", className)
},
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
}
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref });
});
}
function Dropdown_menu_trigger($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { ref = null, $$slots, $$events, ...restProps } = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Menu_trigger?.($$renderer3, spread_props([
{ "data-slot": "dropdown-menu-trigger" },
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
}
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref });
});
}
function Switch($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
class: className,
checked = false,
$$slots,
$$events,
...restProps
} = $$props;
let $$settled = true;
let $$inner_renderer;
function $$render_inner($$renderer3) {
$$renderer3.push("<!---->");
Switch$1?.($$renderer3, spread_props([
{
"data-slot": "switch",
class: cn("data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className)
},
restProps,
{
get ref() {
return ref;
},
set ref($$value) {
ref = $$value;
$$settled = false;
},
get checked() {
return checked;
},
set checked($$value) {
checked = $$value;
$$settled = false;
},
children: ($$renderer4) => {
$$renderer4.push("<!---->");
Switch_thumb?.($$renderer4, {
"data-slot": "switch-thumb",
class: cn("bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0")
});
$$renderer4.push(`<!---->`);
},
$$slots: { default: true }
}
]));
$$renderer3.push(`<!---->`);
}
do {
$$settled = true;
$$inner_renderer = $$renderer2.copy();
$$render_inner($$inner_renderer);
} while (!$$settled);
$$renderer2.subsume($$inner_renderer);
bind_props($$props, { ref, checked });
});
}
function _layout($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data, children } = $$props;
let darkmode = false;
let onDarkmodeChange = () => {
};
$$renderer2.push(`<div class="app-shell">`);
if (data.user) {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<header class="flex items-center justify-between w-full"><h1 class="text-lg font-semibold">Base</h1> `);
$$renderer2.push("<!---->");
Dropdown_menu?.($$renderer2, {
children: ($$renderer3) => {
$$renderer3.push("<!---->");
Dropdown_menu_trigger?.($$renderer3, {
class: "rounded-full border border-input bg-background hover:bg-accent",
onclick: (e) => e.preventDefault(),
children: ($$renderer4) => {
$$renderer4.push("<!---->");
Avatar?.($$renderer4, {
class: "h-8 w-8",
children: ($$renderer5) => {
$$renderer5.push("<!---->");
Avatar_fallback?.($$renderer5, {
class: "text-xs",
children: ($$renderer6) => {
$$renderer6.push(`<!---->${escape_html(data.user.name ? String(data.user.name).slice(0, 2).toUpperCase() : data.user.email ? String(data.user.email).slice(0, 2).toUpperCase() : "?")}`);
},
$$slots: { default: true }
});
$$renderer5.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!----> `);
$$renderer3.push("<!---->");
Dropdown_menu_content?.($$renderer3, {
align: "end",
class: "w-48",
children: ($$renderer4) => {
$$renderer4.push(`<div class="relative flex cursor-default items-center gap-2 rounded-sm py-1.5 px-2 text-sm outline-none select-none" role="button" tabindex="0">`);
Label($$renderer4, {
for: "darkmode-switch",
class: "flex-1 cursor-pointer",
children: ($$renderer5) => {
$$renderer5.push(`<!---->Dark mode`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
Switch($$renderer4, {
id: "darkmode-switch",
checked: darkmode,
onCheckedChange: (v) => v !== void 0 && onDarkmodeChange()
});
$$renderer4.push(`<!----></div> `);
$$renderer4.push("<!---->");
Dropdown_menu_separator?.($$renderer4, {});
$$renderer4.push(`<!----> <form method="POST" action="/logout" class="contents"><button type="submit" class="relative flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Log out</button></form>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></header>`);
} else {
$$renderer2.push("<!--[!-->");
}
$$renderer2.push(`<!--]--> <main class="flex-1 flex flex-col gap-4 min-h-0">`);
children?.($$renderer2);
$$renderer2.push(`<!----></main></div>`);
});
}
export { _layout as default };
//# sourceMappingURL=_layout.svelte-C9R7TwNZ.js.map