grainjs 0.1.0 → 1.0.2

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 (164) hide show
  1. package/README.md +54 -9
  2. package/dist/cjs/index.d.ts +6 -2
  3. package/dist/cjs/index.js +24 -17
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/lib/PriorityQueue.d.ts +1 -1
  6. package/dist/cjs/lib/PriorityQueue.js +1 -0
  7. package/dist/cjs/lib/PriorityQueue.js.map +1 -1
  8. package/dist/cjs/lib/_computed_queue.d.ts +18 -0
  9. package/dist/cjs/lib/_computed_queue.js +6 -1
  10. package/dist/cjs/lib/_computed_queue.js.map +1 -1
  11. package/dist/cjs/lib/binding.d.ts +16 -10
  12. package/dist/cjs/lib/binding.js +22 -27
  13. package/dist/cjs/lib/binding.js.map +1 -1
  14. package/dist/cjs/lib/browserGlobals.d.ts +4 -1
  15. package/dist/cjs/lib/browserGlobals.js +2 -0
  16. package/dist/cjs/lib/browserGlobals.js.map +1 -1
  17. package/dist/cjs/lib/computed.d.ts +11 -7
  18. package/dist/cjs/lib/computed.js +16 -0
  19. package/dist/cjs/lib/computed.js.map +1 -1
  20. package/dist/cjs/lib/dispose.d.ts +106 -14
  21. package/dist/cjs/lib/dispose.js +76 -11
  22. package/dist/cjs/lib/dispose.js.map +1 -1
  23. package/dist/cjs/lib/dom.d.ts +21 -17
  24. package/dist/cjs/lib/dom.js +33 -26
  25. package/dist/cjs/lib/dom.js.map +1 -1
  26. package/dist/cjs/lib/domComponent.d.ts +71 -0
  27. package/dist/cjs/lib/domComponent.js +15 -0
  28. package/dist/cjs/lib/domComponent.js.map +1 -0
  29. package/dist/cjs/lib/domComputed.d.ts +89 -0
  30. package/dist/cjs/lib/domComputed.js +92 -0
  31. package/dist/cjs/lib/domComputed.js.map +1 -0
  32. package/dist/cjs/lib/{_domDispose.d.ts → domDispose.d.ts} +12 -2
  33. package/dist/cjs/lib/{_domDispose.js → domDispose.js} +21 -8
  34. package/dist/cjs/lib/domDispose.js.map +1 -0
  35. package/dist/cjs/lib/{_domForEach.d.ts → domForEach.d.ts} +2 -2
  36. package/dist/cjs/lib/domForEach.js +72 -0
  37. package/dist/cjs/lib/domForEach.js.map +1 -0
  38. package/dist/cjs/lib/{_domImpl.d.ts → domImpl.d.ts} +15 -12
  39. package/dist/cjs/lib/{_domImpl.js → domImpl.js} +23 -6
  40. package/dist/cjs/lib/domImpl.js.map +1 -0
  41. package/dist/cjs/lib/{_domMethods.d.ts → domMethods.d.ts} +27 -62
  42. package/dist/cjs/lib/{_domMethods.js → domMethods.js} +21 -76
  43. package/dist/cjs/lib/domMethods.js.map +1 -0
  44. package/dist/cjs/lib/domevent.d.ts +32 -21
  45. package/dist/cjs/lib/domevent.js +33 -12
  46. package/dist/cjs/lib/domevent.js.map +1 -1
  47. package/dist/cjs/lib/emit.d.ts +25 -2
  48. package/dist/cjs/lib/emit.js +3 -1
  49. package/dist/cjs/lib/emit.js.map +1 -1
  50. package/dist/cjs/lib/kowrap.d.ts +45 -3
  51. package/dist/cjs/lib/kowrap.js +93 -10
  52. package/dist/cjs/lib/kowrap.js.map +1 -1
  53. package/dist/cjs/lib/obsArray.d.ts +8 -8
  54. package/dist/cjs/lib/obsArray.js +1 -0
  55. package/dist/cjs/lib/obsArray.js.map +1 -1
  56. package/dist/cjs/lib/observable.d.ts +6 -1
  57. package/dist/cjs/lib/observable.js +11 -2
  58. package/dist/cjs/lib/observable.js.map +1 -1
  59. package/dist/cjs/lib/pureComputed.d.ts +3 -3
  60. package/dist/cjs/lib/pureComputed.js +2 -1
  61. package/dist/cjs/lib/pureComputed.js.map +1 -1
  62. package/dist/cjs/lib/styled.d.ts +76 -11
  63. package/dist/cjs/lib/styled.js +55 -23
  64. package/dist/cjs/lib/styled.js.map +1 -1
  65. package/dist/cjs/lib/subscribe.d.ts +15 -6
  66. package/dist/cjs/lib/subscribe.js +6 -2
  67. package/dist/cjs/lib/subscribe.js.map +1 -1
  68. package/dist/cjs/lib/util.js +1 -0
  69. package/dist/cjs/lib/util.js.map +1 -1
  70. package/dist/cjs/lib/widgets/input.d.ts +2 -2
  71. package/dist/cjs/lib/widgets/input.js +2 -2
  72. package/dist/cjs/lib/widgets/input.js.map +1 -1
  73. package/dist/cjs/lib/widgets/select.d.ts +1 -1
  74. package/dist/cjs/lib/widgets/select.js +1 -0
  75. package/dist/cjs/lib/widgets/select.js.map +1 -1
  76. package/dist/esm/index.js +6 -2
  77. package/dist/esm/index.js.map +1 -1
  78. package/dist/esm/lib/PriorityQueue.js.map +1 -1
  79. package/dist/esm/lib/_computed_queue.js +5 -1
  80. package/dist/esm/lib/_computed_queue.js.map +1 -1
  81. package/dist/esm/lib/binding.js +20 -27
  82. package/dist/esm/lib/binding.js.map +1 -1
  83. package/dist/esm/lib/browserGlobals.js +1 -0
  84. package/dist/esm/lib/browserGlobals.js.map +1 -1
  85. package/dist/esm/lib/computed.js +15 -0
  86. package/dist/esm/lib/computed.js.map +1 -1
  87. package/dist/esm/lib/dispose.js +74 -11
  88. package/dist/esm/lib/dispose.js.map +1 -1
  89. package/dist/esm/lib/dom.js +21 -17
  90. package/dist/esm/lib/dom.js.map +1 -1
  91. package/dist/esm/lib/domComponent.js +11 -0
  92. package/dist/esm/lib/domComponent.js.map +1 -0
  93. package/dist/esm/lib/domComputed.js +84 -0
  94. package/dist/esm/lib/domComputed.js.map +1 -0
  95. package/dist/esm/lib/{_domDispose.js → domDispose.js} +19 -8
  96. package/dist/esm/lib/domDispose.js.map +1 -0
  97. package/dist/esm/lib/domForEach.js +68 -0
  98. package/dist/esm/lib/domForEach.js.map +1 -0
  99. package/dist/esm/lib/{_domImpl.js → domImpl.js} +20 -4
  100. package/dist/esm/lib/domImpl.js.map +1 -0
  101. package/dist/esm/lib/{_domMethods.js → domMethods.js} +8 -63
  102. package/dist/esm/lib/domMethods.js.map +1 -0
  103. package/dist/esm/lib/domevent.js +30 -11
  104. package/dist/esm/lib/domevent.js.map +1 -1
  105. package/dist/esm/lib/emit.js +2 -1
  106. package/dist/esm/lib/emit.js.map +1 -1
  107. package/dist/esm/lib/kowrap.js +90 -10
  108. package/dist/esm/lib/kowrap.js.map +1 -1
  109. package/dist/esm/lib/obsArray.js.map +1 -1
  110. package/dist/esm/lib/observable.js +9 -1
  111. package/dist/esm/lib/observable.js.map +1 -1
  112. package/dist/esm/lib/pureComputed.js +1 -1
  113. package/dist/esm/lib/pureComputed.js.map +1 -1
  114. package/dist/esm/lib/styled.js +52 -22
  115. package/dist/esm/lib/styled.js.map +1 -1
  116. package/dist/esm/lib/subscribe.js +5 -2
  117. package/dist/esm/lib/subscribe.js.map +1 -1
  118. package/dist/esm/lib/util.js.map +1 -1
  119. package/dist/esm/lib/widgets/input.js +1 -2
  120. package/dist/esm/lib/widgets/input.js.map +1 -1
  121. package/dist/esm/lib/widgets/select.js.map +1 -1
  122. package/dist/grain-full.debug.js +1627 -1222
  123. package/dist/grain-full.min.js +1 -1
  124. package/dist/grain-full.min.js.map +1 -1
  125. package/index.ts +6 -2
  126. package/lib/_computed_queue.ts +7 -1
  127. package/lib/binding.ts +33 -28
  128. package/lib/browserGlobals.ts +3 -1
  129. package/lib/computed.ts +37 -7
  130. package/lib/dispose.ts +81 -33
  131. package/lib/dom.ts +24 -18
  132. package/lib/domComponent.ts +89 -0
  133. package/lib/domComputed.ts +146 -0
  134. package/lib/{_domDispose.ts → domDispose.ts} +26 -8
  135. package/lib/{_domForEach.ts → domForEach.ts} +12 -11
  136. package/lib/{_domImpl.ts → domImpl.ts} +36 -30
  137. package/lib/{_domMethods.ts → domMethods.ts} +33 -103
  138. package/lib/domevent.ts +59 -22
  139. package/lib/emit.ts +2 -1
  140. package/lib/kowrap.ts +109 -11
  141. package/lib/obsArray.ts +2 -2
  142. package/lib/observable.ts +10 -2
  143. package/lib/pureComputed.ts +7 -6
  144. package/lib/styled.ts +65 -39
  145. package/lib/subscribe.ts +24 -8
  146. package/lib/widgets/input.ts +9 -7
  147. package/lib/widgets/select.ts +3 -3
  148. package/package.json +41 -42
  149. package/dist/cjs/lib/_domComponent.d.ts +0 -84
  150. package/dist/cjs/lib/_domComponent.js +0 -160
  151. package/dist/cjs/lib/_domComponent.js.map +0 -1
  152. package/dist/cjs/lib/_domDispose.js.map +0 -1
  153. package/dist/cjs/lib/_domForEach.js +0 -71
  154. package/dist/cjs/lib/_domForEach.js.map +0 -1
  155. package/dist/cjs/lib/_domImpl.js.map +0 -1
  156. package/dist/cjs/lib/_domMethods.js.map +0 -1
  157. package/dist/esm/lib/_domComponent.js +0 -155
  158. package/dist/esm/lib/_domComponent.js.map +0 -1
  159. package/dist/esm/lib/_domDispose.js.map +0 -1
  160. package/dist/esm/lib/_domForEach.js +0 -68
  161. package/dist/esm/lib/_domForEach.js.map +0 -1
  162. package/dist/esm/lib/_domImpl.js.map +0 -1
  163. package/dist/esm/lib/_domMethods.js.map +0 -1
  164. package/lib/_domComponent.ts +0 -167
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const _domDispose_1 = require("./_domDispose");
4
- const _domImpl_1 = require("./_domImpl");
3
+ exports.noTestId = exports.makeTestId = exports.getData = exports.data = exports.dataElem = exports.clsPrefix = exports.cls = exports.clsElem = exports.hide = exports.hideElem = exports.show = exports.showElem = exports.prop = exports.propElem = exports.style = exports.styleElem = exports.text = exports.textElem = exports.boolAttr = exports.boolAttrElem = exports.attr = exports.attrElem = exports.attrs = exports.attrsElem = void 0;
5
4
  const binding_1 = require("./binding");
