tekivex-ui 2.1.0 → 2.3.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/dist/index.cjs +75 -14
- package/dist/index.d.ts +34 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11013 -4880
- package/dist/src/components/TkxAffix.d.ts +10 -0
- package/dist/src/components/TkxAffix.d.ts.map +1 -0
- package/dist/src/components/TkxAnchor.d.ts +14 -0
- package/dist/src/components/TkxAnchor.d.ts.map +1 -0
- package/dist/src/components/TkxCascader.d.ts +16 -0
- package/dist/src/components/TkxCascader.d.ts.map +1 -0
- package/dist/src/components/TkxConfigProvider.d.ts +100 -0
- package/dist/src/components/TkxConfigProvider.d.ts.map +1 -0
- package/dist/src/components/TkxDataGrid.d.ts +5 -1
- package/dist/src/components/TkxDataGrid.d.ts.map +1 -1
- package/dist/src/components/TkxEmpty.d.ts +870 -0
- package/dist/src/components/TkxEmpty.d.ts.map +1 -0
- package/dist/src/components/TkxForm.d.ts +54 -0
- package/dist/src/components/TkxForm.d.ts.map +1 -0
- package/dist/src/components/TkxLayout.d.ts +87 -0
- package/dist/src/components/TkxLayout.d.ts.map +1 -0
- package/dist/src/components/TkxList.d.ts +24 -0
- package/dist/src/components/TkxList.d.ts.map +1 -0
- package/dist/src/components/TkxMentions.d.ts +15 -0
- package/dist/src/components/TkxMentions.d.ts.map +1 -0
- package/dist/src/components/TkxQRCode.d.ts +11 -0
- package/dist/src/components/TkxQRCode.d.ts.map +1 -0
- package/dist/src/components/TkxResult.d.ts +11 -0
- package/dist/src/components/TkxResult.d.ts.map +1 -0
- package/dist/src/components/TkxSegmented.d.ts +16 -0
- package/dist/src/components/TkxSegmented.d.ts.map +1 -0
- package/dist/src/components/TkxSelect.d.ts +5 -1
- package/dist/src/components/TkxSelect.d.ts.map +1 -1
- package/dist/src/components/TkxSpin.d.ts +15 -0
- package/dist/src/components/TkxSpin.d.ts.map +1 -0
- package/dist/src/components/TkxStatistic.d.ts +1746 -0
- package/dist/src/components/TkxStatistic.d.ts.map +1 -0
- package/dist/src/components/TkxTour.d.ts +15 -0
- package/dist/src/components/TkxTour.d.ts.map +1 -0
- package/dist/src/components/TkxTypography.d.ts +2614 -0
- package/dist/src/components/TkxTypography.d.ts.map +1 -0
- package/dist/src/components/TkxWatermark.d.ts +12 -0
- package/dist/src/components/TkxWatermark.d.ts.map +1 -0
- package/dist/src/components/index.d.ts +17 -0
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/engine/tkx.d.ts +38 -0
- package/dist/src/engine/tkx.d.ts.map +1 -1
- package/dist/src/themes/index.d.ts +108 -0
- package/dist/src/themes/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/TkxAffix.tsx +138 -0
- package/src/components/TkxAnchor.tsx +193 -0
- package/src/components/TkxCascader.tsx +276 -0
- package/src/components/TkxConfigProvider.tsx +458 -0
- package/src/components/TkxDataGrid.tsx +65 -2
- package/src/components/TkxEmpty.tsx +219 -0
- package/src/components/TkxForm.tsx +607 -0
- package/src/components/TkxLayout.tsx +647 -0
- package/src/components/TkxList.tsx +242 -0
- package/src/components/TkxMentions.tsx +210 -0
- package/src/components/TkxQRCode.tsx +174 -0
- package/src/components/TkxResult.tsx +128 -0
- package/src/components/TkxSegmented.tsx +169 -0
- package/src/components/TkxSelect.tsx +209 -6
- package/src/components/TkxSpin.tsx +261 -0
- package/src/components/TkxStatistic.tsx +261 -0
- package/src/components/TkxTour.tsx +239 -0
- package/src/components/TkxTypography.tsx +263 -0
- package/src/components/TkxWatermark.tsx +143 -0
- package/src/components/index.ts +17 -0
- package/src/engine/tkx.ts +62 -0
- package/src/themes/index.ts +149 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TkxTypography.d.ts","sourceRoot":"","sources":["../../../src/components/TkxTypography.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface TkxWatermarkProps {
|
|
3
|
+
text: string | string[];
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
rotate?: number;
|
|
6
|
+
gap?: [number, number];
|
|
7
|
+
fontSize?: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
zIndex?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function TkxWatermark({ text, children, rotate, gap, fontSize, color, zIndex, }: TkxWatermarkProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=TkxWatermark.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TkxWatermark.d.ts","sourceRoot":"","sources":["../../../src/components/TkxWatermark.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqD,MAAM,OAAO,CAAC;AAQ1F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkDD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,QAAQ,EACR,MAAY,EACZ,GAAgB,EAChB,QAAa,EACb,KAAK,EACL,MAAW,GACZ,EAAE,iBAAiB,2CAoEnB"}
|
|
@@ -51,4 +51,21 @@ export * from './TkxSnackbar';
|
|
|
51
51
|
export * from './TkxDataGrid';
|
|
52
52
|
export * from './TkxMasonry';
|
|
53
53
|
export * from './TkxRichTextDisplay';
|
|
54
|
+
export * from './TkxForm';
|
|
55
|
+
export * from './TkxLayout';
|
|
56
|
+
export * from './TkxConfigProvider';
|
|
57
|
+
export * from './TkxTypography';
|
|
58
|
+
export * from './TkxSpin';
|
|
59
|
+
export * from './TkxEmpty';
|
|
60
|
+
export * from './TkxStatistic';
|
|
61
|
+
export * from './TkxSegmented';
|
|
62
|
+
export * from './TkxMentions';
|
|
63
|
+
export * from './TkxQRCode';
|
|
64
|
+
export * from './TkxResult';
|
|
65
|
+
export * from './TkxTour';
|
|
66
|
+
export * from './TkxWatermark';
|
|
67
|
+
export * from './TkxAffix';
|
|
68
|
+
export * from './TkxAnchor';
|
|
69
|
+
export * from './TkxCascader';
|
|
70
|
+
export * from './TkxList';
|
|
54
71
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
|
package/dist/src/engine/tkx.d.ts
CHANGED
|
@@ -26,4 +26,42 @@ export declare function resetAtomicCSS(): void;
|
|
|
26
26
|
* Use this to combine a tkx() result with a consumer-provided className prop.
|
|
27
27
|
*/
|
|
28
28
|
export declare function cx(...classes: (string | false | null | undefined)[]): string;
|
|
29
|
+
/**
|
|
30
|
+
* TKX Plugin API — extend the utility engine with custom utilities.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* import { tkxPlugin, tkx } from '@tekivex/ui';
|
|
35
|
+
*
|
|
36
|
+
* // Register custom utilities
|
|
37
|
+
* tkxPlugin({
|
|
38
|
+
* name: 'brand',
|
|
39
|
+
* utilities: {
|
|
40
|
+
* 'brand-gradient': { background: 'linear-gradient(135deg, #667eea, #764ba2)' },
|
|
41
|
+
* 'brand-text': { color: '#667eea', fontWeight: '700' },
|
|
42
|
+
* 'card-shadow': { boxShadow: '0 8px 32px rgba(102, 126, 234, 0.15)' },
|
|
43
|
+
* 'glass': {
|
|
44
|
+
* background: 'rgba(255, 255, 255, 0.05)',
|
|
45
|
+
* backdropFilter: 'blur(12px)',
|
|
46
|
+
* border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
47
|
+
* },
|
|
48
|
+
* },
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* // Use them like any built-in utility
|
|
52
|
+
* const cls = tkx('brand-gradient p-6 rounded-xl card-shadow');
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export interface TkxPluginDef {
|
|
56
|
+
name: string;
|
|
57
|
+
utilities: Record<string, Record<string, string>>;
|
|
58
|
+
}
|
|
59
|
+
export declare function tkxPlugin(plugin: TkxPluginDef): void;
|
|
60
|
+
export declare function tkxRemovePlugin(name: string): void;
|
|
61
|
+
export declare function tkxListPlugins(): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Resolve a plugin utility to CSS properties.
|
|
64
|
+
* Called internally by the TKX engine — but also exported for inspection.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolvePluginUtility(name: string): Record<string, string> | null;
|
|
29
67
|
//# sourceMappingURL=tkx.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tkx.d.ts","sourceRoot":"","sources":["../../../src/engine/tkx.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tkx.d.ts","sourceRoot":"","sources":["../../../src/engine/tkx.ts"],"names":[],"mappings":"AA+tBA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAmBhG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,GAAG,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAmFjD;AAED,qCAAqC;AACrC,eAAO,MAAM,EAAE,YAAM,CAAC;AAItB,qEAAqE;AACrE,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,4DAA4D;AAC5D,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAGD;;;GAGG;AACH,wBAAgB,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,CAE5E;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAID,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAKhF"}
|
|
@@ -23,4 +23,112 @@ export interface ThemeProviderProps {
|
|
|
23
23
|
}
|
|
24
24
|
export declare function ThemeProvider({ theme, children }: ThemeProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<ThemeTokens>>;
|
|
25
25
|
export declare function useTheme(): ThemeTokens;
|
|
26
|
+
export interface ColorPalette {
|
|
27
|
+
50: string;
|
|
28
|
+
100: string;
|
|
29
|
+
200: string;
|
|
30
|
+
300: string;
|
|
31
|
+
400: string;
|
|
32
|
+
500: string;
|
|
33
|
+
600: string;
|
|
34
|
+
700: string;
|
|
35
|
+
800: string;
|
|
36
|
+
900: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function generatePalette(hex: string): ColorPalette;
|
|
39
|
+
export declare const typography: {
|
|
40
|
+
readonly xs: {
|
|
41
|
+
readonly fontSize: "0.75rem";
|
|
42
|
+
readonly lineHeight: "1rem";
|
|
43
|
+
};
|
|
44
|
+
readonly sm: {
|
|
45
|
+
readonly fontSize: "0.875rem";
|
|
46
|
+
readonly lineHeight: "1.25rem";
|
|
47
|
+
};
|
|
48
|
+
readonly base: {
|
|
49
|
+
readonly fontSize: "1rem";
|
|
50
|
+
readonly lineHeight: "1.5rem";
|
|
51
|
+
};
|
|
52
|
+
readonly lg: {
|
|
53
|
+
readonly fontSize: "1.125rem";
|
|
54
|
+
readonly lineHeight: "1.75rem";
|
|
55
|
+
};
|
|
56
|
+
readonly xl: {
|
|
57
|
+
readonly fontSize: "1.25rem";
|
|
58
|
+
readonly lineHeight: "1.75rem";
|
|
59
|
+
};
|
|
60
|
+
readonly '2xl': {
|
|
61
|
+
readonly fontSize: "1.5rem";
|
|
62
|
+
readonly lineHeight: "2rem";
|
|
63
|
+
};
|
|
64
|
+
readonly '3xl': {
|
|
65
|
+
readonly fontSize: "1.875rem";
|
|
66
|
+
readonly lineHeight: "2.25rem";
|
|
67
|
+
};
|
|
68
|
+
readonly '4xl': {
|
|
69
|
+
readonly fontSize: "2.25rem";
|
|
70
|
+
readonly lineHeight: "2.5rem";
|
|
71
|
+
};
|
|
72
|
+
readonly '5xl': {
|
|
73
|
+
readonly fontSize: "3rem";
|
|
74
|
+
readonly lineHeight: "1.15";
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export declare const spacing: {
|
|
78
|
+
readonly 0: "0px";
|
|
79
|
+
readonly 0.5: "2px";
|
|
80
|
+
readonly 1: "4px";
|
|
81
|
+
readonly 1.5: "6px";
|
|
82
|
+
readonly 2: "8px";
|
|
83
|
+
readonly 2.5: "10px";
|
|
84
|
+
readonly 3: "12px";
|
|
85
|
+
readonly 4: "16px";
|
|
86
|
+
readonly 5: "20px";
|
|
87
|
+
readonly 6: "24px";
|
|
88
|
+
readonly 8: "32px";
|
|
89
|
+
readonly 10: "40px";
|
|
90
|
+
readonly 12: "48px";
|
|
91
|
+
readonly 16: "64px";
|
|
92
|
+
readonly 20: "80px";
|
|
93
|
+
readonly 24: "96px";
|
|
94
|
+
};
|
|
95
|
+
export declare const breakpoints: {
|
|
96
|
+
readonly sm: 640;
|
|
97
|
+
readonly md: 768;
|
|
98
|
+
readonly lg: 1024;
|
|
99
|
+
readonly xl: 1280;
|
|
100
|
+
readonly '2xl': 1536;
|
|
101
|
+
};
|
|
102
|
+
export declare const shadows: {
|
|
103
|
+
readonly none: "none";
|
|
104
|
+
readonly xs: "0 1px 2px 0 rgba(0,0,0,0.05)";
|
|
105
|
+
readonly sm: "0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1)";
|
|
106
|
+
readonly md: "0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)";
|
|
107
|
+
readonly lg: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)";
|
|
108
|
+
readonly xl: "0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1)";
|
|
109
|
+
readonly '2xl': "0 25px 50px -12px rgba(0,0,0,0.25)";
|
|
110
|
+
readonly inner: "inset 0 2px 4px 0 rgba(0,0,0,0.06)";
|
|
111
|
+
};
|
|
112
|
+
export declare const zIndex: {
|
|
113
|
+
readonly hide: -1;
|
|
114
|
+
readonly base: 0;
|
|
115
|
+
readonly dropdown: 1000;
|
|
116
|
+
readonly sticky: 1100;
|
|
117
|
+
readonly fixed: 1200;
|
|
118
|
+
readonly overlay: 1300;
|
|
119
|
+
readonly modal: 1400;
|
|
120
|
+
readonly popover: 1500;
|
|
121
|
+
readonly tooltip: 1600;
|
|
122
|
+
readonly toast: 1700;
|
|
123
|
+
readonly max: 9999;
|
|
124
|
+
};
|
|
125
|
+
export declare const radii: {
|
|
126
|
+
readonly none: "0";
|
|
127
|
+
readonly sm: "4px";
|
|
128
|
+
readonly md: "6px";
|
|
129
|
+
readonly lg: "8px";
|
|
130
|
+
readonly xl: "12px";
|
|
131
|
+
readonly '2xl': "16px";
|
|
132
|
+
readonly full: "9999px";
|
|
133
|
+
};
|
|
26
134
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAM5F,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,eAAO,MAAM,WAAW,EAAE,WAazB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAazB,CAAC;AAMF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAuB5F;AAID,eAAO,MAAM,YAAY,sCAA0C,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAmB,EAAE,QAAQ,EAAE,EAAE,kBAAkB,wFAelF;AAED,wBAAgB,QAAQ,IAAI,WAAW,CAEtC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAM5F,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,eAAO,MAAM,WAAW,EAAE,WAazB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAazB,CAAC;AAMF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAuB5F;AAID,eAAO,MAAM,YAAY,sCAA0C,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAmB,EAAE,QAAQ,EAAE,EAAE,kBAAkB,wFAelF;AAED,wBAAgB,QAAQ,IAAI,WAAW,CAEtC;AAoCD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAczD;AAID,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUb,CAAC;AAIX,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;CAiBV,CAAC;AAIX,eAAO,MAAM,WAAW;;;;;;CAMd,CAAC;AAIX,eAAO,MAAM,OAAO;;;;;;;;;CASV,CAAC;AAIX,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAC;AAIX,eAAO,MAAM,KAAK;;;;;;;;CAQR,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { type ReactNode, useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
2
|
+
import { useTheme } from '../themes';
|
|
3
|
+
import { sanitizeString } from '../engine/security';
|
|
4
|
+
import { useReducedMotion } from '../hooks';
|
|
5
|
+
import { tkx } from '../engine/tkx';
|
|
6
|
+
|
|
7
|
+
// ── Types ────────────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
export interface TkxAffixProps {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
offsetTop?: number;
|
|
12
|
+
offsetBottom?: number;
|
|
13
|
+
onChange?: (affixed: boolean) => void;
|
|
14
|
+
target?: () => HTMLElement | Window;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
function getScrollTarget(target?: () => HTMLElement | Window): HTMLElement | Window {
|
|
20
|
+
if (target) {
|
|
21
|
+
try {
|
|
22
|
+
return target();
|
|
23
|
+
} catch {
|
|
24
|
+
return window;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return window;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getTargetRect(el: HTMLElement | Window): { top: number; bottom: number } {
|
|
31
|
+
if (el instanceof Window) {
|
|
32
|
+
return { top: 0, bottom: el.innerHeight };
|
|
33
|
+
}
|
|
34
|
+
const rect = el.getBoundingClientRect();
|
|
35
|
+
return { top: rect.top, bottom: rect.bottom };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Component ────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
export function TkxAffix({
|
|
41
|
+
children,
|
|
42
|
+
offsetTop,
|
|
43
|
+
offsetBottom,
|
|
44
|
+
onChange,
|
|
45
|
+
target,
|
|
46
|
+
}: TkxAffixProps) {
|
|
47
|
+
const theme = useTheme();
|
|
48
|
+
const reducedMotion = useReducedMotion();
|
|
49
|
+
const placeholderRef = useRef<HTMLDivElement>(null);
|
|
50
|
+
const fixedRef = useRef<HTMLDivElement>(null);
|
|
51
|
+
const [affixed, setAffixed] = useState(false);
|
|
52
|
+
const [placeholderSize, setPlaceholderSize] = useState({ width: 0, height: 0 });
|
|
53
|
+
const prevAffixed = useRef(false);
|
|
54
|
+
|
|
55
|
+
// Sanitize any debug info strings for security
|
|
56
|
+
const _labelSafe = useMemo(() => sanitizeString('Sticky content'), []);
|
|
57
|
+
|
|
58
|
+
const checkPosition = useCallback(() => {
|
|
59
|
+
const el = placeholderRef.current;
|
|
60
|
+
if (!el) return;
|
|
61
|
+
|
|
62
|
+
const rect = el.getBoundingClientRect();
|
|
63
|
+
const targetRect = getTargetRect(getScrollTarget(target));
|
|
64
|
+
let shouldAffix = false;
|
|
65
|
+
|
|
66
|
+
if (offsetTop !== undefined) {
|
|
67
|
+
// Affix when element scrolls past the top offset
|
|
68
|
+
shouldAffix = rect.top - targetRect.top <= offsetTop;
|
|
69
|
+
} else if (offsetBottom !== undefined) {
|
|
70
|
+
// Affix when element scrolls past the bottom offset
|
|
71
|
+
shouldAffix = targetRect.bottom - rect.bottom <= offsetBottom;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (shouldAffix !== prevAffixed.current) {
|
|
75
|
+
prevAffixed.current = shouldAffix;
|
|
76
|
+
setAffixed(shouldAffix);
|
|
77
|
+
setPlaceholderSize({
|
|
78
|
+
width: rect.width,
|
|
79
|
+
height: rect.height,
|
|
80
|
+
});
|
|
81
|
+
onChange?.(shouldAffix);
|
|
82
|
+
}
|
|
83
|
+
}, [offsetTop, offsetBottom, onChange, target]);
|
|
84
|
+
|
|
85
|
+
// Attach scroll and resize listeners
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const scrollTarget = getScrollTarget(target);
|
|
88
|
+
|
|
89
|
+
checkPosition();
|
|
90
|
+
scrollTarget.addEventListener('scroll', checkPosition, { passive: true });
|
|
91
|
+
window.addEventListener('resize', checkPosition);
|
|
92
|
+
|
|
93
|
+
return () => {
|
|
94
|
+
scrollTarget.removeEventListener('scroll', checkPosition);
|
|
95
|
+
window.removeEventListener('resize', checkPosition);
|
|
96
|
+
};
|
|
97
|
+
}, [checkPosition, target]);
|
|
98
|
+
|
|
99
|
+
// Build the fixed positioning styles
|
|
100
|
+
const fixedStyle: React.CSSProperties = affixed
|
|
101
|
+
? {
|
|
102
|
+
position: 'fixed',
|
|
103
|
+
zIndex: 100,
|
|
104
|
+
...(offsetTop !== undefined ? { top: offsetTop } : {}),
|
|
105
|
+
...(offsetBottom !== undefined ? { bottom: offsetBottom } : {}),
|
|
106
|
+
width: placeholderSize.width || undefined,
|
|
107
|
+
transition: reducedMotion ? 'none' : 'box-shadow 0.2s ease',
|
|
108
|
+
boxShadow: `0 2px 8px ${theme.border}`,
|
|
109
|
+
}
|
|
110
|
+
: {};
|
|
111
|
+
|
|
112
|
+
// Placeholder keeps the document flow intact when element is fixed
|
|
113
|
+
const placeholderStyle: React.CSSProperties = affixed
|
|
114
|
+
? {
|
|
115
|
+
height: placeholderSize.height,
|
|
116
|
+
width: placeholderSize.width,
|
|
117
|
+
}
|
|
118
|
+
: {};
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<>
|
|
122
|
+
<div
|
|
123
|
+
ref={placeholderRef}
|
|
124
|
+
aria-hidden={affixed}
|
|
125
|
+
style={placeholderStyle}
|
|
126
|
+
/>
|
|
127
|
+
<div
|
|
128
|
+
ref={fixedRef}
|
|
129
|
+
role="region"
|
|
130
|
+
aria-label={_labelSafe}
|
|
131
|
+
className={tkx(affixed ? 'tkx-affixed' : '')}
|
|
132
|
+
style={fixedStyle}
|
|
133
|
+
>
|
|
134
|
+
{children}
|
|
135
|
+
</div>
|
|
136
|
+
</>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import { useTheme } from '../themes';
|
|
3
|
+
import { sanitizeString } from '../engine/security';
|
|
4
|
+
import { useReducedMotion } from '../hooks';
|
|
5
|
+
import { tkx } from '../engine/tkx';
|
|
6
|
+
|
|
7
|
+
// ── Types ────────────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
export interface AnchorLink {
|
|
10
|
+
key: string;
|
|
11
|
+
href: string;
|
|
12
|
+
title: string;
|
|
13
|
+
children?: AnchorLink[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface TkxAnchorProps {
|
|
17
|
+
items: AnchorLink[];
|
|
18
|
+
offsetTop?: number;
|
|
19
|
+
getCurrentAnchor?: (activeLink: string) => string;
|
|
20
|
+
onChange?: (currentLink: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
function flattenLinks(items: AnchorLink[]): AnchorLink[] {
|
|
26
|
+
const result: AnchorLink[] = [];
|
|
27
|
+
for (const item of items) {
|
|
28
|
+
result.push(item);
|
|
29
|
+
if (item.children) result.push(...flattenLinks(item.children));
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getAnchorId(href: string): string {
|
|
35
|
+
return href.startsWith('#') ? href.slice(1) : href;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Link Item ────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function AnchorItem({
|
|
41
|
+
item,
|
|
42
|
+
activeKey,
|
|
43
|
+
depth,
|
|
44
|
+
onClick,
|
|
45
|
+
theme,
|
|
46
|
+
reducedMotion,
|
|
47
|
+
}: {
|
|
48
|
+
item: AnchorLink;
|
|
49
|
+
activeKey: string;
|
|
50
|
+
depth: number;
|
|
51
|
+
onClick: (href: string) => void;
|
|
52
|
+
theme: ReturnType<typeof useTheme>;
|
|
53
|
+
reducedMotion: boolean;
|
|
54
|
+
}) {
|
|
55
|
+
const isActive = item.key === activeKey;
|
|
56
|
+
const safeTitle = sanitizeString(item.title);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<li role="none" style={{ listStyle: 'none' }}>
|
|
60
|
+
<a
|
|
61
|
+
role="treeitem"
|
|
62
|
+
aria-current={isActive ? 'location' : undefined}
|
|
63
|
+
href={item.href}
|
|
64
|
+
onClick={(e) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
onClick(item.href);
|
|
67
|
+
}}
|
|
68
|
+
className={tkx('block text-sm py-1 no-underline')}
|
|
69
|
+
style={{
|
|
70
|
+
paddingLeft: 12 + depth * 16,
|
|
71
|
+
color: isActive ? theme.primary : theme.textMuted,
|
|
72
|
+
fontWeight: isActive ? 600 : 400,
|
|
73
|
+
borderLeft: `2px solid ${isActive ? theme.primary : 'transparent'}`,
|
|
74
|
+
transition: reducedMotion ? 'none' : 'color 0.15s ease, border-color 0.15s ease',
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{safeTitle}
|
|
78
|
+
</a>
|
|
79
|
+
{item.children && item.children.length > 0 && (
|
|
80
|
+
<ul role="group" style={{ margin: 0, padding: 0 }}>
|
|
81
|
+
{item.children.map((child) => (
|
|
82
|
+
<AnchorItem
|
|
83
|
+
key={child.key}
|
|
84
|
+
item={child}
|
|
85
|
+
activeKey={activeKey}
|
|
86
|
+
depth={depth + 1}
|
|
87
|
+
onClick={onClick}
|
|
88
|
+
theme={theme}
|
|
89
|
+
reducedMotion={reducedMotion}
|
|
90
|
+
/>
|
|
91
|
+
))}
|
|
92
|
+
</ul>
|
|
93
|
+
)}
|
|
94
|
+
</li>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── Component ────────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
export function TkxAnchor({
|
|
101
|
+
items,
|
|
102
|
+
offsetTop = 0,
|
|
103
|
+
getCurrentAnchor,
|
|
104
|
+
onChange,
|
|
105
|
+
}: TkxAnchorProps) {
|
|
106
|
+
const theme = useTheme();
|
|
107
|
+
const reducedMotion = useReducedMotion();
|
|
108
|
+
const [activeKey, setActiveKey] = useState(items[0]?.key ?? '');
|
|
109
|
+
const isScrolling = useRef(false);
|
|
110
|
+
|
|
111
|
+
const flat = flattenLinks(items);
|
|
112
|
+
|
|
113
|
+
const updateActive = useCallback(() => {
|
|
114
|
+
if (isScrolling.current) return;
|
|
115
|
+
|
|
116
|
+
let current = flat[0]?.key ?? '';
|
|
117
|
+
for (const link of flat) {
|
|
118
|
+
const id = getAnchorId(link.href);
|
|
119
|
+
const el = document.getElementById(id);
|
|
120
|
+
if (el) {
|
|
121
|
+
const top = el.getBoundingClientRect().top;
|
|
122
|
+
if (top <= offsetTop + 10) {
|
|
123
|
+
current = link.key;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (getCurrentAnchor) {
|
|
129
|
+
current = getCurrentAnchor(current);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (current !== activeKey) {
|
|
133
|
+
setActiveKey(current);
|
|
134
|
+
onChange?.(current);
|
|
135
|
+
}
|
|
136
|
+
}, [flat, offsetTop, getCurrentAnchor, activeKey, onChange]);
|
|
137
|
+
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
window.addEventListener('scroll', updateActive, { passive: true });
|
|
140
|
+
updateActive();
|
|
141
|
+
return () => window.removeEventListener('scroll', updateActive);
|
|
142
|
+
}, [updateActive]);
|
|
143
|
+
|
|
144
|
+
const handleClick = useCallback(
|
|
145
|
+
(href: string) => {
|
|
146
|
+
const id = getAnchorId(href);
|
|
147
|
+
const el = document.getElementById(id);
|
|
148
|
+
if (!el) return;
|
|
149
|
+
|
|
150
|
+
isScrolling.current = true;
|
|
151
|
+
const top = el.getBoundingClientRect().top + window.scrollY - offsetTop;
|
|
152
|
+
window.scrollTo({ top, behavior: reducedMotion ? 'auto' : 'smooth' });
|
|
153
|
+
|
|
154
|
+
// Find the link by href and set active
|
|
155
|
+
const link = flat.find((l) => l.href === href);
|
|
156
|
+
if (link) {
|
|
157
|
+
setActiveKey(link.key);
|
|
158
|
+
onChange?.(link.key);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
isScrolling.current = false;
|
|
163
|
+
}, 800);
|
|
164
|
+
},
|
|
165
|
+
[flat, offsetTop, reducedMotion, onChange],
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<nav
|
|
170
|
+
role="tree"
|
|
171
|
+
aria-label="Anchor navigation"
|
|
172
|
+
className={tkx('font-sans')}
|
|
173
|
+
style={{
|
|
174
|
+
borderLeft: `1px solid ${theme.border}`,
|
|
175
|
+
padding: '4px 0',
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
<ul role="group" style={{ margin: 0, padding: 0 }}>
|
|
179
|
+
{items.map((item) => (
|
|
180
|
+
<AnchorItem
|
|
181
|
+
key={item.key}
|
|
182
|
+
item={item}
|
|
183
|
+
activeKey={activeKey}
|
|
184
|
+
depth={0}
|
|
185
|
+
onClick={handleClick}
|
|
186
|
+
theme={theme}
|
|
187
|
+
reducedMotion={reducedMotion}
|
|
188
|
+
/>
|
|
189
|
+
))}
|
|
190
|
+
</ul>
|
|
191
|
+
</nav>
|
|
192
|
+
);
|
|
193
|
+
}
|