@forcecalendar/interface 1.0.31 → 1.0.33

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forcecalendar/interface",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
4
4
  "type": "module",
5
5
  "description": "Official interface layer for forceCalendar Core - Enterprise calendar components",
6
6
  "main": "dist/force-calendar-interface.umd.js",
@@ -91,21 +91,23 @@ export class ForceCalendar extends BaseComponent {
91
91
  forwardEventAction('remove', data);
92
92
  })
93
93
  );
94
+ // Specific lifecycle events — do NOT call forwardEventAction here; the
95
+ // canonical event:add/update/remove handlers above already forward the
96
+ // generic CustomEvent. These handlers emit only the specific variant so
97
+ // consumers that care about the distinction can subscribe to it without
98
+ // receiving the generic event a second time.
94
99
  this._busUnsubscribers.push(
95
100
  eventBus.on('event:added', data => {
96
- forwardEventAction('add', data);
97
101
  this.emit('calendar-event-added', data);
98
102
  })
99
103
  );
100
104
  this._busUnsubscribers.push(
101
105
  eventBus.on('event:updated', data => {
102
- forwardEventAction('update', data);
103
106
  this.emit('calendar-event-updated', data);
104
107
  })
105
108
  );
106
109
  this._busUnsubscribers.push(
107
110
  eventBus.on('event:deleted', data => {
108
- forwardEventAction('remove', data);
109
111
  this.emit('calendar-event-deleted', data);
110
112
  })
111
113
  );
@@ -46,12 +46,21 @@ class StateManager {
46
46
 
47
47
  /**
48
48
  * Sync state.events from Core calendar (single source of truth)
49
- * This ensures state.events always matches Core's event store
49
+ * This ensures state.events always matches Core's event store.
50
+ *
51
+ * @param {object} options
52
+ * @param {boolean} options.silent - suppress subscriber notifications
53
+ * @param {boolean} options.force - always update even when IDs match
54
+ * (required after updateEvent where IDs
55
+ * are unchanged but content has changed)
50
56
  */
51
57
  _syncEventsFromCore(options = {}) {
58
+ const { force = false } = options;
52
59
  const coreEvents = this.calendar.getEvents() || [];
53
- // Only update if different to avoid unnecessary re-renders
60
+ // Skip the update when nothing changed, unless the caller forces a sync
61
+ // (e.g. after updateEvent where IDs are the same but content differs)
54
62
  if (
63
+ force ||
55
64
  this.state.events.length !== coreEvents.length ||
56
65
  !this._eventsMatch(this.state.events, coreEvents)
57
66
  ) {
@@ -61,7 +70,9 @@ class StateManager {
61
70
  }
62
71
 
63
72
  /**
64
- * Check if two event arrays have the same events (by id)
73
+ * Check if two event arrays have the same events by id.
74
+ * Only used for add/delete guards — updateEvent must pass force:true
75
+ * to bypass this check because IDs are unchanged after an update.
65
76
  */
66
77
  _eventsMatch(arr1, arr2) {
67
78
  if (arr1.length !== arr2.length) return false;
@@ -240,8 +251,9 @@ class StateManager {
240
251
  return null;
241
252
  }
242
253
 
243
- // Sync from Core to ensure consistency (single source of truth)
244
- this._syncEventsFromCore();
254
+ // Force sync from Core IDs are unchanged after an update so the
255
+ // ID-only guard in _eventsMatch would otherwise skip the state update
256
+ this._syncEventsFromCore({ force: true });
245
257
  eventBus.emit('event:update', { event });
246
258
  eventBus.emit('event:updated', { event });
247
259
  return event;