@lisergia/core 23.0.1 → 24.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,599 @@
1
+ // src/App.ts
2
+ import { autorun, computed, makeObservable, observable, observe } from "mobx";
3
+
4
+ // src/EventEmitter.ts
5
+ import AutoBind from "auto-bind";
6
+ import { createNanoEvents } from "nanoevents";
7
+ var EventEmitter = class {
8
+ emitter;
9
+ entries = /* @__PURE__ */ new Map();
10
+ constructor() {
11
+ AutoBind(this);
12
+ this.emitter = createNanoEvents();
13
+ }
14
+ on(event, callback) {
15
+ if (!callback) {
16
+ return console.trace("No callback provided");
17
+ }
18
+ const emitter = this.emitter.on(event, callback);
19
+ this.entries.set(callback, emitter);
20
+ return emitter;
21
+ }
22
+ off(event, callback) {
23
+ const unsubscribe = this.entries.get(callback);
24
+ if (unsubscribe) {
25
+ unsubscribe();
26
+ }
27
+ this.entries.delete(callback);
28
+ }
29
+ fire(event, ...args) {
30
+ this.emitter.emit(event, ...args);
31
+ }
32
+ destroy() {
33
+ this.entries.forEach((unsubscribe) => unsubscribe());
34
+ this.entries.clear();
35
+ }
36
+ };
37
+
38
+ // src/Component.ts
39
+ var Component = class extends EventEmitter {
40
+ application;
41
+ autoListeners;
42
+ autoMount;
43
+ classes;
44
+ selector;
45
+ selectors;
46
+ id;
47
+ element;
48
+ elements = {};
49
+ constructor({
50
+ application,
51
+ autoListeners = true,
52
+ autoMount = true,
53
+ classes,
54
+ element,
55
+ elements,
56
+ id
57
+ }) {
58
+ super();
59
+ this.application = application;
60
+ this.autoListeners = autoListeners;
61
+ this.autoMount = autoMount;
62
+ this.classes = classes;
63
+ this.selector = element;
64
+ this.selectors = elements;
65
+ this.id = id;
66
+ if (this.autoMount) {
67
+ this.create();
68
+ }
69
+ if (this.autoListeners) {
70
+ this.addEventListeners();
71
+ }
72
+ }
73
+ create() {
74
+ if (this.selector) {
75
+ this.initElement(this.selector);
76
+ }
77
+ if (this.selectors) {
78
+ this.initElements(this.selectors);
79
+ }
80
+ }
81
+ initElement(selector) {
82
+ if (selector instanceof HTMLElement) {
83
+ this.element = selector;
84
+ } else {
85
+ this.element = document.querySelector(selector);
86
+ }
87
+ }
88
+ destroyElement() {
89
+ this.element = void 0;
90
+ }
91
+ initElements(selectors) {
92
+ for (const key in selectors) {
93
+ const selector = selectors[key];
94
+ if (selector === window) {
95
+ this.elements[key] = window;
96
+ } else if (selector instanceof HTMLElement) {
97
+ this.elements[key] = selector;
98
+ } else if (selector instanceof NodeList) {
99
+ this.elements[key] = selector;
100
+ } else if (Array.isArray(selector)) {
101
+ this.elements[key] = selector;
102
+ } else {
103
+ const elements = this.element.querySelectorAll(selector);
104
+ if (elements.length === 0) {
105
+ const elements2 = document.querySelectorAll(selector);
106
+ if (elements2.length === 0) {
107
+ this.elements[key] = null;
108
+ } else if (elements2.length === 1) {
109
+ this.elements[key] = elements2[0];
110
+ } else {
111
+ this.elements[key] = elements2;
112
+ }
113
+ } else if (elements.length === 1) {
114
+ this.elements[key] = elements[0];
115
+ } else {
116
+ this.elements[key] = elements;
117
+ }
118
+ }
119
+ }
120
+ }
121
+ destroyElements() {
122
+ this.elements = {};
123
+ }
124
+ addEventListeners() {
125
+ }
126
+ removeEventListeners() {
127
+ }
128
+ destroy() {
129
+ super.destroy();
130
+ this.removeEventListeners();
131
+ this.destroyElements();
132
+ this.destroyElement();
133
+ }
134
+ };
135
+
136
+ // src/Links.ts
137
+ import { reaction } from "mobx";
138
+
139
+ // src/Link.ts
140
+ var Link = class extends Component {
141
+ constructor({ element }) {
142
+ super({ element });
143
+ }
144
+ onClick(event) {
145
+ event.preventDefault();
146
+ this.fire("click", this.element.href);
147
+ }
148
+ addEventListeners() {
149
+ const isLocal = this.element.href.includes(window.location.origin);
150
+ const isLocalPrevented = this.element.dataset.linkOverride === "";
151
+ const isNotEmail = !this.element.href.startsWith("mailto");
152
+ const isNotPhone = !this.element.href.startsWith("tel");
153
+ const isDownload = this.element.hasAttribute("download");
154
+ const isAnchor = this.element.href.includes("#");
155
+ if (isAnchor) {
156
+ const hash = this.element.href.split("#")[1];
157
+ if (hash) {
158
+ const element = document.querySelector(`#${hash}`);
159
+ if (element) {
160
+ return;
161
+ }
162
+ }
163
+ }
164
+ if (isLocalPrevented || isDownload) {
165
+ return;
166
+ }
167
+ if (isLocal) {
168
+ this.element.onclick = this.onClick;
169
+ } else if (isNotEmail && isNotPhone) {
170
+ this.element.rel = "noopener";
171
+ this.element.setAttribute("target", "_blank");
172
+ }
173
+ }
174
+ removeEventListeners() {
175
+ this.element.onclick = null;
176
+ }
177
+ };
178
+
179
+ // src/Links.ts
180
+ var Links = class extends EventEmitter {
181
+ constructor(application) {
182
+ super();
183
+ this.application = application;
184
+ reaction(
185
+ () => application.currentPage,
186
+ () => this.refresh(),
187
+ { fireImmediately: true }
188
+ );
189
+ }
190
+ addEventListeners() {
191
+ var _a;
192
+ (_a = this.links) == null ? void 0 : _a.forEach((link) => link.destroy());
193
+ const links = document.querySelectorAll("a");
194
+ this.links = Array.from(links).map((element) => {
195
+ const link = new Link({
196
+ element
197
+ });
198
+ link.on("click", this.onLinkClick);
199
+ return link;
200
+ });
201
+ }
202
+ onLinkClick(href) {
203
+ this.application.route = href.replace(window.location.origin, "");
204
+ }
205
+ refresh() {
206
+ this.addEventListeners();
207
+ }
208
+ };
209
+
210
+ // src/App.ts
211
+ var ApplicationManager = class extends Component {
212
+ template = document.documentElement.dataset.template ?? "404";
213
+ constructor() {
214
+ super({
215
+ autoListeners: false,
216
+ element: ".app"
217
+ });
218
+ makeObservable(this, {
219
+ // Application DOM Element.
220
+ element: observable,
221
+ // Components.
222
+ canvas: observable,
223
+ components: observable,
224
+ transition: observable,
225
+ // Page Information.
226
+ currentPage: observable,
227
+ nextPage: observable,
228
+ // Route Information.
229
+ route: observable,
230
+ routeHistory: observable,
231
+ // Template Information.
232
+ template: observable,
233
+ // Page Scroll.
234
+ scroll: computed
235
+ });
236
+ observe(this.components, this.onComponentChange);
237
+ observe(this, "route", this.onRouteChange);
238
+ autorun(this.onTitleUpdate);
239
+ autorun(this.onTemplateUpdate);
240
+ this.addEventListeners();
241
+ }
242
+ onTitleUpdate() {
243
+ var _a;
244
+ const title = (_a = this.nextPage) == null ? void 0 : _a.title;
245
+ if (title) {
246
+ document.title = title;
247
+ }
248
+ }
249
+ onTemplateUpdate() {
250
+ var _a;
251
+ const template = (_a = this.nextPage) == null ? void 0 : _a.template;
252
+ if (template) {
253
+ document.documentElement.dataset.template = template;
254
+ this.template = template;
255
+ }
256
+ }
257
+ //
258
+ // Components.
259
+ //
260
+ canvas;
261
+ components = [];
262
+ transition;
263
+ initComponents(components) {
264
+ const classes = components.map(
265
+ ({ component: Component2 }) => new Component2({
266
+ application: this
267
+ })
268
+ );
269
+ this.canvas = classes.find((component) => component.id === "canvas");
270
+ this.transition = classes.find((component) => component.id === "transition");
271
+ classes.forEach((component) => {
272
+ this.addComponent(component);
273
+ });
274
+ }
275
+ addComponent(component) {
276
+ this.components.push(component);
277
+ }
278
+ removeComponent(component) {
279
+ component.destroy();
280
+ const index = this.components.indexOf(component);
281
+ if (index !== -1) {
282
+ this.components.splice(index, 1);
283
+ }
284
+ }
285
+ onComponentChange(event) {
286
+ if (event.type === "splice") {
287
+ const { added, removed } = event;
288
+ }
289
+ }
290
+ //
291
+ // Datasets.
292
+ //
293
+ datasets = [];
294
+ initDatasets(datasets) {
295
+ this.datasets = datasets;
296
+ }
297
+ //
298
+ // Routes.
299
+ //
300
+ pages = /* @__PURE__ */ new Map();
301
+ initRoutes(routes) {
302
+ routes.forEach(({ component, template }) => {
303
+ this.pages.set(template, component);
304
+ });
305
+ }
306
+ //
307
+ // Sprites.
308
+ //
309
+ async initSprites(url = "/bundle.svg") {
310
+ const request = await window.fetch(url);
311
+ const response = await request.text();
312
+ const sprite = document.createElement("div");
313
+ sprite.innerHTML = response;
314
+ sprite.style.left = "-999999px";
315
+ sprite.style.opacity = "0";
316
+ sprite.style.position = "absolute";
317
+ sprite.style.top = "0";
318
+ document.body.appendChild(sprite);
319
+ }
320
+ //
321
+ // Initialization.
322
+ //
323
+ IS_LINKS_ENABLED = true;
324
+ initPage() {
325
+ this.createPage();
326
+ this.createLinks();
327
+ }
328
+ //
329
+ // Links.
330
+ //
331
+ createLinks() {
332
+ if (!this.IS_LINKS_ENABLED) {
333
+ return;
334
+ }
335
+ this.links = new Links(this);
336
+ }
337
+ //
338
+ // Page.
339
+ //
340
+ currentPage = void 0;
341
+ createPage(template = this.template) {
342
+ const PageClass = this.pages.get(template);
343
+ const page = new PageClass({
344
+ application: this,
345
+ datasets: this.datasets
346
+ });
347
+ this.currentPage = page;
348
+ this.currentPage.create();
349
+ }
350
+ destroyPage() {
351
+ if (this.currentPage) {
352
+ this.currentPage.destroy();
353
+ }
354
+ }
355
+ //
356
+ // Navigate.
357
+ //
358
+ route = window.location.pathname;
359
+ routeHistory = [this.route];
360
+ routePushState = true;
361
+ onRouteChange({ oldValue, newValue }) {
362
+ const href = newValue.replace(window.location.origin, "");
363
+ this.onRouteChangeRequest({
364
+ href,
365
+ pushState: this.routePushState
366
+ });
367
+ }
368
+ async onRouteChangeRequest({ href, pushState = true }) {
369
+ const request = await window.fetch(href);
370
+ const response = await request.text();
371
+ this.onRequest({
372
+ href,
373
+ response,
374
+ pushState
375
+ });
376
+ }
377
+ //
378
+ // Request.
379
+ //
380
+ nextPage = {};
381
+ async onRequest({ href, response, pushState }) {
382
+ var _a, _b;
383
+ let domParser = new DOMParser();
384
+ let dom = domParser.parseFromString(response, "text/html");
385
+ const html = dom.querySelector("html");
386
+ const app = dom.querySelector(".app");
387
+ this.nextPage = {
388
+ element: app,
389
+ template: html.dataset.template ?? this.template,
390
+ title: dom.title ?? document.title
391
+ };
392
+ if (this.transition) {
393
+ await ((_b = (_a = this.transition).onTransition) == null ? void 0 : _b.call(_a, this));
394
+ } else {
395
+ this.currentPage.element.remove();
396
+ this.currentPage.destroy();
397
+ this.element.appendChild(this.nextPage.element.firstElementChild);
398
+ this.createPage(this.nextPage.template);
399
+ }
400
+ if (pushState) {
401
+ window.history.pushState({}, this.nextPage.title, href);
402
+ }
403
+ this.routeHistory.push(href);
404
+ domParser = null;
405
+ dom = null;
406
+ }
407
+ //
408
+ // Pop State.
409
+ //
410
+ onPopState(event) {
411
+ this.routePushState = false;
412
+ this.route = document.location.pathname;
413
+ this.routePushState = true;
414
+ }
415
+ //
416
+ // Scroll.
417
+ //
418
+ get scroll() {
419
+ return this.currentPage.scroll ?? 0;
420
+ }
421
+ //
422
+ // Listeners.
423
+ //
424
+ addEventListeners() {
425
+ window.addEventListener("popstate", this.onPopState);
426
+ }
427
+ removeEventListeners() {
428
+ window.removeEventListener("popstate", this.onPopState);
429
+ }
430
+ };
431
+ var Application = new ApplicationManager();
432
+
433
+ // src/Page.ts
434
+ import Lenis from "lenis";
435
+ import { makeObservable as makeObservable2, observable as observable2 } from "mobx";
436
+ import GSAP from "gsap";
437
+ import ScrollTrigger from "gsap/src/ScrollTrigger";
438
+ import Tempus from "tempus";
439
+ var Page = class extends Component {
440
+ datasets = [];
441
+ scroll = 0;
442
+ scrollEnabled = true;
443
+ scrollOptions = {};
444
+ constructor({
445
+ application,
446
+ classes,
447
+ datasets,
448
+ element,
449
+ elements,
450
+ scrollEnabled = true,
451
+ scrollOptions = {}
452
+ }) {
453
+ super({
454
+ autoMount: false,
455
+ autoListeners: false,
456
+ classes,
457
+ element,
458
+ elements
459
+ });
460
+ this.application = application;
461
+ this.datasets = datasets;
462
+ this.scrollEnabled = scrollEnabled;
463
+ this.scrollOptions = scrollOptions;
464
+ makeObservable2(this, {
465
+ element: observable2,
466
+ elements: observable2,
467
+ components: observable2,
468
+ scroll: observable2
469
+ });
470
+ }
471
+ create() {
472
+ super.create();
473
+ this.createResizeObserver();
474
+ this.createComponents();
475
+ this.createScroll();
476
+ this.addEventListeners();
477
+ }
478
+ createResizeObserver() {
479
+ this.resizeObserver = new ResizeObserver(() => {
480
+ this.onResize();
481
+ });
482
+ this.resizeObserver.observe(this.elements.wrapper);
483
+ }
484
+ destroyResizeObserver() {
485
+ this.resizeObserver.disconnect();
486
+ }
487
+ //
488
+ // Components.
489
+ //
490
+ components = /* @__PURE__ */ new Set();
491
+ createComponents() {
492
+ this.datasets.map(({ component: Component2, selector }) => {
493
+ const elements = this.element.querySelectorAll(selector);
494
+ const components = Array.from(elements).map((element) => {
495
+ const component = new Component2({
496
+ application: this.application,
497
+ element
498
+ });
499
+ return component;
500
+ });
501
+ components.forEach((component) => {
502
+ this.application.addComponent(component);
503
+ this.components.add(component);
504
+ });
505
+ });
506
+ }
507
+ destroyComponents() {
508
+ this.components.forEach((component) => {
509
+ this.application.removeComponent(component);
510
+ });
511
+ this.components.clear();
512
+ }
513
+ createScroll() {
514
+ if (!this.scrollEnabled) {
515
+ this.element.addEventListener("scroll", this.onScrollFallback);
516
+ return;
517
+ }
518
+ this.lenis = new Lenis({
519
+ content: this.elements.wrapper,
520
+ wrapper: this.element,
521
+ ...this.scrollOptions
522
+ });
523
+ GSAP.ticker.add(this.onGSAPTicker);
524
+ GSAP.ticker.lagSmoothing(0);
525
+ this.lenis.on("scroll", this.onLenisScroll);
526
+ }
527
+ onGSAPTicker(time) {
528
+ this.lenis.raf(time * 1e3);
529
+ }
530
+ onLenisScroll(event) {
531
+ ScrollTrigger.update();
532
+ this.onScroll(event.scroll);
533
+ this.emitter.emit("scroll", event);
534
+ }
535
+ destroyScroll() {
536
+ var _a;
537
+ if (!this.scrollEnabled) {
538
+ this.element.removeEventListener("scroll", this.onScrollFallback);
539
+ return;
540
+ }
541
+ GSAP.ticker.remove(this.onGSAPTicker);
542
+ this.lenis.off("scroll", this.onLenisScroll);
543
+ (_a = this.lenis) == null ? void 0 : _a.destroy();
544
+ this.lenis = void 0;
545
+ }
546
+ //
547
+ // Events.
548
+ //
549
+ onResize() {
550
+ var _a;
551
+ (_a = this.lenis) == null ? void 0 : _a.resize();
552
+ }
553
+ onRAF(time) {
554
+ var _a;
555
+ (_a = this.lenis) == null ? void 0 : _a.raf(time);
556
+ }
557
+ onScroll(scroll) {
558
+ this.scroll = scroll;
559
+ }
560
+ onScrollFallback() {
561
+ this.scroll = this.element.scrollTop;
562
+ this.emitter.emit("scroll", { scroll: this.scroll });
563
+ }
564
+ //
565
+ // Events.
566
+ //
567
+ addEventListeners() {
568
+ super.addEventListeners();
569
+ this.unsubscribeRaf = Tempus.add(this.onRAF);
570
+ }
571
+ removeEventListeners() {
572
+ var _a;
573
+ super.removeEventListeners();
574
+ (_a = this.unsubscribeRaf) == null ? void 0 : _a.call(this);
575
+ this.unsubscribeRaf = void 0;
576
+ }
577
+ //
578
+ // Destroy.
579
+ //
580
+ destroy() {
581
+ this.destroyResizeObserver();
582
+ this.destroyComponents();
583
+ this.destroyScroll();
584
+ super.destroy();
585
+ }
586
+ };
587
+
588
+ // src/index.ts
589
+ import Tempus2 from "tempus";
590
+ export {
591
+ Application,
592
+ ApplicationManager,
593
+ Component,
594
+ EventEmitter,
595
+ Link,
596
+ Links,
597
+ Page,
598
+ Tempus2 as Tempus
599
+ };