nesquick 0.0.26 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -161,7 +161,7 @@ class NesquickComponent {
161
161
  _renderStyle(element, style) {
162
162
  switch (typeof style) {
163
163
  case "function": {
164
- (0, State_1.useRender)(style, (style, isState) => {
164
+ (0, State_1.useRender)(style, (style, lastReaction) => {
165
165
  if (this._styleSubscriptions != null) {
166
166
  this._styleSubscriptions.dispose();
167
167
  this._styleSubscriptions = null;
@@ -169,16 +169,16 @@ class NesquickComponent {
169
169
  switch (typeof style) {
170
170
  case "object": {
171
171
  if (style) {
172
- if (isState) {
172
+ if (lastReaction) {
173
+ this._renderStyles(element, style);
174
+ }
175
+ else {
173
176
  element.removeAttribute("style");
174
177
  this._styleSubscriptions = new State_1.Subscriptions();
175
178
  State_1.subscriptions.set(this._styleSubscriptions);
176
179
  this._renderStyles(element, style);
177
180
  State_1.subscriptions.reset();
178
181
  }
179
- else {
180
- this._renderStyles(element, style);
181
- }
182
182
  }
183
183
  break;
184
184
  }
package/lib/State.js CHANGED
@@ -4,6 +4,7 @@ exports.subscriptions = exports.Subscriptions = void 0;
4
4
  exports.useState = useState;
5
5
  exports.useEffect = useEffect;
6
6
  exports.useRender = useRender;
7
+ exports.useMemo = useMemo;
7
8
  exports.useDispose = useDispose;
8
9
  let currentReactor = [];
9
10
  var reactor;
@@ -87,18 +88,57 @@ function useState(value) {
87
88
  return value;
88
89
  };
89
90
  const setValue = (newValue) => {
90
- value = newValue;
91
- for (const reactor of reactors) {
92
- renderReactor(reactor, reactor.effect);
91
+ if (value !== newValue) {
92
+ value = newValue;
93
+ for (const reactor of reactors) {
94
+ renderReactor(reactor, reactor.effect);
95
+ }
93
96
  }
94
97
  };
95
98
  return [getValue, setValue];
96
99
  }
97
100
  function useEffect(cb, reaction = null) {
98
- newSubscription(cb, reaction, true);
101
+ const sub = newSubscription(cb, reaction, true);
102
+ runSubscription(sub);
99
103
  }
100
104
  function useRender(cb, reaction = null) {
101
- newSubscription(cb, reaction, false);
105
+ const sub = newSubscription(cb, reaction, false);
106
+ runSubscription(sub);
107
+ }
108
+ function useMemo(cb) {
109
+ const reactors = new Set();
110
+ let state = 0;
111
+ let value;
112
+ const sub = newSubscription(() => {
113
+ if (state === 0) {
114
+ sub.iteration--;
115
+ }
116
+ else if (state === 1) {
117
+ state = 2;
118
+ value = cb();
119
+ }
120
+ else {
121
+ sub.iteration--;
122
+ state = 0;
123
+ for (const reactor of reactors) {
124
+ renderReactor(reactor, reactor.effect);
125
+ }
126
+ }
127
+ }, null, true);
128
+ return () => {
129
+ if (state === 0) {
130
+ state = 1;
131
+ runSubscription(sub);
132
+ }
133
+ if (!sub.cancelled) {
134
+ const reactor = currentReactor[currentReactor.length - 1];
135
+ if (reactor) {
136
+ reactors.add(reactor);
137
+ reactor.states.set(reactors, reactor.iteration);
138
+ }
139
+ }
140
+ return value;
141
+ };
102
142
  }
103
143
  function useDispose(cb) {
104
144
  const container = currentSubscriptions[currentSubscriptions.length - 1];
@@ -107,8 +147,10 @@ function useDispose(cb) {
107
147
  }
108
148
  }
109
149
  function newSubscription(cb, reaction, effect) {
110
- const sub = {
150
+ return {
111
151
  cb: cb,
152
+ firstRun: true,
153
+ lastValue: null,
112
154
  reaction: reaction,
113
155
  iteration: 0,
114
156
  states: new Map(),
@@ -117,16 +159,6 @@ function newSubscription(cb, reaction, effect) {
117
159
  cancelled: false,
118
160
  pending: false
119
161
  };
120
- renderReactor(sub, true);
121
- if (sub.states.size === 0) {
122
- cancelSubscription(sub);
123
- }
124
- else {
125
- const container = currentSubscriptions[currentSubscriptions.length - 1];
126
- if (container) {
127
- container.list.push(sub);
128
- }
129
- }
130
162
  }
131
163
  function cancelSubscription(sub) {
132
164
  sub.cancelled = true;
@@ -136,6 +168,7 @@ function cancelSubscription(sub) {
136
168
  }
137
169
  function runSubscription(sub) {
138
170
  sub.pending = false;
171
+ sub.iteration++;
139
172
  reactor.set(sub);
140
173
  const res = sub.cb();
141
174
  reactor.reset();
@@ -144,5 +177,24 @@ function runSubscription(sub) {
144
177
  sub.states.delete(state);
145
178
  }
146
179
  }
147
- sub.reaction?.(res, sub.states.size > 0);
180
+ if (sub.states.size === 0) {
181
+ cancelSubscription(sub);
182
+ }
183
+ if (sub.firstRun) {
184
+ sub.firstRun = false;
185
+ if (sub.states.size > 0) {
186
+ const container = currentSubscriptions[currentSubscriptions.length - 1];
187
+ if (container) {
188
+ container.list.push(sub);
189
+ }
190
+ }
191
+ if (sub.reaction) {
192
+ sub.lastValue = res;
193
+ sub.reaction(res, sub.cancelled);
194
+ }
195
+ }
196
+ else if (sub.reaction && sub.lastValue !== res) {
197
+ sub.lastValue = res;
198
+ sub.reaction(res, sub.cancelled);
199
+ }
148
200
  }
@@ -24,60 +24,121 @@ function getSingleBody(node) {
24
24
  }
25
25
  return null;
26
26
  }
27
- function hasIdentifier(node) {
28
- let found = false;
29
- node.forEachChild(node => {
30
- if (!found && (TS.isIdentifier(node) || hasIdentifier(node))) {
31
- found = true;
32
- }
33
- });
34
- return found;
35
- }
36
27
  const transformer = context => {
37
28
  return sourceFile => {
38
29
  const visitGeneric = (node, options) => {
30
+ let hasSpread = options.userComponent && TS.isJsxSpreadAttribute(node);
31
+ let hasChildIdentifier = false;
39
32
  if (TS.isJsxOpeningLikeElement(node)) {
40
33
  const firstLetter = node.tagName.getText()[0];
41
34
  const userComponent = firstLetter !== firstLetter.toLowerCase();
42
- return TS.visitEachChild(node, node => visitGeneric(node, { userComponent }), context);
35
+ node = TS.visitEachChild(node, node => {
36
+ const res = visitGeneric(node, { userComponent });
37
+ hasSpread = hasSpread || res.hasSpread;
38
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
39
+ return res.node;
40
+ }, context);
41
+ if (userComponent && hasSpread) {
42
+ const symbol = TS.factory.createCallExpression(TS.factory.createPropertyAccessExpression(TS.factory.createIdentifier("Symbol"), "for"), void 0, [TS.factory.createStringLiteral("$nesquickSpreadProps")]);
43
+ if (TS.isJsxOpeningLikeElement(node)) {
44
+ const attributes = TS.factory.updateJsxAttributes(node.attributes, [
45
+ ...node.attributes.properties,
46
+ TS.factory.createJsxSpreadAttribute(TS.factory.createObjectLiteralExpression([
47
+ TS.factory.createPropertyAssignment(TS.factory.createComputedPropertyName(symbol), TS.factory.createTrue())
48
+ ]))
49
+ ]);
50
+ if (TS.isJsxOpeningElement(node)) {
51
+ node = TS.factory.updateJsxOpeningElement(node, node.tagName, node.typeArguments, attributes);
52
+ }
53
+ else if (TS.isJsxSelfClosingElement(node)) {
54
+ node = TS.factory.updateJsxSelfClosingElement(node, node.tagName, node.typeArguments, attributes);
55
+ }
56
+ }
57
+ }
43
58
  }
44
- if (TS.isJsxAttribute(node)) {
45
- return TS.visitEachChild(node, node => visitGeneric(node, { ...options, isJsxAttribute: true }), context);
59
+ else if (TS.isJsxAttribute(node)) {
60
+ node = TS.visitEachChild(node, node => {
61
+ const res = visitGeneric(node, { ...options, isJsxAttribute: true });
62
+ hasSpread = hasSpread || res.hasSpread;
63
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
64
+ return res.node;
65
+ }, context);
46
66
  }
47
67
  else if (TS.isJsxExpression(node)) {
48
- return TS.visitEachChild(node, node => visitorExpression(node, { ...options, isJsxAttribute: false }), context);
68
+ node = TS.visitEachChild(node, node => {
69
+ const res = visitorExpression(node, { ...options, isJsxAttribute: false });
70
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
71
+ return res.node;
72
+ }, context);
49
73
  }
50
74
  else if (options.isJsxAttribute && TS.isStringLiteral(node)) {
51
- const returnNode = TS.visitNode(node, node => visitorExpression(node, { ...options, isJsxAttribute: false }), TS.isExpression);
52
- if (!TS.isStringLiteral(returnNode)) {
53
- return TS.factory.createJsxExpression(undefined, returnNode);
75
+ const returnNode = TS.visitNode(node, node => {
76
+ const res = visitorExpression(node, { ...options, isJsxAttribute: false });
77
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
78
+ return res.node;
79
+ }, TS.isExpression);
80
+ if (TS.isStringLiteral(returnNode)) {
81
+ node = returnNode;
54
82
  }
55
- return returnNode;
83
+ else {
84
+ node = TS.factory.createJsxExpression(undefined, returnNode);
85
+ }
86
+ }
87
+ else {
88
+ node = TS.visitEachChild(node, node => {
89
+ const res = visitGeneric(node, { ...options, isJsxAttribute: false });
90
+ hasSpread = hasSpread || res.hasSpread;
91
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
92
+ return res.node;
93
+ }, context);
56
94
  }
57
- return TS.visitEachChild(node, node => visitGeneric(node, { ...options, isJsxAttribute: false }), context);
95
+ return { hasSpread, hasChildIdentifier, node };
58
96
  };
59
97
  const visitorExpression = (node, options) => {
98
+ let hasChildIdentifier = false;
60
99
  if (TS.isParenthesizedExpression(node)) {
61
100
  const body = getSingleBody(node);
62
101
  if (body) {
63
- return TS.visitNode(body, node => visitorExpression(node, options));
102
+ node = TS.visitNode(body, node => {
103
+ const res = visitorExpression(node, options);
104
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
105
+ return res.node;
106
+ });
64
107
  }
65
108
  }
66
109
  else if (TS.isCallExpression(node)) {
67
110
  const identifier = getSingleIdentifier(node);
68
111
  if (identifier) {
69
- return identifier;
112
+ node = identifier;
70
113
  }
71
114
  else {
72
- return TS.factory.createArrowFunction(undefined, undefined, [], undefined, TS.factory.createToken(TS.SyntaxKind.EqualsGreaterThanToken), TS.visitNode(node, node => visitGeneric(node, {}), TS.isConciseBody));
115
+ node = TS.factory.createArrowFunction(undefined, undefined, [], undefined, TS.factory.createToken(TS.SyntaxKind.EqualsGreaterThanToken), TS.visitNode(node, node => {
116
+ const res = visitGeneric(node, {});
117
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
118
+ return res.node;
119
+ }, TS.isConciseBody));
120
+ }
121
+ }
122
+ else if (!TS.isFunctionLike(node) && TS.isExpression(node)) {
123
+ node = TS.visitNode(node, node => {
124
+ const res = visitGeneric(node, {});
125
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier;
126
+ return res.node;
127
+ });
128
+ if ((options.userComponent || hasChildIdentifier) && TS.isConciseBody(node)) {
129
+ node = TS.factory.createArrowFunction(undefined, undefined, [], undefined, TS.factory.createToken(TS.SyntaxKind.EqualsGreaterThanToken), node);
73
130
  }
74
131
  }
75
- else if (!TS.isFunctionLike(node) && TS.isExpression(node) && (options.userComponent || hasIdentifier(node))) {
76
- return TS.factory.createArrowFunction(undefined, undefined, [], undefined, TS.factory.createToken(TS.SyntaxKind.EqualsGreaterThanToken), TS.visitNode(node, node => visitGeneric(node, {}), TS.isConciseBody));
132
+ else {
133
+ node = TS.visitNode(node, node => {
134
+ const res = visitGeneric(node, {});
135
+ hasChildIdentifier = hasChildIdentifier || res.hasChildIdentifier || TS.isIdentifier(node);
136
+ return res.node;
137
+ });
77
138
  }
78
- return TS.visitNode(node, node => visitGeneric(node, {}));
139
+ return { hasChildIdentifier, node };
79
140
  };
80
- return TS.visitNode(sourceFile, node => visitGeneric(node, {}), TS.isSourceFile);
141
+ return TS.visitNode(sourceFile, node => visitGeneric(node, {}).node, TS.isSourceFile);
81
142
  };
82
143
  };
83
144
  exports.transformer = transformer;
@@ -4,11 +4,16 @@ exports.JSX = exports.jsx = exports.Fragment = void 0;
4
4
  exports.jsxs = jsxs;
5
5
  const NesquickComponent_1 = require("./NesquickComponent");
6
6
  const NesquickFragment_1 = require("./NesquickFragment");
7
+ const jsx_runtime_1 = require("./no-transformer/jsx-runtime");
8
+ const propsSpreadSymbol = Symbol.for("$nesquickSpreadProps");
7
9
  exports.Fragment = Symbol();
8
10
  function jsxs(type, props, key) {
9
11
  if (type === exports.Fragment) {
10
12
  return new NesquickFragment_1.NesquickFragment(props.children);
11
13
  }
14
+ if (props[propsSpreadSymbol]) {
15
+ (0, jsx_runtime_1.functionizeProps)(props);
16
+ }
12
17
  if (key !== undefined) {
13
18
  props.key = key;
14
19
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.JSX = exports.jsx = exports.Fragment = void 0;
4
+ exports.functionizeProps = functionizeProps;
4
5
  exports.jsxs = jsxs;
5
6
  const NesquickComponent_1 = require("../NesquickComponent");
6
7
  const NesquickFragment_1 = require("../NesquickFragment");
@@ -1,8 +1,12 @@
1
- export type State<T> = [get: () => T, set: (value: T) => void];
2
- export type Subscription<T> = {
1
+ export type Getter<T> = () => T;
2
+ export type Setter<T> = (value: T) => void;
3
+ export type State<T> = [get: Getter<T>, set: Setter<T>];
4
+ type Subscription<T> = {
3
5
  cb: () => T;
4
- reaction: ((data: T, isState: boolean) => void) | null;
5
6
  iteration: number;
7
+ lastValue: T | null;
8
+ firstRun: boolean;
9
+ reaction: ((data: T, lastReaction: boolean) => void) | null;
6
10
  states: Map<Set<Subscription<any>>, number>;
7
11
  next: Subscription<T> | null;
8
12
  effect: boolean;
@@ -19,6 +23,8 @@ export declare namespace subscriptions {
19
23
  function reset(): void;
20
24
  }
21
25
  export declare function useState<T>(value: T): State<T>;
22
- export declare function useEffect<T>(cb: () => T, reaction?: ((data: T, isState: boolean) => void) | null): void;
23
- export declare function useRender<T>(cb: () => T, reaction?: ((data: T, isState: boolean) => void) | null): void;
26
+ export declare function useEffect<T>(cb: () => T, reaction?: ((data: T, lastReaction: boolean) => void) | null): void;
27
+ export declare function useRender<T>(cb: () => T, reaction?: ((data: T, lastReaction: boolean) => void) | null): void;
28
+ export declare function useMemo<T>(cb: () => T): Getter<T>;
24
29
  export declare function useDispose(cb: () => void): void;
30
+ export {};
@@ -1,7 +1,10 @@
1
1
  import { FunctionComponent, ComponentProps, NesquickComponent } from "./NesquickComponent";
2
2
  import { NesquickFragment } from "./NesquickFragment";
3
+ declare const propsSpreadSymbol: unique symbol;
3
4
  export declare const Fragment: unique symbol;
4
- export declare function jsxs<P extends ComponentProps>(type: string | FunctionComponent<P> | typeof Fragment, props: P, key?: string | number | null): NesquickFragment | NesquickComponent<P>;
5
+ export declare function jsxs<P extends ComponentProps & {
6
+ [propsSpreadSymbol]?: true;
7
+ }>(type: string | FunctionComponent<P> | typeof Fragment, props: P, key?: string | number | null): NesquickFragment | NesquickComponent<P>;
5
8
  export declare const jsx: typeof jsxs;
6
9
  type HasUndefined<T, K extends keyof T> = {
7
10
  [L in K]-?: T[K] | undefined;
@@ -1,6 +1,7 @@
1
1
  import { FunctionComponent, ComponentProps, NesquickComponent } from "../NesquickComponent";
2
2
  import { NesquickFragment } from "../NesquickFragment";
3
3
  export declare const Fragment: unique symbol;
4
+ export declare function functionizeProps(props: ComponentProps): void;
4
5
  export declare function jsxs<P extends ComponentProps>(type: string | FunctionComponent<P> | typeof Fragment, props: P, key?: string | number | null): NesquickFragment | NesquickComponent<P>;
5
6
  export declare const jsx: typeof jsxs;
6
7
  type HasUndefined<T, K extends keyof T> = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nesquick",
3
- "version": "0.0.26",
3
+ "version": "1.0.0",
4
4
  "description": "React-like library with focus on drawing performance",
5
5
  "types": "./lib/types",
6
6
  "main": "./lib",