diff options
Diffstat (limited to 'alpinejs/packages/alpinejs/src')
50 files changed, 0 insertions, 2729 deletions
diff --git a/alpinejs/packages/alpinejs/src/alpine.js b/alpinejs/packages/alpinejs/src/alpine.js deleted file mode 100644 index 0d5505c..0000000 --- a/alpinejs/packages/alpinejs/src/alpine.js +++ /dev/null @@ -1,54 +0,0 @@ -import { setReactivityEngine, disableEffectScheduling, reactive, effect, release, raw } from './reactivity' -import { mutateDom, deferMutations, flushAndStopDeferringMutations, stopObservingMutations } from './mutation' -import { mapAttributes, directive, setPrefix as prefix } from './directives' -import { start, addRootSelector, closestRoot, initTree, destroyTree } from './lifecycle' -import { setEvaluator, evaluate, evaluateLater } from './evaluator' -import { transition } from './directives/x-transition' -import { interceptor } from './interceptor' -import { setStyles } from './utils/styles' -import { debounce } from './utils/debounce' -import { throttle } from './utils/throttle' -import { nextTick } from './nextTick' -import { plugin } from './plugin' -import { magic } from './magics' -import { store } from './store' -import { clone } from './clone' -import { data } from './datas' - -let Alpine = { - get reactive() { return reactive }, - get release() { return release }, - get effect() { return effect }, - get raw() { return raw }, - version: ALPINE_VERSION, - flushAndStopDeferringMutations, - disableEffectScheduling, - stopObservingMutations, - setReactivityEngine, - addRootSelector, - deferMutations, - mapAttributes, - evaluateLater, - setEvaluator, - destroyTree, - closestRoot, - interceptor, // INTERNAL: not public API and is subject to change without major release. - transition, // INTERNAL - setStyles, // INTERNAL - mutateDom, - directive, - throttle, - debounce, - evaluate, - initTree, - nextTick, - prefix, - plugin, - magic, - store, - start, - clone, - data, -} - -export default Alpine diff --git a/alpinejs/packages/alpinejs/src/clone.js b/alpinejs/packages/alpinejs/src/clone.js deleted file mode 100644 index 0f37d05..0000000 --- a/alpinejs/packages/alpinejs/src/clone.js +++ /dev/null @@ -1,65 +0,0 @@ -import { effect, release, overrideEffect } from "./reactivity" -import { initTree, isRoot } from "./lifecycle" -import { walk } from "./utils/walk" - -let isCloning = false - -export function skipDuringClone(callback) { - return (...args) => isCloning || callback(...args) -} - -export function onlyDuringClone(callback) { - return (...args) => isCloning && callback(...args) -} - -export function skipWalkingSubClone(callback) { - return (...args) => isCloning || callback(...args) -} - -export function interuptCrawl(callback) { - return (...args) => isCloning || callback(...args) -} - -export function clone(oldEl, newEl) { - newEl._x_dataStack = oldEl._x_dataStack - - isCloning = true - - dontRegisterReactiveSideEffects(() => { - cloneTree(newEl) - }) - - isCloning = false -} - -export function cloneTree(el) { - let hasRunThroughFirstEl = false - - let shallowWalker = (el, callback) => { - walk(el, (el, skip) => { - if (hasRunThroughFirstEl && isRoot(el)) return skip() - - hasRunThroughFirstEl = true - - callback(el, skip) - }) - } - - initTree(el, shallowWalker) -} - -function dontRegisterReactiveSideEffects(callback) { - let cache = effect - - overrideEffect((callback, el) => { - let storedEffect = cache(callback) - - release(storedEffect) - - return () => {} - }) - - callback() - - overrideEffect(cache) -} diff --git a/alpinejs/packages/alpinejs/src/datas.js b/alpinejs/packages/alpinejs/src/datas.js deleted file mode 100644 index 9706581..0000000 --- a/alpinejs/packages/alpinejs/src/datas.js +++ /dev/null @@ -1,22 +0,0 @@ - -let datas = {} - -export function data(name, callback) { - datas[name] = callback -} - -export function injectDataProviders(obj, context) { - Object.entries(datas).forEach(([name, callback]) => { - Object.defineProperty(obj, name, { - get() { - return (...args) => { - return callback.bind(context)(...args) - } - }, - - enumerable: false, - }) - }) - - return obj -} diff --git a/alpinejs/packages/alpinejs/src/directives.js b/alpinejs/packages/alpinejs/src/directives.js deleted file mode 100644 index 906822f..0000000 --- a/alpinejs/packages/alpinejs/src/directives.js +++ /dev/null @@ -1,179 +0,0 @@ -import { onAttributeRemoved, onElRemoved } from './mutation' -import { evaluate, evaluateLater } from './evaluator' -import { elementBoundEffect } from './reactivity' -import Alpine from './alpine' - -let prefixAsString = 'x-' - -export function prefix(subject = '') { - return prefixAsString + subject -} - -export function setPrefix(newPrefix) { - prefixAsString = newPrefix -} - -let directiveHandlers = {} - -export function directive(name, callback) { - directiveHandlers[name] = callback -} - -export function directives(el, attributes, originalAttributeOverride) { - let transformedAttributeMap = {} - - let directives = Array.from(attributes) - .map(toTransformedAttributes((newName, oldName) => transformedAttributeMap[newName] = oldName)) - .filter(outNonAlpineAttributes) - .map(toParsedDirectives(transformedAttributeMap, originalAttributeOverride)) - .sort(byPriority) - - return directives.map(directive => { - return getDirectiveHandler(el, directive) - }) -} - -export function attributesOnly(attributes) { - return Array.from(attributes) - .map(toTransformedAttributes()) - .filter(attr => ! outNonAlpineAttributes(attr)) -} - -let isDeferringHandlers = false -let directiveHandlerStacks = new Map -let currentHandlerStackKey = Symbol() - -export function deferHandlingDirectives(callback) { - isDeferringHandlers = true - - let key = Symbol() - - currentHandlerStackKey = key - - directiveHandlerStacks.set(key, []) - - let flushHandlers = () => { - while (directiveHandlerStacks.get(key).length) directiveHandlerStacks.get(key).shift()() - - directiveHandlerStacks.delete(key) - } - - let stopDeferring = () => { isDeferringHandlers = false; flushHandlers() } - - callback(flushHandlers) - - stopDeferring() -} - -export function getDirectiveHandler(el, directive) { - let noop = () => {} - - let handler = directiveHandlers[directive.type] || noop - - let cleanups = [] - - let cleanup = callback => cleanups.push(callback) - - let [effect, cleanupEffect] = elementBoundEffect(el) - - cleanups.push(cleanupEffect) - - let utilities = { - Alpine, - effect, - cleanup, - evaluateLater: evaluateLater.bind(evaluateLater, el), - evaluate: evaluate.bind(evaluate, el), - } - - let doCleanup = () => cleanups.forEach(i => i()) - - onAttributeRemoved(el, directive.original, doCleanup) - - let fullHandler = () => { - if (el._x_ignore || el._x_ignoreSelf) return - - handler.inline && handler.inline(el, directive, utilities) - - handler = handler.bind(handler, el, directive, utilities) - - isDeferringHandlers ? directiveHandlerStacks.get(currentHandlerStackKey).push(handler) : handler() - } - - fullHandler.runCleanups = doCleanup - - return fullHandler -} - -export let startingWith = (subject, replacement) => ({ name, value }) => { - if (name.startsWith(subject)) name = name.replace(subject, replacement) - - return { name, value } -} - -export let into = i => i - -function toTransformedAttributes(callback = () => {}) { - return ({ name, value }) => { - let { name: newName, value: newValue } = attributeTransformers.reduce((carry, transform) => { - return transform(carry) - }, { name, value }) - - if (newName !== name) callback(newName, name) - - return { name: newName, value: newValue } - } -} - -let attributeTransformers = [] - -export function mapAttributes(callback) { - attributeTransformers.push(callback) -} - -function outNonAlpineAttributes({ name }) { - return alpineAttributeRegex().test(name) -} - -let alpineAttributeRegex = () => (new RegExp(`^${prefixAsString}([^:^.]+)\\b`)) - -function toParsedDirectives(transformedAttributeMap, originalAttributeOverride) { - return ({ name, value }) => { - let typeMatch = name.match(alpineAttributeRegex()) - let valueMatch = name.match(/:([a-zA-Z0-9\-:]+)/) - let modifiers = name.match(/\.[^.\]]+(?=[^\]]*$)/g) || [] - let original = originalAttributeOverride || transformedAttributeMap[name] || name - - return { - type: typeMatch ? typeMatch[1] : null, - value: valueMatch ? valueMatch[1] : null, - modifiers: modifiers.map(i => i.replace('.', '')), - expression: value, - original, - } - } -} - -const DEFAULT = 'DEFAULT' - -let directiveOrder = [ - 'ignore', - 'ref', - 'data', - 'bind', - 'init', - 'for', - 'model', - 'transition', - 'show', - 'if', - DEFAULT, - 'element', -] - -function byPriority(a, b) { - let typeA = directiveOrder.indexOf(a.type) === -1 ? DEFAULT : a.type - let typeB = directiveOrder.indexOf(b.type) === -1 ? DEFAULT : b.type - - return directiveOrder.indexOf(typeA) - directiveOrder.indexOf(typeB) -} diff --git a/alpinejs/packages/alpinejs/src/directives/index.js b/alpinejs/packages/alpinejs/src/directives/index.js deleted file mode 100644 index e9e05c7..0000000 --- a/alpinejs/packages/alpinejs/src/directives/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import './x-transition' -import './x-ignore' -import './x-effect' -import './x-model' -import './x-cloak' -import './x-init' -import './x-text' -import './x-html' -import './x-bind' -import './x-data' -import './x-show' -import './x-for' -import './x-ref' -import './x-if' -import './x-on' diff --git a/alpinejs/packages/alpinejs/src/directives/x-bind.js b/alpinejs/packages/alpinejs/src/directives/x-bind.js deleted file mode 100644 index 3f8611b..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-bind.js +++ /dev/null @@ -1,54 +0,0 @@ -import { attributesOnly, directive, directives, into, mapAttributes, prefix, startingWith } from '../directives' -import { evaluateLater } from '../evaluator' -import { mutateDom } from '../mutation' -import bind from '../utils/bind' - -mapAttributes(startingWith(':', into(prefix('bind:')))) - -directive('bind', (el, { value, modifiers, expression, original }, { effect }) => { - if (! value) return applyBindingsObject(el, expression, original, effect) - - if (value === 'key') return storeKeyForXFor(el, expression) - - let evaluate = evaluateLater(el, expression) - - effect(() => evaluate(result => { - // If nested object key is undefined, set the default value to empty string. - if (result === undefined && expression.match(/\./)) result = '' - - mutateDom(() => bind(el, value, result, modifiers)) - })) -}) - -function applyBindingsObject(el, expression, original, effect) { - let getBindings = evaluateLater(el, expression) - - let cleanupRunners = [] - - effect(() => { - while (cleanupRunners.length) cleanupRunners.pop()() - - getBindings(bindings => { - let attributes = Object.entries(bindings).map(([name, value]) => ({ name, value })) - - // Handle binding normal HTML attributes (non-Alpine directives). - attributesOnly(attributes).forEach(({ name, value }, index) => { - attributes[index] = { - name: `x-bind:${name}`, - value: `"${value}"`, - } - }) - - directives(el, attributes, original).map(handle => { - cleanupRunners.push(handle.runCleanups) - - handle() - }) - }) - - }) -} - -function storeKeyForXFor(el, expression) { - el._x_keyExpression = expression -} diff --git a/alpinejs/packages/alpinejs/src/directives/x-cloak.js b/alpinejs/packages/alpinejs/src/directives/x-cloak.js deleted file mode 100644 index 84639f0..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-cloak.js +++ /dev/null @@ -1,4 +0,0 @@ -import { directive, prefix } from '../directives' -import { mutateDom } from '../mutation' - -directive('cloak', el => queueMicrotask(() => mutateDom(() => el.removeAttribute(prefix('cloak'))))) diff --git a/alpinejs/packages/alpinejs/src/directives/x-data.js b/alpinejs/packages/alpinejs/src/directives/x-data.js deleted file mode 100644 index e88802c..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-data.js +++ /dev/null @@ -1,43 +0,0 @@ -import { directive, prefix } from '../directives' -import { initInterceptors } from '../interceptor' -import { injectDataProviders } from '../datas' -import { addRootSelector } from '../lifecycle' -import { skipDuringClone } from '../clone' -import { addScopeToNode } from '../scope' -import { injectMagics, magic } from '../magics' -import { reactive } from '../reactivity' -import { evaluate } from '../evaluator' - -addRootSelector(() => `[${prefix('data')}]`) - -directive('data', skipDuringClone((el, { expression }, { cleanup }) => { - expression = expression === '' ? '{}' : expression - - let magicContext = {} - let cleanup1 = injectMagics(magicContext, el).cleanup - - let dataProviderContext = {} - injectDataProviders(dataProviderContext, magicContext) - - let data = evaluate(el, expression, { scope: dataProviderContext }) - - let cleanup2 = injectMagics(data, el).cleanup - - let reactiveData = reactive(data) - - initInterceptors(reactiveData) - - let undo = addScopeToNode(el, reactiveData) - - reactiveData['init'] && evaluate(el, reactiveData['init']) - - cleanup(() => { - undo() - - // MemLeak1: Issue #2140 - cleanup1() - cleanup2() - - reactiveData['destroy'] && evaluate(el, reactiveData['destroy']) - }) -})) diff --git a/alpinejs/packages/alpinejs/src/directives/x-effect.js b/alpinejs/packages/alpinejs/src/directives/x-effect.js deleted file mode 100644 index c421417..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-effect.js +++ /dev/null @@ -1,4 +0,0 @@ -import { directive } from '../directives' -import { evaluateLater } from '../evaluator' - -directive('effect', (el, { expression }, { effect }) => effect(evaluateLater(el, expression))) diff --git a/alpinejs/packages/alpinejs/src/directives/x-for.js b/alpinejs/packages/alpinejs/src/directives/x-for.js deleted file mode 100644 index 504306d..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-for.js +++ /dev/null @@ -1,262 +0,0 @@ -import { addScopeToNode, refreshScope } from '../scope' -import { evaluateLater } from '../evaluator' -import { directive } from '../directives' -import { reactive } from '../reactivity' -import { initTree } from '../lifecycle' -import { mutateDom } from '../mutation' -import { flushJobs } from '../scheduler' -import { warn } from '../utils/warn' - -directive('for', (el, { expression }, { effect, cleanup }) => { - let iteratorNames = parseForExpression(expression) - - let evaluateItems = evaluateLater(el, iteratorNames.items) - let evaluateKey = evaluateLater(el, - // the x-bind:key expression is stored for our use instead of evaluated. - el._x_keyExpression || 'index' - ) - - el._x_prevKeys = [] - el._x_lookup = {} - - effect(() => loop(el, iteratorNames, evaluateItems, evaluateKey)) - - cleanup(() => { - Object.values(el._x_lookup).forEach(el => el.remove()) - - delete el._x_prevKeys - delete el._x_lookup - }) -}) - -let shouldFastRender = true - -function loop(el, iteratorNames, evaluateItems, evaluateKey) { - let isObject = i => typeof i === 'object' && ! Array.isArray(i) - let templateEl = el - - evaluateItems(items => { - // Prepare yourself. There's a lot going on here. Take heart, - // every bit of complexity in this function was added for - // the purpose of making Alpine fast with large datas. - - // Support number literals. Ex: x-for="i in 100" - if (isNumeric(items) && items >= 0) { - items = Array.from(Array(items).keys(), i => i + 1) - } - - if (items === undefined) items = [] - - let lookup = el._x_lookup - let prevKeys = el._x_prevKeys - let scopes = [] - let keys = [] - - // In order to preserve DOM elements (move instead of replace) - // we need to generate all the keys for every iteration up - // front. These will be our source of truth for diffing. - if (isObject(items)) { - items = Object.entries(items).map(([key, value]) => { - let scope = getIterationScopeVariables(iteratorNames, value, key, items) - - evaluateKey(value => keys.push(value), { scope: { index: key, ...scope} }) - - scopes.push(scope) - }) - } else { - for (let i = 0; i < items.length; i++) { - let scope = getIterationScopeVariables(iteratorNames, items[i], i, items) - - evaluateKey(value => keys.push(value), { scope: { index: i, ...scope} }) - - scopes.push(scope) - } - } - - // Rather than making DOM manipulations inside one large loop, we'll - // instead track which mutations need to be made in the following - // arrays. After we're finished, we can batch them at the end. - let adds = [] - let moves = [] - let removes = [] - let sames = [] - - // First, we track elements that will need to be removed. - for (let i = 0; i < prevKeys.length; i++) { - let key = prevKeys[i] - - if (keys.indexOf(key) === -1) removes.push(key) - } - - // Notice we're mutating prevKeys as we go. This makes it - // so that we can efficiently make incremental comparisons. - prevKeys = prevKeys.filter(key => ! removes.includes(key)) - - let lastKey = 'template' - - // This is the important part of the diffing algo. Identifying - // which keys (future DOM elements) are new, which ones have - // or haven't moved (noting where they moved to / from). - for (let i = 0; i < keys.length; i++) { - let key = keys[i] - - let prevIndex = prevKeys.indexOf(key) - - if (prevIndex === -1) { - // New key found. - prevKeys.splice(i, 0, key) - - adds.push([lastKey, i]) - } else if (prevIndex !== i) { - // A key has moved. - let keyInSpot = prevKeys.splice(i, 1)[0] - let keyForSpot = prevKeys.splice(prevIndex - 1, 1)[0] - - prevKeys.splice(i, 0, keyForSpot) - prevKeys.splice(prevIndex, 0, keyInSpot) - - moves.push([keyInSpot, keyForSpot]) - } else { - // This key hasn't moved, but we'll still keep track - // so that we can refresh it later on. - sames.push(key) - } - - lastKey = key - } - - // Now that we've done the diffing work, we can apply the mutations - // in batches for both separating types work and optimizing - // for browser performance. - - // We'll remove all the nodes that need to be removed, - // letting the mutation observer pick them up and - // clean up any side effects they had. - for (let i = 0; i < removes.length; i++) { - let key = removes[i] - - lookup[key].remove() - - lookup[key] = null - delete lookup[key] - } - - // Here we'll move elements around, skipping - // mutation observer triggers by using "mutateDom". - for (let i = 0; i < moves.length; i++) { - let [keyInSpot, keyForSpot] = moves[i] - - let elInSpot = lookup[keyInSpot] - let elForSpot = lookup[keyForSpot] - - let marker = document.createElement('div') - - mutateDom(() => { - elForSpot.after(marker) - elInSpot.after(elForSpot) - marker.before(elInSpot) - marker.remove() - }) - - refreshScope(elForSpot, scopes[keys.indexOf(keyForSpot)]) - } - - // We can now create and add new elements. - for (let i = 0; i < adds.length; i++) { - let [lastKey, index] = adds[i] - - let lastEl = (lastKey === 'template') ? templateEl : lookup[lastKey] - - let scope = scopes[index] - let key = keys[index] - - let clone = document.importNode(templateEl.content, true).firstElementChild - - addScopeToNode(clone, reactive(scope), templateEl) - - mutateDom(() => { - lastEl.after(clone) - - initTree(clone) - }) - - if (typeof key === 'object') { - warn('x-for key cannot be an object, it must be a string or an integer', templateEl) - } - - lookup[key] = clone - } - - // If an element hasn't changed, we still want to "refresh" the - // data it depends on in case the data has changed in an - // "unobservable" way. - for (let i = 0; i < sames.length; i++) { - refreshScope(lookup[sames[i]], scopes[keys.indexOf(sames[i])]) - } - - // Now we'll log the keys (and the order they're in) for comparing - // against next time. - templateEl._x_prevKeys = keys - }) -} - -// This was taken from VueJS 2.* core. Thanks Vue! -function parseForExpression(expression) { - let forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/ - let stripParensRE = /^\s*\(|\)\s*$/g - let forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/ - let inMatch = expression.match(forAliasRE) - - if (! inMatch) return - - let res = {} - res.items = inMatch[2].trim() - let item = inMatch[1].replace(stripParensRE, '').trim() - let iteratorMatch = item.match(forIteratorRE) - - if (iteratorMatch) { - res.item = item.replace(forIteratorRE, '').trim() - res.index = iteratorMatch[1].trim() - - if (iteratorMatch[2]) { - res.collection = iteratorMatch[2].trim() - } - } else { - res.item = item - } - - return res -} - -function getIterationScopeVariables(iteratorNames, item, index, items) { - // We must create a new object, so each iteration has a new scope - let scopeVariables = {} - - // Support array destructuring ([foo, bar]). - if (/^\[.*\]$/.test(iteratorNames.item) && Array.isArray(item)) { - let names = iteratorNames.item.replace('[', '').replace(']', '').split(',').map(i => i.trim()) - - names.forEach((name, i) => { - scopeVariables[name] = item[i] - }) - // Support object destructuring ({ foo: 'oof', bar: 'rab' }). - } else if (/^\{.*\}$/.test(iteratorNames.item) && ! Array.isArray(item) && typeof item === 'object') { - let names = iteratorNames.item.replace('{', '').replace('}', '').split(',').map(i => i.trim()) - - names.forEach(name => { - scopeVariables[name] = item[name] - }) - } else { - scopeVariables[iteratorNames.item] = item - } - - if (iteratorNames.index) scopeVariables[iteratorNames.index] = index - - if (iteratorNames.collection) scopeVariables[iteratorNames.collection] = items - - return scopeVariables -} - -function isNumeric(subject){ - return ! Array.isArray(subject) && ! isNaN(subject) -} diff --git a/alpinejs/packages/alpinejs/src/directives/x-html.js b/alpinejs/packages/alpinejs/src/directives/x-html.js deleted file mode 100644 index b4977d3..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-html.js +++ /dev/null @@ -1,13 +0,0 @@ -import { evaluateLater } from '../evaluator' -import { directive } from '../directives' -import { mutateDom } from '../mutation' - -directive('html', (el, { expression }, { effect, evaluateLater }) => { - let evaluate = evaluateLater(expression) - - effect(() => { - evaluate(value => { - el.innerHTML = value - }) - }) -}) diff --git a/alpinejs/packages/alpinejs/src/directives/x-if.js b/alpinejs/packages/alpinejs/src/directives/x-if.js deleted file mode 100644 index 8cbb030..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-if.js +++ /dev/null @@ -1,43 +0,0 @@ -import { evaluateLater } from '../evaluator' -import { addScopeToNode } from '../scope' -import { directive } from '../directives' -import { initTree } from '../lifecycle' -import { mutateDom } from '../mutation' - -directive('if', (el, { expression }, { effect, cleanup }) => { - let evaluate = evaluateLater(el, expression) - - let show = () => { - if (el._x_currentIfEl) return el._x_currentIfEl - - let clone = el.content.cloneNode(true).firstElementChild - - addScopeToNode(clone, {}, el) - - mutateDom(() => { - el.after(clone) - - initTree(clone) - }) - - el._x_currentIfEl = clone - - el._x_undoIf = () => { clone.remove(); delete el._x_currentIfEl } - - return clone - } - - let hide = () => { - if (! el._x_undoIf) return - - el._x_undoIf() - - delete el._x_undoIf - } - - effect(() => evaluate(value => { - value ? show() : hide() - })) - - cleanup(() => el._x_undoIf && el._x_undoIf()) -}) diff --git a/alpinejs/packages/alpinejs/src/directives/x-ignore.js b/alpinejs/packages/alpinejs/src/directives/x-ignore.js deleted file mode 100644 index 2f21de3..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-ignore.js +++ /dev/null @@ -1,17 +0,0 @@ -import { directive } from "../directives" - -let handler = () => {} - -handler.inline = (el, { modifiers }, { cleanup }) => { - modifiers.includes('self') - ? el._x_ignoreSelf = true - : el._x_ignore = true - - cleanup(() => { - modifiers.includes('self') - ? delete el._x_ignoreSelf - : delete el._x_ignore - }) -} - -directive('ignore', handler) diff --git a/alpinejs/packages/alpinejs/src/directives/x-init.js b/alpinejs/packages/alpinejs/src/directives/x-init.js deleted file mode 100644 index a11cb04..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-init.js +++ /dev/null @@ -1,14 +0,0 @@ -import { directive, prefix } from "../directives"; -import { addInitSelector } from "../lifecycle"; -import { skipDuringClone } from "../clone"; -import { evaluate } from "../evaluator"; - -addInitSelector(() => `[${prefix('init')}]`) - -directive('init', skipDuringClone((el, { expression }) => { - if (typeof expression === 'string') { - return !! expression.trim() && evaluate(el, expression, {}, false) - } - - return evaluate(el, expression, {}, false) -})) diff --git a/alpinejs/packages/alpinejs/src/directives/x-model.js b/alpinejs/packages/alpinejs/src/directives/x-model.js deleted file mode 100644 index 12ee3d8..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-model.js +++ /dev/null @@ -1,107 +0,0 @@ -import { evaluateLater } from '../evaluator' -import { directive } from '../directives' -import { mutateDom } from '../mutation' -import bind from '../utils/bind' -import on from '../utils/on' - -directive('model', (el, { modifiers, expression }, { effect, cleanup }) => { - let evaluate = evaluateLater(el, expression) - let assignmentExpression = `${expression} = rightSideOfExpression($event, ${expression})` - let evaluateAssignment = evaluateLater(el, assignmentExpression) - - // If the element we are binding to is a select, a radio, or checkbox - // we'll listen for the change event instead of the "input" event. - var event = (el.tagName.toLowerCase() === 'select') - || ['checkbox', 'radio'].includes(el.type) - || modifiers.includes('lazy') - ? 'change' : 'input' - - let assigmentFunction = generateAssignmentFunction(el, modifiers, expression) - - let removeListener = on(el, event, modifiers, (e) => { - evaluateAssignment(() => {}, { scope: { - '$event': e, - rightSideOfExpression: assigmentFunction - }}) - }) - - cleanup(() => removeListener()) - - el._x_forceModelUpdate = () => { - evaluate(value => { - // If nested model key is undefined, set the default value to empty string. - if (value === undefined && expression.match(/\./)) value = '' - - // @todo: This is nasty - window.fromModel = true - mutateDom(() => bind(el, 'value', value)) - delete window.fromModel - }) - } - - effect(() => { - // Don't modify the value of the input if it's focused. - if (modifiers.includes('unintrusive') && document.activeElement.isSameNode(el)) return - - el._x_forceModelUpdate() - }) -}) - -function generateAssignmentFunction(el, modifiers, expression) { - if (el.type === 'radio') { - // Radio buttons only work properly when they share a name attribute. - // People might assume we take care of that for them, because - // they already set a shared "x-model" attribute. - mutateDom(() => { - if (! el.hasAttribute('name')) el.setAttribute('name', expression) - }) - } - - return (event, currentValue) => { - return mutateDom(() => { - // Check for event.detail due to an issue where IE11 handles other events as a CustomEvent. - // Safari autofill triggers event as CustomEvent and assigns value to target - // so we return event.target.value instead of event.detail - if (event instanceof CustomEvent && event.detail !== undefined) { - return event.detail || event.target.value - } else if (el.type === 'checkbox') { - // If the data we are binding to is an array, toggle its value inside the array. - if (Array.isArray(currentValue)) { - let newValue = modifiers.includes('number') ? safeParseNumber(event.target.value) : event.target.value - - return event.target.checked ? currentValue.concat([newValue]) : currentValue.filter(el => ! checkedAttrLooseCompare(el, newValue)) - } else { - return event.target.checked - } - } else if (el.tagName.toLowerCase() === 'select' && el.multiple) { - return modifiers.includes('number') - ? Array.from(event.target.selectedOptions).map(option => { - let rawValue = option.value || option.text - return safeParseNumber(rawValue) - }) - : Array.from(event.target.selectedOptions).map(option => { - return option.value || option.text - }) - } else { - let rawValue = event.target.value - return modifiers.includes('number') - ? safeParseNumber(rawValue) - : (modifiers.includes('trim') ? rawValue.trim() : rawValue) - } - }) - } -} - -function safeParseNumber(rawValue) { - let number = rawValue ? parseFloat(rawValue) : null - - return isNumeric(number) ? number : rawValue -} - -function checkedAttrLooseCompare(valueA, valueB) { - return valueA == valueB -} - -function isNumeric(subject){ - return ! Array.isArray(subject) && ! isNaN(subject) -} diff --git a/alpinejs/packages/alpinejs/src/directives/x-on.js b/alpinejs/packages/alpinejs/src/directives/x-on.js deleted file mode 100644 index 91c6d89..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-on.js +++ /dev/null @@ -1,16 +0,0 @@ -import { directive, into, mapAttributes, prefix, startingWith } from '../directives' -import { evaluateLater } from '../evaluator' -import { skipDuringClone } from '../clone' -import on from '../utils/on' - -mapAttributes(startingWith('@', into(prefix('on:')))) - -directive('on', skipDuringClone((el, { value, modifiers, expression }, { cleanup }) => { - let evaluate = expression ? evaluateLater(el, expression) : () => {} - - let removeListener = on(el, value, modifiers, e => { - evaluate(() => {}, { scope: { '$event': e }, params: [e] }) - }) - - cleanup(() => removeListener()) -})) diff --git a/alpinejs/packages/alpinejs/src/directives/x-ref.js b/alpinejs/packages/alpinejs/src/directives/x-ref.js deleted file mode 100644 index 9d6bbf6..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-ref.js +++ /dev/null @@ -1,16 +0,0 @@ -import { closestRoot } from '../lifecycle' -import { directive } from '../directives' - -function handler () {} - -handler.inline = (el, { expression }, { cleanup }) => { - let root = closestRoot(el) - - if (! root._x_refs) root._x_refs = {} - - root._x_refs[expression] = el - - cleanup(() => delete root._x_refs[expression]) -} - -directive('ref', handler) diff --git a/alpinejs/packages/alpinejs/src/directives/x-show.js b/alpinejs/packages/alpinejs/src/directives/x-show.js deleted file mode 100644 index b9619b5..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-show.js +++ /dev/null @@ -1,56 +0,0 @@ -import { evaluateLater } from '../evaluator' -import { directive } from '../directives' -import { mutateDom } from '../mutation' -import { once } from '../utils/once' - -directive('show', (el, { modifiers, expression }, { effect }) => { - let evaluate = evaluateLater(el, expression) - - let hide = () => mutateDom(() => { - el.style.display = 'none' - - el._x_isShown = false - }) - - let show = () => mutateDom(() => { - if (el.style.length === 1 && el.style.display === 'none') { - el.removeAttribute('style') - } else { - el.style.removeProperty('display') - } - - el._x_isShown = true - }) - - // We are wrapping this function in a setTimeout here to prevent - // a race condition from happening where elements that have a - // @click.away always view themselves as shown on the page. - let clickAwayCompatibleShow = () => setTimeout(show) - - let toggle = once( - value => value ? show() : hide(), - value => { - if (typeof el._x_toggleAndCascadeWithTransitions === 'function') { - el._x_toggleAndCascadeWithTransitions(el, value, show, hide) - } else { - value ? clickAwayCompatibleShow() : hide() - } - } - ) - - let oldValue - let firstTime = true - - effect(() => evaluate(value => { - // Let's make sure we only call this effect if the value changed. - // This prevents "blip" transitions. (1 tick out, then in) - if (! firstTime && value === oldValue) return - - if (modifiers.includes('immediate')) value ? clickAwayCompatibleShow() : hide() - - toggle(value) - - oldValue = value - firstTime = false - })) -}) diff --git a/alpinejs/packages/alpinejs/src/directives/x-text.js b/alpinejs/packages/alpinejs/src/directives/x-text.js deleted file mode 100644 index 74be109..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-text.js +++ /dev/null @@ -1,14 +0,0 @@ -import { directive } from '../directives' -import { mutateDom } from '../mutation' - -directive('text', (el, { expression }, { effect, evaluateLater }) => { - let evaluate = evaluateLater(expression) - - effect(() => { - evaluate(value => { - mutateDom(() => { - el.textContent = value - }) - }) - }) -}) diff --git a/alpinejs/packages/alpinejs/src/directives/x-transition.js b/alpinejs/packages/alpinejs/src/directives/x-transition.js deleted file mode 100644 index 7e82a78..0000000 --- a/alpinejs/packages/alpinejs/src/directives/x-transition.js +++ /dev/null @@ -1,325 +0,0 @@ -import { releaseNextTicks, holdNextTicks } from '../nextTick' -import { setClasses } from '../utils/classes' -import { setStyles } from '../utils/styles' -import { directive } from '../directives' -import { mutateDom } from '../mutation' -import { once } from '../utils/once' - -directive('transition', (el, { value, modifiers, expression }, { evaluate }) => { - if (typeof expression === 'function') expression = evaluate(expression) - - if (! expression) { - registerTransitionsFromHelper(el, modifiers, value) - } else { - registerTransitionsFromClassString(el, expression, value) - } -}) - -function registerTransitionsFromClassString(el, classString, stage) { - registerTransitionObject(el, setClasses, '') - - let directiveStorageMap = { - 'enter': (classes) => { el._x_transition.enter.during = classes }, - 'enter-start': (classes) => { el._x_transition.enter.start = classes }, - 'enter-end': (classes) => { el._x_transition.enter.end = classes }, - 'leave': (classes) => { el._x_transition.leave.during = classes }, - 'leave-start': (classes) => { el._x_transition.leave.start = classes }, - 'leave-end': (classes) => { el._x_transition.leave.end = classes }, - } - - directiveStorageMap[stage](classString) -} - -function registerTransitionsFromHelper(el, modifiers, stage) { - registerTransitionObject(el, setStyles) - - let doesntSpecify = (! modifiers.includes('in') && ! modifiers.includes('out')) && ! stage - let transitioningIn = doesntSpecify || modifiers.includes('in') || ['enter'].includes(stage) - let transitioningOut = doesntSpecify || modifiers.includes('out') || ['leave'].includes(stage) - - if (modifiers.includes('in') && ! doesntSpecify) { - modifiers = modifiers.filter((i, index) => index < modifiers.indexOf('out')) - } - - if (modifiers.includes('out') && ! doesntSpecify) { - modifiers = modifiers.filter((i, index) => index > modifiers.indexOf('out')) - } - - let wantsAll = ! modifiers.includes('opacity') && ! modifiers.includes('scale') - let wantsOpacity = wantsAll || modifiers.includes('opacity') - let wantsScale = wantsAll || modifiers.includes('scale') - let opacityValue = wantsOpacity ? 0 : 1 - let scaleValue = wantsScale ? modifierValue(modifiers, 'scale', 95) / 100 : 1 - let delay = modifierValue(modifiers, 'delay', 0) - let origin = modifierValue(modifiers, 'origin', 'center') - let property = 'opacity, transform' - let durationIn = modifierValue(modifiers, 'duration', 150) / 1000 - let durationOut = modifierValue(modifiers, 'duration', 75) / 1000 - let easing = `cubic-bezier(0.4, 0.0, 0.2, 1)` - - if (transitioningIn) { - el._x_transition.enter.during = { - transformOrigin: origin, - transitionDelay: delay, - transitionProperty: property, - transitionDuration: `${durationIn}s`, - transitionTimingFunction: easing, - } - - el._x_transition.enter.start = { - opacity: opacityValue, - transform: `scale(${scaleValue})`, - } - - el._x_transition.enter.end = { - opacity: 1, - transform: `scale(1)`, - } - } - - if (transitioningOut) { - el._x_transition.leave.during = { - transformOrigin: origin, - transitionDelay: delay, - transitionProperty: property, - transitionDuration: `${durationOut}s`, - transitionTimingFunction: easing, - } - - el._x_transition.leave.start = { - opacity: 1, - transform: `scale(1)`, - } - - el._x_transition.leave.end = { - opacity: opacityValue, - transform: `scale(${scaleValue})`, - } - } -} - -function registerTransitionObject(el, setFunction, defaultValue = {}) { - if (! el._x_transition) el._x_transition = { - enter: { during: defaultValue, start: defaultValue, end: defaultValue }, - - leave: { during: defaultValue, start: defaultValue, end: defaultValue }, - - in(before = () => {}, after = () => {}) { - transition(el, setFunction, { - during: this.enter.during, - start: this.enter.start, - end: this.enter.end, - }, before, after) - }, - - out(before = () => {}, after = () => {}) { - transition(el, setFunction, { - during: this.leave.during, - start: this.leave.start, - end: this.leave.end, - }, before, after) - }, - } -} - -window.Element.prototype._x_toggleAndCascadeWithTransitions = function (el, value, show, hide) { - // We are running this function after one tick to prevent - // a race condition from happening where elements that have a - // @click.away always view themselves as shown on the page. - // If the tab is active, we prioritise requestAnimationFrame which plays - // nicely with nested animations otherwise we use setTimeout to make sure - // it keeps running in background. setTimeout has a lower priority in the - // event loop so it would skip nested transitions but when the tab is - // hidden, it's not relevant. - let clickAwayCompatibleShow = () => {document.visibilityState === 'visible' ? requestAnimationFrame(show) : setTimeout(show)} - - if (value) { - el._x_transition - ? el._x_transition.in(show) - : clickAwayCompatibleShow() - - return - } - - // Livewire depends on el._x_hidePromise. - el._x_hidePromise = el._x_transition - ? new Promise((resolve, reject) => { - el._x_transition.out(() => {}, () => resolve(hide)) - - el._x_transitioning.beforeCancel(() => reject({ isFromCancelledTransition: true })) - }) - : Promise.resolve(hide) - - queueMicrotask(() => { - let closest = closestHide(el) - - if (closest) { - if (! closest._x_hideChildren) closest._x_hideChildren = [] - - closest._x_hideChildren.push(el) - } else { - queueMicrotask(() => { - let hideAfterChildren = el => { - let carry = Promise.all([ - el._x_hidePromise, - ...(el._x_hideChildren || []).map(hideAfterChildren), - ]).then(([i]) => i()) - - delete el._x_hidePromise - delete el._x_hideChildren - - return carry - } - - hideAfterChildren(el).catch((e) => { - if (! e.isFromCancelledTransition) throw e - }) - }) - } - }) -} - -function closestHide(el) { - let parent = el.parentNode - - if (! parent) return - - return parent._x_hidePromise ? parent : closestHide(parent) -} - -export function transition(el, setFunction, { during, start, end } = {}, before = () => {}, after = () => {}) { - if (el._x_transitioning) el._x_transitioning.cancel() - - if (Object.keys(during).length === 0 && Object.keys(start).length === 0 && Object.keys(end).length === 0) { - // Execute right away if there is no transition. - before(); after() - return - } - - let undoStart, undoDuring, undoEnd - - performTransition(el, { - start() { - undoStart = setFunction(el, start) - }, - during() { - undoDuring = setFunction(el, during) - }, - before, - end() { - undoStart() - - undoEnd = setFunction(el, end) - }, - after, - cleanup() { - undoDuring() - undoEnd() - }, - }) -} - -export function performTransition(el, stages) { - // All transitions need to be truly "cancellable". Meaning we need to - // account for interruptions at ALL stages of the transitions and - // immediately run the rest of the transition. - let interrupted, reachedBefore, reachedEnd - - let finish = once(() => { - mutateDom(() => { - interrupted = true - - if (! reachedBefore) stages.before() - - if (! reachedEnd) { - stages.end() - - releaseNextTicks() - } - - stages.after() - - // Adding an "isConnected" check, in case the callback removed the element from the DOM. - if (el.isConnected) stages.cleanup() - - delete el._x_transitioning - }) - }) - - el._x_transitioning = { - beforeCancels: [], - beforeCancel(callback) { this.beforeCancels.push(callback) }, - cancel: once(function () { while (this.beforeCancels.length) { this.beforeCancels.shift()() }; finish(); }), - finish, - } - - mutateDom(() => { - stages.start() - stages.during() - }) - - holdNextTicks() - - requestAnimationFrame(() => { - if (interrupted) return - - // Note: Safari's transitionDuration property will list out comma separated transition durations - // for every single transition property. Let's grab the first one and call it a day. - let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000 - let delay = Number(getComputedStyle(el).transitionDelay.replace(/,.*/, '').replace('s', '')) * 1000 - - if (duration === 0) duration = Number(getComputedStyle(el).animationDuration.replace('s', '')) * 1000 - - mutateDom(() => { - stages.before() - }) - - reachedBefore = true - - requestAnimationFrame(() => { - if (interrupted) return - - mutateDom(() => { - stages.end() - }) - - releaseNextTicks() - - setTimeout(el._x_transitioning.finish, duration + delay) - - reachedEnd = true - }) - }) -} - -export function modifierValue(modifiers, key, fallback) { - // If the modifier isn't present, use the default. - if (modifiers.indexOf(key) === -1) return fallback - - // If it IS present, grab the value after it: x-show.transition.duration.500ms - const rawValue = modifiers[modifiers.indexOf(key) + 1] - - if (! rawValue) return fallback - - if (key === 'scale') { - // Check if the very next value is NOT a number and return the fallback. - // If x-show.transition.scale, we'll use the default scale value. - // That is how a user opts out of the opacity transition. - if (isNaN(rawValue)) return fallback - } - - if (key === 'duration') { - // Support x-transition.duration.500ms && duration.500 - let match = rawValue.match(/([0-9]+)ms/) - if (match) return match[1] - } - - if (key === 'origin') { - // Support chaining origin directions: x-show.transition.top.right - if (['top', 'right', 'left', 'center', 'bottom'].includes(modifiers[modifiers.indexOf(key) + 2])) { - return [rawValue, modifiers[modifiers.indexOf(key) + 2]].join(' ') - } - } - - return rawValue -} diff --git a/alpinejs/packages/alpinejs/src/evaluator.js b/alpinejs/packages/alpinejs/src/evaluator.js deleted file mode 100644 index 2bb4d11..0000000 --- a/alpinejs/packages/alpinejs/src/evaluator.js +++ /dev/null @@ -1,125 +0,0 @@ -import { closestDataStack, mergeProxies } from './scope' -import { injectMagics } from './magics' -import { onAttributeRemoved } from './mutation' - -export function evaluate(el, expression, extras = {}) { - let result - - evaluateLater(el, expression)(value => result = value, extras) - - return result -} - -export function evaluateLater(...args) { - return theEvaluatorFunction(...args) -} - -let theEvaluatorFunction = normalEvaluator - -export function setEvaluator(newEvaluator) { - theEvaluatorFunction = newEvaluator -} - -export function normalEvaluator(el, expression) { - let overriddenMagics = {} - - let cleanup = injectMagics(overriddenMagics, el).cleanup - - // MemLeak1: Issue #2140 (note: there are other uses of injectMagics) - onAttributeRemoved(el, "evaluator", cleanup) - - let dataStack = [overriddenMagics, ...closestDataStack(el)] - - if (typeof expression === 'function') { - return generateEvaluatorFromFunction(dataStack, expression) - } - - let evaluator = generateEvaluatorFromString(dataStack, expression) - - return tryCatch.bind(null, el, expression, evaluator) -} - -export function generateEvaluatorFromFunction(dataStack, func) { - return (receiver = () => {}, { scope = {}, params = [] } = {}) => { - let result = func.apply(mergeProxies([scope, ...dataStack]), params) - - runIfTypeOfFunction(receiver, result) - } -} - -let evaluatorMemo = {} - -function generateFunctionFromString(expression) { - if (evaluatorMemo[expression]) { - return evaluatorMemo[expression] - } - - let AsyncFunction = Object.getPrototypeOf(async function(){}).constructor - - // Some expressions that are useful in Alpine are not valid as the right side of an expression. - // Here we'll detect if the expression isn't valid for an assignement and wrap it in a self- - // calling function so that we don't throw an error AND a "return" statement can b e used. - let rightSideSafeExpression = 0 - // Support expressions starting with "if" statements like: "if (...) doSomething()" - || /^[\n\s]*if.*\(.*\)/.test(expression) - // Support expressions starting with "let/const" like: "let foo = 'bar'" - || /^(let|const)/.test(expression) - ? `(() => { ${expression} })()` - : expression - - let func = new AsyncFunction(['__self', 'scope'], `with (scope) { __self.result = ${rightSideSafeExpression} }; __self.finished = true; return __self.result;`) - - evaluatorMemo[expression] = func - - return func -} - -function generateEvaluatorFromString(dataStack, expression) { - let func = generateFunctionFromString(expression) - - return (receiver = () => {}, { scope = {}, params = [] } = {}) => { - func.result = undefined - func.finished = false - - // Run the function. - - let completeScope = mergeProxies([ scope, ...dataStack ]) - - let promise = func(func, completeScope) - - // Check if the function ran synchronously, - if (func.finished) { - // Return the immediate result. - runIfTypeOfFunction(receiver, func.result, completeScope, params) - } else { - // If not, return the result when the promise resolves. - promise.then(result => { - runIfTypeOfFunction(receiver, result, completeScope, params) - }) - } - } -} - -export function runIfTypeOfFunction(receiver, value, scope, params) { - if (typeof value === 'function') { - let result = value.apply(scope, params) - - if (result instanceof Promise) { - result.then(i => runIfTypeOfFunction(receiver, i, scope, params)) - } else { - receiver(result) - } - } else { - receiver(value) - } -} - -export function tryCatch(el, expression, callback, ...args) { - try { - return callback(...args) - } catch (e) { - console.warn(`Alpine Expression Error: ${e.message}\n\nExpression: "${expression}"\n\n`, el) - - throw e - } -} diff --git a/alpinejs/packages/alpinejs/src/index.js b/alpinejs/packages/alpinejs/src/index.js deleted file mode 100644 index b0ea550..0000000 --- a/alpinejs/packages/alpinejs/src/index.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * _ - * /\ | | (_) (_) - * / \ | |_ __ _ _ __ ___ _ ___ - * / /\ \ | | '_ \| | '_ \ / _ \ | / __| - * / ____ \| | |_) | | | | | __/_| \__ \ - * /_/ \_\_| .__/|_|_| |_|\___(_) |___/ - * | | _/ | - * |_| |__/ - * - * Let's build Alpine together. It's easier than you think. - * For starters, we'll import Alpine's core. This is the - * object that will expose all of Alpine's public API. - */ -import Alpine from './alpine' - -/** - * _______________________________________________________ - * The Evaluator - * ------------------------------------------------------- - * - * Now we're ready to bootstrap Alpine's evaluation system. - * It's the function that converts raw JavaScript string - * expressions like @click="toggle()", into actual JS. - */ -import { normalEvaluator } from './evaluator' - -Alpine.setEvaluator(normalEvaluator) - -/** - * _______________________________________________________ - * The Reactivity Engine - * ------------------------------------------------------- - * - * This is the reactivity core of Alpine. It's the part of - * Alpine that triggers an element with x-text="message" - * to update its inner text when "message" is changed. - */ -import { reactive, effect, stop, toRaw } from '@vue/reactivity' - -Alpine.setReactivityEngine({ reactive, effect, release: stop, raw: toRaw }) - -/** - * _______________________________________________________ - * The Magics - * ------------------------------------------------------- - * - * Yeah, we're calling them magics here like they're nouns. - * These are the properties that are magically available - * to all the Alpine expressions, within your web app. - */ -import './magics/index' - -/** - * _______________________________________________________ - * The Directives - * ------------------------------------------------------- - * - * Now that the core is all set up, we can register Alpine - * directives like x-text or x-on that form the basis of - * how Alpine adds behavior to an app's static markup. - */ -import './directives/index' - -/** - * _______________________________________________________ - * The Alpine Global - * ------------------------------------------------------- - * - * Now that we have set everything up internally, anything - * Alpine-related that will need to be accessed on-going - * will be made available through the "Alpine" global. - */ -export default Alpine diff --git a/alpinejs/packages/alpinejs/src/interceptor.js b/alpinejs/packages/alpinejs/src/interceptor.js deleted file mode 100644 index 0f9f557..0000000 --- a/alpinejs/packages/alpinejs/src/interceptor.js +++ /dev/null @@ -1,77 +0,0 @@ -// Warning: The concept of "interceptors" in Alpine is not public API and is subject to change -// without tagging a major release. - -export function initInterceptors(data) { - let isObject = val => typeof val === 'object' && !Array.isArray(val) && val !== null - - let recurse = (obj, basePath = '') => { - Object.entries(Object.getOwnPropertyDescriptors(obj)).forEach(([key, { value, enumerable }]) => { - // Skip getters. - if (enumerable === false || value === undefined) return - - let path = basePath === '' ? key : `${basePath}.${key}` - - if (typeof value === 'object' && value !== null && value._x_interceptor) { - obj[key] = value.initialize(data, path, key) - } else { - if (isObject(value) && value !== obj && ! (value instanceof Element)) { - recurse(value, path) - } - } - }) - } - - return recurse(data) -} - -export function interceptor(callback, mutateObj = () => {}) { - let obj = { - initialValue: undefined, - - _x_interceptor: true, - - initialize(data, path, key) { - return callback(this.initialValue, () => get(data, path), (value) => set(data, path, value), path, key) - } - } - - mutateObj(obj) - - return initialValue => { - if (typeof initialValue === 'object' && initialValue !== null && initialValue._x_interceptor) { - // Support nesting interceptors. - let initialize = obj.initialize.bind(obj) - - obj.initialize = (data, path, key) => { - let innerValue = initialValue.initialize(data, path, key) - - obj.initialValue = innerValue - - return initialize(data, path, key) - } - } else { - obj.initialValue = initialValue - } - - return obj - } -} - -function get(obj, path) { - return path.split('.').reduce((carry, segment) => carry[segment], obj) -} - -function set(obj, path, value) { - if (typeof path === 'string') path = path.split('.') - - if (path.length === 1) obj[path[0]] = value; - else if (path.length === 0) throw error; - else { - if (obj[path[0]]) - return set(obj[path[0]], path.slice(1), value); - else { - obj[path[0]] = {}; - return set(obj[path[0]], path.slice(1), value); - } - } -} diff --git a/alpinejs/packages/alpinejs/src/lifecycle.js b/alpinejs/packages/alpinejs/src/lifecycle.js deleted file mode 100644 index cbf079f..0000000 --- a/alpinejs/packages/alpinejs/src/lifecycle.js +++ /dev/null @@ -1,75 +0,0 @@ -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 => nextTick(() => 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) { - if (!el) return - - const selectors = includeInitSelectors ? allSelectors() : rootSelectors() - - if (selectors.some(selector => el.matches(selector))) return el - - if (! el.parentElement) return - - return closestRoot(el.parentElement, includeInitSelectors) -} - -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)) -} diff --git a/alpinejs/packages/alpinejs/src/magics.js b/alpinejs/packages/alpinejs/src/magics.js deleted file mode 100644 index b24515c..0000000 --- a/alpinejs/packages/alpinejs/src/magics.js +++ /dev/null @@ -1,26 +0,0 @@ -import Alpine from './alpine' -import { interceptor } from './interceptor' - -let magics = {} - -export function magic(name, callback) { - magics[name] = callback -} - -export function injectMagics(obj, el) { - Object.entries(magics).forEach(([name, callback]) => { - Object.defineProperty(obj, `$${name}`, { - get() { return callback(el, { Alpine, interceptor }) }, - - enumerable: false, - }) - }) - - return { - obj, - cleanup: () => { - // MemLeak1: Issue #2140 - el = null; - } - }; -} diff --git a/alpinejs/packages/alpinejs/src/magics/$dispatch.js b/alpinejs/packages/alpinejs/src/magics/$dispatch.js deleted file mode 100644 index 6eb878d..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$dispatch.js +++ /dev/null @@ -1,4 +0,0 @@ -import { dispatch } from '../utils/dispatch' -import { magic } from '../magics' - -magic('dispatch', el => dispatch.bind(dispatch, el)) diff --git a/alpinejs/packages/alpinejs/src/magics/$el.js b/alpinejs/packages/alpinejs/src/magics/$el.js deleted file mode 100644 index 10b9f49..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$el.js +++ /dev/null @@ -1,3 +0,0 @@ -import { magic } from "../magics"; - -magic('el', el => el) diff --git a/alpinejs/packages/alpinejs/src/magics/$nextTick.js b/alpinejs/packages/alpinejs/src/magics/$nextTick.js deleted file mode 100644 index 8318cc6..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$nextTick.js +++ /dev/null @@ -1,4 +0,0 @@ -import { nextTick } from '../nextTick' -import { magic } from '../magics' - -magic('nextTick', () => nextTick) diff --git a/alpinejs/packages/alpinejs/src/magics/$refs.js b/alpinejs/packages/alpinejs/src/magics/$refs.js deleted file mode 100644 index afd48ed..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$refs.js +++ /dev/null @@ -1,25 +0,0 @@ -import { closestRoot } from '../lifecycle' -import { mergeProxies } from '../scope' -import { magic } from '../magics' - -magic('refs', el => { - if (el._x_refs_proxy) return el._x_refs_proxy - - el._x_refs_proxy = mergeProxies(getArrayOfRefObject(el)) - - return el._x_refs_proxy -}) - -function getArrayOfRefObject(el) { - let refObjects = [] - - let currentEl = el - - while (currentEl) { - if (currentEl._x_refs) refObjects.push(currentEl._x_refs) - - currentEl = currentEl.parentNode - } - - return refObjects -} diff --git a/alpinejs/packages/alpinejs/src/magics/$root.js b/alpinejs/packages/alpinejs/src/magics/$root.js deleted file mode 100644 index 140eece..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$root.js +++ /dev/null @@ -1,4 +0,0 @@ -import { closestRoot } from "../lifecycle"; -import { magic } from "../magics"; - -magic('root', el => closestRoot(el)) diff --git a/alpinejs/packages/alpinejs/src/magics/$store.js b/alpinejs/packages/alpinejs/src/magics/$store.js deleted file mode 100644 index a14d40d..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$store.js +++ /dev/null @@ -1,4 +0,0 @@ -import { getStores } from '../store' -import { magic } from '../magics' - -magic('store', getStores) diff --git a/alpinejs/packages/alpinejs/src/magics/$watch.js b/alpinejs/packages/alpinejs/src/magics/$watch.js deleted file mode 100644 index 865e2db..0000000 --- a/alpinejs/packages/alpinejs/src/magics/$watch.js +++ /dev/null @@ -1,37 +0,0 @@ -import { evaluateLater } from '../evaluator' -import { elementBoundEffect } from '../reactivity' -import { magic } from '../magics' -import { onAttributeRemoved } from '../mutation' - -magic('watch', el => (key, callback) => { - let evaluate = evaluateLater(el, key) - - let firstTime = true - - let oldValue - - let [effect, cleanupEffect] = elementBoundEffect(el) - - // MemLeak1: Issue #2140 - onAttributeRemoved(el, key, cleanupEffect) - - effect(() => evaluate(value => { - // This is a hack to force deep reactivity for things like "items.push()". - let div = document.createElement('div') - div.dataset.throwAway = value - - if (! firstTime) { - // We have to queue this watcher as a microtask so that - // the watcher doesn't pick up its own dependencies. - queueMicrotask(() => { - callback(value, oldValue) - - oldValue = value - }) - } else { - oldValue = value - } - - firstTime = false - })) -}) diff --git a/alpinejs/packages/alpinejs/src/magics/index.js b/alpinejs/packages/alpinejs/src/magics/index.js deleted file mode 100644 index 1e1089c..0000000 --- a/alpinejs/packages/alpinejs/src/magics/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './$nextTick' -import './$dispatch' -import './$watch' -import './$store' -import './$root' -import './$refs' -import './$el' diff --git a/alpinejs/packages/alpinejs/src/mutation.js b/alpinejs/packages/alpinejs/src/mutation.js deleted file mode 100644 index 409a096..0000000 --- a/alpinejs/packages/alpinejs/src/mutation.js +++ /dev/null @@ -1,195 +0,0 @@ -import { walk } from './utils/walk'; - -let onAttributeAddeds = [] -let onElRemoveds = [] -let onElAddeds = [] - -export function onElAdded(callback) { - onElAddeds.push(callback) -} - -export function onElRemoved(callback) { - onElRemoveds.push(callback) -} - -export function onAttributesAdded(callback) { - onAttributeAddeds.push(callback) -} - -export function onAttributeRemoved(el, name, callback) { - if (! el._x_attributeCleanups) el._x_attributeCleanups = {} - if (! el._x_attributeCleanups[name]) el._x_attributeCleanups[name] = [] - - el._x_attributeCleanups[name].push(callback) -} - -export function cleanupAttributes(el, names) { - if (! el._x_attributeCleanups) return - - Object.entries(el._x_attributeCleanups).forEach(([name, value]) => { - if (names === undefined || names.includes(name)) { - value.forEach(i => i()) - - delete el._x_attributeCleanups[name] - } - }) -} - -let observer = new MutationObserver(onMutate) - -let currentlyObserving = false - -export function startObservingMutations() { - observer.observe(document, { subtree: true, childList: true, attributes: true, attributeOldValue: true }) - - currentlyObserving = true -} - -export function stopObservingMutations() { - flushObserver() - - observer.disconnect() - - currentlyObserving = false -} - -let recordQueue = [] -let willProcessRecordQueue = false - -export function flushObserver() { - recordQueue = recordQueue.concat(observer.takeRecords()) - - if (recordQueue.length && ! willProcessRecordQueue) { - willProcessRecordQueue = true - - queueMicrotask(() => { - processRecordQueue() - - willProcessRecordQueue = false - }) - } -} - -function processRecordQueue() { - onMutate(recordQueue) - - recordQueue.length = 0 -} - -export function mutateDom(callback) { - if (! currentlyObserving) return callback() - - stopObservingMutations() - - let result = callback() - - startObservingMutations() - - return result -} - -let isCollecting = false -let deferredMutations = [] - -export function deferMutations() { - isCollecting = true -} - -export function flushAndStopDeferringMutations() { - isCollecting = false - - onMutate(deferredMutations) - - deferredMutations = [] -} - -function onMutate(mutations) { - if (isCollecting) { - deferredMutations = deferredMutations.concat(mutations) - - return - } - - let addedNodes = [] - let removedNodes = [] - let addedAttributes = new Map - let removedAttributes = new Map - - for (let i = 0; i < mutations.length; i++) { - if (mutations[i].target._x_ignoreMutationObserver) continue - - if (mutations[i].type === 'childList') { - mutations[i].addedNodes.forEach(node => node.nodeType === 1 && addedNodes.push(node)) - mutations[i].removedNodes.forEach(node => node.nodeType === 1 && removedNodes.push(node)) - } - - if (mutations[i].type === 'attributes') { - let el = mutations[i].target - let name = mutations[i].attributeName - let oldValue = mutations[i].oldValue - - let add = () => { - if (! addedAttributes.has(el)) addedAttributes.set(el, []) - - addedAttributes.get(el).push({ name, value: el.getAttribute(name) }) - } - - let remove = () => { - if (! removedAttributes.has(el)) removedAttributes.set(el, []) - - removedAttributes.get(el).push(name) - } - - // New attribute. - if (el.hasAttribute(name) && oldValue === null) { - add() - // Changed atttribute. - } else if (el.hasAttribute(name)) { - remove() - add() - // Removed atttribute. - } else { - remove() - } - } - } - - removedAttributes.forEach((attrs, el) => { - cleanupAttributes(el, attrs) - }) - - addedAttributes.forEach((attrs, el) => { - onAttributeAddeds.forEach(i => i(el, attrs)) - }) - - for (let node of addedNodes) { - // If an element gets moved on a page, it's registered - // as both an "add" and "remove", so we want to skip those. - if (removedNodes.includes(node)) continue - - onElAddeds.forEach(i => i(node)) - } - - for (let node of removedNodes) { - // If an element gets moved on a page, it's registered - // as both an "add" and "remove", so we want to skip those. - if (addedNodes.includes(node)) continue - - onElRemoveds.forEach(i => i(node)) - - // Mem leak patch, see https://github.com/alpinejs/alpine/issues/2126#issuecomment-940942921 - if (node.localName === 'body') { - node.querySelectorAll('[x-data]').forEach((el) => { - walk(el, (el) => { - onElRemoveds.forEach((i) => i(el)); - el.remove(); - }); - }); - } - } - - addedNodes = null - removedNodes = null - addedAttributes = null - removedAttributes = null -} diff --git a/alpinejs/packages/alpinejs/src/nextTick.js b/alpinejs/packages/alpinejs/src/nextTick.js deleted file mode 100644 index e5c0d88..0000000 --- a/alpinejs/packages/alpinejs/src/nextTick.js +++ /dev/null @@ -1,24 +0,0 @@ - -let tickStack = [] - -let isHolding = false - -export function nextTick(callback) { - tickStack.push(callback) - - queueMicrotask(() => { - isHolding || setTimeout(() => { - releaseNextTicks() - }) - }) -} - -export function releaseNextTicks() { - isHolding = false - - while (tickStack.length) tickStack.shift()() -} - -export function holdNextTicks() { - isHolding = true -} diff --git a/alpinejs/packages/alpinejs/src/plugin.js b/alpinejs/packages/alpinejs/src/plugin.js deleted file mode 100644 index 98a547b..0000000 --- a/alpinejs/packages/alpinejs/src/plugin.js +++ /dev/null @@ -1,5 +0,0 @@ -import Alpine from './alpine' - -export function plugin(callback) { - callback(Alpine) -} diff --git a/alpinejs/packages/alpinejs/src/reactivity.js b/alpinejs/packages/alpinejs/src/reactivity.js deleted file mode 100644 index b233d06..0000000 --- a/alpinejs/packages/alpinejs/src/reactivity.js +++ /dev/null @@ -1,62 +0,0 @@ - -import { scheduler } from './scheduler' - -let reactive, effect, release, raw - -let shouldSchedule = true -export function disableEffectScheduling(callback) { - shouldSchedule = false - - callback() - - shouldSchedule = true -} - -export function setReactivityEngine(engine) { - reactive = engine.reactive - release = engine.release - effect = (callback) => engine.effect(callback, { scheduler: task => { - if (shouldSchedule) { - scheduler(task) - } else { - task() - } - } }) - raw = engine.raw -} - -export function overrideEffect(override) { effect = override } - -export function elementBoundEffect(el) { - let cleanup = () => {} - - let wrappedEffect = (callback) => { - let effectReference = effect(callback) - - if (! el._x_effects) { - el._x_effects = new Set - - // Livewire depends on el._x_runEffects. - el._x_runEffects = () => { el._x_effects.forEach(i => i()) } - } - - el._x_effects.add(effectReference) - - cleanup = () => { - if (effectReference === undefined) return - - el._x_effects.delete(effectReference) - - release(effectReference) - } - } - - return [wrappedEffect, () => { cleanup() }] -} - -export { - release, - reactive, - effect, - raw, -} diff --git a/alpinejs/packages/alpinejs/src/scheduler.js b/alpinejs/packages/alpinejs/src/scheduler.js deleted file mode 100644 index 622e453..0000000 --- a/alpinejs/packages/alpinejs/src/scheduler.js +++ /dev/null @@ -1,33 +0,0 @@ - -let flushPending = false -let flushing = false -let queue = [] - -export function scheduler (callback) { queueJob(callback) } - -function queueJob(job) { - if (! queue.includes(job)) queue.push(job) - - queueFlush() -} - -function queueFlush() { - if (! flushing && ! flushPending) { - flushPending = true - - queueMicrotask(flushJobs) - } -} - -export function flushJobs() { - flushPending = false - flushing = true - - for (let i = 0; i < queue.length; i++) { - queue[i]() - } - - queue.length = 0 - - flushing = false -} diff --git a/alpinejs/packages/alpinejs/src/scope.js b/alpinejs/packages/alpinejs/src/scope.js deleted file mode 100644 index abceae6..0000000 --- a/alpinejs/packages/alpinejs/src/scope.js +++ /dev/null @@ -1,105 +0,0 @@ - -export function scope(node) { - return mergeProxies(closestDataStack(node)) -} - -export function addScopeToNode(node, data, referenceNode) { - node._x_dataStack = [data, ...closestDataStack(referenceNode || node)] - - return () => { - node._x_dataStack = node._x_dataStack.filter(i => i !== data) - } -} - -export function hasScope(node) { - return !! node._x_dataStack -} - -export function refreshScope(element, scope) { - let existingScope = element._x_dataStack[0] - - Object.entries(scope).forEach(([key, value]) => { - existingScope[key] = value - }) -} - -export function closestDataStack(node) { - if (node._x_dataStack) return node._x_dataStack - - if (typeof ShadowRoot === 'function' && node instanceof ShadowRoot) { - return closestDataStack(node.host) - } - - if (! node.parentNode) { - return [] - } - - return closestDataStack(node.parentNode) -} - -export function closestDataProxy(el) { - return mergeProxies(closestDataStack(el)) -} - -export function mergeProxies(objects) { - let thisProxy = new Proxy({}, { - ownKeys: () => { - return Array.from(new Set(objects.flatMap(i => Object.keys(i)))) - }, - - has: (target, name) => { - return objects.some(obj => obj.hasOwnProperty(name)) - }, - - get: (target, name) => { - return (objects.find(obj => { - if (obj.hasOwnProperty(name)) { - let descriptor = Object.getOwnPropertyDescriptor(obj, name) - - // If we already bound this getter, don't rebind. - if ((descriptor.get && descriptor.get._x_alreadyBound) || (descriptor.set && descriptor.set._x_alreadyBound)) { - return true - } - - // Properly bind getters and setters to this wrapper Proxy. - if ((descriptor.get || descriptor.set) && descriptor.enumerable) { - // Only bind user-defined getters, not our magic properties. - let getter = descriptor.get - let setter = descriptor.set - let property = descriptor - - getter = getter && getter.bind(thisProxy) - setter = setter && setter.bind(thisProxy) - - if (getter) getter._x_alreadyBound = true - if (setter) setter._x_alreadyBound = true - - Object.defineProperty(obj, name, { - ...property, - get: getter, - set: setter, - }) - } - - return true - } - - return false - }) || {})[name] - }, - - set: (target, name, value) => { - let closestObjectWithKey = objects.find(obj => obj.hasOwnProperty(name)) - - if (closestObjectWithKey) { - closestObjectWithKey[name] = value - } else { - objects[objects.length - 1][name] = value - } - - return true - }, - }) - - return thisProxy -} diff --git a/alpinejs/packages/alpinejs/src/store.js b/alpinejs/packages/alpinejs/src/store.js deleted file mode 100644 index 9c1f18f..0000000 --- a/alpinejs/packages/alpinejs/src/store.js +++ /dev/null @@ -1,20 +0,0 @@ -import { reactive } from "./reactivity" - -let stores = {} -let isReactive = false - -export function store(name, value) { - if (! isReactive) { stores = reactive(stores); isReactive = true; } - - if (value === undefined) { - return stores[name] - } - - stores[name] = value - - if (typeof value === 'object' && value !== null && value.hasOwnProperty('init') && typeof value.init === 'function') { - stores[name].init() - } -} - -export function getStores() { return stores } diff --git a/alpinejs/packages/alpinejs/src/utils/bind.js b/alpinejs/packages/alpinejs/src/utils/bind.js deleted file mode 100644 index 4d53dfc..0000000 --- a/alpinejs/packages/alpinejs/src/utils/bind.js +++ /dev/null @@ -1,129 +0,0 @@ -import { reactive } from '../reactivity' -import { setClasses } from './classes' -import { setStyles } from './styles' - -export default function bind(el, name, value, modifiers = []) { - // Register bound data as pure observable data for other APIs to use. - if (! el._x_bindings) el._x_bindings = reactive({}) - - el._x_bindings[name] = value - - name = modifiers.includes('camel') ? camelCase(name) : name - - switch (name) { - case 'value': - bindInputValue(el, value) - break; - - case 'style': - bindStyles(el, value) - break; - - case 'class': - bindClasses(el, value) - break; - - default: - bindAttribute(el, name, value) - break; - } -} - -function bindInputValue(el, value) { - if (el.type === 'radio') { - // Set radio value from x-bind:value, if no "value" attribute exists. - // If there are any initial state values, radio will have a correct - // "checked" value since x-bind:value is processed before x-model. - if (el.attributes.value === undefined) { - el.value = value - } - - // @todo: yuck - if (window.fromModel) { - el.checked = checkedAttrLooseCompare(el.value, value) - } - } else if (el.type === 'checkbox') { - // If we are explicitly binding a string to the :value, set the string, - // If the value is a boolean/array/number/null/undefined, leave it alone, it will be set to "on" - // automatically. - if (Number.isInteger(value)) { - el.value = value - } else if (! Number.isInteger(value) && ! Array.isArray(value) && typeof value !== 'boolean' && ! [null, undefined].includes(value)) { - el.value = String(value) - } else { - if (Array.isArray(value)) { - el.checked = value.some(val => checkedAttrLooseCompare(val, el.value)) - } else { - el.checked = !!value - } - } - } else if (el.tagName === 'SELECT') { - updateSelect(el, value) - } else { - if (el.value === value) return - - el.value = value - } -} - -function bindClasses(el, value) { - if (el._x_undoAddedClasses) el._x_undoAddedClasses() - - el._x_undoAddedClasses = setClasses(el, value) -} - -function bindStyles(el, value) { - if (el._x_undoAddedStyles) el._x_undoAddedStyles() - - el._x_undoAddedStyles = setStyles(el, value) -} - -function bindAttribute(el, name, value) { - if ([null, undefined, false].includes(value) && attributeShouldntBePreservedIfFalsy(name)) { - el.removeAttribute(name) - } else { - if (isBooleanAttr(name)) value = name - - setIfChanged(el, name, value) - } -} - -function setIfChanged(el, attrName, value) { - if (el.getAttribute(attrName) != value) { - el.setAttribute(attrName, value) - } -} - -function updateSelect(el, value) { - const arrayWrappedValue = [].concat(value).map(value => { return value + '' }) - - Array.from(el.options).forEach(option => { - option.selected = arrayWrappedValue.includes(option.value) - }) -} - -function camelCase(subject) { - return subject.toLowerCase().replace(/-(\w)/g, (match, char) => char.toUpperCase()) -} - -function checkedAttrLooseCompare(valueA, valueB) { - return valueA == valueB -} - -function isBooleanAttr(attrName) { - // As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute - // Array roughly ordered by estimated usage - const booleanAttributes = [ - 'disabled','checked','required','readonly','hidden','open', 'selected', - 'autofocus', 'itemscope', 'multiple', 'novalidate','allowfullscreen', - 'allowpaymentrequest', 'formnovalidate', 'autoplay', 'controls', 'loop', - 'muted', 'playsinline', 'default', 'ismap', 'reversed', 'async', 'defer', - 'nomodule' - ] - - return booleanAttributes.includes(attrName) -} - -function attributeShouldntBePreservedIfFalsy(name) { - return ! ['aria-pressed', 'aria-checked', 'aria-expanded'].includes(name) -} diff --git a/alpinejs/packages/alpinejs/src/utils/classes.js b/alpinejs/packages/alpinejs/src/utils/classes.js deleted file mode 100644 index 0fd02aa..0000000 --- a/alpinejs/packages/alpinejs/src/utils/classes.js +++ /dev/null @@ -1,58 +0,0 @@ - -export function setClasses(el, value) { - if (Array.isArray(value)) { - return setClassesFromString(el, value.join(' ')) - } else if (typeof value === 'object' && value !== null) { - return setClassesFromObject(el, value) - } else if (typeof value === 'function') { - return setClasses(el, value()) - } - - return setClassesFromString(el, value) -} - -function setClassesFromString(el, classString) { - let split = classString => classString.split(' ').filter(Boolean) - - let missingClasses = classString => classString.split(' ').filter(i => ! el.classList.contains(i)).filter(Boolean) - - let addClassesAndReturnUndo = classes => { - el.classList.add(...classes) - - return () => { el.classList.remove(...classes) } - } - - // This is to allow short-circuit expressions like: :class="show || 'hidden'" && "show && 'block'" - classString = (classString === true) ? classString = '' : (classString || '') - - return addClassesAndReturnUndo(missingClasses(classString)) -} - -function setClassesFromObject(el, classObject) { - let split = classString => classString.split(' ').filter(Boolean) - - let forAdd = Object.entries(classObject).flatMap(([classString, bool]) => bool ? split(classString) : false).filter(Boolean) - let forRemove = Object.entries(classObject).flatMap(([classString, bool]) => ! bool ? split(classString) : false).filter(Boolean) - - let added = [] - let removed = [] - - forRemove.forEach(i => { - if (el.classList.contains(i)) { - el.classList.remove(i) - removed.push(i) - } - }) - - forAdd.forEach(i => { - if (! el.classList.contains(i)) { - el.classList.add(i) - added.push(i) - } - }) - - return () => { - removed.forEach(i => el.classList.add(i)) - added.forEach(i => el.classList.remove(i)) - } -} diff --git a/alpinejs/packages/alpinejs/src/utils/debounce.js b/alpinejs/packages/alpinejs/src/utils/debounce.js deleted file mode 100644 index 850a3b1..0000000 --- a/alpinejs/packages/alpinejs/src/utils/debounce.js +++ /dev/null @@ -1,18 +0,0 @@ - -export function debounce(func, wait) { - var timeout - - return function() { - var context = this, args = arguments - - var later = function () { - timeout = null - - func.apply(context, args) - } - - clearTimeout(timeout) - - timeout = setTimeout(later, wait) - } -} diff --git a/alpinejs/packages/alpinejs/src/utils/dispatch.js b/alpinejs/packages/alpinejs/src/utils/dispatch.js deleted file mode 100644 index 26f198a..0000000 --- a/alpinejs/packages/alpinejs/src/utils/dispatch.js +++ /dev/null @@ -1,12 +0,0 @@ - -export function dispatch(el, name, detail = {}) { - el.dispatchEvent( - new CustomEvent(name, { - detail, - bubbles: true, - // Allows events to pass the shadow DOM barrier. - composed: true, - cancelable: true, - }) - ) -} diff --git a/alpinejs/packages/alpinejs/src/utils/on.js b/alpinejs/packages/alpinejs/src/utils/on.js deleted file mode 100644 index e053560..0000000 --- a/alpinejs/packages/alpinejs/src/utils/on.js +++ /dev/null @@ -1,163 +0,0 @@ -import { debounce } from './debounce' -import { throttle } from './throttle' - -export default function on (el, event, modifiers, callback) { - let listenerTarget = el - - let handler = e => callback(e) - - let options = {} - - // This little helper allows us to add functionality to the listener's - // handler more flexibly in a "middleware" style. - let wrapHandler = (callback, wrapper) => (e) => wrapper(callback, e) - - if (modifiers.includes("dot")) event = dotSyntax(event) - if (modifiers.includes('camel')) event = camelCase(event) - if (modifiers.includes('passive')) options.passive = true - if (modifiers.includes('capture')) options.capture = true - if (modifiers.includes('window')) listenerTarget = window - if (modifiers.includes('document')) listenerTarget = document - if (modifiers.includes('prevent')) handler = wrapHandler(handler, (next, e) => { e.preventDefault(); next(e) }) - if (modifiers.includes('stop')) handler = wrapHandler(handler, (next, e) => { e.stopPropagation(); next(e) }) - if (modifiers.includes('self')) handler = wrapHandler(handler, (next, e) => { e.target === el && next(e) }) - - if (modifiers.includes('away') || modifiers.includes('outside')) { - listenerTarget = document - - handler = wrapHandler(handler, (next, e) => { - if (el.contains(e.target)) return - - if (el.offsetWidth < 1 && el.offsetHeight < 1) return - - next(e) - }) - } - - // Handle :keydown and :keyup listeners. - handler = wrapHandler(handler, (next, e) => { - if (isKeyEvent(event)) { - if (isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers)) { - return - } - } - - next(e) - }) - - if (modifiers.includes('debounce')) { - let nextModifier = modifiers[modifiers.indexOf('debounce')+1] || 'invalid-wait' - let wait = isNumeric(nextModifier.split('ms')[0]) ? Number(nextModifier.split('ms')[0]) : 250 - - handler = debounce(handler, wait) - } - - if (modifiers.includes('throttle')) { - let nextModifier = modifiers[modifiers.indexOf('throttle')+1] || 'invalid-wait' - let wait = isNumeric(nextModifier.split('ms')[0]) ? Number(nextModifier.split('ms')[0]) : 250 - - handler = throttle(handler, wait) - } - - if (modifiers.includes('once')) { - handler = wrapHandler(handler, (next, e) => { - next(e) - - listenerTarget.removeEventListener(event, handler, options) - }) - } - - listenerTarget.addEventListener(event, handler, options) - - return () => { - listenerTarget.removeEventListener(event, handler, options) - } -} - -function dotSyntax(subject) { - return subject.replace(/-/g, ".") -} - -function camelCase(subject) { - return subject.toLowerCase().replace(/-(\w)/g, (match, char) => char.toUpperCase()) -} - -function isNumeric(subject){ - return ! Array.isArray(subject) && ! isNaN(subject) -} - -function kebabCase(subject) { - return subject.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[_\s]/, '-').toLowerCase() -} - -function isKeyEvent(event) { - return ['keydown', 'keyup'].includes(event) -} - -function isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers) { - let keyModifiers = modifiers.filter(i => { - return ! ['window', 'document', 'prevent', 'stop', 'once'].includes(i) - }) - - if (keyModifiers.includes('debounce')) { - let debounceIndex = keyModifiers.indexOf('debounce') - keyModifiers.splice(debounceIndex, isNumeric((keyModifiers[debounceIndex+1] || 'invalid-wait').split('ms')[0]) ? 2 : 1) - } - - // If no modifier is specified, we'll call it a press. - if (keyModifiers.length === 0) return false - - // If one is passed, AND it matches the key pressed, we'll call it a press. - if (keyModifiers.length === 1 && keyToModifiers(e.key).includes(keyModifiers[0])) return false - - // The user is listening for key combinations. - const systemKeyModifiers = ['ctrl', 'shift', 'alt', 'meta', 'cmd', 'super'] - const selectedSystemKeyModifiers = systemKeyModifiers.filter(modifier => keyModifiers.includes(modifier)) - - keyModifiers = keyModifiers.filter(i => ! selectedSystemKeyModifiers.includes(i)) - - if (selectedSystemKeyModifiers.length > 0) { - const activelyPressedKeyModifiers = selectedSystemKeyModifiers.filter(modifier => { - // Alias "cmd" and "super" to "meta" - if (modifier === 'cmd' || modifier === 'super') modifier = 'meta' - - return e[`${modifier}Key`] - }) - - // If all the modifiers selected are pressed, ... - if (activelyPressedKeyModifiers.length === selectedSystemKeyModifiers.length) { - // AND the remaining key is pressed as well. It's a press. - if (keyToModifiers(e.key).includes(keyModifiers[0])) return false - } - } - - // We'll call it NOT a valid keypress. - return true -} - -function keyToModifiers(key) { - if (! key) return [] - - key = kebabCase(key) - - let modifierToKeyMap = { - 'ctrl': 'control', - 'slash': '/', - 'space': '-', - 'spacebar': '-', - 'cmd': 'meta', - 'esc': 'escape', - 'up': 'arrow-up', - 'down': 'arrow-down', - 'left': 'arrow-left', - 'right': 'arrow-right', - 'period': '.', - 'equal': '=', - } - - modifierToKeyMap[key] = key - - return Object.keys(modifierToKeyMap).map(modifier => { - if (modifierToKeyMap[modifier] === key) return modifier - }).filter(modifier => modifier) -} diff --git a/alpinejs/packages/alpinejs/src/utils/once.js b/alpinejs/packages/alpinejs/src/utils/once.js deleted file mode 100644 index 643ee6f..0000000 --- a/alpinejs/packages/alpinejs/src/utils/once.js +++ /dev/null @@ -1,14 +0,0 @@ - -export function once(callback, fallback = () => {}) { - let called = false - - return function () { - if (! called) { - called = true - - callback.apply(this, arguments) - } else { - fallback.apply(this, arguments) - } - } -} diff --git a/alpinejs/packages/alpinejs/src/utils/styles.js b/alpinejs/packages/alpinejs/src/utils/styles.js deleted file mode 100644 index 0761d7b..0000000 --- a/alpinejs/packages/alpinejs/src/utils/styles.js +++ /dev/null @@ -1,45 +0,0 @@ - -export function setStyles(el, value) { - if (typeof value === 'object' && value !== null) { - return setStylesFromObject(el, value) - } - - return setStylesFromString(el, value) -} - -function setStylesFromObject(el, value) { - let previousStyles = {} - - Object.entries(value).forEach(([key, value]) => { - previousStyles[key] = el.style[key] - - // When we use javascript object, css properties use the camelCase - // syntax but when we use setProperty, we need the css format - // so we need to convert camelCase to kebab-case - el.style.setProperty(kebabCase(key), value) - }) - - setTimeout(() => { - if (el.style.length === 0) { - el.removeAttribute('style') - } - }) - - return () => { - setStyles(el, previousStyles) - } -} - -function setStylesFromString(el, value) { - let cache = el.getAttribute('style', value) - - el.setAttribute('style', value) - - return () => { - el.setAttribute('style', cache) - } -} - -function kebabCase(subject) { - return subject.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase() -} diff --git a/alpinejs/packages/alpinejs/src/utils/throttle.js b/alpinejs/packages/alpinejs/src/utils/throttle.js deleted file mode 100644 index c49108b..0000000 --- a/alpinejs/packages/alpinejs/src/utils/throttle.js +++ /dev/null @@ -1,16 +0,0 @@ - -export function throttle(func, limit) { - let inThrottle - - return function() { - let context = this, args = arguments - - if (! inThrottle) { - func.apply(context, args) - - inThrottle = true - - setTimeout(() => inThrottle = false, limit) - } - } -} diff --git a/alpinejs/packages/alpinejs/src/utils/walk.js b/alpinejs/packages/alpinejs/src/utils/walk.js deleted file mode 100644 index 909df1a..0000000 --- a/alpinejs/packages/alpinejs/src/utils/walk.js +++ /dev/null @@ -1,38 +0,0 @@ -export function walk(el, callback) { - if (typeof ShadowRoot === 'function' && el instanceof ShadowRoot) { - Array.from(el.children).forEach(el => walk(el, callback)) - - return - } - - let skip = false - - callback(el, () => skip = true) - - if (skip) return - - let node = el.firstElementChild - - while (node) { - walk(node, callback, false) - - node = node.nextElementSibling - } -} -// export function walk(el, callback) { -// if (el instanceof ShadowRoot || el instanceof DocumentFragment) { -// Array.from(el.children).forEach(el => walk(el, callback)) - -// return -// } - -// callback(el, () => { -// let node = el.firstElementChild - -// while (node) { -// walk(node, callback) - -// node = node.nextElementSibling -// } -// }) -// } diff --git a/alpinejs/packages/alpinejs/src/utils/warn.js b/alpinejs/packages/alpinejs/src/utils/warn.js deleted file mode 100644 index b01f80b..0000000 --- a/alpinejs/packages/alpinejs/src/utils/warn.js +++ /dev/null @@ -1,4 +0,0 @@ - -export function warn(message, ...args) { - console.warn(`Alpine Warning: ${message}`, ...args) -} |