UNPKG

@ionic/core

Version:
148 lines (144 loc) 5.77 kB
/*! * (C) Ionic http://ionicframework.com - MIT License */ import { w as win } from './index5.js'; import { r as raf } from './helpers.js'; import { a as printIonError } from './index6.js'; /** * 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 (win !== undefined && 'MutationObserver' in 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. */ 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, }; }; 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) { printIonError('Exception in provided `counterFormatter`.', e); return defaultCounterText; } }; const defaultCounterFormatter = (length, maxlength) => { return `${length} / ${maxlength}`; }; export { createSlotMutationController as c, getCounterText as g };