@tanstack/angular-table 9.0.0-alpha.49 → 9.0.0-alpha.51

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.
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, input, inject, Directive, reflectComponentType, Injectable, KeyValueDiffers, ChangeDetectorRef, OutputEmitterRef, TemplateRef, Type, runInInjectionContext, computed, effect, untracked, Injector, ViewContainerRef, DestroyRef, NgZone, signal, assertInInjectionContext } from '@angular/core';
3
3
  import { constructTable, createColumnHelper } from '@tanstack/table-core';
4
4
  export * from '@tanstack/table-core';
5
- import { toObservable } from '@angular/core/rxjs-interop';
5
+ import { batch, createAtom } from '@tanstack/angular-store';
6
6
  export { shallow } from '@tanstack/angular-store';
7
7
 
8
8
  /**
@@ -1113,59 +1113,140 @@ function lazyInit(initializer) {
1113
1113
  });
1114
1114
  }
1115
1115
 
1116
- function signalToReadonlyAtom(signal, injector) {
1117
- return Object.assign(signal, {
1118
- get: () => signal(),
1119
- subscribe: (observer) => {
1120
- return toObservable(computed(signal), { injector: injector }).subscribe(observer);
1116
+ const optionsStoreDebugName = 'table/optionsStore';
1117
+ function observerToCallback(observerOrNext) {
1118
+ return typeof observerOrNext === 'function'
1119
+ ? observerOrNext
1120
+ : (value) => observerOrNext.next?.(value);
1121
+ }
1122
+ function signalToReadonlyAtom(source, getSource, subscribeSource) {
1123
+ return Object.assign(source, {
1124
+ get: () => {
1125
+ const value = getSource();
1126
+ source();
1127
+ return value;
1121
1128
  },
1129
+ subscribe: subscribeSource,
1122
1130
  });
1123
1131
  }
1124
- function signalToWritableAtom(signal, injector) {
1125
- return Object.assign(signal.asReadonly(), {
1132
+ function signalToWritableAtom(source, injector) {
1133
+ const observers = new Set();
1134
+ let observed = false;
1135
+ effect(() => {
1136
+ const value = source();
1137
+ if (!observed) {
1138
+ observed = true;
1139
+ return;
1140
+ }
1141
+ observers.forEach((observer) => observer(value));
1142
+ }, { injector });
1143
+ return Object.assign(source.asReadonly(), {
1126
1144
  set: (updater) => {
1127
1145
  typeof updater === 'function'
1128
- ? signal.update(updater)
1129
- : signal.set(updater);
1130
- },
1131
- get: () => signal(),
1132
- subscribe: (observer) => {
1133
- return toObservable(computed(signal), { injector: injector }).subscribe(observer);
1146
+ ? source.update(updater)
1147
+ : source.set(updater);
1134
1148
  },
1149
+ get: () => source(),
1150
+ subscribe: ((observerOrNext) => {
1151
+ const observer = observerToCallback(observerOrNext);
1152
+ observers.add(observer);
1153
+ return {
1154
+ unsubscribe: () => observers.delete(observer),
1155
+ };
1156
+ }),
1135
1157
  });
1136
1158
  }
1137
1159
  /**
1138
1160
  * Creates the table-core reactivity bindings used by the Angular adapter.
1139
1161
  *
1140
- * Readonly table atoms are backed by Angular `computed` signals and writable
1141
- * atoms by Angular `signal`. Subscriptions bridge through `toObservable` with
1142
- * the caller's injector so table APIs can be consumed from Angular `computed`
1143
- * and `effect` calls.
1162
+ * Table state atoms are backed by TanStack Store atoms. The options store stays
1163
+ * framework-native because row-model APIs read `table.options` directly during
1164
+ * render. Readonly table atoms bridge Store dependency tracking into Angular
1165
+ * computed signals.
1144
1166
  */
