Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
titouanmathis committed Dec 17, 2024
1 parent acce904 commit 4c143da
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 80 deletions.
3 changes: 3 additions & 0 deletions packages/demo/meta.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { prototyping } from '@studiometa/webpack-config-preset-prototyping';

export default defineConfig({
presets: [prototyping({ ts: true })],
server(config) {
config.snippet = false;
},
webpack(config) {
config.resolve.alias = {
...config.resolve.alias,
Expand Down
57 changes: 9 additions & 48 deletions packages/demo/src/js/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
BaseConfig,
withDrag,
withName,
getInstances,
} from '@studiometa/js-toolkit';
import { matrix } from '@studiometa/js-toolkit/utils';
import ScrollToDemo from './components/ScrollToDemo.js';
Expand All @@ -24,52 +25,6 @@ import ScrolledInViewOffset from './components/ScrolledInViewOffset.js';
import MediaQueryDemo from './components/MediaQueryDemo.js';
import PointerProps from './components/PointerProps.js';

let numberOfTick = 0;
let time = performance.now();
let interval = setInterval(() => {
const newTime = performance.now();
numberOfTick += 1;
console.log('#%d blocking time: %d ms', numberOfTick, newTime - time);
time = newTime;

if (numberOfTick > total * 2) {
clearInterval(interval)
}
}, 0)

let count = 0;
const total = 66;

function getDeepNestedComponentName(index) {
return `TestDeepNested${index}`
}

function makeDeepNestedComponent(index) {
return class extends withExtraConfig(Base, { name: getDeepNestedComponentName(index), components: {} }) {
mounted() {
// console.log(this.$id);
}
};
}

const TestDeepNested = makeDeepNestedComponent(0);
let CurrentClass = TestDeepNested;
while (count < total) {
count += 1;
const NewClass = makeDeepNestedComponent(count);
// @ts-ignore
CurrentClass.config.components[NewClass.config.name] = NewClass;

CurrentClass = NewClass;
}


const TestManyInstance = class extends withExtraConfig(Base, { name: 'TestManyInstance', debug: false }) {
mounted() {
// console.log(this.$id);
}
};

/**
* App class.
*/
Expand Down Expand Up @@ -98,8 +53,8 @@ class App extends Base {
AnimateTestMultiple,
ResponsiveOptions,
ScrolledInViewOffset,
TestDeepNested,
TestManyInstance,
// TestDeepNested,
// TestManyInstance,
Accordion: (app) =>
importWhenVisible(
async () => {
Expand Down Expand Up @@ -183,9 +138,15 @@ class App extends Base {
* @inheritdoc
*/
mounted() {
window.APP = this;
this.$log('Mounted 🎉');
}

updated() {
console.log(this.$children.TestManyInstance)
console.log(getInstances());
}

onModalOpen(...args) {
this.$log('onModalOpen', ...args);
}
Expand Down
1 change: 1 addition & 0 deletions packages/demo/src/js/components/ParentNativeEvent/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default class ParentNativeEvent extends Base {
static config = {
name: 'ParentNativeEvent',
log: true,
debug: true,
components: {
Child,
},
Expand Down
53 changes: 23 additions & 30 deletions packages/js-toolkit/Base/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,46 +326,38 @@ export class Base<T extends BaseProps = BaseProps> {
if (!service.has(key)) {
service.add(key, (props) => {
const updates = new Map<Base, () => any>();
const terminations = new Map<Base, () => any>();

console.log(props.mutations);
for (const instance of getInstances()) {
for (const mutation of props.mutations) {
// Update components whose children have changed their data-component attribute
if (mutation.type === 'attributes') {
if (!updates.has(instance) && instance.$el.contains(mutation.target.parentNode)) {
updates.set(instance, () => instance.$update());
}

continue;
}

// Terminate components whose root element has been removed from the DOM
// @todo move this to the ChildrenManager within the `$update()` Base method
for (const node of mutation.removedNodes) {
if (node.isConnected) continue;

if (!terminations.has(instance) && node.contains(instance.$el)) {
terminations.set(instance, () => instance.$terminate());
}
}

// Update components whose children have been changed
for (const node of mutation.addedNodes) {
if (!updates.has(instance) && instance.$el.contains(node)) {
updates.set(instance, () => instance.$update());
}
const shouldUpdateAfterAttributeChange =
mutation.type === 'attributes' && instance.$el.contains(mutation.target.parentNode);
const shouldUpdateAfterNodeRemoval =
mutation.type === 'childList' &&
Array.from(mutation.removedNodes).some((node) => instance.$el !== node && instance.$el.contains(node));
const shouldUpdateAfterNodeAddition =
mutation.type === 'childList' &&
Array.from(mutation.addedNodes).some((node) => instance.$el.contains(node));

// @todo removedNode has no parent
console.log(instance.$id, {
shouldUpdateAfterAttributeChange,
shouldUpdateAfterNodeRemoval,
shouldUpdateAfterNodeAddition,
});
if (
shouldUpdateAfterAttributeChange ||
shouldUpdateAfterNodeRemoval ||
shouldUpdateAfterNodeAddition
) {
updates.set(instance, () => instance.$update());
}
}
}

console.log(updates);
for (const update of updates.values()) {
update();
}

for (const termination of terminations.values()) {
termination();
}
});
}

Expand Down Expand Up @@ -425,6 +417,7 @@ export class Base<T extends BaseProps = BaseProps> {
await Promise.all([
// Undo
addToQueue(() => this.__refs.unregisterAll()),
addToQueue(() => this.__children.unregisterAll()),
addToQueue(() => this.__services.disableAll()),
// Redo
addToQueue(() => this.__children.registerAll()),
Expand Down
20 changes: 18 additions & 2 deletions packages/js-toolkit/Base/managers/ChildrenManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { getComponentElements, addToQueue } from '../utils.js';
/**
* Children manager.
*/
export class ChildrenManager<T> extends AbstractManager<T> {
export class ChildrenManager<
T extends Record<string, Base[] | Promise<Base>[]>,
> extends AbstractManager<T> {
/**
* Store async component promises to avoid calling them multiple times and
* waiting for them when they are already resolved.
Expand All @@ -23,6 +25,20 @@ export class ChildrenManager<T> extends AbstractManager<T> {
return Object.keys(this.props);
}

async unregisterAll() {
for (const instances of Object.values(this.props)) {
for (let instance of instances) {
if (instance instanceof Promise) {
instance = await instance;
}

if (!instance.$el.isConnected) {
instance.$terminate();
}
}
}
}

/**
* Register instances of all children components.
*/
Expand Down Expand Up @@ -91,7 +107,7 @@ export class ChildrenManager<T> extends AbstractManager<T> {
Object.defineProperty(this.props, name, {
enumerable: true,
configurable: true,
get: () => this.__getValue(name, component),
value: this.__getValue(name, component),
});
}

Expand Down

0 comments on commit 4c143da

Please sign in to comment.