tangrid 0.1.0 → 1.0.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.
- package/README.md +20 -0
- package/config/package.json +3 -0
- package/fesm2022/tangrid-table-virtual-provider-DS8nOCc-.mjs +168 -0
- package/fesm2022/tangrid-table.mjs +35 -181
- package/fesm2022/tangrid-virtual-provider-DS8nOCc-.mjs +168 -0
- package/fesm2022/tangrid.mjs +35 -181
- package/package.json +13 -11
- package/styles/themes/ant-alt.css +1 -0
- package/styles/themes/ant.css +1 -0
- package/styles/themes/bootstrap.css +1 -0
- package/styles/themes/material.css +1 -0
- package/table/package.json +3 -0
- package/table/table.component.d.ts +6 -4
- package/theme/package.json +3 -0
- package/esm2022/config/ngs-config.mjs +0 -24
- package/esm2022/config/public-api.mjs +0 -2
- package/esm2022/config/tangrid-config.mjs +0 -5
- package/esm2022/index.mjs +0 -17
- package/esm2022/table/public-api.mjs +0 -4
- package/esm2022/table/table.component.mjs +0 -1433
- package/esm2022/table/table.module.mjs +0 -19
- package/esm2022/table/table.types.mjs +0 -2
- package/esm2022/table/tangrid-table.mjs +0 -5
- package/esm2022/table/virtual-provider.mjs +0 -165
- package/esm2022/tangrid.mjs +0 -5
- package/esm2022/theme/ngs-theme.service.mjs +0 -83
- package/esm2022/theme/public-api.mjs +0 -2
- package/esm2022/theme/tangrid-theme.mjs +0 -5
- package/fesm2022/tangrid-config.mjs.map +0 -1
- package/fesm2022/tangrid-table.mjs.map +0 -1
- package/fesm2022/tangrid-theme.mjs.map +0 -1
- package/fesm2022/tangrid.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -102,6 +102,26 @@ export class UsersTableComponent {
|
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
## Theming
|
|
106
|
+
|
|
107
|
+
The default theme is included with the component. For Material, Bootstrap, Ant, or Ant-alt themes, add the optional theme CSS to your global styles:
|
|
108
|
+
|
|
109
|
+
**angular.json:**
|
|
110
|
+
```json
|
|
111
|
+
"styles": [
|
|
112
|
+
"node_modules/tangrid/styles/themes/material.css",
|
|
113
|
+
"node_modules/tangrid/styles/themes/bootstrap.css"
|
|
114
|
+
]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Or in `styles.scss`:**
|
|
118
|
+
```scss
|
|
119
|
+
@import 'tangrid/styles/themes/material.css';
|
|
120
|
+
@import 'tangrid/styles/themes/bootstrap.css';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use the `[theme]` input to switch: `theme="default"` | `theme="material"` | `theme="bootstrap"` | `theme="ant"` | `theme="ant-alt"`.
|
|
124
|
+
|
|
105
125
|
## API Reference
|
|
106
126
|
|
|
107
127
|
### `<tan-grid>` Component
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { untracked, computed, signal, effect, afterNextRender, AfterRenderPhase, inject, DestroyRef } from '@angular/core';
|
|
2
|
+
import { Virtualizer, elementScroll, observeElementOffset, observeElementRect, windowScroll, observeWindowOffset, observeWindowRect } from '@tanstack/virtual-core';
|
|
3
|
+
|
|
4
|
+
function proxyVirtualizer(virtualizerSignal, lazyInit) {
|
|
5
|
+
return new Proxy(virtualizerSignal, {
|
|
6
|
+
apply() {
|
|
7
|
+
return virtualizerSignal();
|
|
8
|
+
},
|
|
9
|
+
get(target, property) {
|
|
10
|
+
const untypedTarget = target;
|
|
11
|
+
if (untypedTarget[property]) {
|
|
12
|
+
return untypedTarget[property];
|
|
13
|
+
}
|
|
14
|
+
let virtualizer = untracked(virtualizerSignal);
|
|
15
|
+
if (virtualizer == null) {
|
|
16
|
+
virtualizer = lazyInit();
|
|
17
|
+
untracked(() => virtualizerSignal.set(virtualizer));
|
|
18
|
+
}
|
|
19
|
+
// Create computed signals for each property that represents a reactive value
|
|
20
|
+
if (typeof property === 'string' &&
|
|
21
|
+
[
|
|
22
|
+
'getTotalSize',
|
|
23
|
+
'getVirtualItems',
|
|
24
|
+
'isScrolling',
|
|
25
|
+
'options',
|
|
26
|
+
'range',
|
|
27
|
+
'scrollDirection',
|
|
28
|
+
'scrollElement',
|
|
29
|
+
'scrollOffset',
|
|
30
|
+
'scrollRect',
|
|
31
|
+
'measureElementCache',
|
|
32
|
+
'measurementsCache',
|
|
33
|
+
].includes(property)) {
|
|
34
|
+
const isFunction = typeof virtualizer[property] === 'function';
|
|
35
|
+
Object.defineProperty(untypedTarget, property, {
|
|
36
|
+
value: isFunction
|
|
37
|
+
? computed(() => target()[property]())
|
|
38
|
+
: computed(() => target()[property]),
|
|
39
|
+
configurable: true,
|
|
40
|
+
enumerable: true,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Create plain signals for functions that accept arguments and return reactive values
|
|
44
|
+
if (typeof property === 'string' &&
|
|
45
|
+
[
|
|
46
|
+
'getOffsetForAlignment',
|
|
47
|
+
'getOffsetForIndex',
|
|
48
|
+
'getVirtualItemForOffset',
|
|
49
|
+
'indexFromElement',
|
|
50
|
+
].includes(property)) {
|
|
51
|
+
const fn = virtualizer[property];
|
|
52
|
+
Object.defineProperty(untypedTarget, property, {
|
|
53
|
+
value: toComputed(virtualizerSignal, fn),
|
|
54
|
+
configurable: true,
|
|
55
|
+
enumerable: true,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return untypedTarget[property] || virtualizer[property];
|
|
59
|
+
},
|
|
60
|
+
has(_, property) {
|
|
61
|
+
return !!untracked(virtualizerSignal)[property];
|
|
62
|
+
},
|
|
63
|
+
ownKeys() {
|
|
64
|
+
return Reflect.ownKeys(untracked(virtualizerSignal));
|
|
65
|
+
},
|
|
66
|
+
getOwnPropertyDescriptor() {
|
|
67
|
+
return {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function toComputed(signal, fn) {
|
|
75
|
+
const computedCache = {};
|
|
76
|
+
return (...args) => {
|
|
77
|
+
// Cache computeds by their arguments to avoid re-creating the computed on each call
|
|
78
|
+
const serializedArgs = serializeArgs(...args);
|
|
79
|
+
if (Object.prototype.hasOwnProperty.call(computedCache, serializedArgs)) {
|
|
80
|
+
return computedCache[serializedArgs]?.();
|
|
81
|
+
}
|
|
82
|
+
const computedSignal = computed(() => {
|
|
83
|
+
void signal();
|
|
84
|
+
return fn(...args);
|
|
85
|
+
});
|
|
86
|
+
computedCache[serializedArgs] = computedSignal;
|
|
87
|
+
return computedSignal();
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function serializeArgs(...args) {
|
|
91
|
+
return JSON.stringify(args);
|
|
92
|
+
}
|
|
93
|
+
function createVirtualizerBase(options) {
|
|
94
|
+
let virtualizer;
|
|
95
|
+
function lazyInit() {
|
|
96
|
+
if (!virtualizer) {
|
|
97
|
+
virtualizer = new Virtualizer(options());
|
|
98
|
+
}
|
|
99
|
+
return virtualizer;
|
|
100
|
+
}
|
|
101
|
+
const virtualizerSignal = signal(virtualizer, { equal: () => false });
|
|
102
|
+
// two-way sync options
|
|
103
|
+
effect(() => {
|
|
104
|
+
const _options = options();
|
|
105
|
+
lazyInit();
|
|
106
|
+
virtualizerSignal.set(virtualizer);
|
|
107
|
+
virtualizer.setOptions({
|
|
108
|
+
..._options,
|
|
109
|
+
onChange: (instance, sync) => {
|
|
110
|
+
// update virtualizerSignal so that dependent computeds recompute.
|
|
111
|
+
virtualizerSignal.set(instance);
|
|
112
|
+
_options.onChange?.(instance, sync);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
// update virtualizerSignal so that dependent computeds recompute.
|
|
116
|
+
virtualizerSignal.set(virtualizer);
|
|
117
|
+
}, { allowSignalWrites: true });
|
|
118
|
+
const scrollElement = computed(() => options().getScrollElement());
|
|
119
|
+
// let the virtualizer know when the scroll element is changed
|
|
120
|
+
effect(() => {
|
|
121
|
+
const el = scrollElement();
|
|
122
|
+
if (el) {
|
|
123
|
+
untracked(virtualizerSignal)._willUpdate();
|
|
124
|
+
}
|
|
125
|
+
}, { allowSignalWrites: true });
|
|
126
|
+
let cleanup;
|
|
127
|
+
// FIX: Use function callback with options for afterNextRender
|
|
128
|
+
afterNextRender(() => (virtualizer ?? lazyInit())._didMount(), { phase: AfterRenderPhase.Read });
|
|
129
|
+
inject(DestroyRef).onDestroy(() => cleanup?.());
|
|
130
|
+
return proxyVirtualizer(virtualizerSignal, lazyInit);
|
|
131
|
+
}
|
|
132
|
+
function injectVirtualizer(options) {
|
|
133
|
+
const resolvedOptions = computed(() => {
|
|
134
|
+
const opts = options();
|
|
135
|
+
return {
|
|
136
|
+
observeElementRect: observeElementRect,
|
|
137
|
+
observeElementOffset: observeElementOffset,
|
|
138
|
+
scrollToFn: elementScroll,
|
|
139
|
+
getScrollElement: () => {
|
|
140
|
+
const elementOrRef = opts.scrollElement;
|
|
141
|
+
return ((isElementRef(elementOrRef)
|
|
142
|
+
? elementOrRef.nativeElement
|
|
143
|
+
: elementOrRef) ?? null);
|
|
144
|
+
},
|
|
145
|
+
...opts,
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
return createVirtualizerBase(resolvedOptions);
|
|
149
|
+
}
|
|
150
|
+
function isElementRef(elementOrRef) {
|
|
151
|
+
return elementOrRef != null && 'nativeElement' in elementOrRef;
|
|
152
|
+
}
|
|
153
|
+
function injectWindowVirtualizer(options) {
|
|
154
|
+
const resolvedOptions = computed(() => {
|
|
155
|
+
return {
|
|
156
|
+
getScrollElement: () => (typeof document !== 'undefined' ? window : null),
|
|
157
|
+
observeElementRect: observeWindowRect,
|
|
158
|
+
observeElementOffset: observeWindowOffset,
|
|
159
|
+
scrollToFn: windowScroll,
|
|
160
|
+
initialOffset: () => (typeof document !== 'undefined' ? window.scrollY : 0),
|
|
161
|
+
...options(),
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
return createVirtualizerBase(resolvedOptions);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { injectVirtualizer, injectWindowVirtualizer };
|
|
168
|
+
//# sourceMappingURL=tangrid-table-virtual-provider-DS8nOCc-.mjs.map
|