tekivex-ui 2.5.1 → 2.5.3

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 (80) hide show
  1. package/README.md +436 -83
  2. package/dist/TkxForm-DSMDo2Ol.js +388 -0
  3. package/dist/TkxForm-DwV_n-eE.cjs +12 -0
  4. package/dist/headless.cjs +1 -1
  5. package/dist/headless.js +396 -195
  6. package/dist/i18n.cjs +1 -0
  7. package/dist/i18n.js +757 -0
  8. package/dist/index.cjs +27 -22
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +4994 -5089
  12. package/dist/quantum.cjs +91 -0
  13. package/dist/quantum.js +2312 -0
  14. package/dist/realtime.cjs +25 -0
  15. package/dist/realtime.js +944 -0
  16. package/dist/security-C369oOWH.cjs +1 -0
  17. package/dist/security-CzAmaMqa.js +97 -0
  18. package/dist/src/components/TkxDataGrid.d.ts +9 -1
  19. package/dist/src/components/TkxDataGrid.d.ts.map +1 -1
  20. package/dist/src/components/TkxDropdown.d.ts +41 -0
  21. package/dist/src/components/TkxDropdown.d.ts.map +1 -0
  22. package/dist/src/components/TkxLiveFeed.d.ts +891 -0
  23. package/dist/src/components/TkxLiveFeed.d.ts.map +1 -0
  24. package/dist/src/components/TkxLiveLog.d.ts +892 -0
  25. package/dist/src/components/TkxLiveLog.d.ts.map +1 -0
  26. package/dist/src/components/TkxLiveMetrics.d.ts +24 -0
  27. package/dist/src/components/TkxLiveMetrics.d.ts.map +1 -0
  28. package/dist/src/components/TkxPlayground.d.ts +15 -0
  29. package/dist/src/components/TkxPlayground.d.ts.map +1 -0
  30. package/dist/src/components/TkxQuantumForm.d.ts +20 -0
  31. package/dist/src/components/TkxQuantumForm.d.ts.map +1 -0
  32. package/dist/src/components/TkxRealTimeChart.d.ts +27 -0
  33. package/dist/src/components/TkxRealTimeChart.d.ts.map +1 -0
  34. package/dist/src/components/TkxTable.d.ts +11 -1
  35. package/dist/src/components/TkxTable.d.ts.map +1 -1
  36. package/dist/src/components/TkxThemeBuilder.d.ts +9 -0
  37. package/dist/src/components/TkxThemeBuilder.d.ts.map +1 -0
  38. package/dist/src/components/index.d.ts +1 -0
  39. package/dist/src/components/index.d.ts.map +1 -1
  40. package/dist/src/engine/index.d.ts +2 -0
  41. package/dist/src/engine/index.d.ts.map +1 -1
  42. package/dist/src/engine/quantum-ai.d.ts +201 -0
  43. package/dist/src/engine/quantum-ai.d.ts.map +1 -0
  44. package/dist/src/engine/tkx.d.ts.map +1 -1
  45. package/dist/src/headless/index.d.ts +6 -0
  46. package/dist/src/headless/index.d.ts.map +1 -1
  47. package/dist/src/headless/useInfiniteQuery.d.ts +35 -0
  48. package/dist/src/headless/useInfiniteQuery.d.ts.map +1 -0
  49. package/dist/src/headless/useSSE.d.ts +36 -0
  50. package/dist/src/headless/useSSE.d.ts.map +1 -0
  51. package/dist/src/headless/useWebSocket.d.ts +33 -0
  52. package/dist/src/headless/useWebSocket.d.ts.map +1 -0
  53. package/dist/src/quantum/index.d.ts +9 -0
  54. package/dist/src/quantum/index.d.ts.map +1 -0
  55. package/dist/src/realtime/index.d.ts +9 -0
  56. package/dist/src/realtime/index.d.ts.map +1 -0
  57. package/dist/{TkxForm-BWK4LqY3.js → tkx-BJ10JtMv.js} +372 -721
  58. package/dist/tkx-BeNyC0w7.cjs +4 -0
  59. package/package.json +16 -1
  60. package/src/components/TkxDataGrid.tsx +72 -0
  61. package/src/components/TkxDropdown.tsx +802 -0
  62. package/src/components/TkxLiveFeed.tsx +329 -0
  63. package/src/components/TkxLiveLog.tsx +470 -0
  64. package/src/components/TkxLiveMetrics.tsx +291 -0
  65. package/src/components/TkxPlayground.tsx +736 -0
  66. package/src/components/TkxQuantumForm.tsx +592 -0
  67. package/src/components/TkxRealTimeChart.tsx +381 -0
  68. package/src/components/TkxTable.tsx +351 -77
  69. package/src/components/TkxThemeBuilder.tsx +685 -0
  70. package/src/components/index.ts +4 -0
  71. package/src/engine/index.ts +2 -0
  72. package/src/engine/quantum-ai.ts +1045 -0
  73. package/src/engine/tkx.ts +95 -4
  74. package/src/headless/index.ts +6 -0
  75. package/src/headless/useInfiniteQuery.ts +153 -0
  76. package/src/headless/useSSE.ts +165 -0
  77. package/src/headless/useWebSocket.ts +229 -0
  78. package/src/quantum/index.ts +39 -0
  79. package/src/realtime/index.ts +21 -0
  80. package/dist/TkxForm-ljQjX7KD.cjs +0 -15
