ctrl-fx 0.0.1 → 0.1.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.
Files changed (145) hide show
  1. package/dist/clipboard.d.ts +7 -0
  2. package/dist/clipboard.d.ts.map +1 -0
  3. package/dist/clipboard.js +3 -0
  4. package/dist/db/effects.d.ts +78 -0
  5. package/dist/db/effects.d.ts.map +1 -0
  6. package/dist/db/effects.js +98 -0
  7. package/dist/db/errors.d.ts +21 -0
  8. package/dist/db/errors.d.ts.map +1 -0
  9. package/dist/db/errors.js +13 -0
  10. package/dist/db/index.d.ts +32 -0
  11. package/dist/db/index.d.ts.map +1 -0
  12. package/dist/db/index.js +19 -0
  13. package/dist/db/keypath.d.ts +40 -0
  14. package/dist/db/keypath.d.ts.map +1 -0
  15. package/dist/db/keypath.js +20 -0
  16. package/dist/db/setup.d.ts +83 -0
  17. package/dist/db/setup.d.ts.map +1 -0
  18. package/dist/db/setup.js +100 -0
  19. package/dist/db/testdb.d.ts +19 -0
  20. package/dist/db/testdb.d.ts.map +1 -0
  21. package/dist/db/testdb.js +34 -0
  22. package/dist/dom/attrs.d.ts +67 -0
  23. package/dist/dom/attrs.d.ts.map +1 -0
  24. package/dist/dom/attrs.js +154 -0
  25. package/dist/dom/components.d.ts +43 -0
  26. package/dist/dom/components.d.ts.map +1 -0
  27. package/dist/dom/components.js +86 -0
  28. package/dist/dom/elems.d.ts +121 -0
  29. package/dist/dom/elems.d.ts.map +1 -0
  30. package/dist/dom/elems.js +52 -0
  31. package/dist/dom/events.d.ts +232 -0
  32. package/dist/dom/events.d.ts.map +1 -0
  33. package/dist/dom/events.js +289 -0
  34. package/dist/dom/index.d.ts +248 -0
  35. package/dist/dom/index.d.ts.map +1 -0
  36. package/dist/dom/index.js +266 -0
  37. package/dist/dom/nodeid.d.ts +9 -0
  38. package/dist/dom/nodeid.d.ts.map +1 -0
  39. package/dist/dom/nodeid.js +27 -0
  40. package/dist/dom/svg.d.ts +23 -0
  41. package/dist/dom/svg.d.ts.map +1 -0
  42. package/dist/dom/svg.js +1 -0
  43. package/dist/dom/views.d.ts +60 -0
  44. package/dist/dom/views.d.ts.map +1 -0
  45. package/dist/dom/views.js +154 -0
  46. package/dist/effects.d.ts +580 -0
  47. package/dist/effects.d.ts.map +1 -0
  48. package/dist/effects.js +1556 -0
  49. package/dist/index.d.ts +41 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +78 -0
  52. package/dist/internal/clipboard.d.ts +5 -0
  53. package/dist/internal/clipboard.d.ts.map +1 -0
  54. package/dist/internal/clipboard.js +33 -0
  55. package/dist/internal/cmpmgr.d.ts +46 -0
  56. package/dist/internal/cmpmgr.d.ts.map +1 -0
  57. package/dist/internal/cmpmgr.js +561 -0
  58. package/dist/internal/dbmgr.d.ts +11 -0
  59. package/dist/internal/dbmgr.d.ts.map +1 -0
  60. package/dist/internal/dbmgr.js +200 -0
  61. package/dist/internal/dominterpreter.d.ts +5 -0
  62. package/dist/internal/dominterpreter.d.ts.map +1 -0
  63. package/dist/internal/dominterpreter.js +337 -0
  64. package/dist/internal/eventmgr.d.ts +41 -0
  65. package/dist/internal/eventmgr.d.ts.map +1 -0
  66. package/dist/internal/eventmgr.js +696 -0
  67. package/dist/internal/index.d.ts +19 -0
  68. package/dist/internal/index.d.ts.map +1 -0
  69. package/dist/internal/index.js +38 -0
  70. package/dist/internal/interpreter.d.ts +10 -0
  71. package/dist/internal/interpreter.d.ts.map +1 -0
  72. package/dist/internal/interpreter.js +1 -0
  73. package/dist/internal/locutils.d.ts +4 -0
  74. package/dist/internal/locutils.d.ts.map +1 -0
  75. package/dist/internal/locutils.js +22 -0
  76. package/dist/internal/net.d.ts +4 -0
  77. package/dist/internal/net.d.ts.map +1 -0
  78. package/dist/internal/net.js +64 -0
  79. package/dist/internal/realdom.d.ts +249 -0
  80. package/dist/internal/realdom.d.ts.map +1 -0
  81. package/dist/internal/realdom.js +1 -0
  82. package/dist/internal/styleregistry.d.ts +6 -0
  83. package/dist/internal/styleregistry.d.ts.map +1 -0
  84. package/dist/internal/styleregistry.js +18 -0
  85. package/dist/internal/taskreg.d.ts +9 -0
  86. package/dist/internal/taskreg.d.ts.map +1 -0
  87. package/dist/internal/taskreg.js +28 -0
  88. package/dist/internal/testing.d.ts +12 -0
  89. package/dist/internal/testing.d.ts.map +1 -0
  90. package/dist/internal/testing.js +974 -0
  91. package/dist/internal/testinginterpreter.d.ts +10 -0
  92. package/dist/internal/testinginterpreter.d.ts.map +1 -0
  93. package/dist/internal/testinginterpreter.js +646 -0
  94. package/dist/internal/vdom.d.ts +93 -0
  95. package/dist/internal/vdom.d.ts.map +1 -0
  96. package/dist/internal/vdom.js +470 -0
  97. package/dist/json/index.d.ts +5 -0
  98. package/dist/json/index.d.ts.map +1 -0
  99. package/dist/json/index.js +2 -0
  100. package/dist/json/validation.d.ts +28 -0
  101. package/dist/json/validation.d.ts.map +1 -0
  102. package/dist/json/validation.js +8 -0
  103. package/dist/net/fragment.d.ts +10 -0
  104. package/dist/net/fragment.d.ts.map +1 -0
  105. package/dist/net/fragment.js +27 -0
  106. package/dist/net/index.d.ts +42 -0
  107. package/dist/net/index.d.ts.map +1 -0
  108. package/dist/net/index.js +60 -0
  109. package/dist/net/location.d.ts +21 -0
  110. package/dist/net/location.d.ts.map +1 -0
  111. package/dist/net/location.js +41 -0
  112. package/dist/net/path.d.ts +12 -0
  113. package/dist/net/path.d.ts.map +1 -0
  114. package/dist/net/path.js +29 -0
  115. package/dist/net/queryparam.d.ts +10 -0
  116. package/dist/net/queryparam.d.ts.map +1 -0
  117. package/dist/net/queryparam.js +34 -0
  118. package/dist/router.d.ts +40 -0
  119. package/dist/router.d.ts.map +1 -0
  120. package/dist/router.js +77 -0
  121. package/dist/scroll.d.ts +7 -0
  122. package/dist/scroll.d.ts.map +1 -0
  123. package/dist/scroll.js +3 -0
  124. package/dist/testing.d.ts +248 -0
  125. package/dist/testing.d.ts.map +1 -0
  126. package/dist/testing.js +159 -0
  127. package/dist/utils/apply.d.ts +9 -0
  128. package/dist/utils/apply.d.ts.map +1 -0
  129. package/dist/utils/apply.js +10 -0
  130. package/dist/utils/index.d.ts +22 -0
  131. package/dist/utils/index.d.ts.map +1 -0
  132. package/dist/utils/index.js +138 -0
  133. package/dist/utils/lens.d.ts +18 -0
  134. package/dist/utils/lens.d.ts.map +1 -0
  135. package/dist/utils/lens.js +27 -0
  136. package/dist/utils/match.d.ts +17 -0
  137. package/dist/utils/match.d.ts.map +1 -0
  138. package/dist/utils/match.js +28 -0
  139. package/dist/utils/result.d.ts +47 -0
  140. package/dist/utils/result.d.ts.map +1 -0
  141. package/dist/utils/result.js +97 -0
  142. package/dist/webcomponent.d.ts +15 -0
  143. package/dist/webcomponent.d.ts.map +1 -0
  144. package/dist/webcomponent.js +43 -0
  145. package/package.json +1 -1
