1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777 |
- /*!
- * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
- * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
- * v1.0.0-beta.97
- */
- 'use strict';
- const dom = require('./dom-2ec8c9ed.js');
- const debounce = require('./debounce-2c8b61fb.js');
- function getSide(placement) {
- return placement.split('-')[0];
- }
- function getAlignment(placement) {
- return placement.split('-')[1];
- }
- function getMainAxisFromPlacement(placement) {
- return ['top', 'bottom'].includes(getSide(placement)) ? 'x' : 'y';
- }
- function getLengthFromAxis(axis) {
- return axis === 'y' ? 'height' : 'width';
- }
- function computeCoordsFromPlacement(_ref, placement, rtl) {
- let {
- reference,
- floating
- } = _ref;
- const commonX = reference.x + reference.width / 2 - floating.width / 2;
- const commonY = reference.y + reference.height / 2 - floating.height / 2;
- const mainAxis = getMainAxisFromPlacement(placement);
- const length = getLengthFromAxis(mainAxis);
- const commonAlign = reference[length] / 2 - floating[length] / 2;
- const side = getSide(placement);
- const isVertical = mainAxis === 'x';
- 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[mainAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
- break;
- case 'end':
- coords[mainAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
- break;
- }
- return coords;
- }
- /**
- * Computes the `x` and `y` coordinates that will place the floating element
- * next to a reference element when it is given a certain positioning strategy.
- *
- * 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 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 < middleware.length; i++) {
- const {
- name,
- fn
- } = middleware[i];
- const {
- x: nextX,
- y: nextY,
- data,
- reset
- } = await fn({
- x,
- y,
- initialPlacement: placement,
- placement: statefulPlacement,
- strategy,
- middlewareData,
- rects,
- platform,
- 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;
- continue;
- }
- }
- return {
- x,
- y,
- placement: statefulPlacement,
- strategy,
- middlewareData
- };
- };
- function expandPaddingObject(padding) {
- return {
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- ...padding
- };
- }
- function getSideObjectFromPadding(padding) {
- return typeof padding !== 'number' ? expandPaddingObject(padding) : {
- top: padding,
- right: padding,
- bottom: padding,
- left: padding
- };
- }
- function rectToClientRect(rect) {
- return { ...rect,
- top: rect.y,
- left: rect.x,
- right: rect.x + rect.width,
- bottom: rect.y + rect.height
- };
- }
- /**
- * Resolves with an object of overflow side offsets that determine how much the
- * element is overflowing a given clipping boundary.
- * - 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(middlewareArguments, options) {
- var _await$platform$isEle;
- if (options === void 0) {
- options = {};
- }
- const {
- x,
- y,
- platform,
- rects,
- elements,
- strategy
- } = middlewareArguments;
- const {
- boundary = 'clippingAncestors',
- rootBoundary = 'viewport',
- elementContext = 'floating',
- altBoundary = false,
- padding = 0
- } = options;
- const paddingObject = getSideObjectFromPadding(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 elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
- rect: elementContext === 'floating' ? { ...rects.floating,
- x,
- y
- } : rects.reference,
- offsetParent: await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating)),
- strategy
- }) : rects[elementContext]);
- return {
- top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
- bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
- left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
- right: elementClientRect.right - clippingClientRect.right + paddingObject.right
- };
- }
- const min$1 = Math.min;
- const max$1 = Math.max;
- function within(min$1$1, value, max$1$1) {
- return max$1(min$1$1, min$1(value, max$1$1));
- }
- /**
- * Positions an inner element of the floating element such that it is centered
- * to the reference element.
- * @see https://floating-ui.com/docs/arrow
- */
- const arrow = options => ({
- name: 'arrow',
- options,
- async fn(middlewareArguments) {
- // Since `element` is required, we don't Partial<> the type
- const {
- element,
- padding = 0
- } = options != null ? options : {};
- const {
- x,
- y,
- placement,
- rects,
- platform
- } = middlewareArguments;
- if (element == null) {
- return {};
- }
- const paddingObject = getSideObjectFromPadding(padding);
- const coords = {
- x,
- y
- };
- const axis = getMainAxisFromPlacement(placement);
- const alignment = getAlignment(placement);
- const length = getLengthFromAxis(axis);
- const arrowDimensions = await platform.getDimensions(element);
- const minProp = axis === 'y' ? 'top' : 'left';
- const maxProp = axis === 'y' ? 'bottom' : 'right';
- 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 ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
- if (clientSize === 0) {
- clientSize = rects.floating[length];
- }
- const centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the floating element if the center
- // point is outside the floating element's bounds
- const min = paddingObject[minProp];
- const max = clientSize - arrowDimensions[length] - paddingObject[maxProp];
- const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
- const offset = within(min, center, max); // Make sure that arrow points at the reference
- const alignmentPadding = alignment === 'start' ? paddingObject[minProp] : paddingObject[maxProp];
- const shouldAddOffset = alignmentPadding > 0 && center !== offset && rects.reference[length] <= rects.floating[length];
- const alignmentOffset = shouldAddOffset ? center < min ? min - center : max - center : 0;
- return {
- [axis]: coords[axis] - alignmentOffset,
- data: {
- [axis]: offset,
- centerOffset: center - offset
- }
- };
- }
- });
- const hash$1 = {
- left: 'right',
- right: 'left',
- bottom: 'top',
- top: 'bottom'
- };
- function getOppositePlacement(placement) {
- return placement.replace(/left|right|bottom|top/g, matched => hash$1[matched]);
- }
- function getAlignmentSides(placement, rects, rtl) {
- if (rtl === void 0) {
- rtl = false;
- }
- const alignment = getAlignment(placement);
- const mainAxis = getMainAxisFromPlacement(placement);
- const length = getLengthFromAxis(mainAxis);
- let mainAlignmentSide = mainAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';
- if (rects.reference[length] > rects.floating[length]) {
- mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
- }
- return {
- main: mainAlignmentSide,
- cross: getOppositePlacement(mainAlignmentSide)
- };
- }
- const hash = {
- start: 'end',
- end: 'start'
- };
- function getOppositeAlignmentPlacement(placement) {
- return placement.replace(/start|end/g, matched => hash[matched]);
- }
- const sides = ['top', 'right', 'bottom', 'left'];
- const allPlacements = /*#__PURE__*/sides.reduce((acc, side) => acc.concat(side, side + "-start", side + "-end"), []);
- function getPlacementList(alignment, autoAlignment, allowedPlacements) {
- const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);
- return allowedPlacementsSortedByAlignment.filter(placement => {
- if (alignment) {
- return getAlignment(placement) === alignment || (autoAlignment ? getOppositeAlignmentPlacement(placement) !== placement : false);
- }
- return true;
- });
- }
- /**
- * Automatically chooses the `placement` which has the most space available.
- * @see https://floating-ui.com/docs/autoPlacement
- */
- const autoPlacement = function (options) {
- if (options === void 0) {
- options = {};
- }
- return {
- name: 'autoPlacement',
- options,
- async fn(middlewareArguments) {
- var _middlewareData$autoP, _middlewareData$autoP2, _middlewareData$autoP3, _middlewareData$autoP4, _placementsSortedByLe;
- const {
- x,
- y,
- rects,
- middlewareData,
- placement,
- platform,
- elements
- } = middlewareArguments;
- const {
- alignment = null,
- allowedPlacements = allPlacements,
- autoAlignment = true,
- ...detectOverflowOptions
- } = options;
- const placements = getPlacementList(alignment, autoAlignment, allowedPlacements);
- const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
- const currentIndex = (_middlewareData$autoP = (_middlewareData$autoP2 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP2.index) != null ? _middlewareData$autoP : 0;
- const currentPlacement = placements[currentIndex];
- if (currentPlacement == null) {
- return {};
- }
- const {
- main,
- cross
- } = getAlignmentSides(currentPlacement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))); // Make `computeCoords` start from the right place
- if (placement !== currentPlacement) {
- return {
- x,
- y,
- reset: {
- placement: placements[0]
- }
- };
- }
- const currentOverflows = [overflow[getSide(currentPlacement)], overflow[main], overflow[cross]];
- const allOverflows = [...((_middlewareData$autoP3 = (_middlewareData$autoP4 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP4.overflows) != null ? _middlewareData$autoP3 : []), {
- placement: currentPlacement,
- overflows: currentOverflows
- }];
- const nextPlacement = placements[currentIndex + 1]; // There are more placements to check
- if (nextPlacement) {
- return {
- data: {
- index: currentIndex + 1,
- overflows: allOverflows
- },
- reset: {
- placement: nextPlacement
- }
- };
- }
- const placementsSortedByLeastOverflow = allOverflows.slice().sort((a, b) => a.overflows[0] - b.overflows[0]);
- const placementThatFitsOnAllSides = (_placementsSortedByLe = placementsSortedByLeastOverflow.find(_ref => {
- let {
- overflows
- } = _ref;
- return overflows.every(overflow => overflow <= 0);
- })) == null ? void 0 : _placementsSortedByLe.placement;
- const resetPlacement = placementThatFitsOnAllSides != null ? placementThatFitsOnAllSides : placementsSortedByLeastOverflow[0].placement;
- if (resetPlacement !== placement) {
- return {
- data: {
- index: currentIndex + 1,
- overflows: allOverflows
- },
- reset: {
- placement: resetPlacement
- }
- };
- }
- return {};
- }
- };
- };
- function getExpandedPlacements(placement) {
- const oppositePlacement = getOppositePlacement(placement);
- return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
- }
- /**
- * Changes the placement of the floating element to one that will fit if the
- * initially specified `placement` does not.
- * @see https://floating-ui.com/docs/flip
- */
- const flip = function (options) {
- if (options === void 0) {
- options = {};
- }
- return {
- name: 'flip',
- options,
- async fn(middlewareArguments) {
- var _middlewareData$flip;
- const {
- placement,
- middlewareData,
- rects,
- initialPlacement,
- platform,
- elements
- } = middlewareArguments;
- const {
- mainAxis: checkMainAxis = true,
- crossAxis: checkCrossAxis = true,
- fallbackPlacements: specifiedFallbackPlacements,
- fallbackStrategy = 'bestFit',
- flipAlignment = true,
- ...detectOverflowOptions
- } = options;
- const side = getSide(placement);
- const isBasePlacement = side === initialPlacement;
- const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
- const placements = [initialPlacement, ...fallbackPlacements];
- const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
- const overflows = [];
- let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
- if (checkMainAxis) {
- overflows.push(overflow[side]);
- }
- if (checkCrossAxis) {
- const {
- main,
- cross
- } = getAlignmentSides(placement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)));
- overflows.push(overflow[main], overflow[cross]);
- }
- overflowsData = [...overflowsData, {
- placement,
- overflows
- }]; // One or more sides is overflowing
- if (!overflows.every(side => side <= 0)) {
- var _middlewareData$flip$, _middlewareData$flip2;
- const nextIndex = ((_middlewareData$flip$ = (_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) != null ? _middlewareData$flip$ : 0) + 1;
- const nextPlacement = placements[nextIndex];
- if (nextPlacement) {
- // Try next placement and re-run the lifecycle
- return {
- data: {
- index: nextIndex,
- overflows: overflowsData
- },
- reset: {
- placement: nextPlacement
- }
- };
- }
- let resetPlacement = 'bottom';
- switch (fallbackStrategy) {
- case 'bestFit':
- {
- var _overflowsData$map$so;
- const placement = (_overflowsData$map$so = overflowsData.map(d => [d, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$map$so[0].placement;
- 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 = function (_temp) {
- let {
- strategy = 'referenceHidden',
- ...detectOverflowOptions
- } = _temp === void 0 ? {} : _temp;
- return {
- name: 'hide',
- async fn(middlewareArguments) {
- const {
- rects
- } = middlewareArguments;
- switch (strategy) {
- case 'referenceHidden':
- {
- const overflow = await detectOverflow(middlewareArguments, { ...detectOverflowOptions,
- elementContext: 'reference'
- });
- const offsets = getSideOffsets(overflow, rects.reference);
- return {
- data: {
- referenceHiddenOffsets: offsets,
- referenceHidden: isAnySideFullyClipped(offsets)
- }
- };
- }
- case 'escaped':
- {
- const overflow = await detectOverflow(middlewareArguments, { ...detectOverflowOptions,
- altBoundary: true
- });
- const offsets = getSideOffsets(overflow, rects.floating);
- return {
- data: {
- escapedOffsets: offsets,
- escaped: isAnySideFullyClipped(offsets)
- }
- };
- }
- default:
- {
- return {};
- }
- }
- }
- };
- };
- async function convertValueToCoords(middlewareArguments, value) {
- const {
- placement,
- platform,
- elements
- } = middlewareArguments;
- const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
- const side = getSide(placement);
- const alignment = getAlignment(placement);
- const isVertical = getMainAxisFromPlacement(placement) === 'x';
- const mainAxisMulti = ['left', 'top'].includes(side) ? -1 : 1;
- const crossAxisMulti = rtl && isVertical ? -1 : 1;
- const rawValue = typeof value === 'function' ? value(middlewareArguments) : value; // eslint-disable-next-line prefer-const
- let {
- mainAxis,
- crossAxis,
- alignmentAxis
- } = typeof rawValue === 'number' ? {
- mainAxis: rawValue,
- crossAxis: 0,
- alignmentAxis: null
- } : {
- mainAxis: 0,
- crossAxis: 0,
- alignmentAxis: null,
- ...rawValue
- };
- 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
- };
- }
- /**
- * Displaces the floating element from its reference element.
- * @see https://floating-ui.com/docs/offset
- */
- const offset = function (value) {
- if (value === void 0) {
- value = 0;
- }
- return {
- name: 'offset',
- options: value,
- async fn(middlewareArguments) {
- const {
- x,
- y
- } = middlewareArguments;
- const diffCoords = await convertValueToCoords(middlewareArguments, value);
- return {
- x: x + diffCoords.x,
- y: y + diffCoords.y,
- data: diffCoords
- };
- }
- };
- };
- function getCrossAxis(axis) {
- return axis === 'x' ? 'y' : 'x';
- }
- /**
- * Shifts the floating element in order to keep it in view when it will overflow
- * a clipping boundary.
- * @see https://floating-ui.com/docs/shift
- */
- const shift = function (options) {
- if (options === void 0) {
- options = {};
- }
- return {
- name: 'shift',
- options,
- async fn(middlewareArguments) {
- const {
- x,
- y,
- placement
- } = middlewareArguments;
- const {
- mainAxis: checkMainAxis = true,
- crossAxis: checkCrossAxis = false,
- limiter = {
- fn: _ref => {
- let {
- x,
- y
- } = _ref;
- return {
- x,
- y
- };
- }
- },
- ...detectOverflowOptions
- } = options;
- const coords = {
- x,
- y
- };
- const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
- const mainAxis = getMainAxisFromPlacement(getSide(placement));
- const crossAxis = getCrossAxis(mainAxis);
- 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 = within(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 = within(min, crossAxisCoord, max);
- }
- const limitedCoords = limiter.fn({ ...middlewareArguments,
- [mainAxis]: mainAxisCoord,
- [crossAxis]: crossAxisCoord
- });
- return { ...limitedCoords,
- data: {
- x: limitedCoords.x - x,
- y: limitedCoords.y - y
- }
- };
- }
- };
- };
- function isWindow(value) {
- return value && value.document && value.location && value.alert && value.setInterval;
- }
- function getWindow(node) {
- if (node == null) {
- return window;
- }
- if (!isWindow(node)) {
- const ownerDocument = node.ownerDocument;
- return ownerDocument ? ownerDocument.defaultView || window : window;
- }
- return node;
- }
- function getComputedStyle(element) {
- return getWindow(element).getComputedStyle(element);
- }
- function getNodeName(node) {
- return isWindow(node) ? '' : node ? (node.nodeName || '').toLowerCase() : '';
- }
- function getUAString() {
- const uaData = navigator.userAgentData;
- if (uaData != null && uaData.brands) {
- return uaData.brands.map(item => item.brand + "/" + item.version).join(' ');
- }
- return navigator.userAgent;
- }
- function isHTMLElement(value) {
- return value instanceof getWindow(value).HTMLElement;
- }
- function isElement(value) {
- return value instanceof getWindow(value).Element;
- }
- function isNode(value) {
- return value instanceof getWindow(value).Node;
- }
- function isShadowRoot(node) {
- // Browsers without `ShadowRoot` support
- if (typeof ShadowRoot === 'undefined') {
- return false;
- }
- const OwnElement = getWindow(node).ShadowRoot;
- return node instanceof OwnElement || node instanceof ShadowRoot;
- }
- function isOverflowElement(element) {
- // Firefox wants us to check `-x` and `-y` variations as well
- const {
- overflow,
- overflowX,
- overflowY,
- display
- } = getComputedStyle(element);
- return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);
- }
- function isTableElement(element) {
- return ['table', 'td', 'th'].includes(getNodeName(element));
- }
- function isContainingBlock(element) {
- // TODO: Try and use feature detection here instead
- const isFirefox = /firefox/i.test(getUAString());
- const css = getComputedStyle(element); // This is non-exhaustive but covers the most common CSS properties that
- // create a containing block.
- // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
- return css.transform !== 'none' || css.perspective !== 'none' || isFirefox && css.willChange === 'filter' || isFirefox && (css.filter ? css.filter !== 'none' : false) || ['transform', 'perspective'].some(value => css.willChange.includes(value)) || ['paint', 'layout', 'strict', 'content'].some( // TS 4.1 compat
- value => {
- const contain = css.contain;
- return contain != null ? contain.includes(value) : false;
- });
- }
- function isLayoutViewport() {
- // Not Safari
- return !/^((?!chrome|android).)*safari/i.test(getUAString()); // Feature detection for this fails in various ways
- // • Always-visible scrollbar or not
- // • Width of <html>, etc.
- // const vV = win.visualViewport;
- // return vV ? Math.abs(win.innerWidth / vV.scale - vV.width) < 0.5 : true;
- }
- function isLastTraversableNode(node) {
- return ['html', 'body', '#document'].includes(getNodeName(node));
- }
- const min = Math.min;
- const max = Math.max;
- const round = Math.round;
- function getBoundingClientRect(element, includeScale, isFixedStrategy) {
- var _win$visualViewport$o, _win$visualViewport, _win$visualViewport$o2, _win$visualViewport2;
- if (includeScale === void 0) {
- includeScale = false;
- }
- if (isFixedStrategy === void 0) {
- isFixedStrategy = false;
- }
- const clientRect = element.getBoundingClientRect();
- let scaleX = 1;
- let scaleY = 1;
- if (includeScale && isHTMLElement(element)) {
- scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
- scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
- }
- const win = isElement(element) ? getWindow(element) : window;
- const addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
- const x = (clientRect.left + (addVisualOffsets ? (_win$visualViewport$o = (_win$visualViewport = win.visualViewport) == null ? void 0 : _win$visualViewport.offsetLeft) != null ? _win$visualViewport$o : 0 : 0)) / scaleX;
- const y = (clientRect.top + (addVisualOffsets ? (_win$visualViewport$o2 = (_win$visualViewport2 = win.visualViewport) == null ? void 0 : _win$visualViewport2.offsetTop) != null ? _win$visualViewport$o2 : 0 : 0)) / scaleY;
- const width = clientRect.width / scaleX;
- const height = clientRect.height / scaleY;
- return {
- width,
- height,
- top: y,
- right: x + width,
- bottom: y + height,
- left: x,
- x,
- y
- };
- }
- function getDocumentElement(node) {
- return ((isNode(node) ? node.ownerDocument : node.document) || window.document).documentElement;
- }
- function getNodeScroll(element) {
- if (isElement(element)) {
- return {
- scrollLeft: element.scrollLeft,
- scrollTop: element.scrollTop
- };
- }
- return {
- scrollLeft: element.pageXOffset,
- scrollTop: element.pageYOffset
- };
- }
- function getWindowScrollBarX(element) {
- // If <html> has a CSS width greater than the viewport, then this will be
- // incorrect for RTL.
- return getBoundingClientRect(getDocumentElement(element)).left + getNodeScroll(element).scrollLeft;
- }
- function isScaled(element) {
- const rect = getBoundingClientRect(element);
- return round(rect.width) !== element.offsetWidth || round(rect.height) !== element.offsetHeight;
- }
- function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
- const isOffsetParentAnElement = isHTMLElement(offsetParent);
- const documentElement = getDocumentElement(offsetParent);
- const rect = getBoundingClientRect(element, // @ts-ignore - checked above (TS 4.1 compat)
- isOffsetParentAnElement && isScaled(offsetParent), strategy === 'fixed');
- let scroll = {
- scrollLeft: 0,
- scrollTop: 0
- };
- const offsets = {
- x: 0,
- y: 0
- };
- if (isOffsetParentAnElement || !isOffsetParentAnElement && strategy !== 'fixed') {
- if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
- scroll = getNodeScroll(offsetParent);
- }
- if (isHTMLElement(offsetParent)) {
- const offsetRect = getBoundingClientRect(offsetParent, true);
- offsets.x = offsetRect.x + offsetParent.clientLeft;
- offsets.y = offsetRect.y + offsetParent.clientTop;
- } else if (documentElement) {
- offsets.x = getWindowScrollBarX(documentElement);
- }
- }
- return {
- x: rect.left + scroll.scrollLeft - offsets.x,
- y: rect.top + scroll.scrollTop - offsets.y,
- width: rect.width,
- height: rect.height
- };
- }
- function getParentNode(node) {
- if (getNodeName(node) === 'html') {
- return node;
- }
- return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
- // @ts-ignore
- node.assignedSlot || // step into the shadow DOM of the parent of a slotted node
- node.parentNode || ( // DOM Element detected
- isShadowRoot(node) ? node.host : null) || // ShadowRoot detected
- getDocumentElement(node) // fallback
- );
- }
- function getTrueOffsetParent(element) {
- if (!isHTMLElement(element) || getComputedStyle(element).position === 'fixed') {
- return null;
- }
- return element.offsetParent;
- }
- function getContainingBlock(element) {
- let currentNode = getParentNode(element);
- if (isShadowRoot(currentNode)) {
- currentNode = currentNode.host;
- }
- while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
- if (isContainingBlock(currentNode)) {
- return currentNode;
- } else {
- const parent = currentNode.parentNode;
- currentNode = isShadowRoot(parent) ? parent.host : parent;
- }
- }
- return null;
- } // Gets the closest ancestor positioned element. Handles some edge cases,
- // such as table ancestors and cross browser bugs.
- function getOffsetParent(element) {
- const window = getWindow(element);
- let offsetParent = getTrueOffsetParent(element);
- while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {
- offsetParent = getTrueOffsetParent(offsetParent);
- }
- if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static' && !isContainingBlock(offsetParent))) {
- return window;
- }
- return offsetParent || getContainingBlock(element) || window;
- }
- function getDimensions(element) {
- if (isHTMLElement(element)) {
- return {
- width: element.offsetWidth,
- height: element.offsetHeight
- };
- }
- const rect = getBoundingClientRect(element);
- return {
- width: rect.width,
- height: rect.height
- };
- }
- function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
- let {
- rect,
- offsetParent,
- strategy
- } = _ref;
- const isOffsetParentAnElement = isHTMLElement(offsetParent);
- const documentElement = getDocumentElement(offsetParent);
- if (offsetParent === documentElement) {
- return rect;
- }
- let scroll = {
- scrollLeft: 0,
- scrollTop: 0
- };
- const offsets = {
- x: 0,
- y: 0
- };
- if (isOffsetParentAnElement || !isOffsetParentAnElement && strategy !== 'fixed') {
- if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
- scroll = getNodeScroll(offsetParent);
- }
- if (isHTMLElement(offsetParent)) {
- const offsetRect = getBoundingClientRect(offsetParent, true);
- offsets.x = offsetRect.x + offsetParent.clientLeft;
- offsets.y = offsetRect.y + offsetParent.clientTop;
- } // This doesn't appear to be need to be negated.
- // else if (documentElement) {
- // offsets.x = getWindowScrollBarX(documentElement);
- // }
- }
- return { ...rect,
- x: rect.x - scroll.scrollLeft + offsets.x,
- y: rect.y - scroll.scrollTop + offsets.y
- };
- }
- function getViewportRect(element, strategy) {
- const win = getWindow(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 layoutViewport = isLayoutViewport();
- if (layoutViewport || !layoutViewport && strategy === 'fixed') {
- x = visualViewport.offsetLeft;
- y = visualViewport.offsetTop;
- }
- }
- return {
- width,
- height,
- x,
- y
- };
- }
- // of the `<html>` and `<body>` rect bounds if horizontally scrollable
- function getDocumentRect(element) {
- var _element$ownerDocumen;
- const html = getDocumentElement(element);
- const scroll = getNodeScroll(element);
- const body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
- const width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
- const height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
- let x = -scroll.scrollLeft + getWindowScrollBarX(element);
- const y = -scroll.scrollTop;
- if (getComputedStyle(body || html).direction === 'rtl') {
- x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
- }
- return {
- width,
- height,
- x,
- y
- };
- }
- function getNearestOverflowAncestor(node) {
- const parentNode = getParentNode(node);
- if (isLastTraversableNode(parentNode)) {
- // @ts-ignore assume body is always available
- return node.ownerDocument.body;
- }
- if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
- return parentNode;
- }
- return getNearestOverflowAncestor(parentNode);
- }
- function getOverflowAncestors(node, list) {
- var _node$ownerDocument;
- if (list === void 0) {
- list = [];
- }
- const scrollableAncestor = getNearestOverflowAncestor(node);
- const isBody = scrollableAncestor === ((_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.body);
- const win = getWindow(scrollableAncestor);
- const target = isBody ? [win].concat(win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : []) : scrollableAncestor;
- const updatedList = list.concat(target);
- return isBody ? updatedList : // @ts-ignore: isBody tells us target will be an HTMLElement here
- updatedList.concat(getOverflowAncestors(target));
- }
- function contains(parent, child) {
- const rootNode = child.getRootNode == null ? void 0 : child.getRootNode(); // First, attempt with faster native method
- if (parent.contains(child)) {
- return true;
- } // then fallback to custom implementation with Shadow DOM support
- else if (rootNode && isShadowRoot(rootNode)) {
- let next = child;
- do {
- // use `===` replace node.isSameNode()
- if (next && parent === next) {
- return true;
- } // @ts-ignore: need a better way to handle this...
- next = next.parentNode || next.host;
- } while (next);
- }
- return false;
- }
- function getNearestParentCapableOfEscapingClipping(element, clippingAncestors) {
- let currentNode = element;
- while (currentNode && !isLastTraversableNode(currentNode) && // @ts-expect-error
- !clippingAncestors.includes(currentNode)) {
- if (isElement(currentNode) && ['absolute', 'fixed'].includes(getComputedStyle(currentNode).position)) {
- break;
- }
- const parentNode = getParentNode(currentNode);
- currentNode = isShadowRoot(parentNode) ? parentNode.host : parentNode;
- }
- return currentNode;
- }
- function getInnerBoundingClientRect(element, strategy) {
- const clientRect = getBoundingClientRect(element, false, strategy === 'fixed');
- const top = clientRect.top + element.clientTop;
- const left = clientRect.left + element.clientLeft;
- return {
- top,
- left,
- x: left,
- y: top,
- right: left + element.clientWidth,
- bottom: top + element.clientHeight,
- width: element.clientWidth,
- height: element.clientHeight
- };
- }
- function getClientRectFromClippingAncestor(element, clippingParent, strategy) {
- if (clippingParent === 'viewport') {
- return rectToClientRect(getViewportRect(element, strategy));
- }
- if (isElement(clippingParent)) {
- return getInnerBoundingClientRect(clippingParent, strategy);
- }
- return rectToClientRect(getDocumentRect(getDocumentElement(element)));
- } // A "clipping ancestor" is an overflowable container with the characteristic of
- // clipping (or hiding) overflowing elements with a position different from
- // `initial`
- function getClippingAncestors(element) {
- const clippingAncestors = getOverflowAncestors(element);
- const nearestEscapableParent = getNearestParentCapableOfEscapingClipping(element, clippingAncestors);
- let clipperElement = null;
- if (nearestEscapableParent && isHTMLElement(nearestEscapableParent)) {
- const offsetParent = getOffsetParent(nearestEscapableParent);
- if (isOverflowElement(nearestEscapableParent)) {
- clipperElement = nearestEscapableParent;
- } else if (isHTMLElement(offsetParent)) {
- clipperElement = offsetParent;
- }
- }
- if (!isElement(clipperElement)) {
- return [];
- } // @ts-ignore isElement check ensures we return Array<Element>
- return clippingAncestors.filter(clippingAncestors => clipperElement && isElement(clippingAncestors) && contains(clippingAncestors, clipperElement) && getNodeName(clippingAncestors) !== 'body');
- } // 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 mainClippingAncestors = boundary === 'clippingAncestors' ? getClippingAncestors(element) : [].concat(boundary);
- const clippingAncestors = [...mainClippingAncestors, 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
- };
- }
- const platform = {
- getClippingRect,
- convertOffsetParentRelativeRectToViewportRelativeRect,
- isElement,
- getDimensions,
- getOffsetParent,
- getDocumentElement,
- getElementRects: _ref => {
- let {
- reference,
- floating,
- strategy
- } = _ref;
- return {
- reference: getRectRelativeToOffsetParent(reference, getOffsetParent(floating), strategy),
- floating: { ...getDimensions(floating),
- x: 0,
- y: 0
- }
- };
- },
- getClientRects: element => Array.from(element.getClientRects()),
- isRTL: element => getComputedStyle(element).direction === 'rtl'
- };
- /**
- * Automatically updates the position of the floating element when necessary.
- * @see https://floating-ui.com/docs/autoUpdate
- */
- function autoUpdate(reference, floating, update, options) {
- if (options === void 0) {
- options = {};
- }
- const {
- ancestorScroll: _ancestorScroll = true,
- ancestorResize = true,
- elementResize = true,
- animationFrame = false
- } = options;
- const ancestorScroll = _ancestorScroll && !animationFrame;
- const ancestors = ancestorScroll || ancestorResize ? [...(isElement(reference) ? getOverflowAncestors(reference) : []), ...getOverflowAncestors(floating)] : [];
- ancestors.forEach(ancestor => {
- ancestorScroll && ancestor.addEventListener('scroll', update, {
- passive: true
- });
- ancestorResize && ancestor.addEventListener('resize', update);
- });
- let observer = null;
- if (elementResize) {
- let initialUpdate = true;
- observer = new ResizeObserver(() => {
- if (!initialUpdate) {
- update();
- }
- initialUpdate = false;
- });
- isElement(reference) && !animationFrame && observer.observe(reference);
- observer.observe(floating);
- }
- let frameId;
- let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null;
- if (animationFrame) {
- frameLoop();
- }
- function frameLoop() {
- const nextRefRect = getBoundingClientRect(reference);
- if (prevRefRect && (nextRefRect.x !== prevRefRect.x || nextRefRect.y !== prevRefRect.y || nextRefRect.width !== prevRefRect.width || nextRefRect.height !== prevRefRect.height)) {
- update();
- }
- prevRefRect = nextRefRect;
- frameId = requestAnimationFrame(frameLoop);
- }
- update();
- return () => {
- var _observer;
- ancestors.forEach(ancestor => {
- ancestorScroll && ancestor.removeEventListener('scroll', update);
- ancestorResize && ancestor.removeEventListener('resize', update);
- });
- (_observer = observer) == null ? void 0 : _observer.disconnect();
- observer = null;
- if (animationFrame) {
- cancelAnimationFrame(frameId);
- }
- };
- }
- /**
- * Computes the `x` and `y` coordinates that will place the floating element
- * next to a reference element when it is given a certain CSS positioning
- * strategy.
- */
- const computePosition = (reference, floating, options) => computePosition$1(reference, floating, {
- platform,
- ...options
- });
- /**
- * This module helps users provide custom configuration for component internals.
- *
- * @internal
- */
- const configOverrides = globalThis["calciteComponentsConfig"];
- const config = {
- /**
- * We apply a custom fix to improve positioning for non-Chromium browsers.
- * The fix comes at a performance cost, so provides users a way to opt-out if necessary.
- *
- * @internal
- */
- floatingUINonChromiumPositioningFix: true,
- ...configOverrides
- };
- const floatingUIBrowserCheck = patchFloatingUiForNonChromiumBrowsers();
- async function patchFloatingUiForNonChromiumBrowsers() {
- function getUAString() {
- const uaData = navigator.userAgentData;
- if (uaData === null || uaData === void 0 ? void 0 : uaData.brands) {
- return uaData.brands.map((item) => `${item.brand}/${item.version}`).join(" ");
- }
- return navigator.userAgent;
- }
- if (config.floatingUINonChromiumPositioningFix &&
- // ⚠️ browser-sniffing is not a best practice and should be avoided ⚠️
- /firefox|safari/i.test(getUAString())) {
- const { getClippingRect, getElementRects, getOffsetParent } = await Promise.resolve().then(function () { return require('./nonChromiumPlatformUtils-95812e02.js'); });
- platform.getClippingRect = getClippingRect;
- platform.getOffsetParent = getOffsetParent;
- platform.getElementRects = getElementRects;
- }
- }
- const placementDataAttribute = "data-placement";
- /**
- * Exported for testing purposes only
- */
- const repositionDebounceTimeout = 100;
- const effectivePlacements = [
- "top",
- "bottom",
- "right",
- "left",
- "top-start",
- "top-end",
- "bottom-start",
- "bottom-end",
- "right-start",
- "right-end",
- "left-start",
- "left-end"
- ];
- const defaultMenuPlacement = "bottom-start";
- const FloatingCSS = {
- animation: "calcite-floating-ui-anim",
- animationActive: "calcite-floating-ui-anim--active"
- };
- function getMiddleware({ placement, disableFlip, flipPlacements, offsetDistance, offsetSkidding, arrowEl, type }) {
- const defaultMiddleware = [shift(), hide()];
- if (type === "menu") {
- return [
- ...defaultMiddleware,
- flip({
- fallbackPlacements: flipPlacements || ["top-start", "top", "top-end", "bottom-start", "bottom", "bottom-end"]
- })
- ];
- }
- if (type === "popover" || type === "tooltip") {
- const middleware = [
- ...defaultMiddleware,
- offset({
- mainAxis: typeof offsetDistance === "number" ? offsetDistance : 0,
- crossAxis: typeof offsetSkidding === "number" ? offsetSkidding : 0
- })
- ];
- if (placement === "auto" || placement === "auto-start" || placement === "auto-end") {
- middleware.push(autoPlacement({ alignment: placement === "auto-start" ? "start" : placement === "auto-end" ? "end" : null }));
- }
- else if (!disableFlip) {
- middleware.push(flip(flipPlacements ? { fallbackPlacements: flipPlacements } : {}));
- }
- if (arrowEl) {
- middleware.push(arrow({
- element: arrowEl
- }));
- }
- return middleware;
- }
- return [];
- }
- function filterComputedPlacements(placements, el) {
- const filteredPlacements = placements.filter((placement) => effectivePlacements.includes(placement));
- if (filteredPlacements.length !== placements.length) {
- console.warn(`${el.tagName}: Invalid value found in: flipPlacements. Try any of these: ${effectivePlacements
- .map((placement) => `"${placement}"`)
- .join(", ")
- .trim()}`, { el });
- }
- return filteredPlacements;
- }
- /*
- In floating-ui, "*-start" and "*-end" are already flipped in RTL.
- There is no need for our "*-leading" and "*-trailing" values anymore.
- https://github.com/floating-ui/floating-ui/issues/1530
- https://github.com/floating-ui/floating-ui/issues/1563
- */
- function getEffectivePlacement(floatingEl, placement) {
- const placements = ["left", "right"];
- if (dom.getElementDir(floatingEl) === "rtl") {
- placements.reverse();
- }
- return placement
- .replace(/-leading/gi, "-start")
- .replace(/-trailing/gi, "-end")
- .replace(/leading/gi, placements[0])
- .replace(/trailing/gi, placements[1]);
- }
- /**
- * Convenience function to manage `reposition` calls for FloatingUIComponents that use `positionFloatingUI.
- *
- * Note: this is not needed for components that use `calcite-popover`.
- *
- * @param component
- * @param options
- * @param options.referenceEl
- * @param options.floatingEl
- * @param options.overlayPositioning
- * @param options.placement
- * @param options.disableFlip
- * @param options.flipPlacements
- * @param options.offsetDistance
- * @param options.offsetSkidding
- * @param options.arrowEl
- * @param options.type
- * @param delayed
- */
- async function reposition(component, options, delayed = false) {
- if (!component.open) {
- return;
- }
- return delayed ? debouncedReposition(options) : positionFloatingUI(options);
- }
- const debouncedReposition = debounce.debounce(positionFloatingUI, repositionDebounceTimeout, {
- leading: true,
- maxWait: repositionDebounceTimeout
- });
- /**
- * Positions the floating element relative to the reference element.
- *
- * **Note:** exported for testing purposes only
- *
- * @param root0
- * @param root0.referenceEl
- * @param root0.floatingEl
- * @param root0.overlayPositioning
- * @param root0.placement
- * @param root0.disableFlip
- * @param root0.flipPlacements
- * @param root0.offsetDistance
- * @param root0.offsetSkidding
- * @param root0.arrowEl
- * @param root0.type
- * @param root0.includeArrow
- */
- async function positionFloatingUI({ referenceEl, floatingEl, overlayPositioning = "absolute", placement, disableFlip, flipPlacements, offsetDistance, offsetSkidding, includeArrow = false, arrowEl, type }) {
- var _a;
- if (!referenceEl || !floatingEl || (includeArrow && !arrowEl)) {
- return null;
- }
- await floatingUIBrowserCheck;
- const { x, y, placement: effectivePlacement, strategy: position, middlewareData } = await computePosition(referenceEl, floatingEl, {
- strategy: overlayPositioning,
- placement: placement === "auto" || placement === "auto-start" || placement === "auto-end"
- ? undefined
- : getEffectivePlacement(floatingEl, placement),
- middleware: getMiddleware({
- placement,
- disableFlip,
- flipPlacements,
- offsetDistance,
- offsetSkidding,
- arrowEl,
- type
- })
- });
- if (middlewareData === null || middlewareData === void 0 ? void 0 : middlewareData.arrow) {
- const { x: arrowX, y: arrowY } = middlewareData.arrow;
- Object.assign(arrowEl.style, {
- left: arrowX != null ? `${arrowX}px` : "",
- top: arrowY != null ? `${arrowY}px` : ""
- });
- }
- const referenceHidden = (_a = middlewareData === null || middlewareData === void 0 ? void 0 : middlewareData.hide) === null || _a === void 0 ? void 0 : _a.referenceHidden;
- const visibility = referenceHidden ? "hidden" : null;
- const pointerEvents = visibility ? "none" : null;
- floatingEl.setAttribute(placementDataAttribute, effectivePlacement);
- const transform = `translate(${Math.round(x)}px,${Math.round(y)}px)`;
- Object.assign(floatingEl.style, {
- visibility,
- pointerEvents,
- position,
- top: "0",
- left: "0",
- transform
- });
- }
- /**
- * Exported for testing purposes only
- *
- * @internal
- */
- const cleanupMap = new WeakMap();
- /**
- * Helper to set up floating element interactions on connectedCallback.
- *
- * @param component
- * @param referenceEl
- * @param floatingEl
- */
- function connectFloatingUI(component, referenceEl, floatingEl) {
- if (!floatingEl || !referenceEl) {
- return;
- }
- disconnectFloatingUI(component, referenceEl, floatingEl);
- const position = component.overlayPositioning;
- // ensure position matches for initial positioning
- floatingEl.style.position = position;
- if (position === "absolute") {
- moveOffScreen(floatingEl);
- }
- const runAutoUpdate = autoUpdate
- ;
- cleanupMap.set(component, runAutoUpdate(referenceEl, floatingEl, () => component.reposition()));
- }
- /**
- * Helper to tear down floating element interactions on disconnectedCallback.
- *
- * @param component
- * @param referenceEl
- * @param floatingEl
- */
- function disconnectFloatingUI(component, referenceEl, floatingEl) {
- if (!floatingEl || !referenceEl) {
- return;
- }
- getTransitionTarget(floatingEl).removeEventListener("transitionend", handleTransitionElTransitionEnd);
- const cleanup = cleanupMap.get(component);
- if (cleanup) {
- cleanup();
- }
- cleanupMap.delete(component);
- }
- const visiblePointerSize = 4;
- /**
- * Default offset the position of the floating element away from the reference element.
- *
- * @default 6
- */
- const defaultOffsetDistance = Math.ceil(Math.hypot(visiblePointerSize, visiblePointerSize));
- /**
- * This utils applies floating element styles to avoid affecting layout when closed.
- *
- * This should be called when the closing transition will start.
- *
- * @param floatingEl
- */
- function updateAfterClose(floatingEl) {
- if (!floatingEl || floatingEl.style.position !== "absolute") {
- return;
- }
- getTransitionTarget(floatingEl).addEventListener("transitionend", handleTransitionElTransitionEnd);
- }
- function getTransitionTarget(floatingEl) {
- // assumes floatingEl w/ shadowRoot is a FloatingUIComponent
- return floatingEl.shadowRoot || floatingEl;
- }
- function handleTransitionElTransitionEnd(event) {
- const floatingTransitionEl = event.target;
- if (
- // using any prop from floating-ui transition
- event.propertyName === "opacity" &&
- floatingTransitionEl.classList.contains(FloatingCSS.animation)) {
- const floatingEl = getFloatingElFromTransitionTarget(floatingTransitionEl);
- moveOffScreen(floatingEl);
- getTransitionTarget(floatingEl).removeEventListener("transitionend", handleTransitionElTransitionEnd);
- }
- }
- function moveOffScreen(floatingEl) {
- floatingEl.style.transform = "";
- floatingEl.style.top = "-99999px";
- floatingEl.style.left = "-99999px";
- }
- function getFloatingElFromTransitionTarget(floatingTransitionEl) {
- return dom.closestElementCrossShadowBoundary(floatingTransitionEl, `[${placementDataAttribute}]`);
- }
- exports.FloatingCSS = FloatingCSS;
- exports.connectFloatingUI = connectFloatingUI;
- exports.defaultMenuPlacement = defaultMenuPlacement;
- exports.defaultOffsetDistance = defaultOffsetDistance;
- exports.disconnectFloatingUI = disconnectFloatingUI;
- exports.filterComputedPlacements = filterComputedPlacements;
- exports.rectToClientRect = rectToClientRect;
- exports.reposition = reposition;
- exports.updateAfterClose = updateAfterClose;
|