turbo-web 4.3.0 → 4.5.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 (3) hide show
  1. package/README.md +9 -0
  2. package/dist/turbo.js +33 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -84,7 +84,10 @@ JavaScript object tree that represents the UI.
84
84
  ### [CORE] Feature 4: Components
85
85
  **Encapsulation & Reusability** principles: making UI building blocks with better combined hierarchical tree structure.
86
86
 
87
+ // Events accept additional modificator ```.stop .prevent``` to stop event bubbling and prevent default browser behaviour.
88
+
87
89
  ```component.js // building scheme: h(tagOrComponent, { attributes, class, style, on: events }, [children])```
90
+
88
91
  ### Feature 5: Client-Side Router (#hash-based)
89
92
  Allows for the **SPA design** (Single Page Application) with route guards (fn: checkNavigation) and a common "catch-all route" (cases: route not found). Based on a hash part of the URL, implemented with regex pattern matching by simulating URL path, parameters and query as part of the hash fragment itself.
90
93
 
@@ -190,4 +193,10 @@ onMounted() {
190
193
  onUnmounted() {
191
194
  if (this.unsubscribe) this.unsubscribe();
192
195
  },
196
+ ```
197
+ ### [6] Event bubbling & default browser behaviour override
198
+ It is possible to prevent both by passing additional modificators with functions.
199
+ ```
200
+ on: { 'click.stop': () => this.addLog('Button with .stop Clicked') }
201
+ on: { 'click.prevent': () => this.addLog('Link with .prevent Clicked') }
193
202
  ```
package/dist/turbo.js CHANGED
@@ -194,25 +194,42 @@ function hSlot(name = 'default', children = []) {
194
194
  return { type: DOM_TYPES.SLOT, name: name, children: children }
195
195
  }
196
196
 
197
- function addEventListener(eventName, handler, el, hostComponent = null) {
198
- function boundHandler() {
197
+ function addEventListener(eventNameWithModifiers, handlerConfig, el, hostComponent = null) {
198
+ const [eventName, ...modifiers] = eventNameWithModifiers.split('.');
199
+ const isDelegated = typeof handlerConfig === 'object' && handlerConfig.delegate;
200
+ const handler = isDelegated ? handlerConfig.handler : handlerConfig;
201
+ const selector = isDelegated ? handlerConfig.delegate : null;
202
+ function boundHandler(event) {
203
+ let target = event.target;
204
+ if (isDelegated) {
205
+ target = event.target.closest(selector);
206
+ if (!target || !el.contains(target)) return;
207
+ }
208
+ if (modifiers.includes('stop')) {
209
+ event.stopPropagation();
210
+ }
211
+ if (modifiers.includes('prevent')) {
212
+ event.preventDefault();
213
+ }
214
+ const args = isDelegated ? [event, target] : [event];
199
215
  hostComponent
200
- ? handler.apply(hostComponent, arguments)
201
- : handler(...arguments);
216
+ ? handler.apply(hostComponent, args)
217
+ : handler(...args);
202
218
  }
203
219
  el.addEventListener(eventName, boundHandler);
204
220
  return boundHandler
205
221
  }
206
222
  function addEventListeners(listeners = {}, el, hostComponent = null ) {
207
223
  const addedListeners = {};
208
- Object.entries(listeners).forEach(([eventName, handler]) => {
209
- const listener = addEventListener(eventName, handler, el, hostComponent);
224
+ Object.entries(listeners).forEach(([eventName, handlerConfig]) => {
225
+ const listener = addEventListener(eventName, handlerConfig, el, hostComponent);
210
226
  addedListeners[eventName] = listener;
211
227
  });
212
228
  return addedListeners
213
229
  }
214
230
  function removeEventListeners(listeners = {}, el) {
215
- Object.entries(listeners).forEach(([eventName, handler]) => {
231
+ Object.entries(listeners).forEach(([eventNameWithModifiers, handler]) => {
232
+ const eventName = eventNameWithModifiers.split('.')[0];
216
233
  el.removeEventListener(eventName, handler);
217
234
  });
218
235
  }
@@ -893,14 +910,15 @@ function patchStyles(el, oldStyle = {}, newStyle = {}) {
893
910
  }
894
911
  function patchEvents(el, oldListeners = {}, oldEvents = {}, newEvents = {}, hostComponent) {
895
912
  const { removed, added, updated } = objectsDiff(oldEvents, newEvents);
896
- for (const eventName of removed.concat(updated)) {
897
- el.removeEventListener(eventName, oldListeners[eventName]);
898
- }
899
- const addedListeners = {};
900
- for (const eventName of added.concat(updated)) {
901
- const listener =
902
- addEventListener(eventName, newEvents[eventName], el, hostComponent);
903
- addedListeners[eventName] = listener;
913
+ for (const eventNameWithModifiers of removed.concat(updated)) {
914
+ const eventName = eventNameWithModifiers.split('.')[0];
915
+ el.removeEventListener(eventName, oldListeners[eventNameWithModifiers]);
916
+ }
917
+ const addedListeners = { ...oldListeners };
918
+ removed.forEach(key => delete addedListeners[key]);
919
+ for (const eventNameWithModifiers of added.concat(updated)) {
920
+ const listener = addEventListener(eventNameWithModifiers, newEvents[eventNameWithModifiers], el, hostComponent);
921
+ addedListeners[eventNameWithModifiers] = listener;
904
922
  }
905
923
  return addedListeners
906
924
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo-web",
3
- "version": "4.3.0",
3
+ "version": "4.5.0",
4
4
  "main": "dist/turbo.js",
5
5
  "files": [
6
6
  "dist",