5
+ const domDispose_1 = require("./domDispose");
6
6
  // Use the browser globals in a way that allows replacing them with mocks in tests.
7
7
  const browserGlobals_1 = require("./browserGlobals");
8
8
  /**
@@ -10,13 +10,6 @@ const browserGlobals_1 = require("./browserGlobals");
10
10
  * values from being garbage collected when the owning DOM elements are no longer used.
11
11
  */
12
12
  const _dataMap = new WeakMap();
13
- /**
14
- * Internal helper that binds the callback to valueObs, which may be a value, observble, or
15
- * function, and attaches a disposal callback to the passed-in element.
16
- */
17
- function _subscribe(elem, valueObs, callback) {
18
- _domDispose_1.autoDisposeElem(elem, binding_1.subscribe(valueObs, callback));
19
- }
20
13
  /**
21
14
  * Sets multiple attributes of a DOM element. The `attrs()` variant takes no `elem` argument.
22
15
  * Null and undefined values are omitted, and booleans are either omitted or set to empty string.
@@ -53,7 +46,7 @@ function attrElem(elem, attrName, attrValue) {
53
46
  }
54
47
  exports.attrElem = attrElem;
55
48
  function attr(attrName, attrValueObs) {
56
- return (elem) => _subscribe(elem, attrValueObs, (val) => attrElem(elem, attrName, val));
49
+ return (elem) => binding_1.subscribeElem(elem, attrValueObs, (val) => attrElem(elem, attrName, val));
57
50
  }
58
51
  exports.attr = attr;
59
52
  /**
@@ -69,7 +62,7 @@ function boolAttrElem(elem, attrName, boolValue) {
69
62
  }
70
63
  exports.boolAttrElem = boolAttrElem;
71
64
  function boolAttr(attrName, boolValueObs) {
72
- return (elem) => _subscribe(elem, boolValueObs, (val) => boolAttrElem(elem, attrName, val));
65
+ return (elem) => binding_1.subscribeElem(elem, boolValueObs, (val) => boolAttrElem(elem, attrName, val));
73
66
  }
74
67
  exports.boolAttr = boolAttr;
75
68
  /**
@@ -85,7 +78,7 @@ exports.textElem = textElem;
85
78
  function text(valueObs) {
86
79
  return (elem) => {
87
80
  const textNode = browserGlobals_1.G.document.createTextNode('');
88
- _subscribe(elem, valueObs, (val) => { textNode.nodeValue = val; });
81
+ binding_1.subscribeElem(elem, valueObs, (val) => { textNode.nodeValue = val; });
89
82
  elem.appendChild(textNode);
90
83
  };
91
84
  }
@@ -102,7 +95,7 @@ function styleElem(elem, property, value) {
102
95
  }
103
96
  exports.styleElem = styleElem;
104
97
  function style(property, valueObs) {
105
- return (elem) => _subscribe(elem, valueObs, (val) => styleElem(elem, property, val));
98
+ return (elem) => binding_1.subscribeElem(elem, valueObs, (val) => styleElem(elem, property, val));
106
99
  }
107
100
  exports.style = style;
108
101
  /**
@@ -117,7 +110,7 @@ function propElem(elem, property, value) {
117
110
  }
118
111
  exports.propElem = propElem;
119
112
  function prop(property, valueObs) {
120
- return (elem) => _subscribe(elem, valueObs, (val) => propElem(elem, property, val));
113
+ return (elem) => binding_1.subscribeElem(elem, valueObs, (val) => propElem(elem, property, val));
121
114
  }
122
115
  exports.prop = prop;
123
116
  /**
@@ -132,7 +125,7 @@ function showElem(elem, boolValue) {
132
125
  }
133
126
  exports.showElem = showElem;
134
127
  function show(boolValueObs) {
135
- return (elem) => _subscribe(elem, boolValueObs, (val) => showElem(elem, val));
128
+ return (elem) => binding_1.subscribeElem(elem, boolValueObs, (val) => showElem(elem, val));
136
129
  }
137
130
  exports.show = show;
138
131
  /**
@@ -146,7 +139,7 @@ function hideElem(elem, boolValue) {
146
139
  }
147
140
  exports.hideElem = hideElem;
148
141
  function hide(boolValueObs) {
149
- return (elem) => _subscribe(elem, boolValueObs, (val) => hideElem(elem, val));
142
+ return (elem) => binding_1.subscribeElem(elem, boolValueObs, (val) => hideElem(elem, val));
150
143
  }
151
144
  exports.hide = hide;
152
145
  /**
@@ -164,7 +157,7 @@ function cls(className, boolValue) {
164
157
  return (elem) => clsElem(elem, className, boolValue);
165
158
  }
166
159
  else {
167
- return (elem) => _subscribe(elem, boolValue, (val) => clsElem(elem, className, val));
160
+ return (elem) => binding_1.subscribeElem(elem, boolValue, (val) => clsElem(elem, className, val));
168
161
  }
169
162
  }
170
163
  exports.cls = cls;
@@ -180,7 +173,7 @@ exports.clsPrefix = clsPrefix;
180
173
  function _clsDynamicPrefix(prefix, className) {
181
174
  return (elem) => {
182
175
  let prevClass = null;
183
- _subscribe(elem, className, (name) => {
176
+ binding_1.subscribeElem(elem, className, (name) => {
184
177
  if (prevClass) {
185
178
  elem.classList.remove(prevClass);
186
179
  }
@@ -204,13 +197,13 @@ function dataElem(elem, key, value) {
204
197
  obj[key] = value;
205
198
  }
206
199
  else {
207
- _domDispose_1.onDisposeElem(elem, () => _dataMap.delete(elem));
200
+ domDispose_1.onDisposeElem(elem, () => _dataMap.delete(elem));
208
201
  _dataMap.set(elem, { [key]: value });
209
202
  }
210
203
  }
211
204
  exports.dataElem = dataElem;
212
205
  function data(key, valueObs) {
213
- return (elem) => _subscribe(elem, valueObs, (val) => dataElem(elem, key, val));
206
+ return (elem) => binding_1.subscribeElem(elem, valueObs, (val) => dataElem(elem, key, val));
214
207
  }
215
208
  exports.data = data;
216
209
  function getData(elem, key) {
@@ -219,63 +212,15 @@ function getData(elem, key) {
219
212
  }
220
213
  exports.getData = getData;
221
214
  /**
222
- * Replaces the content between nodeBefore and nodeAfter, which should be two siblings within the
223
- * same parent node. New content may be anything allowed as an argument to dom(), including null
224
- * to insert nothing. Runs disposers, if any, on all removed content.
215
+ * See documentation for TestId above.
225
216
  */
