Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Machy8 committed Feb 27, 2024
1 parent e66000b commit c4bf683
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 169 deletions.
226 changes: 120 additions & 106 deletions packages/signalizejs/src/plugins/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,137 +35,151 @@ export default ($) => {
};

$.bind = (element, attributes) => {
/** @type {CallableFunction[]} */
const unwatchSignalCallbacks = [];
const cleanups = [];

for (let [attr, attrOptions] of Object.entries(attributes)) {
if (attrOptions.length === 1) {
attrOptions = attrOptions[0];
}

const attrOptionsAsArray = Array.isArray(attrOptions) ? attrOptions : [attrOptions];
const isNumericInput = numericInputAttributes.includes(element.getAttribute('type') ?? '');
const attributeBinder = attrOptionsAsArray.pop();
const signalsToWatch = attrOptionsAsArray;
const attributeBinderType = typeof attributeBinder;
const attributeBinderIsSignal = attributeBinder instanceof Signal;
let attributeInited = false;
let previousSettedValue;
let previousValue;

/**
* @param {string} attribute
* @param {string|number} value
* @returns {Promise<void>}
*/
const setAttribute = async (attribute, value) => {
value = value instanceof Promise ? await value : value;
if (attributeInited && previousValue === value) {
return;
const bind = () => {
/** @type {CallableFunction[]} */
const unwatchSignalCallbacks = [];
const cleanups = [];

for (let [attr, attrOptions] of Object.entries(attributes)) {
if (attrOptions.length === 1) {
attrOptions = attrOptions[0];
}
previousValue = value;
attribute = attributesAliases[attribute] ?? attribute;

if (textContentAttributes.includes(attribute)) {
element[attribute] = value;
} else if (booleanAttributes.includes(attribute)) {
element[attribute] = !!value;
} else if (attribute === 'class') {
if (attributeInited) {
if (previousSettedValue !== undefined) {
for (const className of previousSettedValue) {
element.classList.remove(className);

const attrOptionsAsArray = Array.isArray(attrOptions) ? attrOptions : [attrOptions];
const isNumericInput = numericInputAttributes.includes(element.getAttribute('type') ?? '');
const attributeBinder = attrOptionsAsArray.pop();
const signalsToWatch = attrOptionsAsArray;
const attributeBinderType = typeof attributeBinder;
const attributeBinderIsSignal = attributeBinder instanceof Signal;
let attributeInited = false;
let previousSettedValue;
let previousValue;

/**
* @param {string} attribute
* @param {string|number} value
* @returns {Promise<void>}
*/
const setAttribute = async (attribute, value) => {
value = value instanceof Promise ? await value : value;
if (attributeInited && previousValue === value) {
return;
}
previousValue = value;
attribute = attributesAliases[attribute] ?? attribute;

if (textContentAttributes.includes(attribute)) {
element[attribute] = value;
} else if (booleanAttributes.includes(attribute)) {
element[attribute] = !!value;
} else if (attribute === 'class') {
if (attributeInited) {
if (previousSettedValue !== undefined) {
for (const className of previousSettedValue) {
element.classList.remove(className);
}
}
}
}

const valueToSet = value.trim().split(' ').filter((className) => className.trim().length > 0);
previousSettedValue = valueToSet;
const valueToSet = value.trim().split(' ').filter((className) => className.trim().length > 0);
previousSettedValue = valueToSet;

for (const className of valueToSet) {
element.classList.add(className);
for (const className of valueToSet) {
element.classList.add(className);
}
} else {
element.setAttribute(attribute, value);
}
} else {
element.setAttribute(attribute, value);
attributeInited = true;
};

if (['string', 'number'].includes(attributeBinderType)) {
setAttribute(attr, attributeBinder);
continue;
}
attributeInited = true;
};

if (['string', 'number'].includes(attributeBinderType)) {
setAttribute(attr, attributeBinder);
continue;
}
if (attributeBinderIsSignal) {
signalsToWatch.push(attributeBinder);
}

if (attributeBinderIsSignal) {
signalsToWatch.push(attributeBinder);
}
/** @type {CallableFunction|null} */
let getListener = null;
/** @type {CallableFunction|null} */
let setListener = null;
/** @type {any} */
let initValue = undefined;
if (attributeBinderIsSignal) {
getListener = () => attributeBinder();
setListener = (value) => attributeBinder(value);
} else {
if (typeof attributeBinder?.get === 'function') {
getListener = () => attributeBinder.get();
}

/** @type {CallableFunction|null} */
let getListener = null;
/** @type {CallableFunction|null} */
let setListener = null;
/** @type {any} */
let initValue = undefined;
if (attributeBinderIsSignal) {
getListener = () => attributeBinder();
setListener = (value) => attributeBinder(value);
} else {
if (typeof attributeBinder?.get === 'function') {
getListener = () => attributeBinder.get();
}
if (typeof attributeBinder?.set === 'function') {
setListener = (value) => attributeBinder.set(value);
}

if (typeof attributeBinder?.set === 'function') {
setListener = (value) => attributeBinder.set(value);
}
if (typeof attributeBinder?.value !== 'undefined') {
initValue = attributeBinder?.value;
}

if (typeof attributeBinder?.value !== 'undefined') {
initValue = attributeBinder?.value;
}
if (getListener === null) {
if (typeof attributeBinder === 'function') {
getListener = () => attributeBinder();
} else if (signalsToWatch.length === 1) {
getListener = () => signalsToWatch[0]();
}
}

if (getListener === null) {
if (typeof attributeBinder === 'function') {
getListener = () => attributeBinder();
} else if (signalsToWatch.length === 1) {
getListener = () => signalsToWatch[0]();
if (setListener === null && signalsToWatch.length === 1) {
setListener = (value) => signalsToWatch[0](value);
}
}

if (setListener === null && signalsToWatch.length === 1) {
setListener = (value) => signalsToWatch[0](value);
if (getListener !== null || initValue !== undefined) {
setAttribute(attr, initValue !== undefined ? initValue : getListener());
}
}

if (getListener !== null || initValue !== undefined) {
setAttribute(attr, initValue !== undefined ? initValue : getListener());
}
for (const signalToWatch of signalsToWatch) {
unwatchSignalCallbacks.push(
signalToWatch.watch(() => setAttribute(attr, getListener()))
);
}

for (const signalToWatch of signalsToWatch) {
unwatchSignalCallbacks.push(
signalToWatch.watch(() => setAttribute(attr, getListener()))
);
if (typeof setListener === 'function' && reactiveInputAttributes.includes(attr)) {
const inputListener = () => {
setListener(isNumericInput ? Number(element[attr].replace(',', '.')) : element[attr]);
};

on('input', element, inputListener, { passive: true });
cleanups.push(() => $.off('input', element, inputListener));
}
}

if (typeof setListener === 'function' && reactiveInputAttributes.includes(attr)) {
const inputListener = () => {
setListener(isNumericInput ? Number(element[attr].replace(',', '.')) : element[attr]);
};
$.scope(element, ({ $cleanup }) => {
$cleanup(() => {
for (const cleanup of cleanups) {
cleanup();
}

on('input', element, inputListener, { passive: true });
cleanups.push(() => $.off('input', element, inputListener));
}
}
for (const unwatch of unwatchSignalCallbacks) {
unwatch();
}
});
});
};

$.scope(element, ({ $cleanup }) => {
$cleanup(() => {
for (const cleanup of cleanups) {
cleanup();
}
const tagName = element.tagName;

for (const unwatch of unwatchSignalCallbacks) {
unwatch();
if (tagName.split('-').length > 1 && customElements.get(tagName) === undefined) {
on('component:beforeSetuped', ({ target }) => {
if (target === element) {
bind();
}
});
});
} else {
bind();
}
};
};
39 changes: 2 additions & 37 deletions packages/signalizejs/src/plugins/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,41 +120,6 @@ export default ($) => {
}
});

/**
* @param {string} name
*/
this.#scope.$children = async (name) => {
if (customElements.get(name) === undefined) {
await customElements.whenDefined(name);
}

const childComponents = this.#scope.$el.querySelectorAll(name);
const initPromises = [];
for (const childComponent of childComponents) {
const componentScope = scope(childComponent);
initPromises.push(
componentScope?._setuped === true
? componentScope
: new Promise((resolve) => {
$.on('component:setuped', ({ detail }) => {
if (detail.$el === childComponent) {
resolve(detail);
}
});
})
);
}

return await Promise.all(initPromises);
};

/**
* @param {string} name
*/
this.#scope.$child = async (name) => {
return (await this.#scope.$children(name))[0] ?? null;
};

for (const attr of this.#scope.$el.attributes) {
this.attributeChangedCallback(attr.name, undefined, this.#scope.$el.getAttribute(attr.name));
}
Expand Down Expand Up @@ -206,9 +171,9 @@ root
select('slot:not([name])', template.content)?.replaceWith(currentTemplate.content);
} */

dispatch('component:setuped', this.#scope, { target: this.#scope.$el, bubbles: true });
dispatch('component:beforeSetuped', this.#scope, { target: this.#scope.$el, bubbles: true });
this.#scope._setuped = true;
dispatch('component:setuped', this.#scope, { target: this.#scope.$el, bubbles: true });
}

/**
Expand Down
48 changes: 22 additions & 26 deletions packages/signalizejs/src/plugins/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,36 +127,32 @@ export default ($) => {
cleanChildren(this.$el);
};

/**
* @param {string} name
* @returns {Element|null}
*/
$ref = (name) => {
return this.$refs(name)[0] ?? null;
};

/**
* @param {string} name
* @returns {Element[]}
*/
$refs = (name) => {
return [...this.$el.querySelectorAll(`[${refAttribute}=${name}]`)].filter((element) => {
const checkParentElement = (el) => {
const parentElement = el.parentNode;
if (parentElement === this.$el) {
return true;
}

if (parentElement.tagName.toLowerCase().includes('-')) {
return false;
}

return checkParentElement(parentElement);
};

return checkParentElement(element);
});
};
$refs = new Proxy({}, {
get: (target, key) => {
const refs = [...this.$el.querySelectorAll(`[${refAttribute}=${key}]`)].filter((element) => {
const checkParentElement = (el) => {
const parentElement = el.parentNode;
if (parentElement === this.$el) {
return true;
}

if (parentElement.tagName.toLowerCase().includes('-')) {
return false;
}

return checkParentElement(parentElement);
};

return checkParentElement(element);
});

return refs.length === 1 ? refs[0] : refs;
}
});
}

/**
Expand Down

0 comments on commit c4bf683

Please sign in to comment.