@esportsplus/template 0.32.3 → 0.32.5

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.
@@ -1,15 +1,6 @@
1
1
  import { Attributes, Element } from './types.js';
2
- declare const set: (element: Element, name: string, value: unknown) => void;
3
2
  declare const setClass: (element: Element, classlist: false | string | undefined, value: unknown) => void;
4
3
  declare const setProperty: (element: Element, name: string, value: unknown) => void;
4
+ declare const setProperties: (element: Element, value: Attributes | Attributes[]) => void;
5
5
  declare const setStyle: (element: Element, styles: false | string | undefined, value: unknown) => void;
6
- declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
7
- declare const _default: {
8
- set: (element: Element, name: string, value: unknown) => void;
9
- setClass: (element: Element, classlist: false | string | undefined, value: unknown) => void;
10
- setProperty: (element: Element, name: string, value: unknown) => void;
11
- setStyle: (element: Element, styles: false | string | undefined, value: unknown) => void;
12
- spread: (element: Element, value: Attributes | Attributes[]) => void;
13
- };
14
- export default _default;
15
- export { set, setClass, setProperty, setStyle, spread };
6
+ export { setClass, setProperty, setProperties, setStyle };
@@ -1,9 +1,9 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isObject } from '@esportsplus/utilities';
3
- import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE } from './constants.js';
3
+ import { STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE } from './constants.js';
4
4
  import { raf } from './utilities.js';
5
5
  import q from '@esportsplus/queue';