226
- function replaceContent(nodeBefore, nodeAfter, content) {
227
- const elem = nodeBefore.parentNode;
228
- if (elem) {
229
- let next;
230
- for (let n = nodeBefore.nextSibling; n && n !== nodeAfter; n = next) {
231
- next = n.nextSibling;
232
- _domDispose_1.domDispose(n);
233
- elem.removeChild(n);
234
- }
235
- if (content) {
236
- elem.insertBefore(content instanceof browserGlobals_1.G.Node ? content : _domImpl_1.frag(content), nodeAfter);
237
- }
238
- }
217
+ function makeTestId(prefix) {
218
+ return clsPrefix.bind(null, prefix);
239
219
  }
240
- exports.replaceContent = replaceContent;
241
- function domComputed(valueObs, contentFunc) {
242
- const _contentFunc = contentFunc || identity;
243
- return (elem) => {
244
- const markerPre = browserGlobals_1.G.document.createComment('a');
245
- const markerPost = browserGlobals_1.G.document.createComment('b');
246
- elem.appendChild(markerPre);
247
- elem.appendChild(markerPost);
248
- _subscribe(elem, valueObs, (value) => replaceContent(markerPre, markerPost, _contentFunc(value)));
249
- };
250
- }
251
- exports.domComputed = domComputed;
252
- function identity(arg) { return arg; }
220
+ exports.makeTestId = makeTestId;
253
221
  /**
254
- * Conditionally appends DOM to an element. The value may be an observable or function (from which
255
- * a computed is created), whose value -- if truthy -- will be passed to `contentFunc` which
256
- * should return DOM content. If the value is falsy, DOM content is removed.
257
- *
258
- * Note that if the observable changes between different truthy values, contentFunc gets called
259
- * for each value, and previous content gets destroyed. To consider all truthy values the same,
260
- * use an observable that returns a proper boolean, e.g.
261
- *
262
- * dom.maybe(use => Boolean(use(fooObs)), () => dom(...));
263
- *
264
- * As with domComputed(), dom.maybe() may but should not be used when the argument is not an
265
- * observable or function. The following are equivalent:
266
- *
267
- * dom(..., dom.maybe(myValue, () => dom(...)));
268
- * dom(..., myValue ? dom(...) : null);
269
- *
270
- * The latter is preferred for being simpler.
271
- *
272
- * @param {Element} elem: The element to which to append the DOM content.
273
- * @param {Object} boolValueObs: Observable or function for a computed.
274
- * @param [Function] contentFunc: Function called with the result of boolValueObs when it is
275
- * truthy. Should returning DOM as output.
222
+ * See documentation for TestId above.
276
223
  */
277
- function maybe(boolValueObs, contentFunc) {
278
- return domComputed(boolValueObs, (value) => value ? contentFunc(value) : null);
279
- }
280
- exports.maybe = maybe;
281
- //# sourceMappingURL=_domMethods.js.map
224
+ const noTestId = (name) => null;
225
+ exports.noTestId = noTestId;
226
+ //# sourceMappingURL=domMethods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domMethods.js","sourceRoot":"","sources":["../../../lib/domMethods.ts"],"names":[],"mappings":"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"}
@@ -38,9 +38,11 @@
38
38
  * If you need to remove the callback on first call, here's a useful pattern:
39
39
  * let lis = domevent.onElem(elem, 'mouseup', e => { lis.dispose(); other_work(); });
40
40
  */
41
- import { DomElementMethod } from './_domImpl';
42
41
  import { IDisposable } from './dispose';
43
- export declare type EventCB = (this: void, event: Event, elem: Element) => void;
42
+ import { DomElementMethod, DomMethod } from './domImpl';
43
+ export declare type EventName = keyof HTMLElementEventMap;
44
+ export declare type EventType<E extends EventName | string> = E extends EventName ? HTMLElementEventMap[E] : Event;
45
+ export declare type EventCB<E extends Event = Event, T extends EventTarget = EventTarget> = (this: void, event: E, elem: T) => void;
44
46
  /**
45
47
  * Listen to a DOM event. The `on()` variant takes no `elem` argument, and may be used as an
46
48
  * argument to dom() function.
@@ -51,12 +53,12 @@ export declare type EventCB = (this: void, event: Event, elem: Element) => void;
51
53
  * rarely be useful (e.g. JQuery doesn't even offer it as an option).
52
54
  * @returns {Object} Listener object whose .dispose() method will remove the event listener.
53
55
  */
54
- export declare function onElem(elem: EventTarget, eventType: string, callback: EventCB, {useCapture}?: {
55
- useCapture?: boolean;
56
+ export declare function onElem<E extends EventName | string, T extends EventTarget>(elem: T, eventType: E, callback: EventCB<EventType<E>, T>, { useCapture }?: {
57
+ useCapture?: boolean | undefined;
56
58
  }): IDisposable;
57
- export declare function on(eventType: string, callback: EventCB, {useCapture}?: {
58
- useCapture?: boolean;
59
- }): DomElementMethod;
59
+ export declare function on<E extends EventName | string, T extends EventTarget>(eventType: E, callback: EventCB<EventType<E>, T>, { useCapture }?: {
60
+ useCapture?: boolean | undefined;
61
+ }): DomMethod<T>;
60
62
  /**
61
63
  * Listen to a DOM event on descendants of the given elem matching the given selector. The
62
64
  * `onMatch()` variant takes no `elem` argument, and may be used as an argument to dom().
@@ -72,30 +74,39 @@ export declare function on(eventType: string, callback: EventCB, {useCapture}?:
72
74
  * rarely be useful (e.g. JQuery doesn't even offer it as an option).
73
75
  * @returns {Object} Listener object whose .dispose() method will remove the event listener.
74
76
  */
75
- export declare function onMatchElem(elem: EventTarget, selector: string, eventType: string, callback: EventCB, {useCapture}?: {
76
- useCapture?: boolean;
77
+ export declare function onMatchElem(elem: EventTarget, selector: string, eventType: string, callback: EventCB, { useCapture }?: {
78
+ useCapture?: boolean | undefined;
77
79
  }): IDisposable;
78
- export declare function onMatch(selector: string, eventType: string, callback: EventCB, {useCapture}?: {
79
- useCapture?: boolean;
80
+ export declare function onMatch(selector: string, eventType: string, callback: EventCB, { useCapture }?: {
81
+ useCapture?: boolean | undefined;
80
82
  }): DomElementMethod;
83
+ export declare type KeyEventType = 'keypress' | 'keyup' | 'keydown';
84
+ export interface IKeyHandlers<T extends HTMLElement = HTMLElement> {
85
+ [key: string]: (this: void, ev: KeyboardEvent, elem: T) => void;
86
+ }
81
87
  /**
82
- * Listen to key presses, with specified per-key callbacks. The `onKeyPress()` variant takes no
83
- * `elem` argument, and may be used as an argument to dom().
84
- *
88
+ * Listen to key events (typically 'keydown' or 'keypress'), with specified per-key callbacks.
85
89
  * Key names are listed at https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
86
90
  *
91
+ * Methods onKeyPress() and onKeyDown() are intended to be used as arguments to dom().
92
+ *
93
+ * By default, handled events are stopped from bubbling with stopPropagation() and
94
+ * preventDefault(). If, however, you register a key with a "$" suffix (i.e. "Enter$" instead of
95
+ * "Enter"), then the event is allowed to bubble normally.
96
+ *
97
+ * When this handler is set on an element, we automatically ensure that tabindex attribute is set,
98
+ * to allow this element to receive keyboard events.
99
+ *
87
100
  * For example:
88
101
  *
89
102
  * dom('input', ...
90
- * dom.onKeyPress({
103
+ * dom.onKeyDown({
91
104
  * Enter: (e, elem) => console.log("Enter pressed"),
92
105
  * Escape: (e, elem) => console.log("Escape pressed"),
106
+ * Delete$: (e, elem) => console.log("Delete pressed, will bubble"),
93
107
  * })
94
108
  * )
95
109
  */
96
- export declare function onKeyPressElem(elem: EventTarget, callbacks: {
97
- [key: string]: EventCB;
98
- }): IDisposable;
99
- export declare function onKeyPress(callbacks: {
100
- [key: string]: EventCB;
101
- }): DomElementMethod;
110
+ export declare function onKeyElem<T extends HTMLElement>(elem: T, evType: KeyEventType, keyHandlers: IKeyHandlers<T>): IDisposable;
111
+ export declare function onKeyPress<T extends HTMLElement>(keyHandlers: IKeyHandlers<T>): DomMethod<T>;
112
+ export declare function onKeyDown<T extends HTMLElement>(keyHandlers: IKeyHandlers<T>): DomMethod<T>;
@@ -40,6 +40,7 @@
40
40
  * let lis = domevent.onElem(elem, 'mouseup', e => { lis.dispose(); other_work(); });
41
41
  */
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.onKeyDown = exports.onKeyPress = exports.onKeyElem = exports.onMatch = exports.onMatchElem = exports.on = exports.onElem = void 0;
43
44
  function _findMatch(inner, outer, selector) {
44
45
  for (let el = inner; el && el !== outer; el = el.parentElement) {
45
46
  if (el.matches(selector)) {
@@ -118,31 +119,51 @@ function onMatch(selector, eventType, callback, { useCapture = false } = {}) {
118
119
  }
119
120
  exports.onMatch = onMatch;
120
121
  /**
121
- * Listen to key presses, with specified per-key callbacks. The `onKeyPress()` variant takes no
122
- * `elem` argument, and may be used as an argument to dom().
123
- *
122
+ * Listen to key events (typically 'keydown' or 'keypress'), with specified per-key callbacks.
124
123
  * Key names are listed at https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
125
124
  *
125
+ * Methods onKeyPress() and onKeyDown() are intended to be used as arguments to dom().
126
+ *
127
+ * By default, handled events are stopped from bubbling with stopPropagation() and
128
+ * preventDefault(). If, however, you register a key with a "$" suffix (i.e. "Enter$" instead of
129
+ * "Enter"), then the event is allowed to bubble normally.
130
+ *
131
+ * When this handler is set on an element, we automatically ensure that tabindex attribute is set,
132
+ * to allow this element to receive keyboard events.
133
+ *
126
134
  * For example:
127
135
  *
128
136
  * dom('input', ...
129
- * dom.onKeyPress({
137
+ * dom.onKeyDown({
130
138
  * Enter: (e, elem) => console.log("Enter pressed"),
131
139
  * Escape: (e, elem) => console.log("Escape pressed"),
140
+ * Delete$: (e, elem) => console.log("Delete pressed, will bubble"),
132
141
  * })
133
142
  * )
134
143
  */
135
- function onKeyPressElem(elem, callbacks) {
136
- return onElem(elem, 'keypress', (e, _elem) => {
137
- const cb = callbacks[e.key];
138
- if (cb) {
139
- cb(e, _elem);
144
+ function onKeyElem(elem, evType, keyHandlers) {
145
+ if (!(elem.tabIndex >= 0)) { // If tabIndex property is undefined or -1,
146
+ elem.setAttribute('tabindex', '-1'); // Set tabIndex attribute to make the element focusable.
147
+ }
148
+ return onElem(elem, evType, (ev, _elem) => {
149
+ const plainHandler = keyHandlers[ev.key];
150
+ const handler = plainHandler || keyHandlers[ev.key + '$'];
151
+ if (handler) {
152
+ if (plainHandler) {
153
+ ev.stopPropagation();
154
+ ev.preventDefault();
155
+ }
156
+ handler(ev, _elem);
140
157
  }
141
158
  });
142
159
  }
143
- exports.onKeyPressElem = onKeyPressElem;
144
- function onKeyPress(callbacks) {
145
- return (elem) => { onKeyPressElem(elem, callbacks); };
160
+ exports.onKeyElem = onKeyElem;
161
+ function onKeyPress(keyHandlers) {
162
+ return (elem) => { onKeyElem(elem, 'keypress', keyHandlers); };
146
163
  }
147
164
  exports.onKeyPress = onKeyPress;
165
+ function onKeyDown(keyHandlers) {
166
+ return (elem) => { onKeyElem(elem, 'keydown', keyHandlers); };
167
+ }
168
+ exports.onKeyDown = onKeyDown;
148
169
  //# sourceMappingURL=domevent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"domevent.js","sourceRoot":"","sources":["../../../lib/domevent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"domevent.js","sourceRoot":"","sources":["../../../lib/domevent.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,25 @@
1
+ /**
2
+ * emit.js implements an Emitter class which emits events to a list of listeners. Listeners are
3
+ * simply functions to call, and "emitting an event" just calls those functions.
4
+ *
5
+ * This is similar to Backbone events, with more focus on efficiency. Both inserting and removing
6
+ * listeners is constant time.
7
+ *
8
+ * To create an emitter:
9
+ * let emitter = new Emitter();
10
+ *
11
+ * To add a listener:
12
+ * let listener = fooEmitter.addListener(callback);
13
+ * To remove a listener:
14
+ * listener.dispose();
15
+ *
16
+ * The only way to remove a listener is to dispose the Listener object returned by addListener().
17
+ * You can often use autoDispose to do this automatically when subscribing in a constructor:
18
+ * this.autoDispose(fooEmitter.addListener(this.onFoo, this));
19
+ *
20
+ * To emit an event, call emit() with any number of arguments:
21
+ * emitter.emit("hello", "world");
22
+ */
1
23
  export declare type ListenerCB<T> = (this: T, ...args: any[]) => void;
2
24
  export declare type ChangeCB = (hasListeners: boolean) => void;
3
25
  /**
@@ -34,7 +56,8 @@ export declare class Emitter extends LLink {
34
56
  * Sets the single callback that would get called when a listener is added or removed.
35
57
  * @param {Function} changeCB(hasListeners): Function to call after a listener is added or
36
58
  * removed. It's called with a boolean indicating whether this Emitter has any listeners.
37
- * Pass in `null` to unset the callback.
59
+ * Pass in `null` to unset the callback. Note that it can be called multiple times in a row
60
+ * with hasListeners `true`.
38
61
  */
39
62
  setChangeCB(changeCB: ChangeCB, optContext?: any): void;
40
63
  /**
@@ -58,7 +81,7 @@ export declare class Emitter extends LLink {
58
81
  export declare class Listener extends LLink {
59
82
  private emitter;
60
83
  private callback;
61
- private context;
84
+ private context?;
62
85
  static callAll(begin: LLink, end: LLink, args: any[]): void;
63
86
  constructor(emitter: Emitter, callback: ListenerCB<any>, context?: any);
64
87
  dispose(): void;
@@ -22,6 +22,7 @@
22
22
  * emitter.emit("hello", "world");
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.Listener = exports.Emitter = exports.LLink = void 0;
25
26
  // Note about a possible alternative implementation.
26
27
  //
27
28
  // We could implement the same interface using an array of listeners. Certain issues apply, in
@@ -104,7 +105,8 @@ class Emitter extends LLink {
104
105
  * Sets the single callback that would get called when a listener is added or removed.
105
106
  * @param {Function} changeCB(hasListeners): Function to call after a listener is added or
106
107
  * removed. It's called with a boolean indicating whether this Emitter has any listeners.
107
- * Pass in `null` to unset the callback.
108
+ * Pass in `null` to unset the callback. Note that it can be called multiple times in a row
109
+ * with hasListeners `true`.
108
110
  */
109
111
  setChangeCB(changeCB, optContext) {
110
112
  this._changeCB = changeCB || _noop;
@@ -1 +1 @@
1
- {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../lib/emit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../lib/emit.ts"],"names":[],"mappings":"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"}
@@ -19,22 +19,64 @@
19
19
  * knockout as a dependency of grainjs.
20
20
  *
21
21
  * In both cases, calling fromKo/toKo twice on the same observable will return the same wrapper,
22
- * and subscriptions and disposal are appropriately set up to make usage seamless.
22
+ * and subscriptions and disposal are appropriately set up to make usage seamless. In particular,
23
+ * the returned wrapper should not be disposed; it's tied to the lifetime of the wrapped object.
23
24
  */
24
25
  import { Observable } from './observable';
25
- export interface IKnockoutObservable<T> {
26
+ export interface IKnockoutObservable<T> extends IKnockoutReadObservable<T> {
26
27
  (val: T): void;
28
+ }
29
+ export interface IKnockoutReadObservable<T> {
30
+ (): T;
27
31
  peek(): T;
28
32
  subscribe(callback: (newValue: T) => void, target?: any, event?: "change"): any;
33
+ getSubscriptionsCount(): number;
29
34
  }
35
+ export declare type InferKoType<KObs extends IKnockoutReadObservable<any>> = KObs extends {
36
+ peek(): infer T;
37
+ } ? T : never;
30
38
  /**
31
39
  * Returns a Grain.js observable which mirrors a Knockout observable.
40
+ *
41
+ * Do not dispose this wrapper, as it is shared by all code using koObs, and its lifetime is tied
42
+ * to the lifetime of koObs. If unused, it consumes minimal resources, and should get garbage
43
+ * collected along with koObs.
44
+ */
45
+ export declare function fromKo<KObs extends IKnockoutObservable<any>>(koObs: KObs): Observable<InferKoType<KObs>>;
46
+ /**
47
+ * An Observable that wraps a Knockout observable, created via fromKo(). It keeps minimal overhead
48
+ * when unused by only subscribing to the wrapped observable while it itself has subscriptions.
49
+ *
50
+ * This way, when unused, the only reference is from the wrapper to the wrapped object. KoWrapObs
51
+ * should not be disposed; its lifetime is tied to that of the wrapped object.
32
52
  */
33
- export declare function fromKo<T>(koObservable: IKnockoutObservable<T>): Observable<T>;
53
+ export declare class KoWrapObs<T> extends Observable<T> {
54
+ private _koObs;
55
+ private _koSub;
56
+ constructor(_koObs: IKnockoutObservable<T>);
57
+ get(): T;
58
+ set(value: T): void;
59
+ dispose(): void;
60
+ }
34
61
  export interface IKnockoutModule {
35
62
  observable<T>(value: T): IKnockoutObservable<T>;
63
+ cleanNode(node: Node): void;
36
64
  }
37
65
  /**
38
66
  * Returns a Knockout observable which mirrors a Grain.js observable.
39
67
  */
40
68
  export declare function toKo<T>(knockout: IKnockoutModule, grainObs: Observable<T>): IKnockoutObservable<T>;
69
+ /**
70
+ * Set up integration between grainjs and knockout disposal. Knockout does cleanup using
71
+ * ko.removeNode / ko.cleanNode (it also takes care of JQuery cleanup if needed). GrainJS does
72
+ * cleanup using dom.domDispose(). By default these don't know about each other.
73
+ *
74
+ * If you mix the two libraries, however, disposing an element may need to trigger disposers
75
+ * registered by either library.
76
+ *
77
+ * This method ensures that this happens.
78
+ *
79
+ * Note: grainjs disposes text nodes too, but nothing relies on it. When disposal is triggered via
80
+ * knockout, we are forced to rely on knockout's node traversal which ignores text nodes.
81
+ */
82
+ export declare function setupKoDisposal(ko: IKnockoutModule): void;
@@ -20,26 +20,56 @@
20
20
  * knockout as a dependency of grainjs.
21
21
  *
22
22
  * In both cases, calling fromKo/toKo twice on the same observable will return the same wrapper,
23
- * and subscriptions and disposal are appropriately set up to make usage seamless.
23
+ * and subscriptions and disposal are appropriately set up to make usage seamless. In particular,
24
+ * the returned wrapper should not be disposed; it's tied to the lifetime of the wrapped object.
24
25
  */
25
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.setupKoDisposal = exports.toKo = exports.KoWrapObs = exports.fromKo = void 0;
28
+ const domDispose_1 = require("./domDispose");
26
29
  const observable_1 = require("./observable");
27
30
  const fromKoWrappers = new WeakMap();
28
31
  const toKoWrappers = new WeakMap();
29
32
  /**
30
33
  * Returns a Grain.js observable which mirrors a Knockout observable.
34
+ *
35
+ * Do not dispose this wrapper, as it is shared by all code using koObs, and its lifetime is tied
36
+ * to the lifetime of koObs. If unused, it consumes minimal resources, and should get garbage
37
+ * collected along with koObs.
31
38
  */
32
- function fromKo(koObservable) {
33
- const prevObs = fromKoWrappers.get(koObservable);
34
- if (prevObs) {
35
- return prevObs;
36
- }
37
- const newObs = observable_1.observable(koObservable.peek());
38
- fromKoWrappers.set(koObservable, newObs);
39
- koObservable.subscribe((val) => newObs.set(val));
40
- return newObs;
39
+ function fromKo(koObs) {
40
+ return fromKoWrappers.get(koObs) || fromKoWrappers.set(koObs, new KoWrapObs(koObs)).get(koObs);
41
41
  }
42
42
  exports.fromKo = fromKo;
43
+ /**
44
+ * An Observable that wraps a Knockout observable, created via fromKo(). It keeps minimal overhead
45
+ * when unused by only subscribing to the wrapped observable while it itself has subscriptions.
46
+ *
47
+ * This way, when unused, the only reference is from the wrapper to the wrapped object. KoWrapObs
48
+ * should not be disposed; its lifetime is tied to that of the wrapped object.
49
+ */
50
+ class KoWrapObs extends observable_1.Observable {
51
+ constructor(_koObs) {
52
+ super(_koObs.peek());
53
+ this._koObs = _koObs;
54
+ this._koSub = null;
55
+ this.setListenerChangeCB((hasListeners) => {
56
+ if (!hasListeners) {
57
+ this._koSub.dispose();
58
+ this._koSub = null;
59
+ }
60
+ else if (!this._koSub) {
61
+ // TODO this is a little hack, really, BaseObservable should expose a way to set the value
62
+ // directly by derived classes, i.e. a protected setter.
63
+ this._value = this._koObs.peek();
64
+ this._koSub = this._koObs.subscribe((val) => this.setAndTrigger(val));
65
+ }
66
+ });
67
+ }
68
+ get() { return this._koObs.peek(); }
69
+ set(value) { observable_1.bundleChanges(() => this._koObs(value)); }
70
+ dispose() { throw new Error("KoWrapObs should not be disposed"); }
71
+ }
72
+ exports.KoWrapObs = KoWrapObs;
43
73
  /**
44
74
  * Returns a Knockout observable which mirrors a Grain.js observable.
45
75
  */
@@ -54,4 +84,57 @@ function toKo(knockout, grainObs) {
54
84
  return newKoObs;
55
85
  }
56
86
  exports.toKo = toKo;
87
+ // Marker for when knockout-disposal integration has already been setup.
88
+ let koDisposalIsSetup = false;
89
+ /**
90
+ * Set up integration between grainjs and knockout disposal. Knockout does cleanup using
91
+ * ko.removeNode / ko.cleanNode (it also takes care of JQuery cleanup if needed). GrainJS does
92
+ * cleanup using dom.domDispose(). By default these don't know about each other.
93
+ *
94
+ * If you mix the two libraries, however, disposing an element may need to trigger disposers
95
+ * registered by either library.
96
+ *
97
+ * This method ensures that this happens.
98
+ *
99
+ * Note: grainjs disposes text nodes too, but nothing relies on it. When disposal is triggered via
100
+ * knockout, we are forced to rely on knockout's node traversal which ignores text nodes.
101
+ */
102
+ function setupKoDisposal(ko) {
103
+ // Ensure we don't do the setup more than once, or things will get called multiple times.
104
+ if (koDisposalIsSetup) {
105
+ return;
106
+ }
107
+ koDisposalIsSetup = true;
108
+ const koDomNodeDisposal = ko.utils.domNodeDisposal;
109
+ // Knockout by default has an external-data-cleanup func set to cleanup JQuery. Whatever it is
110
+ // set to, we will continue calling it, and also will call grainjs domDisposeNode.
111
+ const origKoCleanExternalData = koDomNodeDisposal.cleanExternalData;
112
+ // The original function called by grainjs to clean nodes recursively. We'll override it.
113
+ const origGrainDisposeRecursive = domDispose_1.domDisposeHooks.disposeRecursive;
114
+ // New function called by knockout to do extra cleanup. Now calls grainjs single-node cleanup.
115
+ // (In knockout, we can only override single-node cleanup.)
116
+ function newKoCleanExternalData(node) {
117
+ origKoCleanExternalData(node);
118
+ domDispose_1.domDisposeHooks.disposeNode(node);
119
+ }
120
+ // Function called by grainjs to clean nodes recursively. We override the recursive cleanup
121
+ // function to call the recursive knockout cleanup (letting knockout do the dom traversal it
122
+ // normally does).
123
+ function newGrainDisposeRecursive(node) {
124
+ origGrainDisposeRecursive(node);
125
+ // While doing knockout cleanup, do NOT have it call grainjs cleanup too, as that would cause
126
+ // multiple unnecessary traversals of DOM.
127
+ koDomNodeDisposal.cleanExternalData = origKoCleanExternalData;
128
+ try {
129
+ ko.cleanNode(node);
130
+ }
131
+ finally {
132
+ koDomNodeDisposal.cleanExternalData = newKoCleanExternalData;
133
+ }
134
+ }
135
+ // Use knockout and grainjs hooks to actually set the new cleanup functions.
136
+ koDomNodeDisposal.cleanExternalData = newKoCleanExternalData;
137
+ domDispose_1.domDisposeHooks.disposeRecursive = newGrainDisposeRecursive;
138
+ }
139
+ exports.setupKoDisposal = setupKoDisposal;
57
140
  //# sourceMappingURL=kowrap.js.map