UNPKG

@ionic/core

Version:
154 lines (151 loc) 5.75 kB
/*! * (C) Ionic http://ionicframework.com - MIT License */ import { w as win } from './index5.js'; import { r as raf } from './helpers.js'; /** * A utility to calculate the size of an outline notch * width relative to the content passed. This is used in * components such as `ion-select` with `fill="outline"` * where we need to pass slotted HTML content. This is not * needed when rendering plaintext content because we can * render the plaintext again hidden with `opacity: 0` inside * of the notch. As a result we can rely on the intrinsic size * of the element to correctly compute the notch width. We * cannot do this with slotted content because we cannot project * it into 2 places at once. * * @internal * @param el: The host element * @param getNotchSpacerEl: A function that returns a reference to the notch spacer element inside of the component template. * @param getLabelSlot: A function that returns a reference to the slotted content. */ const createNotchController = (el, getNotchSpacerEl, getLabelSlot) => { let notchVisibilityIO; const needsExplicitNotchWidth = () => { const notchSpacerEl = getNotchSpacerEl(); if ( /** * If the notch is not being used * then we do not need to set the notch width. */ notchSpacerEl === undefined || /** * If either the label property is being * used or the label slot is not defined, * then we do not need to estimate the notch width. */ el.label !== undefined || getLabelSlot() === null) { return false; } return true; }; const calculateNotchWidth = () => { if (needsExplicitNotchWidth()) { /** * Run this the frame after * the browser has re-painted the host element. * Otherwise, the label element may have a width * of 0 and the IntersectionObserver will be used. */ raf(() => { setNotchWidth(); }); } }; /** * When using a label prop we can render * the label value inside of the notch and * let the browser calculate the size of the notch. * However, we cannot render the label slot in multiple * places so we need to manually calculate the notch dimension * based on the size of the slotted content. * * This function should only be used to set the notch width * on slotted label content. The notch width for label prop * content is automatically calculated based on the * intrinsic size of the label text. */ const setNotchWidth = () => { const notchSpacerEl = getNotchSpacerEl(); if (notchSpacerEl === undefined) { return; } if (!needsExplicitNotchWidth()) { notchSpacerEl.style.removeProperty('width'); return; } const width = getLabelSlot().scrollWidth; if ( /** * If the computed width of the label is 0 * and notchSpacerEl's offsetParent is null * then that means the element is hidden. * As a result, we need to wait for the element * to become visible before setting the notch width. * * We do not check el.offsetParent because * that can be null if the host element has * position: fixed applied to it. * notchSpacerEl does not have position: fixed. */ width === 0 && notchSpacerEl.offsetParent === null && win !== undefined && 'IntersectionObserver' in win) { /** * If there is an IO already attached * then that will update the notch * once the element becomes visible. * As a result, there is no need to create * another one. */ if (notchVisibilityIO !== undefined) { return; } const io = (notchVisibilityIO = new IntersectionObserver((ev) => { /** * If the element is visible then we * can try setting the notch width again. */ if (ev[0].intersectionRatio === 1) { setNotchWidth(); io.disconnect(); notchVisibilityIO = undefined; } }, /** * Set the root to be the host element * This causes the IO callback * to be fired in WebKit as soon as the element * is visible. If we used the default root value * then WebKit would only fire the IO callback * after any animations (such as a modal transition) * finished, and there would potentially be a flicker. */ { threshold: 0.01, root: el })); io.observe(notchSpacerEl); return; } /** * If the element is visible then we can set the notch width. * The notch is only visible when the label is scaled, * which is why we multiply the width by 0.75 as this is * the same amount the label element is scaled by in the host CSS. * (See $form-control-label-stacked-scale in ionic.globals.scss). */ notchSpacerEl.style.setProperty('width', `${width * 0.75}px`); }; const destroy = () => { if (notchVisibilityIO) { notchVisibilityIO.disconnect(); notchVisibilityIO = undefined; } }; return { calculateNotchWidth, destroy, }; }; export { createNotchController as c };