@simpreact/simpreact 0.0.5 → 0.0.6

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.
Files changed (78) hide show
  1. package/LICENSE.txt +1 -1
  2. package/compat/context.d.ts +4 -4
  3. package/compat/context.js +3 -2
  4. package/compat/core.d.ts +4 -0
  5. package/compat/core.js +9 -5
  6. package/compat/dom.d.ts +4 -5
  7. package/compat/dom.js +3 -2
  8. package/compat/hooks.d.ts +16 -13
  9. package/compat/hooks.js +19 -15
  10. package/compat/index.d.ts +10 -9
  11. package/compat/renderRuntime.d.ts +2 -0
  12. package/compat/renderRuntime.js +14 -0
  13. package/component/index.d.ts +16 -0
  14. package/component/index.js +164 -0
  15. package/context/index.d.ts +12 -5
  16. package/context/index.js +62 -57
  17. package/core/createElement.d.ts +29 -20
  18. package/core/createElement.js +159 -133
  19. package/core/hostAdapter.d.ts +8 -12
  20. package/core/hostAdapter.js +1 -4
  21. package/core/hostOperations.d.ts +5 -0
  22. package/core/hostOperations.js +15 -0
  23. package/core/index.d.ts +29 -6
  24. package/core/internal.d.ts +3 -0
  25. package/core/internal.js +3 -0
  26. package/core/lifecycleEventBus.d.ts +15 -6
  27. package/core/lifecycleEventBus.js +16 -2
  28. package/core/memo.d.ts +0 -2
  29. package/core/memo.js +1 -3
  30. package/core/mounting.d.ts +7 -9
  31. package/core/mounting.js +221 -79
  32. package/core/patching.d.ts +7 -8
  33. package/core/patching.js +235 -252
  34. package/core/patchingChildren.d.ts +6 -0
  35. package/core/patchingChildren.js +330 -0
  36. package/core/portal.d.ts +1 -1
  37. package/core/portal.js +17 -7
  38. package/core/processStack.d.ts +69 -0
  39. package/core/processStack.js +63 -0
  40. package/core/ref.d.ts +4 -3
  41. package/core/rerender.d.ts +4 -14
  42. package/core/rerender.js +67 -112
  43. package/core/runtime.d.ts +17 -0
  44. package/core/runtime.js +2 -0
  45. package/core/unmounting.d.ts +11 -6
  46. package/core/unmounting.js +81 -40
  47. package/core/utils.d.ts +10 -0
  48. package/core/utils.js +143 -0
  49. package/dom/attach-element-to-dom.d.ts +4 -3
  50. package/dom/attach-element-to-dom.js +12 -7
  51. package/dom/domAdapter.js +22 -25
  52. package/dom/events.d.ts +5 -5
  53. package/dom/events.js +33 -16
  54. package/dom/index.d.ts +16 -5
  55. package/dom/index.js +4 -3
  56. package/dom/props/controlled/index.d.ts +3 -3
  57. package/dom/props/controlled/index.js +8 -8
  58. package/dom/props/controlled/input.d.ts +3 -3
  59. package/dom/props/controlled/input.js +57 -34
  60. package/dom/props/controlled/select.d.ts +3 -3
  61. package/dom/props/controlled/select.js +39 -26
  62. package/dom/props/controlled/textarea.d.ts +3 -3
  63. package/dom/props/controlled/textarea.js +57 -34
  64. package/dom/props/dangerInnerHTML.d.ts +2 -2
  65. package/dom/props/dangerInnerHTML.js +3 -2
  66. package/dom/props/props.d.ts +4 -4
  67. package/dom/props/props.js +24 -21
  68. package/dom/render.d.ts +4 -5
  69. package/dom/render.js +38 -34
  70. package/hooks/index.d.ts +15 -13
  71. package/hooks/index.js +153 -157
  72. package/jsx-runtime/index.d.ts +2 -1
  73. package/package.json +9 -1
  74. package/shared/index.d.ts +10 -0
  75. package/shared/index.js +4 -7
  76. package/shared/utils.js +4 -4
  77. package/shared/EventBus.d.ts +0 -18
  78. package/shared/EventBus.js +0 -28
