@kupola/kupola 1.2.0 → 1.3.1

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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -286
  3. package/adapters/axios.d.ts +34 -0
  4. package/adapters/axios.js +122 -0
  5. package/adapters/navios-http.d.ts +110 -0
  6. package/adapters/navios-http.js +151 -0
  7. package/dist/css/accessibility.css +119 -0
  8. package/dist/css/animations.css +224 -0
  9. package/dist/css/brand-themes.css +300 -0
  10. package/dist/css/colors_and_type.css +441 -0
  11. package/dist/css/components-ext.css +4165 -0
  12. package/dist/css/components.css +1483 -0
  13. package/dist/css/responsive.css +697 -0
  14. package/dist/css/scaffold.css +145 -0
  15. package/dist/css/states.css +316 -0
  16. package/dist/css/theme-dark.css +296 -0
  17. package/dist/css/theme-light.css +296 -0
  18. package/dist/css/utilities.css +171 -0
  19. package/dist/kupola.cjs.js +219 -161
  20. package/dist/kupola.cjs.js.map +1 -1
  21. package/dist/kupola.esm.js +6643 -5709
  22. package/dist/kupola.esm.js.map +1 -1
  23. package/dist/kupola.umd.js +219 -161
  24. package/dist/kupola.umd.js.map +1 -1
  25. package/dist/plugins/vite-plugin-kupola.js +120 -0
  26. package/dist/types/kupola.d.ts +421 -323
  27. package/js/calendar.js +334 -25
  28. package/js/carousel.js +182 -48
  29. package/js/collapse.js +148 -34
  30. package/js/color-picker.js +416 -108
  31. package/js/component.js +8 -19
  32. package/js/countdown.js +9 -8
  33. package/js/data-bind.js +73 -16
  34. package/js/datepicker.js +488 -110
  35. package/js/depends.js +710 -0
  36. package/js/dialog.js +4 -2
  37. package/js/drawer.js +172 -8
  38. package/js/dropdown.js +272 -17
  39. package/js/dynamic-tags.js +156 -40
  40. package/js/fileupload.js +9 -8
  41. package/js/form.js +280 -254
  42. package/js/global-events.js +281 -188
  43. package/js/heatmap.js +10 -7
  44. package/js/i18n.js +18 -10
  45. package/js/icons.js +141 -161
  46. package/js/image-preview.js +146 -2
  47. package/js/initializer.js +113 -71
  48. package/js/kupola-core.js +123 -45
  49. package/js/kupola-lifecycle.js +13 -11
  50. package/js/message.js +8 -1
  51. package/js/modal.js +207 -59
  52. package/js/notification.js +8 -1
  53. package/js/numberinput.js +9 -8
  54. package/js/pagination.js +263 -0
  55. package/js/registry.js +29 -12
  56. package/js/select.js +482 -27
  57. package/js/slide-captcha.js +11 -2
  58. package/js/slider.js +442 -25
  59. package/js/statcard.js +9 -7
  60. package/js/table.js +1210 -0
  61. package/js/tag.js +268 -14
  62. package/js/theme.js +14 -43
  63. package/js/timepicker.js +335 -66
  64. package/js/tooltip.js +317 -86
  65. package/js/utils.js +6 -2
  66. package/js/validation.js +6 -2
  67. package/js/virtual-list.js +11 -7
  68. package/js/web-components.js +288 -0
  69. package/package.json +77 -67
  70. package/plugins/vite-plugin-kupola.js +120 -0
  71. package/types/kupola.d.ts +421 -323
  72. package/CHANGELOG.md +0 -130
  73. package/INTEGRATION.md +0 -440
  74. package/PROJECT_SUMMARY.md +0 -312
  75. package/SKILL.md +0 -572
  76. package/dist/utils/utils/Kupola.cs +0 -77
  77. package/dist/utils/utils/Kupola.java +0 -104
  78. package/dist/utils/utils/kupola.go +0 -120
  79. package/dist/utils/utils/kupola.js +0 -63
  80. package/dist/utils/utils/kupola.py +0 -1392
  81. package/dist/utils/utils/kupola.rb +0 -69
  82. package/js/composition-api.js +0 -458
  83. package/js/error-handler.js +0 -181
  84. package/js/http.js +0 -419
  85. package/js/kupola-devtools.js +0 -598
  86. package/js/performance.js +0 -250
  87. package/js/router.js +0 -396
  88. package/js/security.js +0 -189
  89. package/js/test-utils.js +0 -251
  90. package/templates/base.html +0 -30
  91. package/templates/base_dashboard.html +0 -99
  92. package/utils/Kupola.cs +0 -77
  93. package/utils/Kupola.java +0 -104
  94. package/utils/kupola.go +0 -120
  95. package/utils/kupola.js +0 -63
  96. package/utils/kupola.py +0 -1392
  97. package/utils/kupola.rb +0 -69
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Axios adapter for Kupola HTTP client plugin system.
3
+ */
4
+
5
+ export interface AxiosAdapterOptions {
6
+ /** Additional Axios request config to merge into every request */
7
+ [key: string]: any;
8
+ }
9
+
10
+ /**
11
+ * Create a Kupola-compatible HTTP client from an Axios instance.
12
+ *
13
+ * @param axiosInstance - An Axios instance (from axios.create() or default axios)
14
+ * @param options - Additional Axios request config to merge into every request
15
+ * @returns Kupola HTTP client object with a `fetch` function
16
+ */
17
+ export function createAxiosAdapter(
18
+ axiosInstance: any,
19
+ options?: AxiosAdapterOptions
20
+ ): {
21
+ fetch(url: string, fetchOptions?: {
22
+ method?: string;
23
+ headers?: Record<string, string>;
24
+ body?: string;
25
+ }): Promise<{
26
+ ok: boolean;
27
+ status: number;
28
+ statusText: string;
29
+ headers: Record<string, string>;
30
+ url: string;
31
+ json(): Promise<any>;
32
+ text(): Promise<string>;
33
+ }>;
34
+ };
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Axios adapter for Kupola HTTP client plugin system.
3
+ *
4
+ * Allows using Axios (with interceptors, custom config, etc.) as the HTTP
5
+ * client for all useDeps() / useQuery() requests.
6
+ *
7
+ * @module adapters/axios
8
+ *
9
+ * @example
10
+ * import { configureHttpClient } from 'kupola';
11
+ * import { createAxiosAdapter } from 'kupola/adapters/axios';
12
+ * import axios from 'axios';
13
+ *
14
+ * const api = axios.create({ baseURL: '/api', timeout: 10000 });
15
+ *
16
+ * // Axios interceptors work as expected
17
+ * api.interceptors.request.use(config => {
18
+ * config.headers.Authorization = `Bearer ${getToken()}`;
19
+ * return config;
20
+ * });
21
+ *
22
+ * configureHttpClient(createAxiosAdapter(api));
23
+ */
24
+
25
+ /**
26
+ * Create a Kupola-compatible HTTP client from an Axios instance.
27
+ *
28
+ * @param {Object} axiosInstance - An Axios instance (from axios.create() or default axios)
29
+ * @param {Object} [options] - Additional Axios request config to merge into every request
30
+ * @returns {{ fetch: Function }} Kupola HTTP client object
31
+ */
32
+ export function createAxiosAdapter(axiosInstance, options = {}) {
33
+ if (!axiosInstance || typeof axiosInstance.request !== 'function') {
34
+ throw new TypeError('[Kupola] createAxiosAdapter: invalid Axios instance (must have .request method)');
35
+ }
36
+
37
+ return {
38
+ /**
39
+ * Fetch function compatible with Kupola's HTTP client interface.
40
+ * Translates Fetch API semantics to Axios, and Axios response back to
41
+ * Fetch API Response shape.
42
+ *
43
+ * @param {string} url - Request URL
44
+ * @param {Object} [fetchOptions] - Fetch-style options
45
+ * @param {string} [fetchOptions.method='GET'] - HTTP method
46
+ * @param {Object} [fetchOptions.headers] - Request headers
47
+ * @param {string} [fetchOptions.body] - Request body (JSON string)
48
+ * @returns {Promise<Object>} Response-like object { ok, status, headers, json(), text() }
49
+ */
50
+ fetch: async function (url, fetchOptions = {}) {
51
+ // Build Axios config
52
+ const axiosConfig = {
53
+ url,
54
+ method: (fetchOptions.method || 'GET').toLowerCase(),
55
+ headers: fetchOptions.headers || {},
56
+ // Don't throw on non-2xx — let Kupola handle error status
57
+ validateStatus: () => true,
58
+ ...options
59
+ };
60
+
61
+ // Parse body if present (Fetch sends body as JSON string)
62
+ if (fetchOptions.body) {
63
+ try {
64
+ axiosConfig.data = JSON.parse(fetchOptions.body);
65
+ } catch (_) {
66
+ axiosConfig.data = fetchOptions.body;
67
+ }
68
+ }
69
+
70
+ try {
71
+ const response = await axiosInstance.request(axiosConfig);
72
+
73
+ // Cache the parsed data to avoid re-parsing on multiple .json() calls
74
+ let _cachedData;
75
+ let _dataParsed = false;
76
+
77
+ return {
78
+ ok: response.status >= 200 && response.status < 300,
79
+ status: response.status,
80
+ statusText: response.statusText || '',
81
+ headers: response.headers || {},
82
+ url,
83
+
84
+ json() {
85
+ if (!_dataParsed) {
86
+ _cachedData = response.data;
87
+ _dataParsed = true;
88
+ }
89
+ return Promise.resolve(_cachedData);
90
+ },
91
+
92
+ text() {
93
+ if (!_dataParsed) {
94
+ _cachedData = typeof response.data === 'string'
95
+ ? response.data
96
+ : JSON.stringify(response.data);
97
+ _dataParsed = true;
98
+ }
99
+ return Promise.resolve(_cachedData);
100
+ }
101
+ };
102
+ } catch (error) {
103
+ // Network error or request was blocked
104
+ return {
105
+ ok: false,
106
+ status: 0,
107
+ statusText: error.message || 'Network Error',
108
+ headers: {},
109
+ url,
110
+
111
+ json() {
112
+ return Promise.resolve({ error: error.message });
113
+ },
114
+
115
+ text() {
116
+ return Promise.resolve(error.message);
117
+ }
118
+ };
119
+ }
120
+ }
121
+ };
122
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @navios/http adapter for Kupola HTTP client plugin system.
3
+ *
4
+ * @navios/http is a lightweight, fetch-based axios replacement that supports
5
+ * interceptors, multiple response types, and works with Next.js / RSC.
6
+ */
7
+
8
+ /** Additional @navios/http request config fields that can be merged into every request. */
9
+ export interface NaviosAdapterOptions {
10
+ /** Response type: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'stream' */
11
+ responseType?: string;
12
+ /** Custom status validator, e.g. (status) => status < 500 */
13
+ validateStatus?: (status: number) => boolean;
14
+ /** Request credentials: 'omit' | 'same-origin' | 'include' */
15
+ credentials?: string;
16
+ /** URL search parameters */
17
+ params?: Record<string, any> | URLSearchParams;
18
+ /** Allow any other @navios/http requestConfig fields */
19
+ [key: string]: any;
20
+ }
21
+
22
+ /** Minimal @navios/http client interface required by the adapter. */
23
+ export interface NaviosHttpClient {
24
+ request(config: any): Promise<{
25
+ data: any;
26
+ status: number;
27
+ statusText?: string;
28
+ headers?: Record<string, string>;
29
+ config?: any;
30
+ }>;
31
+ get(url: string, config?: any): Promise<any>;
32
+ post(url: string, data?: any, config?: any): Promise<any>;
33
+ put(url: string, data?: any, config?: any): Promise<any>;
34
+ patch(url: string, data?: any, config?: any): Promise<any>;
35
+ delete(url: string, config?: any): Promise<any>;
36
+ head(url: string, config?: any): Promise<any>;
37
+ options(url: string, config?: any): Promise<any>;
38
+ defaults: Record<string, any>;
39
+ interceptors: {
40
+ request: { use(onFulfilled: Function, onRejected?: Function): number };
41
+ response: { use(onFulfilled: Function, onRejected?: Function): number };
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Create a Kupola-compatible HTTP client from a @navios/http instance.
47
+ *
48
+ * @param naviosClient - A @navios/http client instance (from create() or default import)
49
+ * @param options - Additional @navios/http request config to merge into every request
50
+ * @returns Kupola HTTP client object with a `fetch` function
51
+ */
52
+ export function createNaviosAdapter(
53
+ naviosClient: NaviosHttpClient,
54
+ options?: NaviosAdapterOptions
55
+ ): {
56
+ fetch(url: string, fetchOptions?: {
57
+ method?: string;
58
+ headers?: Record<string, string>;
59
+ body?: string;
60
+ }): Promise<{
61
+ ok: boolean;
62
+ status: number;
63
+ statusText: string;
64
+ headers: Record<string, string>;
65
+ url: string;
66
+ json(): Promise<any>;
67
+ text(): Promise<string>;
68
+ }>;
69
+ };
70
+ /**
71
+ * @navios/http adapter for Kupola HTTP client plugin system.
72
+ */
73
+
74
+ export interface NaviosAdapterOptions {
75
+ /** Additional request config to merge into every request */
76
+ [key: string]: any;
77
+ }
78
+
79
+ /**
80
+ * Create a Kupola-compatible HTTP client from a @navios/http instance.
81
+ *
82
+ * @param naviosClient - A @navios/http client instance (from create())
83
+ * @param options - Additional request config to merge into every request
84
+ * @returns Kupola HTTP client object with a `fetch` function
85
+ */
86
+ export function createNaviosAdapter(
87
+ naviosClient: {
88
+ request(config: any): Promise<{
89
+ status: number;
90
+ statusText?: string;
91
+ headers?: Record<string, string>;
92
+ data: any;
93
+ }>;
94
+ },
95
+ options?: NaviosAdapterOptions
96
+ ): {
97
+ fetch(url: string, fetchOptions?: {
98
+ method?: string;
99
+ headers?: Record<string, string>;
100
+ body?: string;
101
+ }): Promise<{
102
+ ok: boolean;
103
+ status: number;
104
+ statusText: string;
105
+ headers: Record<string, string>;
106
+ url: string;
107
+ json(): Promise<any>;
108
+ text(): Promise<string>;
109
+ }>;
110
+ };
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @navios/http adapter for Kupola HTTP client plugin system.
3
+ *
4
+ * Allows using @navios/http (with interceptors, custom config, etc.) as the HTTP
5
+ * client for all useDeps() / useQuery() requests.
6
+ *
7
+ * @navios/http is a lightweight, fetch-based axios replacement that supports
8
+ * interceptors, multiple response types, and works with Next.js / RSC.
9
+ *
10
+ * @module adapters/navios-http
11
+ *
12
+ * @example
13
+ * import { configureHttpClient } from 'kupola';
14
+ * import { createNaviosAdapter } from 'kupola/adapters/navios-http';
15
+ * import { create } from '@navios/http';
16
+ *
17
+ * const client = create({ baseURL: '/api' });
18
+ *
19
+ * // @navios/http interceptors work as expected
20
+ * client.interceptors.request.use((config) => {
21
+ * config.headers['Authorization'] = `Bearer ${getToken()}`;
22
+ * return config;
23
+ * });
24
+ *
25
+ * configureHttpClient(createNaviosAdapter(client));
26
+ */
27
+
28
+ /**
29
+ * Create a Kupola-compatible HTTP client from a @navios/http instance.
30
+ *
31
+ * Translates Kupola's fetch-style calls into @navios/http requests,
32
+ * and maps @navios/http responses back to Kupola's standard format:
33
+ * { ok, status, statusText, headers, url, json(), text() }
34
+ *
35
+ * @param {Object} naviosClient - A @navios/http client instance (from create() or default import)
36
+ * Must expose: .request(config), .get(url, config), .post(url, data, config), etc.
37
+ * @param {Object} [options] - Additional @navios/http request config merged into every request.
38
+ * Supports all @navios/http requestConfig fields:
39
+ * - responseType {string}: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'stream'
40
+ * - validateStatus {Function}: custom status validator, e.g. () => true
41
+ * - credentials {string}: 'omit' | 'same-origin' | 'include'
42
+ * - params {Object|URLSearchParams}: URL search parameters
43
+ * @returns {{ fetch: Function }} Kupola HTTP client object
44
+ */
45
+ export function createNaviosAdapter(naviosClient, options = {}) {
46
+ if (!naviosClient || typeof naviosClient.request !== 'function') {
47
+ throw new TypeError('[Kupola] createNaviosAdapter: invalid @navios/http client (must have .request method)');
48
+ }
49
+
50
+ return {
51
+ /**
52
+ * Fetch function compatible with Kupola's HTTP client interface.
53
+ * Translates Fetch API semantics to @navios/http, and response back to
54
+ * Fetch API Response shape.
55
+ *
56
+ * @param {string} url - Request URL
57
+ * @param {Object} [fetchOptions] - Fetch-style options
58
+ * @param {string} [fetchOptions.method='GET'] - HTTP method
59
+ * @param {Object} [fetchOptions.headers] - Request headers
60
+ * @param {string} [fetchOptions.body] - Request body (JSON string)
61
+ * @returns {Promise<Object>} Response-like object { ok, status, headers, json(), text() }
62
+ */
63
+ fetch: async function (url, fetchOptions = {}) {
64
+ const method = (fetchOptions.method || 'GET').toUpperCase();
65
+
66
+ // Build request config for @navios/http
67
+ // Note: @navios/http uses `data` for body (axios-style), not `body` (fetch-style)
68
+ const requestConfig = {
69
+ url,
70
+ method,
71
+ headers: fetchOptions.headers || {},
72
+ // Accept all status codes here; Kupola handles ok/status checking itself
73
+ validateStatus: () => true,
74
+ ...options
75
+ };
76
+
77
+ // Parse body if present (Fetch sends body as JSON string,
78
+ // but @navios/http accepts objects directly as `data`)
79
+ if (fetchOptions.body && ['POST', 'PUT', 'PATCH'].includes(method)) {
80
+ try {
81
+ requestConfig.data = JSON.parse(fetchOptions.body);
82
+ } catch (_) {
83
+ requestConfig.data = fetchOptions.body;
84
+ }
85
+ }
86
+
87
+ try {
88
+ const response = await naviosClient.request(requestConfig);
89
+
90
+ // Cache the parsed data to avoid re-parsing on multiple .json() calls
91
+ let _cachedData;
92
+ let _dataParsed = false;
93
+
94
+ return {
95
+ ok: response.status >= 200 && response.status < 300,
96
+ status: response.status,
97
+ statusText: response.statusText || '',
98
+ headers: response.headers || {},
99
+ url,
100
+
101
+ json() {
102
+ if (!_dataParsed) {
103
+ _cachedData = response.data;
104
+ _dataParsed = true;
105
+ }
106
+ return Promise.resolve(_cachedData);
107
+ },
108
+
109
+ text() {
110
+ if (!_dataParsed) {
111
+ _cachedData = typeof response.data === 'string'
112
+ ? response.data
113
+ : JSON.stringify(response.data);
114
+ _dataParsed = true;
115
+ }
116
+ return Promise.resolve(_cachedData);
117
+ }
118
+ };
119
+ } catch (error) {
120
+ // Network error or interceptor rejection.
121
+ // @navios/http error shape: { message, response?: { status, headers, data }, config }
122
+ const errStatus = (error.response && error.response.status) || 0;
123
+ const errHeaders = (error.response && error.response.headers) || {};
124
+
125
+ return {
126
+ ok: false,
127
+ status: errStatus,
128
+ statusText: error.message || 'Network Error',
129
+ headers: errHeaders,
130
+ url,
131
+
132
+ json() {
133
+ // Try to return structured error data if available
134
+ if (error.response && error.response.data !== undefined) {
135
+ return Promise.resolve(error.response.data);
136
+ }
137
+ return Promise.resolve({ error: error.message });
138
+ },
139
+
140
+ text() {
141
+ if (error.response && error.response.data !== undefined) {
142
+ const d = error.response.data;
143
+ return Promise.resolve(typeof d === 'string' ? d : JSON.stringify(d));
144
+ }
145
+ return Promise.resolve(error.message);
146
+ }
147
+ };
148
+ }
149
+ }
150
+ };
151
+ }
@@ -0,0 +1,119 @@
1
+ /* Accessibility (a11y) */
2
+
3
+ /* Focus styles */
4
+ *:focus-visible {
5
+ outline: 2px solid var(--bg-brand);
6
+ outline-offset: 2px;
7
+ }
8
+
9
+ *:focus:not(:focus-visible) {
10
+ outline: none;
11
+ }
12
+
13
+ /* Skip link */
14
+ .skip-link {
15
+ position: absolute;
16
+ top: -40px;
17
+ left: 0;
18
+ padding: 8px 12px;
19
+ background-color: var(--bg-brand);
20
+ color: var(--text-onbrand);
21
+ font-size: 13px;
22
+ font-weight: 500;
23
+ text-decoration: none;
24
+ z-index: 1000;
25
+ transition: top 0.2s ease;
26
+ }
27
+
28
+ .skip-link:focus {
29
+ top: 0;
30
+ }
31
+
32
+ /* Screen reader only */
33
+ .sr-only {
34
+ position: absolute;
35
+ width: 1px;
36
+ height: 1px;
37
+ padding: 0;
38
+ margin: -1px;
39
+ overflow: hidden;
40
+ clip: rect(0, 0, 0, 0);
41
+ white-space: nowrap;
42
+ border: 0;
43
+ }
44
+
45
+ /* High contrast mode */
46
+ @media (prefers-contrast: high) {
47
+ :root {
48
+ --border-neutral-l1: #000000;
49
+ --border-neutral-l2: #000000;
50
+ --border-neutral-l3: #000000;
51
+ }
52
+
53
+ .ds-btn {
54
+ border-width: 2px;
55
+ }
56
+
57
+ .ds-input {
58
+ border-width: 2px;
59
+ }
60
+
61
+ .ds-card {
62
+ border-width: 2px;
63
+ }
64
+ }
65
+
66
+ /* Reduced motion */
67
+ @media (prefers-reduced-motion: reduce) {
68
+ *,
69
+ *::before,
70
+ *::after {
71
+ animation-duration: 0.01ms !important;
72
+ animation-iteration-count: 1 !important;
73
+ transition-duration: 0.01ms !important;
74
+ }
75
+ }
76
+
77
+ /* Keyboard navigation */
78
+ .ds-btn:not(:disabled):focus-visible,
79
+ .ds-input:focus-visible,
80
+ .ds-toggle input:focus-visible + .ds-toggle__track {
81
+ outline: 2px solid var(--bg-brand);
82
+ outline-offset: 2px;
83
+ }
84
+
85
+ /* Active states for keyboard users */
86
+ .ds-btn:not(:disabled):active,
87
+ .ds-btn:not(:disabled):focus:active {
88
+ transform: translateY(1px);
89
+ }
90
+
91
+ /* Visible focus for better keyboard navigation */
92
+ .ds-dashboard__sidebar-item:focus-visible,
93
+ .ds-activityrail__item:focus-visible,
94
+ .ds-statusbar__item:focus-visible {
95
+ outline: 2px solid var(--bg-brand);
96
+ outline-offset: 2px;
97
+ }
98
+
99
+ /* Color contrast */
100
+ .ds-statcard__delta.is-up {
101
+ color: var(--status-success-default);
102
+ }
103
+
104
+ .ds-statcard__delta.is-down {
105
+ color: var(--status-error-default);
106
+ }
107
+
108
+ /* Selection color */
109
+ ::selection {
110
+ background-color: var(--bg-brand-popup);
111
+ color: var(--text-brand);
112
+ }
113
+
114
+ /* Clearfix */
115
+ .ds-clearfix::after {
116
+ content: '';
117
+ display: table;
118
+ clear: both;
119
+ }