@unsetsoft/ryunixjs 1.2.3-canary.9 → 1.2.4
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/Ryunix.esm.js +635 -365
- package/dist/Ryunix.esm.js.map +1 -1
- package/dist/Ryunix.umd.js +639 -364
- package/dist/Ryunix.umd.js.map +1 -1
- package/dist/Ryunix.umd.min.js +1 -1
- package/dist/Ryunix.umd.min.js.map +1 -1
- package/jsx/jsx-dev-runtime.js +6 -0
- package/jsx/jsx-runtime.js +56 -0
- package/package.json +14 -3
package/dist/Ryunix.esm.js
CHANGED
|
@@ -70,7 +70,12 @@ const is = {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* The `createTextElement` function creates a text element with the specified text content.
|
|
74
|
+
* @param text - The `text` parameter in the `createTextElement` function is the text content that you
|
|
75
|
+
* want to create a text element for. This text will be set as the `nodeValue` of the text element in
|
|
76
|
+
* the returned object.
|
|
77
|
+
* @returns A text element object is being returned with a type of RYUNIX_TYPES.TEXT_ELEMENT and props
|
|
78
|
+
* containing the text value provided in the function argument.
|
|
74
79
|
*/
|
|
75
80
|
const createTextElement = (text) => {
|
|
76
81
|
return {
|
|
@@ -83,7 +88,21 @@ const createTextElement = (text) => {
|
|
|
83
88
|
};
|
|
84
89
|
|
|
85
90
|
/**
|
|
86
|
-
*
|
|
91
|
+
* The `createElement` function creates a virtual DOM element with specified type, properties, and
|
|
92
|
+
* children.
|
|
93
|
+
* @param type - The `type` parameter in the `createElement` function represents the type of element
|
|
94
|
+
* you want to create, such as a HTML tag like 'div', 'span', 'p', etc.
|
|
95
|
+
* @param props - The `props` parameter in the `createElement` function is an object that contains the
|
|
96
|
+
* properties or attributes for the element being created. These properties can include things like
|
|
97
|
+
* class names, styles, event handlers, and any other custom attributes you want to assign to the
|
|
98
|
+
* element. In the code snippet you provided,
|
|
99
|
+
* @param children - The `children` parameter in the `createElement` function represents the child
|
|
100
|
+
* elements or text content that will be nested within the created element. These children can be
|
|
101
|
+
* passed as arguments to the `createElement` function and will be rendered as part of the element's
|
|
102
|
+
* content.
|
|
103
|
+
* @returns An object is being returned with a `type` property representing the type of element, and a
|
|
104
|
+
* `props` property containing the element's properties. The `props` object includes the children of
|
|
105
|
+
* the element, which are processed to ensure they are in the correct format.
|
|
87
106
|
*/
|
|
88
107
|
const createElement = (type, props, ...children) => {
|
|
89
108
|
const safeProps = props || {};
|
|
@@ -102,7 +121,14 @@ const createElement = (type, props, ...children) => {
|
|
|
102
121
|
};
|
|
103
122
|
|
|
104
123
|
/**
|
|
105
|
-
* Fragment
|
|
124
|
+
* The `Fragment` function in JavaScript creates a fragment element with the given children.
|
|
125
|
+
* @param props - The `props` parameter in the `Fragment` function is an object that contains the
|
|
126
|
+
* properties passed to the `Fragment` component. These properties can include `children`, which
|
|
127
|
+
* represents the child elements or components nested within the `Fragment`.
|
|
128
|
+
* @returns The `Fragment` component is returning a Ryunix fragment element created using the
|
|
129
|
+
* `createElement` function. The element is of type `RYUNIX_TYPES.RYUNIX_FRAGMENT` and contains the
|
|
130
|
+
* children passed to the `Fragment` component. If `props.children` is not an array, it is converted
|
|
131
|
+
* into an array before being spread into the `createElement` function.
|
|
106
132
|
*/
|
|
107
133
|
const Fragment = (props) => {
|
|
108
134
|
const children = Array.isArray(props.children)
|
|
@@ -450,6 +476,9 @@ const updateDom = (dom, prevProps = {}, nextProps = {}) => {
|
|
|
450
476
|
});
|
|
451
477
|
};
|
|
452
478
|
|
|
479
|
+
/**
|
|
480
|
+
* The `commitRoot` function commits the changes made to the virtual DOM by updating the actual DOM.
|
|
481
|
+
*/
|
|
453
482
|
const commitRoot = () => {
|
|
454
483
|
const state = getState();
|
|
455
484
|
state.deletions.forEach(commitWork);
|
|
@@ -587,34 +616,6 @@ const reconcileChildren = (wipFiber, elements) => {
|
|
|
587
616
|
});
|
|
588
617
|
};
|
|
589
618
|
|
|
590
|
-
const updateFunctionComponent = (fiber) => {
|
|
591
|
-
const state = getState();
|
|
592
|
-
state.wipFiber = fiber;
|
|
593
|
-
state.hookIndex = 0;
|
|
594
|
-
state.wipFiber.hooks = [];
|
|
595
|
-
|
|
596
|
-
const children = [fiber.type(fiber.props)];
|
|
597
|
-
|
|
598
|
-
if (fiber.type._contextId && fiber.props.value !== undefined) {
|
|
599
|
-
fiber._contextId = fiber.type._contextId;
|
|
600
|
-
fiber._contextValue = fiber.props.value;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
reconcileChildren(fiber, children);
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
const updateHostComponent = (fiber) => {
|
|
607
|
-
if (!fiber.dom) {
|
|
608
|
-
fiber.dom = createDom(fiber);
|
|
609
|
-
}
|
|
610
|
-
const children = fiber.props?.children || [];
|
|
611
|
-
reconcileChildren(fiber, children);
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
const Image = ({ src, ...props }) => {
|
|
615
|
-
return createElement('img', { ...props, src })
|
|
616
|
-
};
|
|
617
|
-
|
|
618
619
|
/**
|
|
619
620
|
* Priority levels for updates
|
|
620
621
|
*/
|
|
@@ -628,369 +629,180 @@ const Priority = {
|
|
|
628
629
|
|
|
629
630
|
Priority.NORMAL;
|
|
630
631
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
this.measures = new Map();
|
|
638
|
-
this.renderTimes = [];
|
|
639
|
-
this.maxSamples = 100;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
startMeasure(name) {
|
|
643
|
-
if (!this.enabled) return
|
|
644
|
-
this.measures.set(name, performance.now());
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
endMeasure(name) {
|
|
648
|
-
if (!this.enabled) return
|
|
649
|
-
const start = this.measures.get(name);
|
|
650
|
-
if (!start) return
|
|
651
|
-
|
|
652
|
-
const duration = performance.now() - start;
|
|
653
|
-
this.measures.delete(name);
|
|
654
|
-
|
|
655
|
-
return duration
|
|
632
|
+
const validateHookCall = () => {
|
|
633
|
+
const state = getState();
|
|
634
|
+
if (!state.wipFiber) {
|
|
635
|
+
throw new Error(
|
|
636
|
+
'Hooks can only be called inside the body of a function component.',
|
|
637
|
+
)
|
|
656
638
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (!this.enabled) return
|
|
660
|
-
|
|
661
|
-
this.renderTimes.push({
|
|
662
|
-
component: componentName,
|
|
663
|
-
duration,
|
|
664
|
-
timestamp: Date.now(),
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
if (this.renderTimes.length > this.maxSamples) {
|
|
668
|
-
this.renderTimes.shift();
|
|
669
|
-
}
|
|
639
|
+
if (!Array.isArray(state.wipFiber.hooks)) {
|
|
640
|
+
state.wipFiber.hooks = [];
|
|
670
641
|
}
|
|
642
|
+
};
|
|
671
643
|
|
|
672
|
-
|
|
673
|
-
|
|
644
|
+
const haveDepsChanged = (oldDeps, newDeps) => {
|
|
645
|
+
if (!oldDeps || !newDeps) return true
|
|
646
|
+
if (oldDeps.length !== newDeps.length) return true
|
|
647
|
+
return oldDeps.some((dep, i) => !Object.is(dep, newDeps[i]))
|
|
648
|
+
};
|
|
674
649
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
650
|
+
/**
|
|
651
|
+
* The `useStore` function in JavaScript is a custom hook that uses a reducer to manage state updates
|
|
652
|
+
* based on actions provided.
|
|
653
|
+
* @param initialState - The `initialState` parameter in the `useStore` function is the initial state
|
|
654
|
+
* of the store that will be used with the `useReducer` hook. It represents the starting state of the
|
|
655
|
+
* store before any actions are dispatched to update it.
|
|
656
|
+
* @returns The `useStore` function is returning the result of calling the `useReducer` hook with the
|
|
657
|
+
* `reducer` function and the `initialState` as arguments.
|
|
658
|
+
*/
|
|
659
|
+
const useStore = (initialState) => {
|
|
660
|
+
const reducer = (state, action) =>
|
|
661
|
+
is.function(action) ? action(state) : action;
|
|
662
|
+
return useReducer(reducer, initialState)
|
|
663
|
+
};
|
|
679
664
|
|
|
680
|
-
|
|
681
|
-
|
|
665
|
+
/**
|
|
666
|
+
* The `useReducer` function in JavaScript is used to manage state and actions.
|
|
667
|
+
*
|
|
668
|
+
* @param reducer - The `reducer` parameter in the `useReducer` function is a function that specifies
|
|
669
|
+
* how the state should be updated in response to an action. It takes the current state and an action
|
|
670
|
+
* as arguments and returns the new state based on the action.
|
|
671
|
+
* @param initialState - The `initialState` parameter in the `useReducer` function represents the
|
|
672
|
+
* initial state of the reducer. It is the state that will be used when the reducer is first called or
|
|
673
|
+
* when the state needs to be reset. This initial state can be a simple value, an object, an array, or
|
|
674
|
+
* @param init - The `init` parameter in the `useReducer` function is an optional function that can be
|
|
675
|
+
* used to initialize the state. If provided, it will be called with the `initialState` as its argument
|
|
676
|
+
* and the return value will be used as the initial state for the reducer. If `init`
|
|
677
|
+
* @returns An array containing the current state and the dispatch function is being returned.
|
|
678
|
+
*/
|
|
679
|
+
const useReducer = (reducer, initialState, init) => {
|
|
680
|
+
validateHookCall();
|
|
682
681
|
|
|
683
|
-
|
|
684
|
-
|
|
682
|
+
const state = getState();
|
|
683
|
+
const { wipFiber, hookIndex } = state;
|
|
684
|
+
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
685
685
|
|
|
686
|
-
|
|
686
|
+
const hook = {
|
|
687
|
+
hookID: hookIndex,
|
|
688
|
+
type: RYUNIX_TYPES.RYUNIX_STORE,
|
|
689
|
+
state: oldHook ? oldHook.state : init ? init(initialState) : initialState,
|
|
690
|
+
queue: [],
|
|
691
|
+
};
|
|
687
692
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
693
|
+
if (oldHook?.queue) {
|
|
694
|
+
oldHook.queue.forEach((action) => {
|
|
695
|
+
try {
|
|
696
|
+
hook.state = reducer(hook.state, action);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
699
|
+
console.error('Error in reducer:', error);
|
|
700
|
+
}
|
|
691
701
|
}
|
|
692
|
-
const stats = byComponent.get(component);
|
|
693
|
-
stats.total += duration;
|
|
694
|
-
stats.count++;
|
|
695
|
-
stats.max = Math.max(stats.max, duration);
|
|
696
702
|
});
|
|
697
|
-
|
|
698
|
-
return Array.from(byComponent.entries())
|
|
699
|
-
.map(([name, stats]) => ({
|
|
700
|
-
name,
|
|
701
|
-
avg: stats.total / stats.count,
|
|
702
|
-
max: stats.max,
|
|
703
|
-
count: stats.count,
|
|
704
|
-
}))
|
|
705
|
-
.sort((a, b) => b.avg - a.avg)
|
|
706
|
-
.slice(0, limit)
|
|
707
703
|
}
|
|
708
704
|
|
|
709
|
-
|
|
710
|
-
if (
|
|
705
|
+
const dispatch = (action) => {
|
|
706
|
+
if (action === undefined) {
|
|
707
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
708
|
+
console.warn('dispatch called with undefined action');
|
|
709
|
+
}
|
|
710
|
+
return
|
|
711
|
+
}
|
|
711
712
|
|
|
712
|
-
|
|
713
|
-
if (!stats) return
|
|
713
|
+
hook.queue.push(action);
|
|
714
714
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
715
|
+
const currentState = getState();
|
|
716
|
+
currentState.wipRoot = {
|
|
717
|
+
dom: currentState.currentRoot.dom,
|
|
718
|
+
props: currentState.currentRoot.props,
|
|
719
|
+
alternate: currentState.currentRoot,
|
|
720
|
+
};
|
|
721
|
+
currentState.deletions = [];
|
|
722
|
+
currentState.hookIndex = 0;
|
|
723
|
+
scheduleWork(currentState.wipRoot);
|
|
724
|
+
};
|
|
721
725
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
console.log(
|
|
727
|
-
`${i + 1}. ${comp.name}: ${comp.avg.toFixed(2)}ms avg (${comp.count} renders)`,
|
|
728
|
-
);
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
console.groupEnd();
|
|
732
|
-
}
|
|
726
|
+
wipFiber.hooks[hookIndex] = hook;
|
|
727
|
+
state.hookIndex++;
|
|
728
|
+
return [hook.state, dispatch]
|
|
729
|
+
};
|
|
733
730
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
731
|
+
/**
|
|
732
|
+
* The `useEffect` function in JavaScript is used to manage side effects in functional components by
|
|
733
|
+
* comparing dependencies and executing a callback function when dependencies change.
|
|
734
|
+
* @param callback - The `callback` parameter in the `useEffect` function is a function that will be
|
|
735
|
+
* executed as the effect. This function can perform side effects like data fetching, subscriptions, or
|
|
736
|
+
* DOM manipulations.
|
|
737
|
+
* @param deps - The `deps` parameter in the `useEffect` function stands for dependencies. It is an
|
|
738
|
+
* optional array that contains values that the effect depends on. The effect will only re-run if any
|
|
739
|
+
* of the values in the `deps` array have changed since the last render. If the `deps` array
|
|
740
|
+
*/
|
|
741
|
+
const useEffect = (callback, deps) => {
|
|
742
|
+
validateHookCall();
|
|
738
743
|
|
|
739
|
-
|
|
740
|
-
|
|
744
|
+
if (!is.function(callback)) {
|
|
745
|
+
throw new Error('useEffect callback must be a function')
|
|
741
746
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
this.enabled = false;
|
|
747
|
+
if (deps !== undefined && !Array.isArray(deps)) {
|
|
748
|
+
throw new Error('useEffect dependencies must be an array or undefined')
|
|
745
749
|
}
|
|
746
|
-
}
|
|
747
750
|
|
|
748
|
-
|
|
749
|
-
const
|
|
751
|
+
const state = getState();
|
|
752
|
+
const { wipFiber, hookIndex } = state;
|
|
753
|
+
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
754
|
+
const hasChanged = haveDepsChanged(oldHook?.deps, deps);
|
|
750
755
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
+
const hook = {
|
|
757
|
+
hookID: hookIndex,
|
|
758
|
+
type: RYUNIX_TYPES.RYUNIX_EFFECT,
|
|
759
|
+
deps,
|
|
760
|
+
effect: hasChanged ? callback : null,
|
|
761
|
+
cancel: oldHook?.cancel,
|
|
762
|
+
};
|
|
756
763
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
profiler.recordRender(componentName, duration);
|
|
760
|
-
}
|
|
764
|
+
wipFiber.hooks[hookIndex] = hook;
|
|
765
|
+
state.hookIndex++;
|
|
761
766
|
};
|
|
762
767
|
|
|
763
768
|
/**
|
|
764
|
-
*
|
|
769
|
+
* The useRef function in JavaScript creates a reference object with an initial value for use in functional components.
|
|
770
|
+
* @param initialValue - The `initialValue` parameter in the `useRef` function represents the initial
|
|
771
|
+
* value that will be assigned to the `current` property of the reference object. This initial value
|
|
772
|
+
* will be used if there is no previous value stored in the hook.
|
|
773
|
+
* @returns The `useRef` function is returning the `current` property of the `hook.value` object, which
|
|
774
|
+
* contains the initial value passed to the `useRef` function.
|
|
765
775
|
*/
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
profiler.startMeasure(name);
|
|
769
|
-
const result = Component(props);
|
|
770
|
-
const duration = profiler.endMeasure(name);
|
|
771
|
-
if (duration) profiler.recordRender(name, duration);
|
|
772
|
-
return result
|
|
773
|
-
}
|
|
774
|
-
};
|
|
776
|
+
const useRef = (initialValue) => {
|
|
777
|
+
validateHookCall();
|
|
775
778
|
|
|
776
|
-
const workLoop = (deadline) => {
|
|
777
779
|
const state = getState();
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
while (state.nextUnitOfWork && !shouldYield) {
|
|
781
|
-
state.nextUnitOfWork = performUnitOfWork(state.nextUnitOfWork);
|
|
782
|
-
shouldYield = deadline.timeRemaining() < 1;
|
|
783
|
-
}
|
|
780
|
+
const { wipFiber, hookIndex } = state;
|
|
781
|
+
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
784
782
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
783
|
+
const hook = {
|
|
784
|
+
hookID: hookIndex,
|
|
785
|
+
type: RYUNIX_TYPES.RYUNIX_REF,
|
|
786
|
+
value: oldHook ? oldHook.value : { current: initialValue },
|
|
787
|
+
};
|
|
788
788
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
requestIdleCallback(workLoop);
|
|
793
|
-
|
|
794
|
-
const performUnitOfWork = (fiber) => {
|
|
795
|
-
const componentName = fiber.type?.name || fiber.type?.displayName || 'Unknown';
|
|
796
|
-
|
|
797
|
-
profiler.startMeasure(componentName);
|
|
798
|
-
|
|
799
|
-
const isFunctionComponent = fiber.type instanceof Function;
|
|
800
|
-
if (isFunctionComponent) {
|
|
801
|
-
updateFunctionComponent(fiber);
|
|
802
|
-
} else {
|
|
803
|
-
updateHostComponent(fiber);
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
const duration = profiler.endMeasure(componentName);
|
|
807
|
-
if (duration) profiler.recordRender(componentName, duration);
|
|
808
|
-
|
|
809
|
-
if (fiber.child) {
|
|
810
|
-
return fiber.child
|
|
811
|
-
}
|
|
812
|
-
let nextFiber = fiber;
|
|
813
|
-
while (nextFiber) {
|
|
814
|
-
if (nextFiber.sibling) {
|
|
815
|
-
return nextFiber.sibling
|
|
816
|
-
}
|
|
817
|
-
nextFiber = nextFiber.parent;
|
|
818
|
-
}
|
|
819
|
-
};
|
|
820
|
-
|
|
821
|
-
const scheduleWork = (root, priority = Priority.NORMAL) => {
|
|
822
|
-
const state = getState();
|
|
823
|
-
state.nextUnitOfWork = root;
|
|
824
|
-
state.wipRoot = root;
|
|
825
|
-
state.deletions = [];
|
|
826
|
-
state.hookIndex = 0;
|
|
827
|
-
state.effects = [];
|
|
828
|
-
|
|
829
|
-
// Higher priority = faster scheduling
|
|
830
|
-
if (priority <= Priority.USER_BLOCKING) {
|
|
831
|
-
requestIdleCallback(workLoop);
|
|
832
|
-
} else {
|
|
833
|
-
setTimeout(() => requestIdleCallback(workLoop), 0);
|
|
834
|
-
}
|
|
835
|
-
};
|
|
836
|
-
|
|
837
|
-
const render = (element, container) => {
|
|
838
|
-
const state = getState();
|
|
839
|
-
state.wipRoot = {
|
|
840
|
-
dom: container,
|
|
841
|
-
props: {
|
|
842
|
-
children: [element],
|
|
843
|
-
},
|
|
844
|
-
alternate: state.currentRoot,
|
|
845
|
-
};
|
|
846
|
-
|
|
847
|
-
state.nextUnitOfWork = state.wipRoot;
|
|
848
|
-
state.deletions = [];
|
|
849
|
-
scheduleWork(state.wipRoot);
|
|
850
|
-
return state.wipRoot
|
|
851
|
-
};
|
|
852
|
-
|
|
853
|
-
const init = (MainElement, root = '__ryunix') => {
|
|
854
|
-
const state = getState();
|
|
855
|
-
state.containerRoot = document.getElementById(root);
|
|
856
|
-
const renderProcess = render(MainElement, state.containerRoot);
|
|
857
|
-
return renderProcess
|
|
858
|
-
};
|
|
859
|
-
|
|
860
|
-
const safeRender = (component, props, onError) => {
|
|
861
|
-
try {
|
|
862
|
-
return component(props)
|
|
863
|
-
} catch (error) {
|
|
864
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
865
|
-
console.error('Component error:', error);
|
|
866
|
-
}
|
|
867
|
-
if (onError) onError(error);
|
|
868
|
-
return null
|
|
869
|
-
}
|
|
870
|
-
};
|
|
871
|
-
|
|
872
|
-
const validateHookCall = () => {
|
|
873
|
-
const state = getState();
|
|
874
|
-
if (!state.wipFiber) {
|
|
875
|
-
throw new Error(
|
|
876
|
-
'Hooks can only be called inside the body of a function component.',
|
|
877
|
-
)
|
|
878
|
-
}
|
|
879
|
-
if (!Array.isArray(state.wipFiber.hooks)) {
|
|
880
|
-
state.wipFiber.hooks = [];
|
|
881
|
-
}
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
const haveDepsChanged = (oldDeps, newDeps) => {
|
|
885
|
-
if (!oldDeps || !newDeps) return true
|
|
886
|
-
if (oldDeps.length !== newDeps.length) return true
|
|
887
|
-
return oldDeps.some((dep, i) => !Object.is(dep, newDeps[i]))
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
const useStore = (initialState) => {
|
|
891
|
-
const reducer = (state, action) =>
|
|
892
|
-
is.function(action) ? action(state) : action;
|
|
893
|
-
return useReducer(reducer, initialState)
|
|
894
|
-
};
|
|
895
|
-
|
|
896
|
-
const useReducer = (reducer, initialState, init) => {
|
|
897
|
-
validateHookCall();
|
|
898
|
-
|
|
899
|
-
const state = getState();
|
|
900
|
-
const { wipFiber, hookIndex } = state;
|
|
901
|
-
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
902
|
-
|
|
903
|
-
const hook = {
|
|
904
|
-
hookID: hookIndex,
|
|
905
|
-
type: RYUNIX_TYPES.RYUNIX_STORE,
|
|
906
|
-
state: oldHook ? oldHook.state : init ? init(initialState) : initialState,
|
|
907
|
-
queue: [], // Siempre nueva cola vacía
|
|
908
|
-
};
|
|
909
|
-
|
|
910
|
-
// Procesar acciones del render anterior
|
|
911
|
-
if (oldHook?.queue) {
|
|
912
|
-
oldHook.queue.forEach((action) => {
|
|
913
|
-
try {
|
|
914
|
-
hook.state = reducer(hook.state, action);
|
|
915
|
-
} catch (error) {
|
|
916
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
917
|
-
console.error('Error in reducer:', error);
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
const dispatch = (action) => {
|
|
924
|
-
if (action === undefined) {
|
|
925
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
926
|
-
console.warn('dispatch called with undefined action');
|
|
927
|
-
}
|
|
928
|
-
return
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
hook.queue.push(action);
|
|
932
|
-
|
|
933
|
-
const currentState = getState();
|
|
934
|
-
currentState.wipRoot = {
|
|
935
|
-
dom: currentState.currentRoot.dom,
|
|
936
|
-
props: currentState.currentRoot.props,
|
|
937
|
-
alternate: currentState.currentRoot,
|
|
938
|
-
};
|
|
939
|
-
currentState.deletions = [];
|
|
940
|
-
currentState.hookIndex = 0;
|
|
941
|
-
scheduleWork(currentState.wipRoot);
|
|
942
|
-
};
|
|
943
|
-
|
|
944
|
-
wipFiber.hooks[hookIndex] = hook;
|
|
945
|
-
state.hookIndex++;
|
|
946
|
-
return [hook.state, dispatch]
|
|
947
|
-
};
|
|
948
|
-
|
|
949
|
-
const useEffect = (callback, deps) => {
|
|
950
|
-
validateHookCall();
|
|
951
|
-
|
|
952
|
-
if (!is.function(callback)) {
|
|
953
|
-
throw new Error('useEffect callback must be a function')
|
|
954
|
-
}
|
|
955
|
-
if (deps !== undefined && !Array.isArray(deps)) {
|
|
956
|
-
throw new Error('useEffect dependencies must be an array or undefined')
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
const state = getState();
|
|
960
|
-
const { wipFiber, hookIndex } = state;
|
|
961
|
-
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
962
|
-
const hasChanged = haveDepsChanged(oldHook?.deps, deps);
|
|
963
|
-
|
|
964
|
-
const hook = {
|
|
965
|
-
hookID: hookIndex,
|
|
966
|
-
type: RYUNIX_TYPES.RYUNIX_EFFECT,
|
|
967
|
-
deps,
|
|
968
|
-
effect: hasChanged ? callback : null,
|
|
969
|
-
cancel: oldHook?.cancel,
|
|
970
|
-
};
|
|
971
|
-
|
|
972
|
-
wipFiber.hooks[hookIndex] = hook;
|
|
973
|
-
state.hookIndex++;
|
|
974
|
-
};
|
|
975
|
-
|
|
976
|
-
const useRef = (initialValue) => {
|
|
977
|
-
validateHookCall();
|
|
978
|
-
|
|
979
|
-
const state = getState();
|
|
980
|
-
const { wipFiber, hookIndex } = state;
|
|
981
|
-
const oldHook = wipFiber.alternate?.hooks?.[hookIndex];
|
|
982
|
-
|
|
983
|
-
const hook = {
|
|
984
|
-
hookID: hookIndex,
|
|
985
|
-
type: RYUNIX_TYPES.RYUNIX_REF,
|
|
986
|
-
value: oldHook ? oldHook.value : { current: initialValue },
|
|
987
|
-
};
|
|
988
|
-
|
|
989
|
-
wipFiber.hooks[hookIndex] = hook;
|
|
990
|
-
state.hookIndex++;
|
|
991
|
-
return hook.value
|
|
789
|
+
wipFiber.hooks[hookIndex] = hook;
|
|
790
|
+
state.hookIndex++;
|
|
791
|
+
return hook.value
|
|
992
792
|
};
|
|
993
793
|
|
|
794
|
+
/**
|
|
795
|
+
* The useMemo function in JavaScript is used to memoize the result of a computation based on
|
|
796
|
+
* dependencies.
|
|
797
|
+
* @param compute - The `compute` parameter in the `useMemo` function is a callback function that
|
|
798
|
+
* calculates the value that `useMemo` will memoize and return. This function will be called to compute
|
|
799
|
+
* the memoized value when necessary.
|
|
800
|
+
* @param deps - The `deps` parameter in the `useMemo` function refers to an array of dependencies.
|
|
801
|
+
* These dependencies are used to determine whether the memoized value needs to be recalculated or if
|
|
802
|
+
* the previously calculated value can be reused. The `useMemo` hook will recompute the memoized value
|
|
803
|
+
* only if
|
|
804
|
+
* @returns The `useMemo` function is returning the `value` calculated by the `compute` function.
|
|
805
|
+
*/
|
|
994
806
|
const useMemo = (compute, deps) => {
|
|
995
807
|
validateHookCall();
|
|
996
808
|
|
|
@@ -1031,6 +843,17 @@ const useMemo = (compute, deps) => {
|
|
|
1031
843
|
return value
|
|
1032
844
|
};
|
|
1033
845
|
|
|
846
|
+
/**
|
|
847
|
+
* The useCallback function in JavaScript ensures that a callback function is memoized based on its
|
|
848
|
+
* dependencies.
|
|
849
|
+
* @param callback - A function that you want to memoize and return for later use.
|
|
850
|
+
* @param deps - The `deps` parameter in the `useCallback` function refers to an array of dependencies.
|
|
851
|
+
* These dependencies are used to determine when the callback function should be re-evaluated and
|
|
852
|
+
* memoized. If any of the dependencies change, the callback function will be re-executed and the
|
|
853
|
+
* memoized value will
|
|
854
|
+
* @returns The useCallback function is returning the memoized version of the callback function passed
|
|
855
|
+
* as the first argument, based on the dependencies array provided as the second argument.
|
|
856
|
+
*/
|
|
1034
857
|
const useCallback = (callback, deps) => {
|
|
1035
858
|
if (!is.function(callback)) {
|
|
1036
859
|
throw new Error('useCallback requires a function as first argument')
|
|
@@ -1038,6 +861,20 @@ const useCallback = (callback, deps) => {
|
|
|
1038
861
|
return useMemo(() => callback, deps)
|
|
1039
862
|
};
|
|
1040
863
|
|
|
864
|
+
/**
|
|
865
|
+
* The createContext function creates a context provider and useContext hook in JavaScript.
|
|
866
|
+
* @param [contextId] - The `contextId` parameter in the `createContext` function is used to specify
|
|
867
|
+
* the unique identifier for the context being created. It defaults to `RYUNIX_TYPES.RYUNIX_CONTEXT` if
|
|
868
|
+
* not provided.
|
|
869
|
+
* @param [defaultValue] - The `defaultValue` parameter in the `createContext` function is used to
|
|
870
|
+
* specify the default value that will be returned by the `useContext` hook if no provider is found in
|
|
871
|
+
* the component tree. It is an optional parameter, and if not provided, an empty object `{}` will be
|
|
872
|
+
* used as
|
|
873
|
+
* @returns The `createContext` function returns an object with two properties: `Provider` and
|
|
874
|
+
* `useContext`. The `Provider` property is a component that accepts `children` and `value` props, and
|
|
875
|
+
* sets the `_contextId` and `_contextValue` properties on the element. The `useContext` property is a
|
|
876
|
+
* hook function that retrieves the context value based on the context ID provided, or
|
|
877
|
+
*/
|
|
1041
878
|
const createContext = (
|
|
1042
879
|
contextId = RYUNIX_TYPES.RYUNIX_CONTEXT,
|
|
1043
880
|
defaultValue = {},
|
|
@@ -1075,6 +912,10 @@ const createContext = (
|
|
|
1075
912
|
return { Provider, useContext }
|
|
1076
913
|
};
|
|
1077
914
|
|
|
915
|
+
/**
|
|
916
|
+
* The `useQuery` function extracts query parameters from the URL in a browser environment.
|
|
917
|
+
* @returns An object containing the query parameters from the current URL is being returned.
|
|
918
|
+
*/
|
|
1078
919
|
const useQuery = () => {
|
|
1079
920
|
if (typeof window === 'undefined') return {}
|
|
1080
921
|
|
|
@@ -1086,6 +927,14 @@ const useQuery = () => {
|
|
|
1086
927
|
return query
|
|
1087
928
|
};
|
|
1088
929
|
|
|
930
|
+
/**
|
|
931
|
+
* The function `useHash` in JavaScript is used to manage and update the hash portion of the URL in a
|
|
932
|
+
* web application.
|
|
933
|
+
* @returns The `useHash` function returns the current hash value from the window's location. If the
|
|
934
|
+
* window is undefined (e.g., in a server-side environment), it returns an empty string. The function
|
|
935
|
+
* also sets up an event listener to update the hash value when the hash in the URL changes and removes
|
|
936
|
+
* the event listener when the component unmounts.
|
|
937
|
+
*/
|
|
1089
938
|
const useHash = () => {
|
|
1090
939
|
if (typeof window === 'undefined') return ''
|
|
1091
940
|
|
|
@@ -1098,6 +947,25 @@ const useHash = () => {
|
|
|
1098
947
|
return hash
|
|
1099
948
|
};
|
|
1100
949
|
|
|
950
|
+
/**
|
|
951
|
+
* The `useMetadata` function in JavaScript is used to dynamically update metadata tags in the document
|
|
952
|
+
* head based on provided tags and options.
|
|
953
|
+
* @param [tags] - The `tags` parameter in the `useMetadata` function is an object that contains
|
|
954
|
+
* metadata information for the webpage. It can include properties like `pageTitle`, `canonical`, and
|
|
955
|
+
* other custom metadata tags like `og:title`, `og:description`, `twitter:title`,
|
|
956
|
+
* `twitter:description`, etc. These tags
|
|
957
|
+
* @param [options] - The `options` parameter in the `useMetadata` function is an object that can
|
|
958
|
+
* contain the following properties:
|
|
959
|
+
* - `title`: An object that can have the following properties:
|
|
960
|
+
* - `template`: A string that defines the template for the page title. It can include a placeholder
|
|
961
|
+
* `%s` that will be replaced with the actual page title.
|
|
962
|
+
* - `prefix`: A string that will be used as the default title if no specific page title is provided.
|
|
963
|
+
* @returns The `useMetadata` function does not return anything. It is a custom hook that updates the
|
|
964
|
+
* document's metadata (such as title and meta tags) based on the provided `tags` and `options` whenever
|
|
965
|
+
* they change.
|
|
966
|
+
* This hook can't be reached by google crawler.
|
|
967
|
+
*/
|
|
968
|
+
|
|
1101
969
|
const useMetadata = (tags = {}, options = {}) => {
|
|
1102
970
|
useEffect(() => {
|
|
1103
971
|
if (typeof document === 'undefined') return
|
|
@@ -1188,6 +1056,12 @@ const findRoute = (routes, path) => {
|
|
|
1188
1056
|
return notFound
|
|
1189
1057
|
};
|
|
1190
1058
|
|
|
1059
|
+
/**
|
|
1060
|
+
* The `RouterProvider` component manages routing in a Ryunix application by updating the location based
|
|
1061
|
+
* on window events and providing context for the current route.
|
|
1062
|
+
* @returns The `RouterProvider` component is returning a `RouterContext.Provider` component with a
|
|
1063
|
+
* `value` prop set to `contextValue`, and wrapping the `children` within a `Fragment`.
|
|
1064
|
+
*/
|
|
1191
1065
|
const RouterProvider = ({ routes, children }) => {
|
|
1192
1066
|
const [location, setLocation] = useStore(window.location.pathname);
|
|
1193
1067
|
|
|
@@ -1224,10 +1098,24 @@ const RouterProvider = ({ routes, children }) => {
|
|
|
1224
1098
|
)
|
|
1225
1099
|
};
|
|
1226
1100
|
|
|
1101
|
+
/**
|
|
1102
|
+
* The function `useRouter` returns the context of the Router for navigation in a Ryunix application.
|
|
1103
|
+
* @returns The `useRouter` function is returning the result of calling
|
|
1104
|
+
* `RouterContext.useContext('ryunix.navigation')`. This function is likely attempting to retrieve the
|
|
1105
|
+
* navigation context from the RouterContext.
|
|
1106
|
+
*/
|
|
1227
1107
|
const useRouter = () => {
|
|
1228
1108
|
return RouterContext.useContext('ryunix.navigation')
|
|
1229
1109
|
};
|
|
1230
1110
|
|
|
1111
|
+
/**
|
|
1112
|
+
* The `Children` function in JavaScript uses router hooks to handle scrolling to a specific element
|
|
1113
|
+
* based on the hash in the URL.
|
|
1114
|
+
* @returns The `Children` component is returning the result of calling `createElement` with
|
|
1115
|
+
* `route.component` as the first argument and an object with `key`, `params`, `query`, and `hash`
|
|
1116
|
+
* properties as the second argument. The `key` property is set to `location`, and the `params`,
|
|
1117
|
+
* `query`, and `hash` properties are passed as values from the component's props.
|
|
1118
|
+
*/
|
|
1231
1119
|
const Children = () => {
|
|
1232
1120
|
const { route, params, query, location } = useRouter();
|
|
1233
1121
|
if (!route || !route.component) return null
|
|
@@ -1249,6 +1137,12 @@ const Children = () => {
|
|
|
1249
1137
|
})
|
|
1250
1138
|
};
|
|
1251
1139
|
|
|
1140
|
+
/**
|
|
1141
|
+
* The NavLink function in JavaScript is a component that generates a link element with customizable
|
|
1142
|
+
* classes and active state based on the current location.
|
|
1143
|
+
* @returns The `NavLink` component is returning a JSX element representing an anchor (`<a>`) tag with
|
|
1144
|
+
* the following attributes and properties:
|
|
1145
|
+
*/
|
|
1252
1146
|
const NavLink = ({ to, exact = false, ...props }) => {
|
|
1253
1147
|
const { location, navigate } = useRouter();
|
|
1254
1148
|
const isActive = exact ? location === to : location.startsWith(to);
|
|
@@ -1361,6 +1255,376 @@ var hooks = /*#__PURE__*/Object.freeze({
|
|
|
1361
1255
|
useTransition: useTransition
|
|
1362
1256
|
});
|
|
1363
1257
|
|
|
1258
|
+
const updateFunctionComponent = (fiber) => {
|
|
1259
|
+
const state = getState();
|
|
1260
|
+
state.wipFiber = fiber;
|
|
1261
|
+
state.hookIndex = 0;
|
|
1262
|
+
state.wipFiber.hooks = [];
|
|
1263
|
+
|
|
1264
|
+
const children = [fiber.type(fiber.props)];
|
|
1265
|
+
|
|
1266
|
+
if (fiber.type._contextId && fiber.props.value !== undefined) {
|
|
1267
|
+
fiber._contextId = fiber.type._contextId;
|
|
1268
|
+
fiber._contextValue = fiber.props.value;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
reconcileChildren(fiber, children);
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
const updateHostComponent = (fiber) => {
|
|
1275
|
+
if (!fiber.dom) {
|
|
1276
|
+
fiber.dom = createDom(fiber);
|
|
1277
|
+
}
|
|
1278
|
+
const children = fiber.props?.children || [];
|
|
1279
|
+
reconcileChildren(fiber, children);
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* The Component `Image` takes in a `src` and other props, and returns an `img` element with the
|
|
1284
|
+
* specified `src` and props.
|
|
1285
|
+
* @returns The `Image` component is being returned. It is a functional component that renders an `img`
|
|
1286
|
+
* element with the specified `src` and other props passed to it.
|
|
1287
|
+
*/
|
|
1288
|
+
const Image = ({ src, ...props }) => {
|
|
1289
|
+
return createElement('img', { ...props, src })
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
const { Provider: MDXProvider, useContext: useMDXComponents } = createContext(
|
|
1293
|
+
'ryunix.mdx',
|
|
1294
|
+
{},
|
|
1295
|
+
);
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* Get merged MDX components from context and provided components
|
|
1299
|
+
* @param {Object} components - Additional components to merge
|
|
1300
|
+
* @returns {Object} Merged components object
|
|
1301
|
+
*/
|
|
1302
|
+
const getMDXComponents = (components) => {
|
|
1303
|
+
const contextComponents = useMDXComponents();
|
|
1304
|
+
return {
|
|
1305
|
+
...contextComponents,
|
|
1306
|
+
...components,
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
/**
|
|
1311
|
+
* Default MDX components with Ryunix-optimized rendering
|
|
1312
|
+
*/
|
|
1313
|
+
const defaultComponents = {
|
|
1314
|
+
// Headings
|
|
1315
|
+
h1: (props) => createElement('h1', { ...props }),
|
|
1316
|
+
h2: (props) => createElement('h2', { ...props }),
|
|
1317
|
+
h3: (props) => createElement('h3', { ...props }),
|
|
1318
|
+
h4: (props) => createElement('h4', { ...props }),
|
|
1319
|
+
h5: (props) => createElement('h5', { ...props }),
|
|
1320
|
+
h6: (props) => createElement('h6', { ...props }),
|
|
1321
|
+
|
|
1322
|
+
// Text
|
|
1323
|
+
p: (props) => createElement('p', { ...props }),
|
|
1324
|
+
a: (props) => createElement('a', { ...props }),
|
|
1325
|
+
strong: (props) => createElement('strong', { ...props }),
|
|
1326
|
+
em: (props) => createElement('em', { ...props }),
|
|
1327
|
+
code: (props) => createElement('code', { ...props }),
|
|
1328
|
+
|
|
1329
|
+
// Lists
|
|
1330
|
+
ul: (props) => createElement('ul', { ...props }),
|
|
1331
|
+
ol: (props) => createElement('ol', { ...props }),
|
|
1332
|
+
li: (props) => createElement('li', { ...props }),
|
|
1333
|
+
|
|
1334
|
+
// Blocks
|
|
1335
|
+
blockquote: (props) => createElement('blockquote', { ...props }),
|
|
1336
|
+
pre: (props) => createElement('pre', { ...props }),
|
|
1337
|
+
hr: (props) => createElement('hr', { ...props }),
|
|
1338
|
+
|
|
1339
|
+
// Tables
|
|
1340
|
+
table: (props) => createElement('table', { ...props }),
|
|
1341
|
+
thead: (props) => createElement('thead', { ...props }),
|
|
1342
|
+
tbody: (props) => createElement('tbody', { ...props }),
|
|
1343
|
+
tr: (props) => createElement('tr', { ...props }),
|
|
1344
|
+
th: (props) => createElement('th', { ...props }),
|
|
1345
|
+
td: (props) => createElement('td', { ...props }),
|
|
1346
|
+
|
|
1347
|
+
// Media
|
|
1348
|
+
img: (props) => createElement('img', { ...props }),
|
|
1349
|
+
};
|
|
1350
|
+
|
|
1351
|
+
/**
|
|
1352
|
+
* MDX Wrapper component
|
|
1353
|
+
* Provides default styling and components for MDX content
|
|
1354
|
+
*/
|
|
1355
|
+
const MDXContent = ({ children, components = {} }) => {
|
|
1356
|
+
const mergedComponents = getMDXComponents(components);
|
|
1357
|
+
|
|
1358
|
+
return createElement(
|
|
1359
|
+
MDXProvider,
|
|
1360
|
+
{ value: mergedComponents },
|
|
1361
|
+
createElement('div', null, children),
|
|
1362
|
+
)
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* Performance profiler for Ryunix
|
|
1367
|
+
*/
|
|
1368
|
+
class Profiler {
|
|
1369
|
+
constructor() {
|
|
1370
|
+
this.enabled = process.env.NODE_ENV !== 'production';
|
|
1371
|
+
this.measures = new Map();
|
|
1372
|
+
this.renderTimes = [];
|
|
1373
|
+
this.maxSamples = 100;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
startMeasure(name) {
|
|
1377
|
+
if (!this.enabled) return
|
|
1378
|
+
this.measures.set(name, performance.now());
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
endMeasure(name) {
|
|
1382
|
+
if (!this.enabled) return
|
|
1383
|
+
const start = this.measures.get(name);
|
|
1384
|
+
if (!start) return
|
|
1385
|
+
|
|
1386
|
+
const duration = performance.now() - start;
|
|
1387
|
+
this.measures.delete(name);
|
|
1388
|
+
|
|
1389
|
+
return duration
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
recordRender(componentName, duration) {
|
|
1393
|
+
if (!this.enabled) return
|
|
1394
|
+
|
|
1395
|
+
this.renderTimes.push({
|
|
1396
|
+
component: componentName,
|
|
1397
|
+
duration,
|
|
1398
|
+
timestamp: Date.now(),
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1401
|
+
if (this.renderTimes.length > this.maxSamples) {
|
|
1402
|
+
this.renderTimes.shift();
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
getStats() {
|
|
1407
|
+
if (!this.enabled) return null
|
|
1408
|
+
|
|
1409
|
+
const total = this.renderTimes.reduce((sum, r) => sum + r.duration, 0);
|
|
1410
|
+
const avg = total / this.renderTimes.length;
|
|
1411
|
+
const max = Math.max(...this.renderTimes.map((r) => r.duration));
|
|
1412
|
+
const min = Math.min(...this.renderTimes.map((r) => r.duration));
|
|
1413
|
+
|
|
1414
|
+
return { total, avg, max, min, count: this.renderTimes.length }
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
getSlowestComponents(limit = 10) {
|
|
1418
|
+
if (!this.enabled) return []
|
|
1419
|
+
|
|
1420
|
+
const byComponent = new Map();
|
|
1421
|
+
|
|
1422
|
+
this.renderTimes.forEach(({ component, duration }) => {
|
|
1423
|
+
if (!byComponent.has(component)) {
|
|
1424
|
+
byComponent.set(component, { total: 0, count: 0, max: 0 });
|
|
1425
|
+
}
|
|
1426
|
+
const stats = byComponent.get(component);
|
|
1427
|
+
stats.total += duration;
|
|
1428
|
+
stats.count++;
|
|
1429
|
+
stats.max = Math.max(stats.max, duration);
|
|
1430
|
+
});
|
|
1431
|
+
|
|
1432
|
+
return Array.from(byComponent.entries())
|
|
1433
|
+
.map(([name, stats]) => ({
|
|
1434
|
+
name,
|
|
1435
|
+
avg: stats.total / stats.count,
|
|
1436
|
+
max: stats.max,
|
|
1437
|
+
count: stats.count,
|
|
1438
|
+
}))
|
|
1439
|
+
.sort((a, b) => b.avg - a.avg)
|
|
1440
|
+
.slice(0, limit)
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
logStats() {
|
|
1444
|
+
if (!this.enabled) return
|
|
1445
|
+
|
|
1446
|
+
const stats = this.getStats();
|
|
1447
|
+
if (!stats) return
|
|
1448
|
+
|
|
1449
|
+
console.group('🔍 Ryunix Performance Stats');
|
|
1450
|
+
console.log(`Total renders: ${stats.count}`);
|
|
1451
|
+
console.log(`Avg render time: ${stats.avg.toFixed(2)}ms`);
|
|
1452
|
+
console.log(
|
|
1453
|
+
`Min: ${stats.min.toFixed(2)}ms | Max: ${stats.max.toFixed(2)}ms`,
|
|
1454
|
+
);
|
|
1455
|
+
|
|
1456
|
+
const slowest = this.getSlowestComponents(5);
|
|
1457
|
+
if (slowest.length > 0) {
|
|
1458
|
+
console.log('\n⚠️ Slowest components:');
|
|
1459
|
+
slowest.forEach((comp, i) => {
|
|
1460
|
+
console.log(
|
|
1461
|
+
`${i + 1}. ${comp.name}: ${comp.avg.toFixed(2)}ms avg (${comp.count} renders)`,
|
|
1462
|
+
);
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
console.groupEnd();
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
clear() {
|
|
1469
|
+
this.renderTimes = [];
|
|
1470
|
+
this.measures.clear();
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
enable() {
|
|
1474
|
+
this.enabled = true;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
disable() {
|
|
1478
|
+
this.enabled = false;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// Global profiler instance
|
|
1483
|
+
const profiler = new Profiler();
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* Hook to profile component render
|
|
1487
|
+
*/
|
|
1488
|
+
const useProfiler = (componentName) => {
|
|
1489
|
+
const startTime = performance.now();
|
|
1490
|
+
|
|
1491
|
+
return () => {
|
|
1492
|
+
const duration = performance.now() - startTime;
|
|
1493
|
+
profiler.recordRender(componentName, duration);
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* HOC to profile component
|
|
1499
|
+
*/
|
|
1500
|
+
const withProfiler = (Component, name) => {
|
|
1501
|
+
return (props) => {
|
|
1502
|
+
profiler.startMeasure(name);
|
|
1503
|
+
const result = Component(props);
|
|
1504
|
+
const duration = profiler.endMeasure(name);
|
|
1505
|
+
if (duration) profiler.recordRender(name, duration);
|
|
1506
|
+
return result
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
|
|
1510
|
+
const workLoop = (deadline) => {
|
|
1511
|
+
const state = getState();
|
|
1512
|
+
let shouldYield = false;
|
|
1513
|
+
|
|
1514
|
+
while (state.nextUnitOfWork && !shouldYield) {
|
|
1515
|
+
state.nextUnitOfWork = performUnitOfWork(state.nextUnitOfWork);
|
|
1516
|
+
shouldYield = deadline.timeRemaining() < 1;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
if (!state.nextUnitOfWork && state.wipRoot) {
|
|
1520
|
+
commitRoot();
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
requestIdleCallback(workLoop);
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1526
|
+
requestIdleCallback(workLoop);
|
|
1527
|
+
|
|
1528
|
+
const performUnitOfWork = (fiber) => {
|
|
1529
|
+
const componentName = fiber.type?.name || fiber.type?.displayName || 'Unknown';
|
|
1530
|
+
|
|
1531
|
+
profiler.startMeasure(componentName);
|
|
1532
|
+
|
|
1533
|
+
const isFunctionComponent = fiber.type instanceof Function;
|
|
1534
|
+
if (isFunctionComponent) {
|
|
1535
|
+
updateFunctionComponent(fiber);
|
|
1536
|
+
} else {
|
|
1537
|
+
updateHostComponent(fiber);
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
const duration = profiler.endMeasure(componentName);
|
|
1541
|
+
if (duration) profiler.recordRender(componentName, duration);
|
|
1542
|
+
|
|
1543
|
+
if (fiber.child) {
|
|
1544
|
+
return fiber.child
|
|
1545
|
+
}
|
|
1546
|
+
let nextFiber = fiber;
|
|
1547
|
+
while (nextFiber) {
|
|
1548
|
+
if (nextFiber.sibling) {
|
|
1549
|
+
return nextFiber.sibling
|
|
1550
|
+
}
|
|
1551
|
+
nextFiber = nextFiber.parent;
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
const scheduleWork = (root, priority = Priority.NORMAL) => {
|
|
1556
|
+
const state = getState();
|
|
1557
|
+
state.nextUnitOfWork = root;
|
|
1558
|
+
state.wipRoot = root;
|
|
1559
|
+
state.deletions = [];
|
|
1560
|
+
state.hookIndex = 0;
|
|
1561
|
+
state.effects = [];
|
|
1562
|
+
|
|
1563
|
+
// Higher priority = faster scheduling
|
|
1564
|
+
if (priority <= Priority.USER_BLOCKING) {
|
|
1565
|
+
requestIdleCallback(workLoop);
|
|
1566
|
+
} else {
|
|
1567
|
+
setTimeout(() => requestIdleCallback(workLoop), 0);
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* The `render` function in JavaScript updates the DOM with a new element and schedules work to be done
|
|
1573
|
+
* on the element.
|
|
1574
|
+
* @param element - The `element` parameter in the `render` function is the element that you want to
|
|
1575
|
+
* render in the specified container. It could be a DOM element, a component, or any other valid
|
|
1576
|
+
* element that you want to display on the screen.
|
|
1577
|
+
* @param container - The `container` parameter in the `render` function is the DOM element where the
|
|
1578
|
+
* `element` will be rendered. It is the target container where the element will be appended as a
|
|
1579
|
+
* child.
|
|
1580
|
+
* @returns The `render` function is returning the `state.wipRoot` object.
|
|
1581
|
+
*/
|
|
1582
|
+
const render = (element, container) => {
|
|
1583
|
+
const state = getState();
|
|
1584
|
+
state.wipRoot = {
|
|
1585
|
+
dom: container,
|
|
1586
|
+
props: {
|
|
1587
|
+
children: [element],
|
|
1588
|
+
},
|
|
1589
|
+
alternate: state.currentRoot,
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
state.nextUnitOfWork = state.wipRoot;
|
|
1593
|
+
state.deletions = [];
|
|
1594
|
+
scheduleWork(state.wipRoot);
|
|
1595
|
+
return state.wipRoot
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
/**
|
|
1599
|
+
* The `init` function initializes a rendering process for a main element within a specified container
|
|
1600
|
+
* root element.
|
|
1601
|
+
* @param MainElement - MainElement is the main component or element that you want to render on the
|
|
1602
|
+
* webpage. It could be a React component, a DOM element, or any other element that you want to display
|
|
1603
|
+
* on the page.
|
|
1604
|
+
* @param [root=__ryunix] - The `root` parameter in the `init` function is a default parameter with the
|
|
1605
|
+
* value `'__ryunix'`. If no value is provided for `root` when calling the `init` function, it will
|
|
1606
|
+
* default to `'__ryunix'`.
|
|
1607
|
+
* @returns The `renderProcess` function is being returned from the `init` function.
|
|
1608
|
+
*/
|
|
1609
|
+
const init = (MainElement, root = '__ryunix') => {
|
|
1610
|
+
const state = getState();
|
|
1611
|
+
state.containerRoot = document.getElementById(root);
|
|
1612
|
+
const renderProcess = render(MainElement, state.containerRoot);
|
|
1613
|
+
return renderProcess
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
const safeRender = (component, props, onError) => {
|
|
1617
|
+
try {
|
|
1618
|
+
return component(props)
|
|
1619
|
+
} catch (error) {
|
|
1620
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1621
|
+
console.error('Component error:', error);
|
|
1622
|
+
}
|
|
1623
|
+
if (onError) onError(error);
|
|
1624
|
+
return null
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1364
1628
|
/**
|
|
1365
1629
|
* memo - Memoize component to prevent unnecessary re-renders
|
|
1366
1630
|
*/
|
|
@@ -1431,7 +1695,11 @@ let isBatching = false;
|
|
|
1431
1695
|
let pendingUpdates = [];
|
|
1432
1696
|
|
|
1433
1697
|
/**
|
|
1434
|
-
*
|
|
1698
|
+
* The `batchUpdates` function in JavaScript allows for batching multiple updates and flushing them all
|
|
1699
|
+
* at once.
|
|
1700
|
+
* @param callback - The `callback` parameter in the `batchUpdates` function is a function that will be
|
|
1701
|
+
* executed within a batch update. This function can contain multiple updates that need to be processed
|
|
1702
|
+
* together in a batch to improve performance and avoid unnecessary re-renders.
|
|
1435
1703
|
*/
|
|
1436
1704
|
const batchUpdates = (callback) => {
|
|
1437
1705
|
const wasBatching = isBatching;
|
|
@@ -1449,7 +1717,9 @@ const batchUpdates = (callback) => {
|
|
|
1449
1717
|
};
|
|
1450
1718
|
|
|
1451
1719
|
/**
|
|
1452
|
-
*
|
|
1720
|
+
* The `flushUpdates` function processes and executes pending updates stored in an array.
|
|
1721
|
+
* @returns If the `pendingUpdates` array is empty, the `flushUpdates` function will return nothing
|
|
1722
|
+
* (undefined).
|
|
1453
1723
|
*/
|
|
1454
1724
|
const flushUpdates = () => {
|
|
1455
1725
|
if (pendingUpdates.length === 0) return
|
|
@@ -1498,5 +1768,5 @@ var Ryunix = /*#__PURE__*/Object.freeze({
|
|
|
1498
1768
|
|
|
1499
1769
|
window.Ryunix = Ryunix;
|
|
1500
1770
|
|
|
1501
|
-
export { Children, Fragment, hooks as Hooks, Image, NavLink, Priority, RouterProvider, Suspense, batchUpdates, createContext, createElement, Ryunix as default, init, lazy, memo, profiler, render, safeRender, useCallback, useDeferredValue, useEffect, useHash, useMemo, useMetadata, useProfiler, useQuery, useReducer, useRef, useRouter, useStore, useStorePriority, useTransition, withProfiler };
|
|
1771
|
+
export { Children, Fragment, hooks as Hooks, Image, MDXContent, MDXProvider, NavLink, Priority, RouterProvider, Suspense, batchUpdates, createContext, createElement, Ryunix as default, defaultComponents, getMDXComponents, init, lazy, memo, profiler, render, safeRender, useCallback, useDeferredValue, useEffect, useHash, useMDXComponents, useMemo, useMetadata, useProfiler, useQuery, useReducer, useRef, useRouter, useStore, useStorePriority, useTransition, withProfiler };
|
|
1502
1772
|
//# sourceMappingURL=Ryunix.esm.js.map
|