1145
1167
  function angularReactivity(injector) {
1146
1168
  const ngZone = injector.get(NgZone);
1169
+ const destroyRef = injector.get(DestroyRef);
1147
1170
  return {
1148
1171
  createOptionsStore: true,
1149
1172
  schedule: (fn) => ngZone.runOutsideAngular(() => queueMicrotask(fn)),
1150
1173
  createReadonlyAtom: (fn, options) => {
1151
- const signal = computed(() => fn(), {
1174
+ const storeAtom = createAtom(() => fn(), {
1175
+ compare: options?.compare,
1176
+ });
1177
+ const version = signal(0, { ...(ngDevMode ? { debugName: "version" } : /* istanbul ignore next */ {}), equal: () => false });
1178
+ const subscription = storeAtom.subscribe(() => {
1179
+ version.update((value) => value + 1);
1180
+ });
1181
+ destroyRef.onDestroy(() => subscription.unsubscribe());
1182
+ const value = computed(() => {
1183
+ version();
1184
+ return storeAtom.get();
1185
+ }, {
1152
1186
  equal: options?.compare,
1153
1187
  debugName: options?.debugName,
1154
1188
  });
1155
- return signalToReadonlyAtom(signal, injector);
1189
+ return signalToReadonlyAtom(value, () => storeAtom.get(), (observerOrNext) => {
1190
+ const observer = observerToCallback(observerOrNext);
1191
+ return storeAtom.subscribe(() => {
1192
+ observer(storeAtom.get());
1193
+ });
1194
+ });
1156
1195
  },
1157
1196
  createWritableAtom: (value, options) => {
1158
- const writableSignal = signal(value, {
1159
- equal: options?.compare,
1160
- debugName: options?.debugName,
1197
+ if (options?.debugName === optionsStoreDebugName) {
1198
+ const writableSignal = signal(value, {
1199
+ equal: options.compare,
1200
+ debugName: options.debugName,
1201
+ });
1202
+ return signalToWritableAtom(writableSignal, injector);
1203
+ }
1204
+ return createAtom(value, {
1205
+ compare: options?.compare,
1161
1206
  });
1162
- return signalToWritableAtom(writableSignal, injector);
1163
1207
  },
1164
1208
  untrack: untracked,
1165
- batch: (fn) => fn(),
1209
+ batch,
1166
1210
  };
1167
1211
  }
1168
1212
 
1213
+ function createStateProxy(table) {
1214
+ const getSnapshot = () => {
1215
+ const snapshot = {};
1216
+ const stateKeys = Object.keys(table.initialState);
1217
+ for (const key of stateKeys) {
1218
+ snapshot[key] = table.atoms[key].get();
1219
+ }
1220
+ return snapshot;
1221
+ };
1222
+ const target = {};
1223
+ return new Proxy(target, {
1224
+ get(target, prop, receiver) {
1225
+ if (prop === 'toJSON') {
1226
+ return getSnapshot;
1227
+ }
1228
+ if (typeof prop === 'string' && prop in table.initialState) {
1229
+ return table.atoms[prop]?.get();
1230
+ }
1231
+ return Reflect.get(target, prop, receiver);
1232
+ },
1233
+ has(_, prop) {
1234
+ return typeof prop === 'string' && prop in table.initialState;
1235
+ },
1236
+ ownKeys() {
1237
+ return Reflect.ownKeys(table.initialState);
1238
+ },
1239
+ getOwnPropertyDescriptor(_, prop) {
1240
+ if (typeof prop !== 'string' || !(prop in table.initialState)) {
1241
+ return undefined;
1242
+ }
1243
+ return {
1244
+ enumerable: true,
1245
+ configurable: true,
1246
+ };
1247
+ },
1248
+ });
1249
+ }
1169
1250
  /**
1170
1251
  * Creates and returns an Angular-reactive table instance.
1171
1252
  *
@@ -1234,6 +1315,14 @@ function injectTable(options) {
1234
1315
  ...options()._features,
1235
1316
  },
1236
1317
  });
1318
+ const stateProxy = createStateProxy(table);
1319
+ Object.defineProperty(table, 'state', {
1320
+ get() {
1321
+ return stateProxy;
1322
+ },
1323
+ configurable: true,
1324
+ enumerable: true,
1325
+ });
1237
1326
  let isMount = true;
1238
1327
  effect(() => {
1239
1328
  const newOptions = options();