diff options
Diffstat (limited to 'alpinejs/packages/alpinejs/src/lifecycle.js')
-rw-r--r-- | alpinejs/packages/alpinejs/src/lifecycle.js | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/alpinejs/packages/alpinejs/src/lifecycle.js b/alpinejs/packages/alpinejs/src/lifecycle.js new file mode 100644 index 0000000..75dc6c8 --- /dev/null +++ b/alpinejs/packages/alpinejs/src/lifecycle.js @@ -0,0 +1,84 @@ +import { startObservingMutations, onAttributesAdded, onElAdded, onElRemoved, cleanupAttributes } from "./mutation" +import { deferHandlingDirectives, directives } from "./directives" +import { dispatch } from './utils/dispatch' +import { nextTick } from "./nextTick" +import { walk } from "./utils/walk" +import { warn } from './utils/warn' + +export function start() { + if (! document.body) warn('Unable to initialize. Trying to load Alpine before `<body>` is available. Did you forget to add `defer` in Alpine\'s `<script>` tag?') + + dispatch(document, 'alpine:init') + dispatch(document, 'alpine:initializing') + + startObservingMutations() + + onElAdded(el => initTree(el, walk)) + onElRemoved(el => destroyTree(el)) + + onAttributesAdded((el, attrs) => { + directives(el, attrs).forEach(handle => handle()) + }) + + let outNestedComponents = el => ! closestRoot(el.parentElement, true) + Array.from(document.querySelectorAll(allSelectors())) + .filter(outNestedComponents) + .forEach(el => { + initTree(el) + }) + + dispatch(document, 'alpine:initialized') +} + +let rootSelectorCallbacks = [] +let initSelectorCallbacks = [] + +export function rootSelectors() { + return rootSelectorCallbacks.map(fn => fn()) +} + +export function allSelectors() { + return rootSelectorCallbacks.concat(initSelectorCallbacks).map(fn => fn()) +} + +export function addRootSelector(selectorCallback) { rootSelectorCallbacks.push(selectorCallback) } +export function addInitSelector(selectorCallback) { initSelectorCallbacks.push(selectorCallback) } + +export function closestRoot(el, includeInitSelectors = false) { + return findClosest(el, element => { + const selectors = includeInitSelectors ? allSelectors() : rootSelectors() + + if (selectors.some(selector => element.matches(selector))) return true + }) +} + +export function findClosest(el, callback) { + if (! el) return + + if (callback(el)) return el + + // Support crawling up teleports. + if (el._x_teleportBack) el = el._x_teleportBack + + if (! el.parentElement) return + + return findClosest(el.parentElement, callback) +} + +export function isRoot(el) { + return rootSelectors().some(selector => el.matches(selector)) +} + +export function initTree(el, walker = walk) { + deferHandlingDirectives(() => { + walker(el, (el, skip) => { + directives(el, el.attributes).forEach(handle => handle()) + + el._x_ignore && skip() + }) + }) +} + +export function destroyTree(root) { + walk(root, el => cleanupAttributes(el)) +} |