@@ -0,0 +1,200 @@
1
+ import { dbVersion } from '../db';
2
+ import { constraintError, notFoundError, unexpectedError, } from '../db/errors';
3
+ import { run as runDbEffect } from '../db/effects';
4
+ import { run as runDbSetupEffect } from '../db/setup';
5
+ import { failure, success } from '../utils/result';
6
+ export class DbManager {
7
+ constructor() {
8
+ Object.defineProperty(this, "openDatabases", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: new Map()
13
+ });
14
+ }
15
+ open(db, version, setup, callback) {
16
+ const idbFactory = globalThis.indexedDB;
17
+ if (!idbFactory) {
18
+ return callback(failure(unexpectedError({ message: 'IndexedDB not supported' })));
19
+ }
20
+ const openRequest = idbFactory.open(db, version);
21
+ openRequest.onblocked = _event => {
22
+ window.alert('A database upgrade is blocked. Please close other tabs with this app.');
23
+ };
24
+ let upgradeError = undefined;
25
+ openRequest.onupgradeneeded = versionChangeEvent => {
26
+ const idbDb = openRequest.result;
27
+ const tx = openRequest.transaction;
28
+ if (!tx) {
29
+ console.warn('Expected idb transaction to be non-null during upgrade');
30
+ return;
31
+ }
32
+ const oldVersion = dbVersion(versionChangeEvent.oldVersion);
33
+ const effect = setup(oldVersion);
34
+ try {
35
+ runDbSetupEffect(effect, setupInterpreter(idbDb, tx), _result => { });
36
+ }
37
+ catch (err) {
38
+ if (err instanceof Error)
39
+ upgradeError = err;
40
+ throw err;
41
+ }
42
+ };
43
+ openRequest.onerror = event => {
44
+ if (upgradeError instanceof DOMException) {
45
+ if (upgradeError.name === 'ConstraintError') {
46
+ return callback(failure(constraintError(upgradeError)));
47
+ }
48
+ if (upgradeError.name === 'NotFoundError') {
49
+ return callback(failure(notFoundError(upgradeError)));
50
+ }
51
+ }
52
+ return callback(failure(unexpectedError({
53
+ message: extractMessage(event),
54
+ cause: upgradeError,
55
+ })));
56
+ };
57
+ openRequest.onsuccess = _event => {
58
+ this.openDatabases.set(db, openRequest.result);
59
+ callback(success(undefined));
60
+ };
61
+ }
62
+ runTransaction(db, objectStores, mode, effect, callback) {
63
+ const idbDb = this.openDatabases.get(db);
64
+ if (!idbDb) {
65
+ return callback(failure(unexpectedError({ message: `Database '${db}' is not open` })));
66
+ }
67
+ const tx = idbDb.transaction([...objectStores], mode);
68
+ let txError = null;
69
+ tx.onerror = _event => {
70
+ txError = tx.error;
71
+ };
72
+ tx.onabort = _event => {
73
+ if (txError !== null) {
74
+ if (txError.name === 'ConstraintError') {
75
+ return callback(failure(constraintError(txError)));
76
+ }
77
+ if (txError.name === 'NotFoundError') {
78
+ return callback(failure(notFoundError(txError)));
79
+ }
80
+ return callback(failure(unexpectedError({ cause: txError })));
81
+ }
82
+ return callback(failure(unexpectedError({ message: 'Transaction aborted' })));
83
+ };
84
+ tx.oncomplete = _event => {
85
+ callback(success(undefined));
86
+ };
87
+ runDbEffect(effect, dbInterpreter(tx), _result => { });
88
+ }
89
+ }
90
+ function setupInterpreter(db, tx) {
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ return (op, onComplete) => {
93
+ switch (op._type) {
94
+ case 'CreateObjectStore': {
95
+ db.createObjectStore(op.objectStore, objectStoreKeyOptions(op.keyPath));
96
+ onComplete(undefined);
97
+ return;
98
+ }
99
+ case 'CreateIndex': {
100
+ const store = tx.objectStore(op.objectStore);
101
+ store.createIndex(op.index, indexKeyPathValue(op.keyPath), {
102
+ unique: op.unique,
103
+ });
104
+ onComplete(undefined);
105
+ return;
106
+ }
107
+ case 'DeleteObjectStore': {
108
+ db.deleteObjectStore(op.objectStore);
109
+ onComplete(undefined);
110
+ return;
111
+ }
112
+ case 'DeleteIndex': {
113
+ const store = tx.objectStore(op.objectStore);
114
+ store.deleteIndex(op.index);
115
+ onComplete(undefined);
116
+ return;
117
+ }
118
+ case 'GetObjectStoreNames': {
119
+ onComplete(Array.from(db.objectStoreNames));
120
+ return;
121
+ }
122
+ case 'GetIndexNames': {
123
+ const store = tx.objectStore(op.objectStore);
124
+ onComplete(Array.from(store.indexNames));
125
+ return;
126
+ }
127
+ case 'RunDbEffect': {
128
+ runDbEffect(op.effect, dbInterpreter(tx), _result => onComplete(undefined));
129
+ return;
130
+ }
131
+ }
132
+ };
133
+ }
134
+ function dbInterpreter(tx) {
135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
+ return (op, onComplete) => {
137
+ switch (op._type) {
138
+ case 'Add': {
139
+ const req = tx.objectStore(op.objectStore).add(op.value);
140
+ req.onsuccess = () => onComplete(undefined);
141
+ return;
142
+ }
143
+ case 'Put': {
144
+ const req = tx.objectStore(op.objectStore).put(op.value);
145
+ req.onsuccess = () => onComplete(undefined);
146
+ return;
147
+ }
148
+ case 'Get': {
149
+ const req = tx.objectStore(op.objectStore).get(op.key);
150
+ req.onsuccess = () => onComplete(req.result ?? undefined);
151
+ return;
152
+ }
153
+ case 'GetAll': {
154
+ const req = tx.objectStore(op.objectStore).getAll();
155
+ req.onsuccess = () => onComplete(req.result);
156
+ return;
157
+ }
158
+ case 'Delete': {
159
+ const req = tx.objectStore(op.objectStore).delete(op.key);
160
+ req.onsuccess = () => onComplete(undefined);
161
+ return;
162
+ }
163
+ case 'Count': {
164
+ const req = tx.objectStore(op.objectStore).count();
165
+ req.onsuccess = () => onComplete(req.result);
166
+ return;
167
+ }
168
+ }
169
+ };
170
+ }
171
+ function objectStoreKeyOptions(keyPath) {
172
+ switch (keyPath._type) {
173
+ case 'AutoIncrement':
174
+ return { keyPath: keyPath.value, autoIncrement: true };
175
+ case 'Manual':
176
+ return { keyPath: keyPath.value, autoIncrement: false };
177
+ case 'Multi':
178
+ return {
179
+ keyPath: [keyPath.first, keyPath.second, ...keyPath.rest],
180
+ autoIncrement: false,
181
+ };
182
+ }
183
+ }
184
+ function indexKeyPathValue(keyPath) {
185
+ switch (keyPath._type) {
186
+ case 'SingleIndex':
187
+ return keyPath.value;
188
+ case 'MultiIndex':
189
+ return [keyPath.first, keyPath.second, ...keyPath.rest];
190
+ }
191
+ }
192
+ function extractMessage(event) {
193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
+ const m = event.message;
195
+ if (typeof m === 'string')
196
+ return m;
197
+ if (m != null)
198
+ return `${m}`;
199
+ return undefined;
200
+ }
@@ -0,0 +1,5 @@
1
+ import { type Effect } from '../effects';
2
+ import type { Callbacks } from './interpreter';
3
+ import { TaskRegistry } from './taskreg';
4
+ export declare function domInterpreter<State, Event, A>(effect: Effect<State, Event, A>, callbacks: Callbacks<State, Event, A>, taskRegistry: TaskRegistry): void;
5
+ //# sourceMappingURL=dominterpreter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dominterpreter.d.ts","sourceRoot":"","sources":["../../src/internal/dominterpreter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,MAAM,EAAe,MAAM,YAAY,CAAA;AAK7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAI9C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAIxC,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAC5C,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EAC/B,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EACrC,YAAY,EAAE,YAAY,GACzB,IAAI,CAobN"}
@@ -0,0 +1,337 @@
1
+ import { generateUuid } from '.';
2
+ import { permission } from '..';
3
+ import { taskId } from '../effects';
4
+ import { formatLocation, parseInternalLocation } from '../net/location';
5
+ import { scrollElementError } from '../scroll';
6
+ import { failure, success } from '../utils/result';
7
+ import { exhaustivenessCheck } from '../utils';
8
+ import { readClipboard, writeClipboard } from './clipboard';
9
+ import { DbManager } from './dbmgr';
10
+ import { makeHttpRequest } from './net';
11
+ import { TaskRegistry } from './taskreg';
12
+ const dbManager = new DbManager();
13
+ export function domInterpreter(effect, callbacks, taskRegistry) {
14
+ switch (effect._type) {
15
+ case 'Return': {
16
+ callbacks.onComplete(effect.value);
17
+ return;
18
+ }
19
+ case 'FlatMap': {
20
+ domInterpreter(effect.effect, {
21
+ ...callbacks,
22
+ onComplete(result) {
23
+ domInterpreter(effect.next(result), callbacks, taskRegistry);
24
+ },
25
+ }, taskRegistry);
26
+ return;
27
+ }
28
+ case 'Suspend': {
29
+ switch (effect.operation._type) {
30
+ case 'Alert': {
31
+ globalThis.window.alert(effect.operation.input);
32
+ callbacks.onComplete(undefined);
33
+ return;
34
+ }
35
+ case 'Confirm': {
36
+ callbacks.onComplete(globalThis.window.confirm(effect.operation.input));
37
+ return;
38
+ }
39
+ case 'Prompt': {
40
+ callbacks.onComplete(globalThis.window.prompt(effect.operation.input.message, effect.operation.input.default));
41
+ return;
42
+ }
43
+ case 'GetNotificationPermission': {
44
+ callbacks.onComplete(permission(globalThis.Notification.permission));
45
+ return;
46
+ }
47
+ case 'RequestNotificationPermission': {
48
+ globalThis.Notification.requestPermission().then(perm => {
49
+ callbacks.onComplete(permission(perm));
50
+ });
51
+ return;
52
+ }
53
+ case 'GetLocation': {
54
+ const loc = globalThis.window.location;
55
+ callbacks.onComplete(parseInternalLocation(loc.pathname + loc.search + loc.hash));
56
+ return;
57
+ }
58
+ case 'Async': {
59
+ const { effect: innerEffect, delayInMillis } = effect.operation.input;
60
+ setTimeout(() => {
61
+ domInterpreter(innerEffect, { ...callbacks, onComplete() { } }, taskRegistry);
62
+ }, delayInMillis);
63
+ callbacks.onComplete(undefined);
64
+ return;
65
+ }
66
+ case 'CancelTask': {
67
+ taskRegistry.cancel(effect.operation.input);
68
+ callbacks.onComplete(undefined);
69
+ return;
70
+ }
71
+ case 'ClearAppBadge': {
72
+ if (globalThis.navigator.clearAppBadge) {
73
+ globalThis.navigator.clearAppBadge();
74
+ }
75
+ callbacks.onComplete(undefined);
76
+ return;
77
+ }
78
+ case 'SetAppBadge': {
79
+ if (globalThis.navigator.setAppBadge) {
80
+ globalThis.navigator.setAppBadge(effect.operation.input);
81
+ }
82
+ callbacks.onComplete(undefined);
83
+ return;
84
+ }
85
+ case 'SetDocumentTitle': {
86
+ globalThis.document.title = effect.operation.input;
87
+ callbacks.onComplete(undefined);
88
+ return;
89
+ }
90
+ case 'FireEvent': {
91
+ callbacks.onFireEvent(effect.operation.input);
92
+ callbacks.onComplete(undefined);
93
+ return;
94
+ }
95
+ case 'GetState': {
96
+ callbacks.onComplete(callbacks.getState());
97
+ return;
98
+ }
99
+ case 'GetTime': {
100
+ callbacks.onComplete(new Date());
101
+ return;
102
+ }
103
+ case 'GetRandom': {
104
+ callbacks.onComplete(Math.random());
105
+ return;
106
+ }
107
+ case 'MakeHttpRequest': {
108
+ makeHttpRequest(effect.operation.input, result => callbacks.onComplete(result));
109
+ return;
110
+ }
111
+ case 'Log': {
112
+ console.log(effect.operation.input);
113
+ callbacks.onComplete(undefined);
114
+ return;
115
+ }
116
+ case 'Product': {
117
+ let resultA = '__ctrl_fx_unset_result';
118
+ let resultB = '__ctrl_fx_unset_result';
119
+ domInterpreter(effect.operation.input[0], {
120
+ ...callbacks,
121
+ onComplete(a) {
122
+ resultA = a;
123
+ if (resultB !== '__ctrl_fx_unset_result') {
124
+ callbacks.onComplete([resultA, resultB]);
125
+ }
126
+ },
127
+ }, taskRegistry);
128
+ domInterpreter(effect.operation.input[1], {
129
+ ...callbacks,
130
+ onComplete(b) {
131
+ resultB = b;
132
+ if (resultA !== '__ctrl_fx_unset_result') {
133
+ callbacks.onComplete([resultA, resultB]);
134
+ }
135
+ },
136
+ }, taskRegistry);
137
+ return;
138
+ }
139
+ case 'ScheduleTask': {
140
+ let tskId;
141
+ // clear task if its already scheduled
142
+ if (effect.operation.input.taskId) {
143
+ taskRegistry.cancel(effect.operation.input.taskId);
144
+ tskId = effect.operation.input.taskId;
145
+ }
146
+ // setTimeout (one-shot)
147
+ if (effect.operation.input.repeatIntervalInMillis === undefined) {
148
+ const timerId = globalThis.setTimeout(() => {
149
+ domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
150
+ }, effect.operation.input.initialDelayInMillis);
151
+ tskId ||= taskId(generateUuid());
152
+ taskRegistry.set(tskId, () => clearTimeout(timerId));
153
+ // setInterval (delay == interval shortcut)
154
+ }
155
+ else if (effect.operation.input.initialDelayInMillis ===
156
+ effect.operation.input.repeatIntervalInMillis) {
157
+ const timerId = globalThis.setInterval(() => {
158
+ domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
159
+ }, effect.operation.input.repeatIntervalInMillis);
160
+ tskId ||= taskId(generateUuid());
161
+ taskRegistry.set(tskId, () => clearInterval(timerId));
162
+ }
163
+ else {
164
+ // initial delay differs from repeat interval: setTimeout then setInterval
165
+ tskId ||= taskId(generateUuid());
166
+ const timerId = globalThis.setTimeout(() => {
167
+ domInterpreter(effect.operation.input.task, {
168
+ ...callbacks,
169
+ onComplete() {
170
+ const newTimerId = globalThis.setInterval(() => {
171
+ domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
172
+ }, effect.operation.input.repeatIntervalInMillis);
173
+ taskRegistry.set(tskId, () => clearInterval(newTimerId));
174
+ },
175
+ }, taskRegistry);
176
+ }, effect.operation.input.initialDelayInMillis);
177
+ taskRegistry.set(tskId, () => clearTimeout(timerId));
178
+ }
179
+ callbacks.onComplete(tskId);
180
+ return;
181
+ }
182
+ case 'SetTimeout': {
183
+ setTimeout(() => {
184
+ callbacks.onComplete(undefined);
185
+ }, effect.operation.input);
186
+ return;
187
+ }
188
+ case 'PushState': {
189
+ const url = formatLocation(effect.operation.input);
190
+ history.pushState(null, '', url);
191
+ window.dispatchEvent(new Event('locationchange'));
192
+ callbacks.onComplete(undefined);
193
+ return;
194
+ }
195
+ case 'ReplaceState': {
196
+ const url = formatLocation(effect.operation.input);
197
+ history.replaceState(null, '', url);
198
+ window.dispatchEvent(new Event('locationchange'));
199
+ callbacks.onComplete(undefined);
200
+ return;
201
+ }
202
+ case 'Go': {
203
+ history.go(effect.operation.input);
204
+ callbacks.onComplete(undefined);
205
+ return;
206
+ }
207
+ case 'GetStorageItem': {
208
+ const store = effect.operation.input.storage === 'local'
209
+ ? localStorage
210
+ : sessionStorage;
211
+ callbacks.onComplete(store.getItem(effect.operation.input.key));
212
+ return;
213
+ }
214
+ case 'SetStorageItem': {
215
+ const store = effect.operation.input.storage === 'local'
216
+ ? localStorage
217
+ : sessionStorage;
218
+ store.setItem(effect.operation.input.key, effect.operation.input.value);
219
+ callbacks.onComplete(undefined);
220
+ return;
221
+ }
222
+ case 'RemoveStorageItem': {
223
+ const store = effect.operation.input.storage === 'local'
224
+ ? localStorage
225
+ : sessionStorage;
226
+ store.removeItem(effect.operation.input.key);
227
+ callbacks.onComplete(undefined);
228
+ return;
229
+ }
230
+ case 'ClearStorage': {
231
+ const store = effect.operation.input.storage === 'local'
232
+ ? localStorage
233
+ : sessionStorage;
234
+ store.clear();
235
+ callbacks.onComplete(undefined);
236
+ return;
237
+ }
238
+ case 'OpenDatabase': {
239
+ const { db, version, setup } = effect.operation.input;
240
+ dbManager.open(db, version, setup, result => {
241
+ callbacks.onComplete(result);
242
+ });
243
+ return;
244
+ }
245
+ case 'RunDbTransaction': {
246
+ const { db, objectStores, mode, effect: dbEffect, } = effect.operation.input;
247
+ dbManager.runTransaction(db, objectStores, mode, dbEffect, result => {
248
+ callbacks.onComplete(result);
249
+ });
250
+ return;
251
+ }
252
+ case 'UpdateState': {
253
+ callbacks.setState(effect.operation.input(callbacks.getState()));
254
+ callbacks.onComplete(undefined);
255
+ return;
256
+ }
257
+ case 'GenerateUuid': {
258
+ callbacks.onComplete(generateUuid());
259
+ return;
260
+ }
261
+ case 'ReadClipboard': {
262
+ readClipboard(result => callbacks.onComplete(result));
263
+ return;
264
+ }
265
+ case 'WriteClipboard': {
266
+ writeClipboard(effect.operation.input, result => callbacks.onComplete(result));
267
+ return;
268
+ }
269
+ case 'Download': {
270
+ const { filename, content, contentType } = effect.operation.input;
271
+ const blob = new Blob([content], { type: contentType });
272
+ const url = URL.createObjectURL(blob);
273
+ const a = globalThis.document.createElement('a');
274
+ a.href = url;
275
+ a.download = filename;
276
+ globalThis.document.body.appendChild(a);
277
+ a.click();
278
+ globalThis.document.body.removeChild(a);
279
+ URL.revokeObjectURL(url);
280
+ callbacks.onComplete(undefined);
281
+ return;
282
+ }
283
+ case 'PostBroadcastMessage': {
284
+ const bc = new BroadcastChannel(effect.operation.input.channel);
285
+ bc.postMessage(effect.operation.input.message);
286
+ bc.close();
287
+ callbacks.onComplete(undefined);
288
+ return;
289
+ }
290
+ case 'SubscribeToBroadcastChannel': {
291
+ const { channel, handler, taskId: tskIdInput } = effect.operation.input;
292
+ const tskId = tskIdInput ?? taskId(generateUuid());
293
+ const bc = new BroadcastChannel(channel);
294
+ bc.onmessage = (event) => {
295
+ domInterpreter(handler(event.data), { ...callbacks, onComplete() { } }, taskRegistry);
296
+ };
297
+ taskRegistry.set(tskId, () => bc.close());
298
+ callbacks.onComplete(tskId);
299
+ return;
300
+ }
301
+ case 'ScrollWindow': {
302
+ globalThis.window.scrollTo(effect.operation.input);
303
+ callbacks.onComplete(undefined);
304
+ return;
305
+ }
306
+ case 'ScrollElement': {
307
+ const { selector, options } = effect.operation.input;
308
+ const el = globalThis.document.querySelector(selector);
309
+ if (el === null) {
310
+ callbacks.onComplete(failure(scrollElementError(selector)));
311
+ }
312
+ else {
313
+ el.scrollTo(options);
314
+ callbacks.onComplete(success(undefined));
315
+ }
316
+ return;
317
+ }
318
+ case 'CustomEffect': {
319
+ const { args, f } = effect.operation.input;
320
+ const result = f(args);
321
+ if (result instanceof Promise) {
322
+ result.then(out => callbacks.onComplete(out));
323
+ }
324
+ else {
325
+ callbacks.onComplete(result);
326
+ }
327
+ return;
328
+ }
329
+ default:
330
+ exhaustivenessCheck(effect.operation);
331
+ }
332
+ break;
333
+ }
334
+ default:
335
+ exhaustivenessCheck(effect);
336
+ }
337
+ }
@@ -0,0 +1,41 @@
1
+ import { type EventListenerResult, type EventOptions } from '../dom/events';
2
+ import type { Effect } from '../effects';
3
+ import type { RealWindow } from './realdom';
4
+ import type { ComponentNode, InternalElementNode, ViewNode } from './vdom';
5
+ type ListenerTotals = {
6
+ regular: number;
7
+ capture: number;
8
+ };
9
+ type ListenerCounts<EventType extends string> = Record<EventType, ListenerTotals>;
10
+ export declare function makeListenerCounts<EventTypes extends readonly string[]>(eventTypes: EventTypes): ListenerCounts<(typeof eventTypes)[number]>;
11
+ /** Given current counts of all listeners, adjust them for a specific node given
12
+ * its old listeners and its new listeners. Return which listener counts have
13
+ * dropped to zero and which listener counts have gone from zero to a positive
14
+ * number. Also include a set of all the new event types.
15
+ */
16
+ export declare function adjustCountsAndGetListenerTypesToRemoveAndAdd<K extends string, L extends {
17
+ _type: K;
18
+ options?: EventOptions;
19
+ }>(counts: Record<K, ListenerTotals>, oldListeners: readonly L[], newListeners: readonly L[]): {
20
+ toRemove: Map<K, {
21
+ regular: boolean;
22
+ capture: boolean;
23
+ }>;
24
+ toAdd: Map<K, {
25
+ regular: boolean;
26
+ capture: boolean;
27
+ }>;
28
+ allNewEvents: Map<K, {
29
+ regular: boolean;
30
+ capture: boolean;
31
+ }>;
32
+ };
33
+ export declare class EventManager {
34
+ private containerDelegate;
35
+ private elementDelegate;
36
+ constructor(window: RealWindow, runEffect: (effect: Effect<unknown, unknown, EventListenerResult>, node: InternalElementNode | ComponentNode | ViewNode, onResult: (result: EventListenerResult) => void) => void);
37
+ setContainerListeners(node: ComponentNode | ViewNode): void;
38
+ setElementListeners(node: InternalElementNode): void;
39
+ }
40
+ export {};
41
+ //# sourceMappingURL=eventmgr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventmgr.d.ts","sourceRoot":"","sources":["../../src/internal/eventmgr.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAIxC,OAAO,KAAK,EAMV,UAAU,EACX,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAoB1E,KAAK,cAAc,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1D,KAAK,cAAc,CAAC,SAAS,SAAS,MAAM,IAAI,MAAM,CACpD,SAAS,EACT,cAAc,CACf,CAAA;AAED,wBAAgB,kBAAkB,CAAC,UAAU,SAAS,SAAS,MAAM,EAAE,EACrE,UAAU,EAAE,UAAU,GACrB,cAAc,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAK7C;AA2BD;;;;GAIG;AACH,wBAAgB,6CAA6C,CAC3D,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,EAE9C,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,EACjC,YAAY,EAAE,SAAS,CAAC,EAAE,EAC1B,YAAY,EAAE,SAAS,CAAC,EAAE,GACzB;IACD,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACxD,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACrD,YAAY,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAC7D,CA8FA;AA8pBD,qBAAa,YAAY;IACvB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,eAAe,CAA6B;gBAGlD,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,CACT,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC,EACrD,IAAI,EAAE,mBAAmB,GAAG,aAAa,GAAG,QAAQ,EACpD,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,KAC5C,IAAI;IASX,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,IAAI;IAI3D,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;CAGrD"}