@@ -1,36 +1,39 @@
1
1
  import { emptyObject } from '../../shared/index.js';
2
+ import { isPropNameEventName, patchEvent } from '../events.js';
2
3
  import { defaultNamespace } from '../namespace.js';
3
4
  import { addControlledFormElementEventHandlers, isEventNameIgnored, isFormElementControlled, removeControlledFormElementEventHandlers, syncControlledFormElementPropsWithAttrs, } from './controlled/index.js';
4
- import { isPropNameEventName, patchEvent } from '../events.js';
5
- import { patchStyle } from './style.js';
6
5
  import { patchDangerInnerHTML } from './dangerInnerHTML.js';
7
- export function mountProps(dom, element, namespace) {
6
+ import { patchStyle } from './style.js';
7
+ export function mountProps(dom, element, namespace, renderRuntime) {
8
8
  if (!isFormElement(element)) {
9
9
  for (const propName in element.props) {
10
- patchDefaultElementPropAndAttrs(propName, dom, null, element, null, element.props[propName], namespace);
10
+ patchDefaultElementPropAndAttrs(propName, dom, null, element, null, element.props[propName], namespace, renderRuntime);
11
11
  }
12
12
  return;
13
13
  }
14
14
  const isControlled = isFormElementControlled(element.props);
15
15
  for (const propName in element.props) {
16
- patchFormElementsPropAndAttrs(propName, dom, element, isControlled, null, element.props[propName]);
16
+ patchFormElementsPropAndAttrs(propName, dom, element, isControlled, null, element.props[propName], renderRuntime);
17
17
  }
18
18
  if (isControlled) {
19
- addControlledFormElementEventHandlers(element);
19
+ addControlledFormElementEventHandlers(element, renderRuntime);
20
20
  syncControlledFormElementPropsWithAttrs(element, element.props, true);
21
21
  }
22
22
  }
23
- export function unmountProps(dom, element) {
23
+ export function unmountProps(dom, element, renderRuntime) {
24
24
  if (!element.props) {
25
25
  return;
26
26
  }
27
+ if (isFormElement(element) && isFormElementControlled(element.props)) {
28
+ removeControlledFormElementEventHandlers(element, renderRuntime);
29
+ }
27
30
  for (const propName in element.props) {
28
31
  if (isPropNameEventName(propName)) {
29
- patchEvent(propName, element.props[propName], null, dom);
32
+ patchEvent(propName, element.props[propName], null, dom, renderRuntime);
30
33
  }
31
34
  }
32
35
  }
33
- export function patchProps(dom, prevElement, nextElement, namespace) {
36
+ export function patchProps(dom, prevElement, nextElement, namespace, renderRuntime) {
34
37
  const prevProps = prevElement.props || emptyObject;
35
38
  const nextProps = nextElement.props || emptyObject;
36
39
  if (!isFormElement(nextElement)) {
@@ -38,12 +41,12 @@ export function patchProps(dom, prevElement, nextElement, namespace) {
38
41
  const prevValue = prevProps[propName];
39
42
  const nextValue = nextProps[propName];
40
43
  if (prevValue !== nextValue) {
41
- patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevValue, nextValue, namespace);
44
+ patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevValue, nextValue, namespace, renderRuntime);
42
45
  }
43
46
  }
44
47
  for (const propName in prevProps) {
45
48
  if (nextProps[propName] == null && prevProps[propName] != null) {
46
- patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevProps[propName], null, namespace);
49
+ patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevProps[propName], null, namespace, renderRuntime);
47
50
  }
48
51
  }
49
52
  return;
@@ -54,25 +57,25 @@ export function patchProps(dom, prevElement, nextElement, namespace) {
54
57
  const prevValue = prevProps[propName];
55
58
  const nextValue = nextProps[propName];
56
59
  if (prevValue !== nextValue) {
57
- patchFormElementsPropAndAttrs(propName, dom, nextElement, isNextElementControlled, prevValue, nextValue);
60
+ patchFormElementsPropAndAttrs(propName, dom, nextElement, isNextElementControlled, prevValue, nextValue, renderRuntime);
58
61
  }
59
62
  }
60
63
  for (const propName in prevProps) {
61
64
  if (nextProps[propName] == null && prevProps[propName] != null) {
62
- patchFormElementsPropAndAttrs(propName, dom, prevElement, isPrevElementControlled, prevProps[propName], null);
65
+ patchFormElementsPropAndAttrs(propName, dom, prevElement, isPrevElementControlled, prevProps[propName], null, renderRuntime);
63
66
  }
64
67
  }
65
68
  if (!isPrevElementControlled && isNextElementControlled) {
66
- addControlledFormElementEventHandlers(nextElement);
69
+ addControlledFormElementEventHandlers(nextElement, renderRuntime);
67
70
  }
68
71
  else if (isPrevElementControlled && !isNextElementControlled) {
69
- removeControlledFormElementEventHandlers(prevElement);
72
+ removeControlledFormElementEventHandlers(prevElement, renderRuntime);
70
73
  }
71
74
  if (isNextElementControlled) {
72
75
  syncControlledFormElementPropsWithAttrs(nextElement, nextProps);
73
76
  }
74
77
  }