@@ -0,0 +1,291 @@
1
+ import {
2
+ useState,
3
+ useEffect,
4
+ useRef,
5
+ useCallback,
6
+ createElement,
7
+ type CSSProperties,
8
+ } from 'react';
9
+ import { useTheme } from '../themes';
10
+ import { sanitizeString } from '../engine/security';
11
+ import { tkx } from '../engine/tkx';
12
+
13
+ // ── Types ────────────────────────────────────────────────────────────────────
14
+
15
+ export interface MetricItem {
16
+ id: string;
17
+ label: string;
18
+ value: number | string;
19
+ unit?: string;
20
+ previousValue?: number;
21
+ trend?: 'up' | 'down' | 'flat';
22
+ trendValue?: string;
23
+ color?: string;
24
+ sparkline?: number[];
25
+ status?: 'normal' | 'warning' | 'critical';
26
+ }
27
+
28
+ export interface TkxLiveMetricsProps {
29
+ metrics: MetricItem[];
30
+ columns?: number;
31
+ animate?: boolean;
32
+ refreshInterval?: number;
33
+ onMetricClick?: (metric: MetricItem) => void;
34
+ }
35
+
36
+ // ── CSS injection ────────────────────────────────────────────────────────────
37
+
38
+ let metricsStylesInjected = false;
39
+ function injectMetricsStyles() {
40
+ if (metricsStylesInjected || typeof document === 'undefined') return;
41
+ metricsStylesInjected = true;
42
+ const el = document.createElement('style');
43
+ el.id = 'tkx-live-metrics-styles';
44
+ el.textContent = `
45
+ @keyframes tkx-metric-pulse {
46
+ 0% { opacity: 1; }
47
+ 40% { opacity: 0.4; }
48
+ 100% { opacity: 1; }
49
+ }
50
+ @keyframes tkx-metric-shimmer {
51
+ 0% { background-position: -200% 0; }
52
+ 100% { background-position: 200% 0; }
53
+ }
54
+ .tkx-metric-shimmer {
55
+ animation: tkx-metric-shimmer 0.6s ease-in-out;
56
+ }
57
+ `.trim();
58
+ document.head.appendChild(el);
59
+ }
60
+
61
+ // ── Helpers ──────────────────────────────────────────────────────────────────
62
+
63
+ function formatValue(val: number | string, unit?: string): string {
64
+ if (typeof val === 'string') return val;
65
+ const formatted = val >= 1_000_000
66
+ ? `${(val / 1_000_000).toFixed(1)}M`
67
+ : val >= 1_000
68
+ ? `${(val / 1_000).toFixed(1)}k`
69
+ : String(Number.isInteger(val) ? val : val.toFixed(2));
70
+ return unit ? `${formatted}${unit}` : formatted;
71
+ }
72
+
73
+ function getStatusColor(status: MetricItem['status'], theme: ReturnType<typeof useTheme>): string {
74
+ switch (status) {
75
+ case 'warning': return theme.warning;
76
+ case 'critical': return theme.danger;
77
+ default: return theme.primary;
78
+ }
79
+ }
80
+
81
+ // ── useCountUp ───────────────────────────────────────────────────────────────
82
+
83
+ function useCountUp(target: number, duration: number, enabled: boolean): number {
84
+ const [displayed, setDisplayed] = useState(target);
85
+ const startRef = useRef(target);
86
+ const startTimeRef = useRef<number | null>(null);
87
+ const rafRef = useRef<number | null>(null);
88
+
89
+ useEffect(() => {
90
+ if (!enabled) {
91
+ setDisplayed(target);
92
+ return;
93
+ }
94
+ const from = startRef.current;
95
+ if (from === target) return;
96
+ startTimeRef.current = null;
97
+
98
+ const step = (now: number) => {
99
+ if (startTimeRef.current === null) startTimeRef.current = now;
100
+ const elapsed = now - startTimeRef.current;
101
+ const progress = Math.min(elapsed / duration, 1);
102
+ // ease-out cubic
103
+ const eased = 1 - Math.pow(1 - progress, 3);
104
+ setDisplayed(from + (target - from) * eased);
105
+ if (progress < 1) {
106
+ rafRef.current = requestAnimationFrame(step);
107
+ } else {
108
+ startRef.current = target;
109
+ }
110
+ };
111
+
112
+ rafRef.current = requestAnimationFrame(step);
113
+ return () => {
114
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
115
+ };
116
+ }, [target, duration, enabled]);
117
+
118
+ return displayed;
119
+ }
120
+
121
+ // ── Sparkline ────────────────────────────────────────────────────────────────
122
+
123
+ function Sparkline({ data, color }: { data: number[]; color: string }) {
124
+ if (data.length < 2) return null;
125
+
126
+ const W = 80;
127
+ const H = 24;
128
+ const minV = Math.min(...data);
129
+ const maxV = Math.max(...data);
130
+ const range = maxV - minV || 1;
131
+
132
+ const points = data.map((v, i) => {
133
+ const x = (i / (data.length - 1)) * W;
134
+ const y = H - ((v - minV) / range) * (H - 2) - 1;
135
+ return `${x.toFixed(1)},${y.toFixed(1)}`;
136
+ });
137
+
138
+ return createElement(
139
+ 'svg',
140
+ { width: W, height: H, viewBox: `0 0 ${W} ${H}`, 'aria-hidden': 'true' },
141
+ createElement('polyline', {
142
+ points: points.join(' '),
143
+ fill: 'none',
144
+ stroke: color,
145
+ strokeWidth: 1.5,
146
+ strokeLinejoin: 'round',
147
+ strokeLinecap: 'round',
148
+ }),
149
+ );
150
+ }
151
+
152
+ // ── TrendIcon ────────────────────────────────────────────────────────────────
153
+
154
+ function TrendIcon({ trend, theme }: { trend: MetricItem['trend']; theme: ReturnType<typeof useTheme> }) {
155
+ if (trend === 'up') return createElement('span', { style: { color: theme.success, fontSize: 14, fontWeight: 700 } }, '▲');
156
+ if (trend === 'down') return createElement('span', { style: { color: theme.danger, fontSize: 14, fontWeight: 700 } }, '▼');
157
+ return createElement('span', { style: { color: theme.textMuted, fontSize: 14 } }, '→');
158
+ }
159
+
160
+ // ── MetricCard ───────────────────────────────────────────────────────────────
161
+
162
+ interface MetricCardProps {
163
+ metric: MetricItem;
164
+ animate: boolean;
165
+ onMetricClick?: (metric: MetricItem) => void;
166
+ theme: ReturnType<typeof useTheme>;
167
+ }
168
+
169
+ function MetricCard({ metric, animate, onMetricClick, theme }: MetricCardProps) {
170
+ const accentColor = metric.color ?? getStatusColor(metric.status, theme);
171
+ const numericValue = typeof metric.value === 'number' ? metric.value : NaN;
172
+ const animatedValue = useCountUp(isNaN(numericValue) ? 0 : numericValue, 600, animate && !isNaN(numericValue));
173
+
174
+ const [shimmer, setShimmer] = useState(false);
175
+ const prevValueRef = useRef(metric.value);
176
+
177
+ useEffect(() => {
178
+ if (prevValueRef.current !== metric.value) {
179
+ prevValueRef.current = metric.value;
180
+ setShimmer(true);
181
+ const t = window.setTimeout(() => setShimmer(false), 700);
182
+ return () => clearTimeout(t);
183
+ }
184
+ return undefined;
185
+ }, [metric.value]);
186
+
187
+ const hasPrev = metric.previousValue !== undefined && metric.previousValue !== numericValue;
188
+
189
+ const cardStyle: CSSProperties = {
190
+ background: theme.surface,
191
+ border: `1px solid ${theme.border}`,
192
+ borderLeft: `4px solid ${accentColor}`,
193
+ borderRadius: 8,
194
+ padding: '14px 16px',
195
+ cursor: onMetricClick ? 'pointer' : 'default',
196
+ position: 'relative',
197
+ overflow: 'hidden',
198
+ boxSizing: 'border-box',
199
+ };
200
+
201
+ const shimmerOverlay: CSSProperties = shimmer
202
+ ? {
203
+ position: 'absolute',
204
+ inset: 0,
205
+ background: `linear-gradient(90deg, transparent 0%, ${accentColor}22 50%, transparent 100%)`,
206
+ backgroundSize: '200% 100%',
207
+ animation: 'tkx-metric-shimmer 0.6s ease-in-out',
208
+ pointerEvents: 'none',
209
+ }
210
+ : {};
211
+
212
+ const displayedText = isNaN(numericValue)
213
+ ? sanitizeString(String(metric.value))
214
+ : formatValue(animatedValue, metric.unit);
215
+
216
+ return createElement(
217
+ 'div',
218
+ {
219
+ style: cardStyle,
220
+ className: shimmer ? 'tkx-metric-shimmer' : undefined,
221
+ onClick: onMetricClick ? () => onMetricClick(metric) : undefined,
222
+ role: onMetricClick ? 'button' : undefined,
223
+ tabIndex: onMetricClick ? 0 : undefined,
224
+ },
225
+ // Shimmer overlay
226
+ shimmer && createElement('div', { style: shimmerOverlay }),
227
+ // Label
228
+ createElement('div', { style: { fontSize: 12, color: theme.textMuted, marginBottom: 6, fontWeight: 500, letterSpacing: '0.03em' } }, sanitizeString(metric.label)),
229
+ // Value row
230
+ createElement(
231
+ 'div',
232
+ { style: { display: 'flex', alignItems: 'flex-end', gap: 6, marginBottom: 6 } },
233
+ createElement('span', { style: { fontSize: 28, fontWeight: 700, color: theme.text, lineHeight: 1 } }, displayedText),
234
+ metric.unit && isNaN(numericValue) && createElement('span', { style: { fontSize: 14, color: theme.textMuted, marginBottom: 2 } }, sanitizeString(metric.unit)),
235
+ ),
236
+ // Trend row
237
+ (metric.trend || metric.trendValue) && createElement(
238
+ 'div',
239
+ { style: { display: 'flex', alignItems: 'center', gap: 4, marginBottom: metric.sparkline ? 8 : 0 } },
240
+ metric.trend && createElement(TrendIcon, { trend: metric.trend, theme }),
241
+ metric.trendValue && createElement('span', { style: { fontSize: 12, color: theme.textMuted } }, sanitizeString(metric.trendValue)),
242
+ ),
243
+ // Previous value
244
+ hasPrev && createElement(
245
+ 'div',
246
+ { style: { fontSize: 11, color: theme.textMuted, marginTop: 2 } },
247
+ `was ${formatValue(metric.previousValue as number)}`,
248
+ ),
249
+ // Sparkline
250
+ metric.sparkline && metric.sparkline.length >= 2 && createElement(
251
+ 'div',
252
+ { style: { marginTop: 8 } },
253
+ createElement(Sparkline, { data: metric.sparkline, color: accentColor }),
254
+ ),
255
+ );
256
+ }
257
+
258
+ // ── TkxLiveMetrics ───────────────────────────────────────────────────────────
259
+
260
+ export function TkxLiveMetrics({
261
+ metrics,
262
+ columns = 3,
263
+ animate = true,
264
+ onMetricClick,
265
+ }: TkxLiveMetricsProps) {
266
+ const theme = useTheme();
267
+ injectMetricsStyles();
268
+
269
+ const gridStyle: CSSProperties = {
270
+ display: 'grid',
271
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
272
+ gap: 16,
273
+ };
274
+
275
+ return createElement(
276
+ 'div',
277
+ { style: gridStyle },
278
+ ...metrics.map((metric) =>
279
+ createElement(MetricCard, {
280
+ key: metric.id,
281
+ metric,
282
+ animate,
283
+ onMetricClick,
284
+ theme,
285
+ }),
286
+ ),
287
+ );
288
+ }
289
+
290
+ // Satisfy import requirement
291
+ void tkx;