@mulanjs/mulanjs 1.0.1-dev.20260220155535 → 1.0.1-dev.20260222103836

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.
@@ -227,3 +227,145 @@ export function muPulse() {
227
227
  export function muVault(key, initial, options = {}) {
228
228
  return persistent(key, initial, Object.assign(Object.assign({}, options), { onCleanup: (fn) => onMuDestroy(fn) }));
229
229
  }
230
+ // --- Next-Gen MulanJS Hooks ---
231
+ /**
232
+ * muSuspense - The Asynchronous Barrier.
233
+ * Natively handles async state (loading/data/error) without wrapper components.
234
+ */
235
+ export function muSuspense(promiseFn) {
236
+ const state = muState({
237
+ loading: true,
238
+ data: null,
239
+ error: null
240
+ });
241
+ // Execute immediately safely
242
+ promiseFn()
243
+ .then(res => {
244
+ state.data = res;
245
+ state.loading = false;
246
+ })
247
+ .catch(err => {
248
+ state.error = err;
249
+ state.loading = false;
250
+ });
251
+ return state;
252
+ }
253
+ /**
254
+ * onMuVisibility - The Intersection Observer Hook.
255
+ * Triggers when the component enters/leaves the viewport.
256
+ */
257
+ export function onMuVisibility(callback, options = { threshold: 0.1 }) {
258
+ const instance = getCurrentInstance();
259
+ // We defer observation to mount phase to ensure DOM exists
260
+ onMuMount(() => {
261
+ if (!instance || !instance.container)
262
+ return;
263
+ const observer = new IntersectionObserver((entries) => {
264
+ entries.forEach(entry => {
265
+ callback(entry.isIntersecting);
266
+ });
267
+ }, options);
268
+ observer.observe(instance.container);
269
+ onMuDestroy(() => {
270
+ observer.disconnect();
271
+ });
272
+ });
273
+ }
274
+ /**
275
+ * muDebounced - High-performance debouncing built directly into a reactive signal.
276
+ */
277
+ export function muDebounced(initialValue, delayMs) {
278
+ const state = muState(initialValue);
279
+ let timeoutId;
280
+ return {
281
+ get value() {
282
+ return state.value;
283
+ },
284
+ set value(newVal) {
285
+ clearTimeout(timeoutId);
286
+ timeoutId = setTimeout(() => {
287
+ state.value = newVal;
288
+ }, delayMs);
289
+ }
290
+ };
291
+ }
292
+ /**
293
+ * muThrottled - High-performance throttling built directly into a reactive signal.
294
+ */
295
+ export function muThrottled(initialValue, delayMs) {
296
+ const state = muState(initialValue);
297
+ let lastRan = 0;
298
+ return {
299
+ get value() {
300
+ return state.value;
301
+ },
302
+ set value(newVal) {
303
+ const now = Date.now();
304
+ if (now - lastRan >= delayMs) {
305
+ state.value = newVal;
306
+ lastRan = now;
307
+ }
308
+ }
309
+ };
310
+ }
311
+ /**
312
+ * onMuPanic - The Iron Fortress Error Boundary.
313
+ * Catches unhandled exceptions within the component scope.
314
+ */
315
+ export function onMuPanic(fallbackFn) {
316
+ const instance = getCurrentInstance();
317
+ const handler = (event) => {
318
+ // Broad catch - in a full implementation, we'd inspect the stack trace
319
+ // to isolate if it originated from `instance` specifically.
320
+ // For Mulan 2.0 MVP, we execute the fallback.
321
+ const error = event instanceof ErrorEvent ? event.error : event.reason;
322
+ console.error(`[Iron Fortress] Component ${(instance === null || instance === void 0 ? void 0 : instance.$uid) || 'Unknown'} Panic:`, error);
323
+ fallbackFn(error);
324
+ // Prevent default browser crash if handled
325
+ event.preventDefault();
326
+ };
327
+ window.addEventListener('error', handler);
328
+ window.addEventListener('unhandledrejection', handler);
329
+ onMuDestroy(() => {
330
+ window.removeEventListener('error', handler);
331
+ window.removeEventListener('unhandledrejection', handler);
332
+ });
333
+ }
334
+ /**
335
+ * muHistory - State with built-in Undo/Redo tracking.
336
+ */
337
+ export function muHistory(initialValue) {
338
+ const state = muState(initialValue);
339
+ // Explicit wrapper object because muState treats bare arrays dynamically
340
+ const historyTracker = muState({ log: [initialValue] });
341
+ const pointer = muState(0);
342
+ const updateValue = (newVal) => {
343
+ // If we are back in history and make a NEW change, we drop the 'future'
344
+ if (pointer.value < historyTracker.log.length - 1) {
345
+ historyTracker.log = historyTracker.log.slice(0, pointer.value + 1);
346
+ }
347
+ historyTracker.log.push(newVal);
348
+ pointer.value = historyTracker.log.length - 1;
349
+ state.value = newVal;
350
+ };
351
+ const undo = () => {
352
+ if (pointer.value > 0) {
353
+ pointer.value--;
354
+ state.value = historyTracker.log[pointer.value];
355
+ }
356
+ };
357
+ const redo = () => {
358
+ if (pointer.value < historyTracker.log.length - 1) {
359
+ pointer.value++;
360
+ state.value = historyTracker.log[pointer.value];
361
+ }
362
+ };
363
+ return {
364
+ get value() { return state.value; },
365
+ set value(newVal) { updateValue(newVal); },
366
+ undo,
367
+ redo,
368
+ get past() { return historyTracker.log.slice(0, pointer.value); },
369
+ get future() { return historyTracker.log.slice(pointer.value + 1); }
370
+ };
371
+ }
package/dist/mulan.esm.js CHANGED
@@ -38,18 +38,24 @@ var hooks_namespaceObject = {};
38
38
  __webpack_require__.r(hooks_namespaceObject);
39
39
  __webpack_require__.d(hooks_namespaceObject, {
40
40
  getCurrentInstance: () => (getCurrentInstance),
41
+ muDebounced: () => (muDebounced),
41
42
  muEffect: () => (muEffect),
42
43
  muGeom: () => (muGeom),
44
+ muHistory: () => (muHistory),
43
45
  muMemo: () => (muMemo),
44
46
  muPulse: () => (muPulse),
45
47
  muState: () => (muState),
48
+ muSuspense: () => (muSuspense),
49
+ muThrottled: () => (muThrottled),
46
50
  muVault: () => (muVault),
47
51
  onMuDestroy: () => (onMuDestroy),
48
52
  onMuIdle: () => (onMuIdle),
49
53
  onMuInit: () => (onMuInit),
50
54
  onMuMount: () => (onMuMount),
55
+ onMuPanic: () => (onMuPanic),
51
56
  onMuResume: () => (onMuResume),
52
57
  onMuShake: () => (onMuShake),
58
+ onMuVisibility: () => (onMuVisibility),
53
59
  onMuVoice: () => (onMuVoice),
54
60
  setCurrentInstance: () => (setCurrentInstance)
55
61
  });
@@ -601,6 +607,148 @@ function muPulse() {
601
607
  function muVault(key, initial, options = {}) {
602
608
  return persistent(key, initial, Object.assign(Object.assign({}, options), { onCleanup: (fn) => onMuDestroy(fn) }));
603
609
  }
610
+ // --- Next-Gen MulanJS Hooks ---
611
+ /**
612
+ * muSuspense - The Asynchronous Barrier.
613
+ * Natively handles async state (loading/data/error) without wrapper components.
614
+ */
615
+ function muSuspense(promiseFn) {
616
+ const state = muState({
617
+ loading: true,
618
+ data: null,
619
+ error: null
620
+ });
621
+ // Execute immediately safely
622
+ promiseFn()
623
+ .then(res => {
624
+ state.data = res;
625
+ state.loading = false;
626
+ })
627
+ .catch(err => {
628
+ state.error = err;
629
+ state.loading = false;
630
+ });
631
+ return state;
632
+ }
633
+ /**
634
+ * onMuVisibility - The Intersection Observer Hook.
635
+ * Triggers when the component enters/leaves the viewport.
636
+ */
637
+ function onMuVisibility(callback, options = { threshold: 0.1 }) {
638
+ const instance = getCurrentInstance();
639
+ // We defer observation to mount phase to ensure DOM exists
640
+ onMuMount(() => {
641
+ if (!instance || !instance.container)
642
+ return;
643
+ const observer = new IntersectionObserver((entries) => {
644
+ entries.forEach(entry => {
645
+ callback(entry.isIntersecting);
646
+ });
647
+ }, options);
648
+ observer.observe(instance.container);
649
+ onMuDestroy(() => {
650
+ observer.disconnect();
651
+ });
652
+ });
653
+ }
654
+ /**
655
+ * muDebounced - High-performance debouncing built directly into a reactive signal.
656
+ */
657
+ function muDebounced(initialValue, delayMs) {
658
+ const state = muState(initialValue);
659
+ let timeoutId;
660
+ return {
661
+ get value() {
662
+ return state.value;
663
+ },
664
+ set value(newVal) {
665
+ clearTimeout(timeoutId);
666
+ timeoutId = setTimeout(() => {
667
+ state.value = newVal;
668
+ }, delayMs);
669
+ }
670
+ };
671
+ }
672
+ /**
673
+ * muThrottled - High-performance throttling built directly into a reactive signal.
674
+ */
675
+ function muThrottled(initialValue, delayMs) {
676
+ const state = muState(initialValue);
677
+ let lastRan = 0;
678
+ return {
679
+ get value() {
680
+ return state.value;
681
+ },
682
+ set value(newVal) {
683
+ const now = Date.now();
684
+ if (now - lastRan >= delayMs) {
685
+ state.value = newVal;
686
+ lastRan = now;
687
+ }
688
+ }
689
+ };
690
+ }
691
+ /**
692
+ * onMuPanic - The Iron Fortress Error Boundary.
693
+ * Catches unhandled exceptions within the component scope.
694
+ */
695
+ function onMuPanic(fallbackFn) {
696
+ const instance = getCurrentInstance();
697
+ const handler = (event) => {
698
+ // Broad catch - in a full implementation, we'd inspect the stack trace
699
+ // to isolate if it originated from `instance` specifically.
700
+ // For Mulan 2.0 MVP, we execute the fallback.
701
+ const error = event instanceof ErrorEvent ? event.error : event.reason;
702
+ console.error(`[Iron Fortress] Component ${(instance === null || instance === void 0 ? void 0 : instance.$uid) || 'Unknown'} Panic:`, error);
703
+ fallbackFn(error);
704
+ // Prevent default browser crash if handled
705
+ event.preventDefault();
706
+ };
707
+ window.addEventListener('error', handler);
708
+ window.addEventListener('unhandledrejection', handler);
709
+ onMuDestroy(() => {
710
+ window.removeEventListener('error', handler);
711
+ window.removeEventListener('unhandledrejection', handler);
712
+ });
713
+ }
714
+ /**
715
+ * muHistory - State with built-in Undo/Redo tracking.
716
+ */
717
+ function muHistory(initialValue) {
718
+ const state = muState(initialValue);
719
+ // Explicit wrapper object because muState treats bare arrays dynamically
720
+ const historyTracker = muState({ log: [initialValue] });
721
+ const pointer = muState(0);
722
+ const updateValue = (newVal) => {
723
+ // If we are back in history and make a NEW change, we drop the 'future'
724
+ if (pointer.value < historyTracker.log.length - 1) {
725
+ historyTracker.log = historyTracker.log.slice(0, pointer.value + 1);
726
+ }
727
+ historyTracker.log.push(newVal);
728
+ pointer.value = historyTracker.log.length - 1;
729
+ state.value = newVal;
730
+ };
731
+ const undo = () => {
732
+ if (pointer.value > 0) {
733
+ pointer.value--;
734
+ state.value = historyTracker.log[pointer.value];
735
+ }
736
+ };
737
+ const redo = () => {
738
+ if (pointer.value < historyTracker.log.length - 1) {
739
+ pointer.value++;
740
+ state.value = historyTracker.log[pointer.value];
741
+ }
742
+ };
743
+ return {
744
+ get value() { return state.value; },
745
+ set value(newVal) { updateValue(newVal); },
746
+ undo,
747
+ redo,
748
+ get past() { return historyTracker.log.slice(0, pointer.value); },
749
+ get future() { return historyTracker.log.slice(pointer.value + 1); }
750
+ };
751
+ }
604
752
 
605
753
  ;// ./src/core/component.ts
606
754
 
@@ -2059,6 +2207,6 @@ if (typeof window !== 'undefined') {
2059
2207
  }
2060
2208
  /* harmony default export */ const src = (Mulan);
2061
2209
 
2062
- export { MuComponent as Component, MuBlochSphereElement, MuComponent, MuInfinity, MuRouter, MuStore, MuRouter as Router, Security, Signal, activeControls, src as default, defineComponent, effect, getCurrentInstance, hydrate, muBurst, muControl, muEffect, muEntangle, muGate, muGeom, muMeasure, muMemo, muParallel, muPulse, muQubit, muRegister, muSearch, muState, muSurge, muSwitch, muTeleport, muVault, onMuDestroy, onMuIdle, onMuInit, onMuMount, onMuResume, onMuShake, onMuVoice, persistent, reactive, ref, render, renderToString, sanitize, setCurrentInstance, useMutation, useQuery };
2210
+ export { MuComponent as Component, MuBlochSphereElement, MuComponent, MuInfinity, MuRouter, MuStore, MuRouter as Router, Security, Signal, activeControls, src as default, defineComponent, effect, getCurrentInstance, hydrate, muBurst, muControl, muDebounced, muEffect, muEntangle, muGate, muGeom, muHistory, muMeasure, muMemo, muParallel, muPulse, muQubit, muRegister, muSearch, muState, muSurge, muSuspense, muSwitch, muTeleport, muThrottled, muVault, onMuDestroy, onMuIdle, onMuInit, onMuMount, onMuPanic, onMuResume, onMuShake, onMuVisibility, onMuVoice, persistent, reactive, ref, render, renderToString, sanitize, setCurrentInstance, useMutation, useQuery };
2063
2211
 
2064
2212
  //# sourceMappingURL=mulan.esm.js.map