75
- function patchFormElementsPropAndAttrs(propName, dom, element, isControlled, prevValue, nextValue) {
78
+ function patchFormElementsPropAndAttrs(propName, dom, element, isControlled, prevValue, nextValue, renderRuntime) {
76
79
  switch (propName) {
77
80
  case 'children':
78
81
  case 'className':
@@ -109,17 +112,17 @@ function patchFormElementsPropAndAttrs(propName, dom, element, isControlled, pre
109
112
  default:
110
113
  if (isPropNameEventName(propName)) {
111
114
  if (isControlled && isEventNameIgnored(element, propName)) {
112
- patchEvent(propName, prevValue, null, dom);
115
+ patchEvent(propName, prevValue, null, dom, renderRuntime);
113
116
  break;
114
117
  }
115
- patchEvent(propName, prevValue, nextValue, dom);
118
+ patchEvent(propName, prevValue, nextValue, dom, renderRuntime);
116
119
  }
117
120
  else {
118
121
  patchDomAttr(dom, nextValue, propName);
119
122
  }
120
123
  }
121
124
  }
122
- function patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevValue, nextValue, namespace) {
125
+ function patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement, prevValue, nextValue, namespace, renderRuntime) {
123
126
  switch (propName) {
124
127
  case 'children':
125
128
  case 'className':
@@ -150,11 +153,11 @@ function patchDefaultElementPropAndAttrs(propName, dom, prevElement, nextElement
150
153
  patchStyle(prevValue, nextValue, dom);
151
154
  break;
152
155
  case 'dangerouslySetInnerHTML':
153
- patchDangerInnerHTML(prevValue, nextValue, prevElement, nextElement, dom);
156
+ patchDangerInnerHTML(prevValue, nextValue, prevElement, nextElement, dom, renderRuntime);
154
157
  break;
155
158
  default:
156
159
  if (isPropNameEventName(propName)) {
157
- patchEvent(propName, prevValue, nextValue, dom);
160
+ patchEvent(propName, prevValue, nextValue, dom, renderRuntime);
158
161
  }
159
162
  else {
160
163
  patchDomAttr(dom, nextValue, propName, namespace);
package/dom/render.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { type SimpElement } from '../core/internal.js';
1
+ import { type SimpElement, type SimpRenderRuntime } from '../core/internal.js';
2
2
  import type { Nullable } from '../shared/index.js';
3
- export declare function render(element: Nullable<SimpElement>, container: Nullable<Element | DocumentFragment>): void;
4
- interface SimpRoot {
3
+ export declare function createRenderer(renderRuntime: SimpRenderRuntime): (element: Nullable<SimpElement>, container: Nullable<Element | DocumentFragment>) => void;
4
+ export interface SimpRoot {
5
5
  render(element: SimpElement): void;
6
6
  unmount(): void;
7
7
  }
8
- export declare function createRoot(container: Element | DocumentFragment): SimpRoot;
9
- export {};
8
+ export declare function createCreateRoot(renderRuntime: SimpRenderRuntime): (container: Element | DocumentFragment) => SimpRoot;
package/dom/render.js CHANGED
@@ -1,41 +1,45 @@
1
- import { renderingRerenderLocker, hostAdapter, mount, patch, provideHostAdapter, remove, } from '../core/internal.js';
2
- import { domAdapter } from './domAdapter.js';
3
- import { attachElementToDom, getElementFromDom } from './attach-element-to-dom.js';
4
- provideHostAdapter(domAdapter);
5
- export function render(element, container) {
6
- if (!container) {
7
- return;
8
- }
9
- const currentRootElement = getElementFromDom(container);
10
- renderingRerenderLocker.lock();
11
- if (!currentRootElement) {
12
- if (element) {
13
- hostAdapter.clearNode(container);
14
- attachElementToDom((element.parent = { flag: 'HOST', reference: container, children: element, parent: null }), container);
15
- mount(element, container, null, null, hostAdapter.getHostNamespaces(element, undefined)?.self);
1
+ import { createElement, mount, patch, unmount } from '../core/internal.js';
2
+ export function createRenderer(renderRuntime) {
3
+ return (element, container) => {
4
+ if (!container) {
5
+ return;
16
6
  }
17
- }
18
- else {
19
- if (!element) {
20
- remove(currentRootElement.children, container);
21
- currentRootElement.children = null;
7
+ const currentRootElement = renderRuntime.hostAdapter.getElementFromReference(container, renderRuntime);
8
+ if (!currentRootElement) {
9
+ if (element) {
10
+ renderRuntime.hostAdapter.clearNode(container);
11
+ element.parent = createElement('', null, element);
12
+ element.parent.type = null;
13
+ element.parent.reference = container;
14
+ renderRuntime.hostAdapter.attachElementToReference(element.parent, container, renderRuntime);
15
+ mount(element, container, null, null, renderRuntime.hostAdapter.getHostNamespaces(element, undefined)?.self, renderRuntime);
16
+ }
22
17
  }
23
18
  else {
24
- const prevChildren = currentRootElement.children;
25
- currentRootElement.children = element;
26
- element.parent = currentRootElement;
27
- patch(prevChildren, element, container, null, null, hostAdapter.getHostNamespaces(element, undefined)?.self);
19
+ if (!element) {
20
+ unmount(currentRootElement.children, renderRuntime);
21
+ renderRuntime.hostAdapter.detachElementFromReference(container, renderRuntime);
22
+ renderRuntime.hostAdapter.clearNode(container);
23
+ }
24
+ else {
25
+ const prevChildren = currentRootElement.children;
26
+ currentRootElement.children = element;
27
+ element.parent = currentRootElement;
28
+ patch(prevChildren, element, container, null, null, renderRuntime.hostAdapter.getHostNamespaces(element, undefined)?.self, renderRuntime);
29
+ }
28
30
  }
29
- }
30
- renderingRerenderLocker.flush();
31
+ };
31
32
  }
32
- export function createRoot(container) {
33
- return {
34
- render(element) {
35
- render(element, container);
36
- },
37
- unmount() {
38
- render(null, container);
39
- },
33
+ export function createCreateRoot(renderRuntime) {
34
+ const render = createRenderer(renderRuntime);
35
+ return (container) => {
36
+ return {
37
+ render(element) {
38
+ render(element, container);
39
+ },
40
+ unmount() {
41
+ render(null, container);
42
+ },
43
+ };
40
44
  };
41
45
  }
package/hooks/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RefObject } from '../core/index.js';
1
+ import type { RefObject, SimpRenderRuntime } from '../core/index.js';
2
2
 
3
3
  export type Cleanup = () => void;
4
4
  export type Effect = () => void | Cleanup;
@@ -7,21 +7,23 @@ export type DependencyList = readonly unknown[];
7
7
  export type Dispatch<A> = (value: A) => void;
8
8
  export type SetStateAction<S> = S | ((prevState: S) => S);
9
9
 
10
- declare function useRef<T>(initialValue: T): RefObject<T>;
11
- declare function useRef<T>(initialValue: T | null): RefObject<T | null>;
12
- declare function useRef<T>(initialValue: T | undefined): RefObject<T | undefined>;
10
+ export interface UseRef {
11
+ <T>(initialValue: T): RefObject<T>;
12
+ <T>(initialValue: T | null): RefObject<T | null>;
13
+ <T = undefined>(initialValue?: T): RefObject<T | undefined>;
14
+ }
15
+ declare function createUseRef(renderRuntime: SimpRenderRuntime): UseRef;
13
16
 
14
- declare function useRerender(): () => void;
17
+ declare function createUseRerender(renderRuntime: SimpRenderRuntime): () => void;
15
18
 
16
- export function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
17
- export function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
19
+ export interface UseState {
20
+ <S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
21
+ <S>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
22
+ }
23
+ declare function createUseState(renderRuntime: SimpRenderRuntime): useState;
18
24
 
19
- declare function useEffect(effect: Effect, deps?: DependencyList): void;
25
+ declare function createUseEffect(renderRuntime: SimpRenderRuntime): (effect: Effect, deps?: DependencyList) => void;
20
26
 
21
- declare function useMounted(effect: Effect): void;
22
-
23
- declare function useUnmounted(cleanup: Cleanup): void;
24
-
25
- declare function useCatch(cb: (error: any) => void): void;
27
+ declare function createUseCatch(renderRuntime: SimpRenderRuntime): (cb: (error: any) => void) => void;
26
28
 
27
29
  declare function areDepsEqual(nextDeps: DependencyList | undefined, prevDeps: DependencyList | undefined): boolean;
package/hooks/index.js CHANGED
@@ -1,194 +1,190 @@
1
- import { lifecycleEventBus, rerender as _rerender } from '../core/internal.js';
2
- import { callOrGet, noop } from '../shared/index.js';
3
- let currentIndex = 0;
4
- // In runtime this is a nullable variable.
5
- let currentElement;
1
+ import { rerender as _rerender, lifecycleEventBus, SIMP_ELEMENT_FLAG_FC, } from '../core/internal.js';
2
+ import { callOrGet, shallowEqual, } from '../shared/index.js';
3
+ const hooksSpecificStoreByElementStore = new WeakMap();
4
+ function getHooksSpecificStore(store) {
5
+ let hooksSpecificStore = hooksSpecificStoreByElementStore.get(store);
6
+ if (!hooksSpecificStore) {
7
+ hooksSpecificStore = { hooksIndex: 0, hookStates: null, effectsHookStates: null, catchHandlers: null };
8
+ hooksSpecificStoreByElementStore.set(store, hooksSpecificStore);
9
+ }
10
+ return hooksSpecificStore;
11
+ }
6
12
  lifecycleEventBus.subscribe(event => {
7
- if (event.type === 'beforeRender') {
8
- currentElement = event.element;
9
- if (currentElement.store?.catchHandlers) {
10
- currentElement.store.catchHandlers = undefined;
13
+ if ((event.element.flag & SIMP_ELEMENT_FLAG_FC) === 0) {
14
+ return;
15
+ }
16
+ let store = getHooksSpecificStore(event.element.store);
17
+ switch (event.type) {
18
+ case 'beforeRender': {
19
+ store.hooksIndex = 0;
20
+ store.catchHandlers = null;
21
+ store.effectsHookStates = null;
22
+ break;
11
23
  }
12
- if (currentElement.store?.effectsHookStates) {
13
- currentElement.store.effectsHookStates = undefined;
24
+ case 'afterRender': {
25
+ store.hooksIndex = 0;
26
+ break;
14
27
  }
15
- }
16
- if (event.type === 'afterRender' || event.type === 'errored') {
17
- currentElement = null;
18
- currentIndex = 0;
19
- }
20
- if (event.type === 'mounted') {
21
- const element = event.element;
22
- if (element.store?.effectsHookStates) {
23
- const effects = element.store.effectsHookStates;
24
- element.store.effectsHookStates = undefined;
28
+ case 'mounted': {
29
+ if (!store.effectsHookStates) {
30
+ break;
31
+ }
32
+ const effects = store.effectsHookStates;
33
+ store.effectsHookStates = null;
25
34
  for (const state of effects) {
26
- state.cleanup = state.effect() || undefined;
35
+ state.cleanup = state.effect() || null;
27
36
  }
37
+ break;
28
38
  }
29
- }
30
- if (event.type === 'updated') {
31
- const element = event.element;
32
- if (element.store?.effectsHookStates) {
33
- const effects = element.store.effectsHookStates;
34
- element.store.effectsHookStates = undefined;
39
+ case 'updated': {
40
+ if (!store.effectsHookStates) {
41
+ break;
42
+ }
43
+ const effects = store.effectsHookStates;
44
+ store.effectsHookStates = null;
35
45
  for (const state of effects) {
36
46
  if (typeof state.cleanup === 'function') {
37
47
  state.cleanup();
38
48
  }
39
- state.cleanup = state.effect() || undefined;
49
+ state.cleanup = state.effect() || null;
40
50
  }
51
+ break;
41
52
  }
42
- }
43
- if (event.type === 'unmounted') {
44
- const element = event.element;
45
- if (element.store?.hookStates) {
46
- const hookStates = element.store.hookStates;
47
- element.store.hookStates = undefined;
53
+ case 'unmounted': {
54
+ if (!store.hookStates) {
55
+ break;
56
+ }
57
+ const hookStates = store.hookStates;
58
+ store.hookStates = null;
48
59
  for (const state of hookStates) {
49
60
  if (state && 'cleanup' in state && typeof state.cleanup === 'function') {
50
61
  state.cleanup();
51
62
  }
52
63
  }
64
+ break;
53
65
  }
54
- }
55
- if (event.type === 'errored') {
56
- function handleError(element, error) {
57
- element = findElementWithCatchHandlers(element);
58
- if (!element) {
59
- throw new Error('Error occurred during rendering a component', { cause: error });
66
+ case 'errored': {
67
+ store.hooksIndex = 0;
68
+ if (event.handled) {
69
+ break;
60
70
  }
61
- try {
62
- for (const state of element.store.catchHandlers) {
63
- state(error);
71
+ let element = event.element;
72
+ let curError = event.error;
73
+ let catchers = null;
74
+ while (element) {
75
+ if ((element.flag & SIMP_ELEMENT_FLAG_FC) === 0) {
76
+ element = element.parent;
77
+ continue;
78
+ }
79
+ store = getHooksSpecificStore(element.store);
80
+ catchers = store.catchHandlers;
81
+ if (!catchers) {
82
+ element = element.parent;
83
+ continue;
84
+ }
85
+ try {
86
+ for (let i = 0; i < catchers.length; i++) {
87
+ catchers[i](curError);
88
+ }
89
+ event.handled = true;
90
+ break;
91
+ }
92
+ catch (error) {
93
+ element = element.parent;
94
+ curError = error;
64
95
  }
65
- }
66
- catch (error) {
67
- handleError(element.parent, error);
68
96
  }
69
97
  }
70
- handleError(event.element, event.error);
71
98
  }
72
99
  });
73
- function findElementWithCatchHandlers(element) {
74
- let temp = element;
75
- while (temp != null) {
76
- if (temp.store?.catchHandlers) {
77
- return temp;
100
+ export function createUseRef(renderRuntime) {
101
+ return initialValue => {
102
+ const store = getHooksSpecificStore(renderRuntime.currentRenderingFCElement.store);
103
+ const hookStates = getOrCreateHookStates(store);
104
+ if (!hookStates[store.hooksIndex]) {
105
+ hookStates[store.hooksIndex] = { current: initialValue };
78
106
  }
79
- temp = temp.parent;
80
- }
81
- return null;
107
+ return hookStates[store.hooksIndex++];
108
+ };
82
109
  }
83
- export function useRef(initialValue) {
84
- const hookStates = getOrCreateHookStates(currentElement);
85
- if (!hookStates[currentIndex]) {
86
- hookStates[currentIndex] = { current: initialValue };
87
- }
88
- return hookStates[currentIndex++];
89
- }
90
- export function useRerender() {
91
- const hookStates = getOrCreateHookStates(currentElement);
92
- if (!hookStates[currentIndex]) {
93
- const elementStore = currentElement.store;
94
- hookStates[currentIndex] = function rerender() {
95
- elementStore.forceRender = true;
96
- _rerender(elementStore.latestElement);
97
- };
98
- }
99
- return hookStates[currentIndex++];
100
- }
101
- export function useState(initialState) {
102
- const hookStates = getOrCreateHookStates(currentElement);
103
- if (!hookStates[currentIndex]) {
104
- const elementStore = currentElement.store;
105
- const state = (hookStates[currentIndex] = [undefined, undefined]);
106
- state[0] = callOrGet(initialState);
107
- state[1] = function dispatch(action) {
108
- const nextValue = callOrGet(action, state[0]);
109
- if (Object.is(state[0], nextValue)) {
110
- return;
111
- }
112
- state[0] = nextValue;
113
- elementStore.forceRender = true;
114
- _rerender(elementStore.latestElement);
115
- };
116
- }
117
- return hookStates[currentIndex++];
118
- }
119
- export function useEffect(effect, deps) {
120
- const hookStates = getOrCreateHookStates(currentElement);
121
- let state = hookStates[currentIndex];
122
- if (!state) {
123
- state = hookStates[currentIndex] = { effect };
124
- }
125
- if (!areDepsEqual(deps, state.deps)) {
126
- state.effect = effect;
127
- state.deps = deps;
128
- getOrCreateEffectHookStates(currentElement).push(state);
129
- }
130
- currentIndex++;
131
- }
132
- export function useMounted(effect) {
133
- const hookStates = getOrCreateHookStates(currentElement);
134
- if (!hookStates[currentIndex]) {
135
- hookStates[currentIndex] = { effect };
136
- getOrCreateEffectHookStates(currentElement).push(hookStates[currentIndex]);
137
- }
138
- currentIndex++;
110
+ export function createUseRerender(renderRuntime) {
111
+ return () => {
112
+ const store = getHooksSpecificStore(renderRuntime.currentRenderingFCElement.store);
113
+ const hookStates = getOrCreateHookStates(store);
114
+ if (!hookStates[store.hooksIndex]) {
115
+ const elementStore = renderRuntime.currentRenderingFCElement.store;
116
+ hookStates[store.hooksIndex] = function rerender() {
117
+ _rerender(elementStore, renderRuntime);
118
+ };
119
+ }
120
+ return hookStates[store.hooksIndex++];
121
+ };
139
122
  }
140
- export function useUnmounted(cleanup) {
141
- const hookStates = getOrCreateHookStates(currentElement);
142
- if (!hookStates[currentIndex]) {
143
- hookStates[currentIndex] = { cleanup, effect: noop };
144
- }
145
- currentIndex++;
123
+ export function createUseState(renderRuntime) {
124
+ return (initialState => {
125
+ const store = getHooksSpecificStore(renderRuntime.currentRenderingFCElement.store);
126
+ const hookStates = getOrCreateHookStates(store);
127
+ if (!hookStates[store.hooksIndex]) {
128
+ const elementStore = renderRuntime.currentRenderingFCElement.store;
129
+ const state = (hookStates[store.hooksIndex] = [undefined, undefined]);
130
+ state[0] = callOrGet(initialState);
131
+ state[1] = function dispatch(action) {
132
+ const nextValue = callOrGet(action, state[0]);
133
+ if (Object.is(state[0], nextValue)) {
134
+ return;
135
+ }
136
+ state[0] = nextValue;
137
+ _rerender(elementStore, renderRuntime);
138
+ };
139
+ }
140
+ return hookStates[store.hooksIndex++];
141
+ });
146
142
  }
147
- export function useCatch(cb) {
148
- if (!currentElement.store) {
149
- currentElement.store = {};
150
- }
151
- if (!currentElement.store.catchHandlers) {
152
- currentElement.store.catchHandlers = [];
153
- }
154
- currentElement.store.catchHandlers.push(cb);
143
+ export function createUseEffect(renderRuntime) {
144
+ return (effect, deps) => {
145
+ const store = getHooksSpecificStore(renderRuntime.currentRenderingFCElement.store);
146
+ const hookStates = getOrCreateHookStates(store);
147
+ let state = hookStates[store.hooksIndex];
148
+ if (!state) {
149
+ state = hookStates[store.hooksIndex] = {
150
+ effect,
151
+ deps: null,
152
+ cleanup: null,
153
+ };
154
+ }
155
+ if (!shallowEqual(deps, state.deps)) {
156
+ state.effect = effect;
157
+ state.deps = deps || null;
158
+ getOrCreateEffectHookStates(store).push(state);
159
+ }
160
+ store.hooksIndex++;
161
+ };
155
162
  }
156
- export function areDepsEqual(nextDeps, prevDeps) {
157
- if (nextDeps == null || prevDeps == null || nextDeps.length !== prevDeps.length) {
158
- return false;
159
- }
160
- for (let i = 0; i < prevDeps.length; i++) {
161
- if (!Object.is(nextDeps[i], prevDeps[i])) {
162
- return false;
163
+ export function createUseCatch(renderRuntime) {
164
+ return cb => {
165
+ const store = getHooksSpecificStore(renderRuntime.currentRenderingFCElement.store);
166
+ if (!store.catchHandlers) {
167
+ store.catchHandlers = [];
163
168
  }
164
- }
165
- return true;
169
+ store.catchHandlers.push(cb);
170
+ };
166
171
  }
167
- function getOrCreateHookStates(element) {
168
- if (!element.store) {
169
- element.store = {};
172
+ function getOrCreateHookStates(store) {
173
+ if (!store.hookStates) {
174
+ store.hookStates = [];
170
175
  }
171
- if (!element.store.hookStates) {
172
- element.store.hookStates = [];
173
- }
174
- return element.store.hookStates;
176
+ return store.hookStates;
175
177
  }
176
- function getOrCreateEffectHookStates(element) {
177
- if (!element.store) {
178
- element.store = {};
179
- }
180
- if (!element.store.effectsHookStates) {
181
- element.store.effectsHookStates = [];
178
+ function getOrCreateEffectHookStates(store) {
179
+ if (!store.effectsHookStates) {
180
+ store.effectsHookStates = [];
182
181
  }
183
- return element.store.effectsHookStates;
182
+ return store.effectsHookStates;
184
183
  }
185
184
  export default {
186
- useRef,
187
- useRerender,
188
- useState,
189
- useEffect,
190
- useMounted,
191
- useUnmounted,
192
- useCatch,
193
- areDepsEqual,
185
+ createUseRef,
186
+ createUseRerender,
187
+ createUseState,
188
+ createUseEffect,
189
+ createUseCatch,
194
190
  };
@@ -1,5 +1,4 @@
1
1
  import type { FC, Fragment as FragmentType, Key, SimpElement } from '../core/index.js';
2
- import type { Maybe } from '../shared/index.js';
3
2
  import type {
4
3
  AnchorHTMLAttributes,
5
4
  AreaHTMLAttributes,
@@ -55,6 +54,7 @@ import type {
55
54
  VideoHTMLAttributes,
56
55
  WebViewHTMLAttributes,
57
56
  } from '../dom/index.js';
57
+ import type { Maybe } from '../shared/index.js';
58
58
 
59
59
  declare function jsx<P = {}>(type: string | FC<P>, props?: P, key?: Maybe<Key>): SimpElement<P>;
60
60
 
@@ -64,6 +64,7 @@ export { jsx as jsxs, jsx as jsxDEV };
64
64
  export { Fragment };
65
65
 
66
66
  declare global {
67
+ // biome-ignore lint/style/noNamespace: React-like API requirement.
67
68
  namespace JSX {
68
69
  interface IntrinsicElements {
69
70
  // HTML
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simpreact/simpreact",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "",
5
5
  "homepage": "https://github.com/dPaskhin/simpreact#readme",
6
6
  "main": "./core/index.js",
@@ -17,6 +17,14 @@
17
17
  "./compat/*": {
18
18
  "import": "./compat/index.js"
19
19
  },
20
+ "./component": {
21
+ "import": "./component/index.js",
22
+ "types": "./component/index.d.ts"
23
+ },
24
+ "./context/*": {
25
+ "import": "./context/index.js",
26
+ "types": "./context/index.d.ts"
27
+ },
20
28
  "./internal": {
21
29
  "import": "./core/internal.js",
22
30
  "types": "./core/internal.d.ts"