6
- import event from './event/index.js';
6
+ import { runtime } from './event/index.js';
7
7
  let delimiters = {
8
8
  class: ' ',
9
9
  style: ';'
@@ -138,36 +138,10 @@ function schedule(ctx, element, name, state, value) {
138
138
  scheduled = true;
139
139
  raf(task);
140
140
  }
141
- function task() {
142
- let context, n = queue.length;
143
- while ((context = queue.next()) && n--) {
144
- let { element, updates } = context;
145
- for (let name in updates) {
146
- apply(element, name, updates[name]);
147
- }
148
- context.updates = {};
149
- context.updating = false;
150
- }
151
- if (queue.length) {
152
- raf(task);
153
- }
154
- else {
155
- scheduled = false;
156
- }
157
- }
158
- const set = (element, name, value) => {
141
+ function set(element, name, value) {
159
142
  if (typeof value === 'function') {
160
143
  if (name[0] === 'o' && name[1] === 'n') {
161
- let e = name.slice(2).toLowerCase(), key = name.toLowerCase();
162
- if (LIFECYCLE_EVENTS.has(key)) {
163
- event[key](element, value);
164
- }
165
- else if (DIRECT_ATTACH_EVENTS.has(key)) {
166
- event.direct(element, e, value);
167
- }
168
- else {
169
- event.delegate(element, e, value);
170
- }
144
+ runtime(element, name, value);
171
145
  }
172
146
  else {
173
147
  reactive(element, name, STATE_HYDRATING, value);
@@ -187,7 +161,24 @@ const set = (element, name, value) => {
187
161
  return;
188
162
  }
189
163
  (name === 'class' || name === 'style' ? list : property)(null, element, null, name, STATE_HYDRATING, value);
190
- };
164
+ }
165
+ function task() {
166
+ let context, n = queue.length;
167
+ while ((context = queue.next()) && n--) {
168
+ let { element, updates } = context;
169
+ for (let name in updates) {
170
+ apply(element, name, updates[name]);
171
+ }
172
+ context.updates = {};
173
+ context.updating = false;
174
+ }
175
+ if (queue.length) {
176
+ raf(task);
177
+ }
178
+ else {
179
+ scheduled = false;
180
+ }
181
+ }
191
182
  const setClass = (element, classlist, value) => {
192
183
  let ctx = context(element), store = ctx.store ??= {};
193
184
  store['class.static'] = classlist || '';
@@ -207,18 +198,7 @@ const setProperty = (element, name, value) => {
207
198
  property(null, element, null, name, STATE_HYDRATING, value);
208
199
  }
209
200
  };
210
- const setStyle = (element, styles, value) => {
211
- let ctx = context(element), store = ctx.store ??= {};
212
- store['style.static'] = styles || '';
213
- store['style'] ??= new Set();
214
- if (typeof value === 'function') {
215
- reactive(element, 'style', STATE_HYDRATING, value);
216
- }
217
- else {
218
- list(ctx, element, null, 'style', STATE_HYDRATING, value);
219
- }
220
- };
221
- const spread = function (element, value) {
201
+ const setProperties = function (element, value) {
222
202
  if (isObject(value)) {
223
203
  for (let name in value) {
224
204
  let v = value[name];
@@ -230,9 +210,19 @@ const spread = function (element, value) {
230
210
  }
231
211
  else if (isArray(value)) {
232
212
  for (let i = 0, n = value.length; i < n; i++) {
233
- spread(element, value[i]);
213
+ setProperties(element, value[i]);
234
214
  }
235
215
  }
236
216
  };
237
- export default { set, setClass, setProperty, setStyle, spread };
238
- export { set, setClass, setProperty, setStyle, spread };
217
+ const setStyle = (element, styles, value) => {
218
+ let ctx = context(element), store = ctx.store ??= {};
219
+ store['style.static'] = styles || '';
220
+ store['style'] ??= new Set();
221
+ if (typeof value === 'function') {
222
+ reactive(element, 'style', STATE_HYDRATING, value);
223
+ }
224
+ else {
225
+ list(ctx, element, null, 'style', STATE_HYDRATING, value);
226
+ }
227
+ };
228
+ export { setClass, setProperty, setProperties, setStyle };
@@ -4,15 +4,15 @@ declare const COMPILER_ENTRYPOINT = "html";
4
4
  declare const COMPILER_ENTRYPOINT_REACTIVITY = "reactive";
5
5
  declare const COMPILER_NAMESPACE: string;
6
6
  declare const enum COMPILER_TYPES {
7
- ArraySlot = 0,
8
- AttributeSlot = 1,
9
- AttributeSpreadSlot = 2,
10
- DocumentFragment = 3,
11
- Effect = 4,
12
- NodeSlot = 5,
13
- Primitive = 6,
14
- Static = 7,
15
- Unknown = 8
7
+ ArraySlot = "array-slot",
8
+ Attributes = "attributes",
9
+ Attribute = "attribute",
10
+ DocumentFragment = "document-fragment",
11
+ Effect = "effect",
12
+ Node = "node",
13
+ Primitive = "primitive",
14
+ Static = "static",
15
+ Unknown = "unknown"
16
16
  }
17
17
  declare const DIRECT_ATTACH_EVENTS: Set<string>;
18
18
  declare const LIFECYCLE_EVENTS: Set<string>;
@@ -6,15 +6,15 @@ const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
6
6
  const COMPILER_NAMESPACE = uid('template');
7
7
  var COMPILER_TYPES;
8
8
  (function (COMPILER_TYPES) {
9
- COMPILER_TYPES[COMPILER_TYPES["ArraySlot"] = 0] = "ArraySlot";
10
- COMPILER_TYPES[COMPILER_TYPES["AttributeSlot"] = 1] = "AttributeSlot";
11
- COMPILER_TYPES[COMPILER_TYPES["AttributeSpreadSlot"] = 2] = "AttributeSpreadSlot";
12
- COMPILER_TYPES[COMPILER_TYPES["DocumentFragment"] = 3] = "DocumentFragment";
13
- COMPILER_TYPES[COMPILER_TYPES["Effect"] = 4] = "Effect";
14
- COMPILER_TYPES[COMPILER_TYPES["NodeSlot"] = 5] = "NodeSlot";
15
- COMPILER_TYPES[COMPILER_TYPES["Primitive"] = 6] = "Primitive";
16
- COMPILER_TYPES[COMPILER_TYPES["Static"] = 7] = "Static";
17
- COMPILER_TYPES[COMPILER_TYPES["Unknown"] = 8] = "Unknown";
9
+ COMPILER_TYPES["ArraySlot"] = "array-slot";
10
+ COMPILER_TYPES["Attributes"] = "attributes";
11
+ COMPILER_TYPES["Attribute"] = "attribute";
12
+ COMPILER_TYPES["DocumentFragment"] = "document-fragment";
13
+ COMPILER_TYPES["Effect"] = "effect";
14
+ COMPILER_TYPES["Node"] = "node";
15
+ COMPILER_TYPES["Primitive"] = "primitive";
16
+ COMPILER_TYPES["Static"] = "static";
17
+ COMPILER_TYPES["Unknown"] = "unknown";
18
18
  })(COMPILER_TYPES || (COMPILER_TYPES = {}));
19
19
  ;
20
20
  const DIRECT_ATTACH_EVENTS = new Set([
@@ -1,11 +1,10 @@
1
1
  import { Element } from '../types.js';
2
- declare const _default: {
3
- delegate: (element: Element, event: string, listener: Function) => void;
4
- direct: (element: Element, event: string, listener: Function) => void;
5
- onconnect: (element: globalThis.Element, listener: Function) => void;
6
- ondisconnect: (element: Element, listener: Function) => void;
7
- onrender: (element: Element, listener: Function) => void;
8
- onresize: (element: Element, listener: Function) => void;
9
- ontick: (element: globalThis.Element, listener: Function) => void;
10
- };
11
- export default _default;
2
+ import onconnect from './onconnect.js';
3
+ import onresize from './onresize.js';
4
+ import ontick from './ontick.js';
5
+ declare const delegate: (element: Element, event: string, listener: Function) => void;
6
+ declare const on: (element: Element, event: string, listener: Function) => void;
7
+ declare const ondisconnect: (element: Element, listener: Function) => void;
8
+ declare const onrender: (element: Element, listener: Function) => void;
9
+ declare const runtime: (element: Element, event: `on${string}`, listener: Function) => void;
10
+ export { delegate, on, onconnect, ondisconnect, onrender, onresize, ontick, runtime };
@@ -4,6 +4,7 @@ import { ondisconnect as disconnect } from '../slot/cleanup.js';
4
4
  import onconnect from './onconnect.js';
5
5
  import onresize from './onresize.js';
6
6
  import ontick from './ontick.js';
7
+ import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants.js';
7
8
  let controllers = new Map(), host = window.document, keys = {}, passive = new Set([
8
9
  'animationend', 'animationiteration', 'animationstart',
9
10
  'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'mousewheel',
@@ -61,7 +62,7 @@ function register(element, event) {
61
62
  const delegate = (element, event, listener) => {
62
63
  element[keys[event] || register(element, event)] = listener;
63
64
  };
64
- const direct = (element, event, listener) => {
65
+ const on = (element, event, listener) => {
65
66
  let handler = (e) => listener.call(element, e);
66
67
  element.addEventListener(event, handler, {
67
68
  passive: passive.has(event)
@@ -76,4 +77,19 @@ const ondisconnect = (element, listener) => {
76
77
  const onrender = (element, listener) => {
77
78
  root(() => listener(element));
78
79
  };
79
- export default { delegate, direct, onconnect, ondisconnect, onrender, onresize, ontick };
80
+ const lifecycle = { onconnect, ondisconnect, onrender, onresize, ontick };
81
+ const runtime = (element, event, listener) => {
82
+ let key = event.toLowerCase();
83
+ if (LIFECYCLE_EVENTS.has(key)) {
84
+ lifecycle[key](element, listener);
85
+ return;
86
+ }
87
+ let e = event.slice(2).toLowerCase();
88
+ if (DIRECT_ATTACH_EVENTS.has(key)) {
89
+ on(element, e, listener);
90
+ }
91
+ else {
92
+ delegate(element, e, listener);
93
+ }
94
+ };
95
+ export { delegate, on, onconnect, ondisconnect, onrender, onresize, ontick, runtime };
package/build/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import './runtime.js';
2
2
  export { default as html } from './html.js';
3
3
  export { default as render } from './render.js';
4
4
  export { default as svg } from './svg.js';
5
- export { default as attributes } from './attributes.js';
6
- export { default as event } from './event/index.js';
5
+ export * from './attributes.js';
6
+ export * from './event/index.js';
7
7
  export { default as slot } from './slot/index.js';
8
8
  export { ArraySlot } from './slot/array.js';
9
9
  export { EffectSlot } from './slot/effect.js';
package/build/index.js CHANGED
@@ -2,8 +2,8 @@ import './runtime.js';
2
2
  export { default as html } from './html.js';
3
3
  export { default as render } from './render.js';
4
4
  export { default as svg } from './svg.js';
5
- export { default as attributes } from './attributes.js';
6
- export { default as event } from './event/index.js';
5
+ export * from './attributes.js';
6
+ export * from './event/index.js';
7
7
  export { default as slot } from './slot/index.js';
8
8
  export { ArraySlot } from './slot/array.js';
9
9
  export { EffectSlot } from './slot/effect.js';
@@ -80,7 +80,7 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
80
80
  }
81
81
  }
82
82
  let name = uid('element'), suffix = path.slice(startIdx).join('.');
83
- declarations.push(`${name} = ${ancestorVar}.${suffix}`);
83
+ declarations.push(`${name} = ${ancestorVar}.${suffix}!`);
84
84
  nodes.set(key, name);
85
85
  }
86
86
  code.push(isArrowBody ? '{' : `(() => {`, `let ${declarations.join(',\n')};`);
@@ -88,11 +88,11 @@ function generateTemplateCode(ctx, { html, slots }, exprTexts, exprNodes, isArro
88
88
  let elementVar = slots[i].path.length === 0
89
89
  ? root
90
90
  : (nodes.get(slots[i].path.join('.')) || root), slot = slots[i];
91
- if (slot.type === COMPILER_TYPES.AttributeSlot) {
91
+ if (slot.type === COMPILER_TYPES.Attribute) {
92
92
  let names = slot.attributes.names;
93
93
  for (let j = 0, m = names.length; j < m; j++) {
94
94
  let name = names[j];
95
- if (name === 'spread') {
95
+ if (name === COMPILER_TYPES.Attributes) {
96
96
  let bindings = generateSpreadBindings(exprNodes[index], exprTexts[index] || 'undefined', elementVar, ctx.checker, COMPILER_NAMESPACE);
97
97
  for (let k = 0, o = bindings.length; k < o; k++) {
98
98
  code.push(bindings[k]);
@@ -5,14 +5,14 @@ declare const _default: {
5
5
  html: string;
6
6
  slots: ({
7
7
  path: NodePath;
8
- type: COMPILER_TYPES.NodeSlot;
8
+ type: COMPILER_TYPES.Node;
9
9
  } | {
10
10
  attributes: {
11
11
  names: string[];
12
12
  statics: Record<string, string>;
13
13
  };
14
14
  path: NodePath;
15
- type: COMPILER_TYPES.AttributeSlot;
15
+ type: COMPILER_TYPES.Attribute;
16
16
  })[] | null;
17
17
  };
18
18
  };
@@ -53,7 +53,7 @@ const parse = (literals) => {
53
53
  if (n === 0) {
54
54
  return { html, slots: null };
55
55
  }
56
- let attributes = {}, buffer = '', events = false, index = 0, level = 0, levels = [{ children: 0, elements: 0, path: [] }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [];
56
+ let attributes = {}, buffer = '', index = 0, level = 0, levels = [{ children: 0, elements: 0, path: [] }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [];
57
57
  {
58
58
  let attribute = '', buffer = '', char = '', quote = '';
59
59
  for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
@@ -102,12 +102,9 @@ const parse = (literals) => {
102
102
  }
103
103
  }
104
104
  else {
105
- names.push('spread');
105
+ names.push(COMPILER_TYPES.Attributes);
106
106
  }
107
107
  }
108
- else if (buffer === 'on') {
109
- events = true;
110
- }
111
108
  }
112
109
  }
113
110
  }
@@ -127,7 +124,7 @@ const parse = (literals) => {
127
124
  if (!attrs) {
128
125
  throw new Error(`${PACKAGE}: attribute metadata could not be found for '${attr}'`);
129
126
  }
130
- slots.push({ attributes: attrs, path, type: COMPILER_TYPES.AttributeSlot });
127
+ slots.push({ attributes: attrs, path, type: COMPILER_TYPES.Attribute });
131
128
  for (let i = 0, n = attrs.names.length; i < n; i++) {
132
129
  buffer += parsed[slot++];
133
130
  }
@@ -139,7 +136,10 @@ const parse = (literals) => {
139
136
  }
140
137
  else if (type === NODE_SLOT) {
141
138
  buffer += parsed[slot++] + SLOT_HTML;
142
- slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type: COMPILER_TYPES.NodeSlot });
139
+ slots.push({
140
+ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'),
141
+ type: COMPILER_TYPES.Node
142
+ });
143
143
  }
144
144
  if (n === slot) {
145
145
  buffer += parsed[slot];
@@ -154,10 +154,9 @@ const parse = (literals) => {
154
154
  index = (match.index || 0) + match[0].length;
155
155
  }
156
156
  }
157
- if (events) {
158
- buffer = buffer.replace(REGEX_EVENTS, '');
159
- }
160
- buffer = buffer.replace(REGEX_EMPTY_ATTRIBUTES, '');
157
+ buffer = buffer
158
+ .replace(REGEX_EVENTS, '')
159
+ .replace(REGEX_EMPTY_ATTRIBUTES, '');
161
160
  return {
162
161
  html: buffer,
163
162
  slots: slots.length ? slots : null
@@ -123,23 +123,23 @@ const generateAttributeBinding = (elementVar, name, expr, staticValue, ns) => {
123
123
  if (name.startsWith('on') && name.length > 2) {
124
124
  let event = name.slice(2).toLowerCase(), key = name.toLowerCase();
125
125
  if (LIFECYCLE_EVENTS.has(key)) {
126
- return `${ns}.event.${key}(${elementVar}, ${expr});`;
126
+ return `${ns}.${key}(${elementVar}, ${expr});`;
127
127
  }
128
128
  if (DIRECT_ATTACH_EVENTS.has(key)) {
129
- return `${ns}.event.direct(${elementVar}, '${event}', ${expr});`;
129
+ return `${ns}.on(${elementVar}, '${event}', ${expr});`;
130
130
  }
131
- return `${ns}.event.delegate(${elementVar}, '${event}', ${expr});`;
131
+ return `${ns}.delegate(${elementVar}, '${event}', ${expr});`;
132
132
  }
133
133
  if (name === 'class') {
134
- return `${ns}.attributes.setClass(${elementVar}, '${staticValue}', ${expr});`;
134
+ return `${ns}.setClass(${elementVar}, '${staticValue}', ${expr});`;
135
135
  }
136
- if (name === 'spread') {
137
- return `${ns}.attributes.spread(${elementVar}, ${expr});`;
136
+ if (name === COMPILER_TYPES.Attributes) {
137
+ return `${ns}.setProperties(${elementVar}, ${expr});`;
138
138
  }
139
139
  if (name === 'style') {
140
- return `${ns}.attributes.setStyle(${elementVar}, '${staticValue}', ${expr});`;
140
+ return `${ns}.setStyle(${elementVar}, '${staticValue}', ${expr});`;
141
141
  }
142
- return `${ns}.attributes.setProperty(${elementVar}, '${name}', ${expr});`;
142
+ return `${ns}.setProperty(${elementVar}, '${name}', ${expr});`;
143
143
  };
144
144
  const generateSpreadBindings = (expr, exprCode, elementVar, checker, ns) => {
145
145
  while (ts.isParenthesizedExpression(expr)) {
@@ -147,7 +147,7 @@ const generateSpreadBindings = (expr, exprCode, elementVar, checker, ns) => {
147
147
  }
148
148
  let analysis = analyzeSpread(expr, checker);
149
149
  if (!analysis.canUnpack) {
150
- return [`${ns}.attributes.spread(${elementVar}, ${exprCode});`];
150
+ return [`${ns}.setProperties(${elementVar}, ${exprCode});`];
151
151
  }
152
152
  let lines = [];
153
153
  if (ts.isObjectLiteralExpression(expr)) {
package/build/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ArraySlot } from './slot/array.js';
2
- import attributes from './attributes.js';
2
+ import { setProperties } from './attributes.js';
3
3
  import slot from './slot/index.js';
4
4
  type Attribute = Effect<Primitive | Primitive[]> | ((...args: any[]) => void) | Primitive;
5
5
  type Attributes<T extends HTMLElement = Element> = {
@@ -27,7 +27,7 @@ type Template = {
27
27
  html: string;
28
28
  literals: TemplateStringsArray;
29
29
  slots: {
30
- fn: typeof attributes.spread | typeof slot;
30
+ fn: typeof setProperties | typeof slot;
31
31
  name: string | null;
32
32
  path: (() => ChildNode | null)[];
33
33
  }[] | null;
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "type": "module",
42
42
  "types": "./build/index.d.ts",
43
- "version": "0.32.3",
43
+ "version": "0.32.5",
44
44
  "scripts": {
45
45
  "build": "tsc",
46
46
  "build:test": "vite build --config test/vite.config.ts",
package/src/attributes.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isObject } from '@esportsplus/utilities';
3
- import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE } from './constants';
3
+ import { STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE } from './constants';
4
4
  import { Attributes, Element } from './types';
5
5
  import { raf } from './utilities';
6
6
  import q from '@esportsplus/queue';
7
- import event from './event';
7
+ import { runtime } from './event';
8
8
 
9
9
 
10
10
  type Context = {
@@ -221,45 +221,10 @@ function schedule(ctx: Context | null, element: Element, name: string, state: St
221
221
  raf(task);
222
222
  }
223
223
 
224
- function task() {
225
- let context,
226
- n = queue.length;
227
-
228
- while ((context = queue.next()) && n--) {
229
- let { element, updates } = context;
230
-
231
- for (let name in updates) {
232
- apply(element, name, updates[name]);
233
- }
234
-
235
- context.updates = {};
236
- context.updating = false;
237
- }
238
-
239
- if (queue.length) {
240
- raf(task);
241
- }
242
- else {
243
- scheduled = false;
244
- }
245
- }
246
-
247
-
248
- const set = (element: Element, name: string, value: unknown) => {
224
+ function set(element: Element, name: string, value: unknown) {
249
225
  if (typeof value === 'function') {
250
226
  if (name[0] === 'o' && name[1] === 'n') {
251
- let e = name.slice(2).toLowerCase(),
252
- key = name.toLowerCase();
253
-
254
- if (LIFECYCLE_EVENTS.has(key)) {
255
- (event as any)[key](element, value as Function);
256
- }
257
- else if (DIRECT_ATTACH_EVENTS.has(key)) {
258
- event.direct(element, e, value as Function);
259
- }
260
- else {
261
- event.delegate(element, e, value as Function);
262
- }
227
+ runtime(element, name as `on${string}`, value as Function);
263
228
  }
264
229
  else {
265
230
  reactive(element, name, STATE_HYDRATING, value);
@@ -283,7 +248,31 @@ const set = (element: Element, name: string, value: unknown) => {
283
248
  }
284
249
 
285
250
  (name === 'class' || name === 'style' ? list : property)(null, element, null, name, STATE_HYDRATING, value);
286
- };
251
+ }
252
+
253
+ function task() {
254
+ let context,
255
+ n = queue.length;
256
+
257
+ while ((context = queue.next()) && n--) {
258
+ let { element, updates } = context;
259
+
260
+ for (let name in updates) {
261
+ apply(element, name, updates[name]);
262
+ }
263
+
264
+ context.updates = {};
265
+ context.updating = false;
266
+ }
267
+
268
+ if (queue.length) {
269
+ raf(task);
270
+ }
271
+ else {
272
+ scheduled = false;
273
+ }
274
+ }
275
+
287
276
 
288
277
  const setClass = (element: Element, classlist: false | string | undefined, value: unknown) => {
289
278
  let ctx = context(element),
@@ -309,22 +298,7 @@ const setProperty = (element: Element, name: string, value: unknown) => {
309
298
  }
310
299
  };
311
300
 
312
- const setStyle = (element: Element, styles: false | string | undefined, value: unknown) => {
313
- let ctx = context(element),
314
- store = ctx.store ??= {};
315
-
316
- store['style.static'] = styles || '';
317
- store['style'] ??= new Set<string>();
318
-
319
- if (typeof value === 'function') {
320
- reactive(element, 'style', STATE_HYDRATING, value);
321
- }
322
- else {
323
- list(ctx, element, null, 'style', STATE_HYDRATING, value);
324
- }
325
- };
326
-
327
- const spread = function (element: Element, value: Attributes | Attributes[]) {
301
+ const setProperties = function (element: Element, value: Attributes | Attributes[]) {
328
302
  if (isObject(value)) {
329
303
  for (let name in value) {
330
304
  let v = value[name];
@@ -338,11 +312,25 @@ const spread = function (element: Element, value: Attributes | Attributes[]) {
338
312
  }
339
313
  else if (isArray(value)) {
340
314
  for (let i = 0, n = value.length; i < n; i++) {
341
- spread(element, value[i]);
315
+ setProperties(element, value[i]);
342
316
  }
343
317
  }
344
318
  };
345
319
 
320
+ const setStyle = (element: Element, styles: false | string | undefined, value: unknown) => {
321
+ let ctx = context(element),
322
+ store = ctx.store ??= {};
323
+
324
+ store['style.static'] = styles || '';
325
+ store['style'] ??= new Set<string>();
326
+
327
+ if (typeof value === 'function') {
328
+ reactive(element, 'style', STATE_HYDRATING, value);
329
+ }
330
+ else {
331
+ list(ctx, element, null, 'style', STATE_HYDRATING, value);
332
+ }
333
+ };
334
+
346
335
 
347
- export default { set, setClass, setProperty, setStyle, spread };
348
- export { set, setClass, setProperty, setStyle, spread };
336
+ export { setClass, setProperty, setProperties, setStyle };
package/src/constants.ts CHANGED
@@ -13,15 +13,15 @@ const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
13
13
  const COMPILER_NAMESPACE = uid('template');
14
14
 
15
15
  const enum COMPILER_TYPES {
16
- ArraySlot,
17
- AttributeSlot,
18
- AttributeSpreadSlot,
19
- DocumentFragment,
20
- Effect,
21
- NodeSlot,
22
- Primitive,
23
- Static,
24
- Unknown
16
+ ArraySlot = 'array-slot',
17
+ Attributes = 'attributes',
18
+ Attribute = 'attribute',
19
+ DocumentFragment = 'document-fragment',
20
+ Effect = 'effect',
21
+ Node = 'node',
22
+ Primitive = 'primitive',
23
+ Static = 'static',
24
+ Unknown = 'unknown'
25
25
  };
26
26
 
27
27
  const DIRECT_ATTACH_EVENTS = new Set<string>([
@@ -5,6 +5,7 @@ import { ondisconnect as disconnect } from '~/slot/cleanup';
5
5
  import onconnect from './onconnect';
6
6
  import onresize from './onresize';
7
7
  import ontick from './ontick';
8
+ import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '~/constants';
8
9
 
9
10
 
10
11
  let controllers = new Map<string, (AbortController & { listeners: number }) | null>(),
@@ -92,7 +93,7 @@ const delegate = (element: Element, event: string, listener: Function): void =>
92
93
  };
93
94
 
94
95
  // DIRECT_ATTACH_EVENTS in ./constants.ts tells compiler to use this function
95
- const direct = (element: Element, event: string, listener: Function): void => {
96
+ const on = (element: Element, event: string, listener: Function): void => {
96
97
  let handler = (e: Event) => listener.call(element, e);
97
98
 
98
99
  element.addEventListener(event, handler, {
@@ -112,5 +113,25 @@ const onrender = (element: Element, listener: Function) => {
112
113
  root(() => listener(element));
113
114
  };
114
115
 
116
+ const lifecycle = { onconnect, ondisconnect, onrender, onresize, ontick };
115
117
 
116
- export default { delegate, direct, onconnect, ondisconnect, onrender, onresize, ontick };
118
+ const runtime = (element: Element, event: `on${string}`, listener: Function): void => {
119
+ let key = event.toLowerCase();
120
+
121
+ if (LIFECYCLE_EVENTS.has(key)) {
122
+ lifecycle[key as keyof typeof lifecycle](element, listener);
123
+ return;
124
+ }
125
+
126
+ let e = event.slice(2).toLowerCase();
127
+
128
+ if (DIRECT_ATTACH_EVENTS.has(key)) {
129
+ on(element, e, listener);
130
+ }
131
+ else {
132
+ delegate(element, e, listener);
133
+ }
134
+ };
135
+
136
+
137
+ export { delegate, on, onconnect, ondisconnect, onrender, onresize, ontick, runtime };
package/src/index.ts CHANGED
@@ -4,8 +4,8 @@ export { default as render } from './render';
4
4
  export { default as svg } from './svg';
5
5
 
6
6
  // Must be exported for compilation even if not used directly
7
- export { default as attributes } from './attributes';
8
- export { default as event } from './event';
7
+ export * from './attributes';
8
+ export * from './event';
9
9
  export { default as slot } from './slot';
10
10
  export { ArraySlot } from './slot/array';
11
11
  export { EffectSlot } from './slot/effect';
@@ -9,13 +9,13 @@ import {
9
9
  import parser from './parser';
10
10
 
11
11
 
12
- type AttributeSlot = {
12
+ type Attribute = {
13
13
  attributes: {
14
14
  names: string[];
15
15
  statics: Record<string, string>;
16
16
  };
17
17
  path: string[];
18
- type: COMPILER_TYPES.AttributeSlot;
18
+ type: COMPILER_TYPES.Attribute;
19
19
  };
20
20
 
21
21
  type CodegenContext = {
@@ -31,14 +31,14 @@ type CodegenResult = {
31
31
  code: string;
32
32
  };
33
33
 
34
- type NodeSlot = {
34
+ type Node = {
35
35
  path: string[];
36
- type: COMPILER_TYPES.NodeSlot;
36
+ type: COMPILER_TYPES.Node;
37
37
  };
38
38
 
39
39
  type ParseResult = {
40
40
  html: string;
41
- slots: (AttributeSlot | NodeSlot)[] | null;
41
+ slots: (Attribute | Node)[] | null;
42
42
  };
43
43
 
44
44
 
@@ -174,7 +174,7 @@ function generateTemplateCode(
174
174
  let name = uid('element'),
175
175
  suffix = path.slice(startIdx).join('.');
176
176
 
177
- declarations.push(`${name} = ${ancestorVar}.${suffix}`);
177
+ declarations.push(`${name} = ${ancestorVar}.${suffix}!`);
178
178
  nodes.set(key, name);
179
179
  }
180
180
 
@@ -189,13 +189,13 @@ function generateTemplateCode(
189
189
  : (nodes.get(slots[i].path.join('.')) || root),
190
190
  slot = slots[i];
191
191
 
192
- if (slot.type === COMPILER_TYPES.AttributeSlot) {
192
+ if (slot.type === COMPILER_TYPES.Attribute) {
193
193
  let names = slot.attributes.names;
194
194
 
195
195
  for (let j = 0, m = names.length; j < m; j++) {
196
196
  let name = names[j];
197
197
 
198
- if (name === 'spread') {
198
+ if (name === COMPILER_TYPES.Attributes) {
199
199
  let bindings = generateSpreadBindings(
200
200
  exprNodes[index],
201
201
  exprTexts[index] || 'undefined',
@@ -1,8 +1,4 @@
1
- import {
2
- COMPILER_TYPES,
3
- PACKAGE,
4
- SLOT_HTML
5
- } from '../constants';
1
+ import { COMPILER_TYPES, PACKAGE, SLOT_HTML } from '../constants';
6
2
 
7
3
 
8
4
  type NodePath = ('firstChild' | 'firstElementChild' | 'nextElementSibling' | 'nextSibling')[];
@@ -88,15 +84,14 @@ const parse = (literals: string[]) => {
88
84
 
89
85
  let attributes: Record<string, { names: string[], statics: Record<string, string> }> = {},
90
86
  buffer = '',
91
- events = false,
92
87
  index = 0,
93
88
  level = 0,
94
89
  levels = [{ children: 0, elements: 0, path: [] as NodePath }],
95
90
  parsed = html.split(SLOT_MARKER),
96
91
  slot = 0,
97
92
  slots: (
98
- { path: NodePath; type: COMPILER_TYPES.NodeSlot } |
99
- { attributes: typeof attributes[string]; path: NodePath; type: COMPILER_TYPES.AttributeSlot }
93
+ { path: NodePath; type: COMPILER_TYPES.Node } |
94
+ { attributes: typeof attributes[string]; path: NodePath; type: COMPILER_TYPES.Attribute }
100
95
  )[] = [];
101
96
 
102
97
  {
@@ -159,12 +154,9 @@ const parse = (literals: string[]) => {
159
154
  }
160
155
  }
161
156
  else {
162
- names.push('spread');
157
+ names.push(COMPILER_TYPES.Attributes);
163
158
  }
164
159
  }
165
- else if (buffer === 'on') {
166
- events = true;
167
- }
168
160
  }
169
161
  }
170
162
  }
@@ -192,7 +184,7 @@ const parse = (literals: string[]) => {
192
184
  throw new Error(`${PACKAGE}: attribute metadata could not be found for '${attr}'`);
193
185
  }
194
186
 
195
- slots.push({ attributes: attrs, path, type: COMPILER_TYPES.AttributeSlot });
187
+ slots.push({ attributes: attrs, path, type: COMPILER_TYPES.Attribute });
196
188
 
197
189
  for (let i = 0, n = attrs.names.length; i < n; i++) {
198
190
  buffer += parsed[slot++];
@@ -207,7 +199,10 @@ const parse = (literals: string[]) => {
207
199
  }
208
200
  else if (type === NODE_SLOT) {
209
201
  buffer += parsed[slot++] + SLOT_HTML;
210
- slots.push({ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'), type: COMPILER_TYPES.NodeSlot });
202
+ slots.push({
203
+ path: methods(parent.children, parent.path, 'firstChild', 'nextSibling'),
204
+ type: COMPILER_TYPES.Node
205
+ });
211
206
  }
212
207
 
213
208
  if (n === slot) {
@@ -226,11 +221,9 @@ const parse = (literals: string[]) => {
226
221
  }
227
222
  }
228
223
 
229
- if (events) {
230
- buffer = buffer.replace(REGEX_EVENTS, '');
231
- }
232
-
233
- buffer = buffer.replace(REGEX_EMPTY_ATTRIBUTES, '');
224
+ buffer = buffer
225
+ .replace(REGEX_EVENTS, '')
226
+ .replace(REGEX_EMPTY_ATTRIBUTES, '');
234
227
 
235
228
  return {
236
229
  html: buffer,
@@ -178,29 +178,29 @@ const generateAttributeBinding = (elementVar: string, name: string, expr: string
178
178
  key = name.toLowerCase();
179
179
 
180
180
  if (LIFECYCLE_EVENTS.has(key)) {
181
- return `${ns}.event.${key}(${elementVar}, ${expr});`;
181
+ return `${ns}.${key}(${elementVar}, ${expr});`;
182
182
  }
183
183
 
184
184
  if (DIRECT_ATTACH_EVENTS.has(key)) {
185
- return `${ns}.event.direct(${elementVar}, '${event}', ${expr});`;
185
+ return `${ns}.on(${elementVar}, '${event}', ${expr});`;
186
186
  }
187
187
 
188
- return `${ns}.event.delegate(${elementVar}, '${event}', ${expr});`;
188
+ return `${ns}.delegate(${elementVar}, '${event}', ${expr});`;
189
189
  }
190
190
 
191
191
  if (name === 'class') {
192
- return `${ns}.attributes.setClass(${elementVar}, '${staticValue}', ${expr});`;
192
+ return `${ns}.setClass(${elementVar}, '${staticValue}', ${expr});`;
193
193
  }
194
194
 
195
- if (name === 'spread') {
196
- return `${ns}.attributes.spread(${elementVar}, ${expr});`;
195
+ if (name === COMPILER_TYPES.Attributes) {
196
+ return `${ns}.setProperties(${elementVar}, ${expr});`;
197
197
  }
198
198
 
199
199
  if (name === 'style') {
200
- return `${ns}.attributes.setStyle(${elementVar}, '${staticValue}', ${expr});`;
200
+ return `${ns}.setStyle(${elementVar}, '${staticValue}', ${expr});`;
201
201
  }
202
202
 
203
- return `${ns}.attributes.setProperty(${elementVar}, '${name}', ${expr});`;
203
+ return `${ns}.setProperty(${elementVar}, '${name}', ${expr});`;
204
204
  };
205
205
 
206
206
  const generateSpreadBindings = (
@@ -217,7 +217,7 @@ const generateSpreadBindings = (
217
217
  let analysis = analyzeSpread(expr, checker);
218
218
 
219
219
  if (!analysis.canUnpack) {
220
- return [`${ns}.attributes.spread(${elementVar}, ${exprCode});`];
220
+ return [`${ns}.setProperties(${elementVar}, ${exprCode});`];
221
221
  }
222
222
 
223
223
  let lines: string[] = [];
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ArraySlot } from './slot/array';
2
- import attributes from './attributes';
2
+ import { setProperties } from './attributes';
3
3
  import slot from './slot';
4
4
 
5
5
 
@@ -38,7 +38,7 @@ type Template = {
38
38
  html: string;
39
39
  literals: TemplateStringsArray;
40
40
  slots: {
41
- fn: typeof attributes.spread | typeof slot;
41
+ fn: typeof setProperties | typeof slot;
42
42
  name: string | null;
43
43
  path: (() => ChildNode | null)[];
44
44
  }[] | null;