UNPKG

forms-reactive

Version:

Reactive Form Web Component

305 lines (299 loc) 11.7 kB
'use strict'; const index = require('./index-a370c7e1.js'); const helpers = require('./helpers-4dca71bf.js'); const index$1 = require('./index-08ee9991.js'); /*! * (C) Ionic http://ionicframework.com - MIT License */ /** * 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. */ helpers.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 && index.win !== undefined && 'IntersectionObserver' in index.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, }; }; /*! * (C) Ionic http://ionicframework.com - MIT License */ /** * Used to update a scoped component that uses emulated slots. This fires when * content is passed into the slot or when the content inside of a slot changes. * This is not needed for components using native slots in the Shadow DOM. * @internal * @param el The host element to observe * @param slotName mutationCallback will fire when nodes on these slot(s) change * @param mutationCallback The callback to fire whenever the slotted content changes */ const createSlotMutationController = (el, slotName, mutationCallback) => { let hostMutationObserver; let slottedContentMutationObserver; if (index.win !== undefined && 'MutationObserver' in index.win) { const slots = Array.isArray(slotName) ? slotName : [slotName]; hostMutationObserver = new MutationObserver((entries) => { for (const entry of entries) { for (const node of entry.addedNodes) { /** * Check to see if the added node * is our slotted content. */ if (node.nodeType === Node.ELEMENT_NODE && slots.includes(node.slot)) { /** * If so, we want to watch the slotted * content itself for changes. This lets us * detect when content inside of the slot changes. */ mutationCallback(); /** * Adding the listener in an raf * waits until Stencil moves the slotted element * into the correct place in the event that * slotted content is being added. */ helpers.raf(() => watchForSlotChange(node)); return; } } } }); hostMutationObserver.observe(el, { childList: true, /** * This fixes an issue with the `ion-input` and * `ion-textarea` not re-rendering in some cases * when using the label slot functionality. * * HTML element patches in Stencil that are enabled * by the `experimentalSlotFixes` flag in Stencil v4 * result in DOM manipulations that won't trigger * the current mutation observer configuration and * callback. */ subtree: true, }); } /** * Listen for changes inside of the slotted content. * We can listen for subtree changes here to be * informed of text within the slotted content * changing. Doing this on the host is possible * but it is much more expensive to do because * it also listens for changes to the internals * of the component. */ const watchForSlotChange = (slottedEl) => { var _a; if (slottedContentMutationObserver) { slottedContentMutationObserver.disconnect(); slottedContentMutationObserver = undefined; } slottedContentMutationObserver = new MutationObserver((entries) => { mutationCallback(); for (const entry of entries) { for (const node of entry.removedNodes) { /** * If the element was removed then we * need to destroy the MutationObserver * so the element can be garbage collected. */ if (node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) { destroySlottedContentObserver(); } } } }); /** * Listen for changes inside of the element * as well as anything deep in the tree. * We listen on the parentElement so that we can * detect when slotted element itself is removed. */ slottedContentMutationObserver.observe((_a = slottedEl.parentElement) !== null && _a !== void 0 ? _a : slottedEl, { subtree: true, childList: true }); }; const destroy = () => { if (hostMutationObserver) { hostMutationObserver.disconnect(); hostMutationObserver = undefined; } destroySlottedContentObserver(); }; const destroySlottedContentObserver = () => { if (slottedContentMutationObserver) { slottedContentMutationObserver.disconnect(); slottedContentMutationObserver = undefined; } }; return { destroy, }; }; /*! * (C) Ionic http://ionicframework.com - MIT License */ const getCounterText = (value, maxLength, counterFormatter) => { const valueLength = value == null ? 0 : value.toString().length; const defaultCounterText = defaultCounterFormatter(valueLength, maxLength); /** * If developers did not pass a custom formatter, * use the default one. */ if (counterFormatter === undefined) { return defaultCounterText; } /** * Otherwise, try to use the custom formatter * and fallback to the default formatter if * there was an error. */ try { return counterFormatter(valueLength, maxLength); } catch (e) { index$1.printIonError('Exception in provided `counterFormatter`.', e); return defaultCounterText; } }; const defaultCounterFormatter = (length, maxlength) => { return `${length} / ${maxlength}`; }; exports.createNotchController = createNotchController; exports.createSlotMutationController = createSlotMutationController; exports.getCounterText = getCounterText; //# sourceMappingURL=input.utils-7c38acc4.js.map