Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Machy8 committed Dec 9, 2023
1 parent ae0d7b7 commit d849760
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 390 deletions.
68 changes: 7 additions & 61 deletions packages/signalizejs/src/Signalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,13 @@ import mutationsObserver from './plugins/mutation-observer';
import off from './plugins/off';
import on from './plugins/on';
import type { CustomEventListener } from './plugins/on';
import scope from './plugins/scope';
import component from './plugins/component';
import dashCase from './plugins/dash-case';
import select from './plugins/select';
import signal from './plugins/signal';
import task from './plugins/task';
import traverseDom from './plugins/traverse-dom';

export * from './plugins/bind';
export * from './plugins/dispatch'
export * from './plugins/dom-ready';
export * from './plugins/mutation-observer';
export * from './plugins/off';
export * from './plugins/on';
export * from './plugins/scope';
export * from './plugins/select';
export * from './plugins/signal';
export * from './plugins/task';
export * from './plugins/traverse-dom';
import vnode from './plugins/vnode';

export type SignalizeGlobals = Record<string, any>

Expand All @@ -43,11 +33,11 @@ export interface SignalizeOptions {
export type SignalizePlugin = (signalize: Signalize) => void

export class Signalize {
#plugins = new Set();
root!: Element | Document;
attributeSeparator!: string;
attributePrefix!: string;
globals!: SignalizeGlobals;
#plugins = new Set();

constructor (options: Partial<SignalizeOptions> = {}) {
this.root = options?.root ?? document;
Expand Down Expand Up @@ -78,9 +68,11 @@ export class Signalize {
domReady(this);
select(this);
traverseDom(this);
scope(this);
vnode(this);
signal(this);
bind(this);
dashCase(this);
component(this);
mutationsObserver(this);

usePlugins(this, options?.plugins ?? []);
Expand All @@ -89,10 +81,6 @@ export class Signalize {
readyListeners.shift()();
}

this.on('dom:ready', () => {
this.observeMutations(this.root);
});

this.root.__signalize = this;
inited = true;
}
Expand All @@ -115,48 +103,6 @@ export class Signalize {
this.#plugins.add(pluginString);
plugin(this);
}

readonly #init = (options: Partial<SignalizeOptions>): void => {
/* this.root = options?.root ?? document;
if (this.root?.__signalize !== undefined) {
return;
}
this.attributePrefix = options?.attributePrefix ?? '';
this.attributeSeparator = options?.attributeSeparator ?? '-';
this.globals = options?.globals ?? {};
const readyListeners: CallableFunction[] = [];
task(this);
dispatch(this);
on(this);
this.customEventListener('signalize:ready', ({ listener }) => {
readyListeners.push(listener);
});
off(this);
domReady(this);
select(this);
traverseDom(this);
scope(this);
signal(this);
bind(this);
mutationsObserver(this);
for (const plugin of options?.plugins ?? []) {
this.use(plugin);
}
while (readyListeners.length > 0) {
readyListeners.shift()();
}
this.on('dom:ready', () => {
this.observeMutations(this.root);
});
this.root.__signalize = this; */
}
}

export default Signalize;
2 changes: 1 addition & 1 deletion packages/signalizejs/src/plugins/bind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export default ($: Signalize): void => {

$.bind = (element, attributes) => {
const unwatchSignalCallbacks: CallableFunction[] = [];
const elementScope = scope(element);

for (let [attr, attrOptions] of Object.entries(attributes)) {
if (attrOptions.length === 1) {
Expand Down Expand Up @@ -137,6 +136,7 @@ export default ($: Signalize): void => {
}
}

const elementScope = scope(element);
if (elementScope instanceof Scope) {
elementScope.cleanup(() => {
for (const unwatch of unwatchSignalCallbacks) {
Expand Down
171 changes: 171 additions & 0 deletions packages/signalizejs/src/plugins/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import type { Signalize } from '..';
import type { CustomEventListener } from './on';
import type { VnodeInterface } from './vnode';

declare module '..' {
interface Signalize {
component: (name: string, init: ComponentOptions) => typeof HTMLElement
}

interface CustomEventListeners {
'component:init': CustomEventListener
'component:defined': CustomEventListener
}
}

export interface ComponentOptions {
props?: Record<string, any> | string[]
template?: string | DocumentFragment
construct?: () => void | Promise<void>
constructed?: () => void | Promise<void>
connected?: () => void | Promise<void>
addopted?: () => void | Promise<void>
disconnected?: () => void | Promise<void>
shadow?: ShadowRootInit
}

export default ($: Signalize): void => {
const { signal, select, selectAll, dashCase } = $;

const refAttribute = `${$.attributePrefix}ref`;
const componentAttribute = `${$.attributePrefix}component`;
const cloakAttribute = `${$.attributePrefix}cloak`;

const component = (name: string, options: ComponentOptions): typeof HTMLElement => {
let componentName = name;

if (!componentName.includes('-')) {
componentName = `x-${componentName}`;
}

const properties = {};

if (Array.isArray(options?.props)) {
for (const property of options?.props) {
properties[property] = undefined;
}
} else if (typeof options?.props === 'object') {
for (const [key, value] of Object.entries(options?.props)) {
properties[key] = value;
}
}

const attributesPropertiesMap = {}

for (const propertyName of Object.keys(properties)) {
attributesPropertiesMap[dashCase(propertyName)] = propertyName;
}

const observableAttributes = Object.keys(attributesPropertiesMap);

class Component extends HTMLElement {
#constructPromise
$el = this;

constructor () {
super();

this.#constructPromise = this.#construct();
}

async #construct (): Promise<void> {
for (const [key, value] of Object.entries(properties)) {
this[key] = signal(value);
}

if (options?.construct !== undefined) {
const data = await options.construct.call(this);

for (const [key, value] of Object.entries(data ?? {})) {
this[key] = value;
}
}

let template = options?.template;

if (typeof template === 'string') {
if (template.startsWith('#')) {
template = select(template)?.content.cloneNode(true);
} else {
const templateElement = document.createElement('template')
templateElement.innerHTML = template;
template = templateElement;
}
}

let root = this;

if (options?.shadow) {
root = this.attachShadow({
...options?.shadow
});
} else if (template !== undefined) {
const currentTemplate = document.createElement('template');
currentTemplate.innerHTML = this.innerHTML.trim();

for (const slot of selectAll('[slot]', currentTemplate.content)) {
const slotName = slot.getAttribute('slot');
slot.removeAttribute('slot');
select(`slot[name="${slotName}"]`, template.content)?.replaceWith(slot);
}

select('slot:not([name])', template.content)?.replaceWith(currentTemplate.content);
}

if (template !== undefined) {
root.innerHTML = template.innerHTML;
}

this.setAttribute(componentAttribute, name);

await options?.constructed?.call(this);
}

static get observedAttributes (): string[] {
return observableAttributes;
}

attributeChangedCallback(name: string, oldValue: string, newValue: string) {
if (observableAttributes.includes(name)) {
const currentProperty = this[attributesPropertiesMap[name]];
currentProperty(
Number.isNaN(currentProperty()) ? newValue : parseFloat(newValue)
);
}
}

async connectedCallback (): void {
await this.#constructPromise;
await options?.connected.call(this);
this.removeAttribute(cloakAttribute);
}

disconnectedCallback (): void {
options?.disconnected.call(this);
}

adoptedCallback (): void {
options?.adopted.call(this);
}

$parent = (name?: string): Element | null => {
return this.closest(`[${componentAttribute}${name === undefined ? '' : `="${name}"`}]`);
}

$ref = (name: string): Element | null => {
return this.$refs(name)[0] ?? null;
}

$refs = (name: string): Element[] => {
return [...selectAll(`[${refAttribute}="${name}"]`, this)].filter((element) => {
return element.closest(`[${componentAttribute}]`) === this;
});
}
}

customElements.define(componentName, Component);
return Component;
}

$.component = component;
}
14 changes: 14 additions & 0 deletions packages/signalizejs/src/plugins/dash-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Signalize } from '..';

declare module '..' {

interface Signalize {
dashCase: (str: string) => string
}
}

export default ($: Signalize): void => {
$.dashCase = (str: string) => {
return str.replace(/[A-Z]/g, (token: string) => '-' + token.toLowerCase())
}
}
8 changes: 1 addition & 7 deletions packages/signalizejs/src/plugins/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,6 @@ export default (pluginOptions?: PluginOptions): SignalizePlugin => {
const mode = options.mode ?? 'init';
const canExecute = ['reinit', 'init'].includes(mode);
const canCompile = mode === 'init';

const elementClosestScope = element.closest(`[${$.scopeAttribute}]`);

if (elementClosestScope && scope(elementClosestScope[$.scopeKey]) === undefined) {
return element;
}

let elementScope = scope(element);

if (mode === 'reinit') {
Expand Down Expand Up @@ -395,6 +388,7 @@ export default (pluginOptions?: PluginOptions): SignalizePlugin => {
});
}
});

on('scope:init', (data) => processElement({ element: data.element }));

$.AsyncFunction = AsyncFunction;
Expand Down
2 changes: 1 addition & 1 deletion packages/signalizejs/src/plugins/h.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default (): SignalizePlugin => {
if (child instanceof Element || child instanceof Node) {
result.push(child);
} else if (child instanceof $.Signal) {
result.push(...normalizeChild(child.get()));
result.push(...normalizeChild(child()));
child.watch(({ newValue }) => {
const newNormalizedChildren = normalizeChild(newValue);
for (const newNormalizedChild of newNormalizedChildren) {
Expand Down
Loading

0 comments on commit d849760

Please sign in to comment.