@kupola/kupola 1.2.0 → 1.4.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/LICENSE +21 -0
- package/README.md +330 -286
- package/adapters/axios.d.ts +34 -0
- package/adapters/axios.js +122 -0
- package/adapters/navios-http.d.ts +110 -0
- package/adapters/navios-http.js +151 -0
- package/css/components-ext.css +157 -0
- package/css/components.css +69 -0
- package/css/theme-dark.css +5 -5
- package/css/utilities.css +119 -1
- package/dist/css/accessibility.css +119 -0
- package/dist/css/animations.css +224 -0
- package/dist/css/brand-themes.css +300 -0
- package/dist/css/colors_and_type.css +441 -0
- package/dist/css/components-ext.css +4165 -0
- package/dist/css/components.css +1483 -0
- package/dist/css/kupola.css +1 -12
- package/dist/css/kupola.min.css +1 -0
- package/dist/css/responsive.css +697 -0
- package/dist/css/scaffold.css +145 -0
- package/dist/css/states.css +316 -0
- package/dist/css/theme-dark.css +296 -0
- package/dist/css/theme-light.css +296 -0
- package/dist/css/utilities.css +171 -0
- package/dist/icons.svg +284 -0
- package/dist/kupola.cjs.js +17409 -257
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.css +9000 -0
- package/dist/kupola.esm.js +17183 -7597
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.min.css +1 -0
- package/dist/kupola.min.js +2 -0
- package/dist/kupola.min.js.map +1 -0
- package/dist/kupola.umd.js +17415 -257
- package/dist/kupola.umd.js.map +1 -1
- package/dist/plugins/vite-plugin-kupola.js +120 -0
- package/dist/types/kupola.d.ts +421 -323
- package/js/calendar.js +334 -25
- package/js/carousel.js +182 -48
- package/js/collapse.js +148 -34
- package/js/color-picker.js +416 -108
- package/js/component.js +8 -19
- package/js/countdown.js +9 -8
- package/js/data-bind.js +73 -16
- package/js/datepicker.js +488 -110
- package/js/depends.js +710 -0
- package/js/dialog.js +4 -2
- package/js/drawer.js +172 -8
- package/js/dropdown.js +272 -17
- package/js/dynamic-tags.js +156 -40
- package/js/fileupload.js +9 -8
- package/js/form.js +280 -254
- package/js/global-events.js +281 -188
- package/js/heatmap.js +10 -7
- package/js/i18n.js +18 -10
- package/js/icons.js +141 -161
- package/js/image-preview.js +146 -2
- package/js/initializer.js +151 -71
- package/js/kupola-core.js +123 -45
- package/js/kupola-lifecycle.js +13 -11
- package/js/message.js +8 -1
- package/js/modal.js +207 -59
- package/js/notification.js +8 -1
- package/js/numberinput.js +9 -8
- package/js/pagination.js +263 -0
- package/js/registry.js +29 -12
- package/js/select.js +482 -27
- package/js/slide-captcha.js +11 -2
- package/js/slider.js +442 -25
- package/js/statcard.js +9 -7
- package/js/table.js +1210 -0
- package/js/tag.js +268 -14
- package/js/theme-standalone.js +88 -0
- package/js/theme.js +14 -43
- package/js/timepicker.js +335 -66
- package/js/tooltip.js +317 -86
- package/js/utils.js +6 -2
- package/js/validation.js +6 -2
- package/js/virtual-list.js +11 -7
- package/js/web-components.js +288 -0
- package/package.json +81 -67
- package/plugins/vite-plugin-kupola.js +120 -0
- package/scripts/build-css.cjs +113 -0
- package/scripts/build-svg-sprite.cjs +107 -0
- package/types/kupola.d.ts +421 -323
- package/CHANGELOG.md +0 -130
- package/INTEGRATION.md +0 -440
- package/PROJECT_SUMMARY.md +0 -312
- package/SKILL.md +0 -572
- package/dist/utils/utils/Kupola.cs +0 -77
- package/dist/utils/utils/Kupola.java +0 -104
- package/dist/utils/utils/kupola.go +0 -120
- package/dist/utils/utils/kupola.js +0 -63
- package/dist/utils/utils/kupola.py +0 -1392
- package/dist/utils/utils/kupola.rb +0 -69
- package/js/composition-api.js +0 -458
- package/js/error-handler.js +0 -181
- package/js/http.js +0 -419
- package/js/kupola-devtools.js +0 -598
- package/js/performance.js +0 -250
- package/js/router.js +0 -396
- package/js/security.js +0 -189
- package/js/test-utils.js +0 -251
- package/templates/base.html +0 -30
- package/templates/base_dashboard.html +0 -99
- package/utils/Kupola.cs +0 -77
- package/utils/Kupola.java +0 -104
- package/utils/kupola.go +0 -120
- package/utils/kupola.js +0 -63
- package/utils/kupola.py +0 -1392
- 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
|
+
}
|
package/css/components-ext.css
CHANGED
|
@@ -1403,6 +1403,42 @@
|
|
|
1403
1403
|
border-radius: 50%;
|
|
1404
1404
|
}
|
|
1405
1405
|
|
|
1406
|
+
/* IMP-009: Skeleton size variants */
|
|
1407
|
+
.ds-skeleton--text {
|
|
1408
|
+
height: 14px;
|
|
1409
|
+
margin-bottom: var(--spacer-8);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.ds-skeleton--heading {
|
|
1413
|
+
height: 24px;
|
|
1414
|
+
width: 40%;
|
|
1415
|
+
margin-bottom: var(--spacer-12);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
.ds-skeleton--block {
|
|
1419
|
+
height: 200px;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.ds-skeleton--avatar {
|
|
1423
|
+
width: 40px;
|
|
1424
|
+
height: 40px;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.ds-skeleton--button {
|
|
1428
|
+
height: 28px;
|
|
1429
|
+
width: 80px;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
.ds-skeleton--input {
|
|
1433
|
+
height: 28px;
|
|
1434
|
+
width: 100%;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
.ds-skeleton--table {
|
|
1438
|
+
height: 200px;
|
|
1439
|
+
width: 100%;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1406
1442
|
@keyframes ds-skeleton-pulse {
|
|
1407
1443
|
0%, 100% { opacity: 1; }
|
|
1408
1444
|
50% { opacity: 0.5; }
|
|
@@ -2661,6 +2697,17 @@
|
|
|
2661
2697
|
right: 2px;
|
|
2662
2698
|
}
|
|
2663
2699
|
|
|
2700
|
+
/* IMP-006: Badge info variant */
|
|
2701
|
+
.ds-badge--info {
|
|
2702
|
+
background: var(--status-info-surface-l1);
|
|
2703
|
+
color: var(--status-info-default);
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
.ds-badge--neutral {
|
|
2707
|
+
background: var(--bg-overlay-l2);
|
|
2708
|
+
color: var(--text-tertiary);
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2664
2711
|
/* ── Tooltip ──────────────────────────────────────────────── */
|
|
2665
2712
|
[data-tooltip] {
|
|
2666
2713
|
position: relative;
|
|
@@ -4162,4 +4209,114 @@
|
|
|
4162
4209
|
|
|
4163
4210
|
.ds-virtual-list--horizontal .ds-virtual-list__item:last-child {
|
|
4164
4211
|
border-right: none;
|
|
4212
|
+
}
|
|
4213
|
+
|
|
4214
|
+
/* ── Tree (IMP-008) ──────────────────────────────────────── */
|
|
4215
|
+
.ds-tree {
|
|
4216
|
+
list-style: none;
|
|
4217
|
+
padding: 0;
|
|
4218
|
+
margin: 0;
|
|
4219
|
+
font-size: var(--body-sm-font-size, 13px);
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
.ds-tree ul {
|
|
4223
|
+
list-style: none;
|
|
4224
|
+
padding: 0;
|
|
4225
|
+
margin: 0;
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4228
|
+
.ds-tree__item {
|
|
4229
|
+
display: flex;
|
|
4230
|
+
align-items: center;
|
|
4231
|
+
gap: var(--spacer-6);
|
|
4232
|
+
padding: var(--spacer-4) var(--spacer-8);
|
|
4233
|
+
border-radius: var(--radius-4);
|
|
4234
|
+
cursor: default;
|
|
4235
|
+
transition: background-color 0.12s ease;
|
|
4236
|
+
user-select: none;
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
.ds-tree__item:hover {
|
|
4240
|
+
background-color: var(--bg-overlay-l1);
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
.ds-tree__item.is-selected {
|
|
4244
|
+
background-color: var(--bg-brand-popup);
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
.ds-tree__toggle {
|
|
4248
|
+
display: inline-flex;
|
|
4249
|
+
align-items: center;
|
|
4250
|
+
justify-content: center;
|
|
4251
|
+
width: 16px;
|
|
4252
|
+
height: 16px;
|
|
4253
|
+
flex-shrink: 0;
|
|
4254
|
+
cursor: pointer;
|
|
4255
|
+
color: var(--icon-secondary);
|
|
4256
|
+
transition: transform 0.15s ease;
|
|
4257
|
+
background: none;
|
|
4258
|
+
border: none;
|
|
4259
|
+
padding: 0;
|
|
4260
|
+
}
|
|
4261
|
+
|
|
4262
|
+
.ds-tree__toggle::before {
|
|
4263
|
+
content: '';
|
|
4264
|
+
display: block;
|
|
4265
|
+
width: 0;
|
|
4266
|
+
height: 0;
|
|
4267
|
+
border-left: 5px solid currentColor;
|
|
4268
|
+
border-top: 3.5px solid transparent;
|
|
4269
|
+
border-bottom: 3.5px solid transparent;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
.ds-tree__toggle.is-open {
|
|
4273
|
+
transform: rotate(90deg);
|
|
4274
|
+
}
|
|
4275
|
+
|
|
4276
|
+
.ds-tree__toggle.is-leaf {
|
|
4277
|
+
visibility: hidden;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
.ds-tree__checkbox {
|
|
4281
|
+
width: 14px;
|
|
4282
|
+
height: 14px;
|
|
4283
|
+
flex-shrink: 0;
|
|
4284
|
+
accent-color: var(--bg-brand);
|
|
4285
|
+
cursor: pointer;
|
|
4286
|
+
}
|
|
4287
|
+
|
|
4288
|
+
.ds-tree__icon {
|
|
4289
|
+
width: 16px;
|
|
4290
|
+
height: 16px;
|
|
4291
|
+
flex-shrink: 0;
|
|
4292
|
+
color: var(--icon-secondary);
|
|
4293
|
+
}
|
|
4294
|
+
|
|
4295
|
+
.ds-tree__label {
|
|
4296
|
+
flex: 1;
|
|
4297
|
+
color: var(--text-default);
|
|
4298
|
+
overflow: hidden;
|
|
4299
|
+
text-overflow: ellipsis;
|
|
4300
|
+
white-space: nowrap;
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4303
|
+
.ds-tree__badge {
|
|
4304
|
+
font-size: var(--body-xs-font-size, 10px);
|
|
4305
|
+
color: var(--text-tertiary);
|
|
4306
|
+
margin-left: auto;
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4309
|
+
.ds-tree__children {
|
|
4310
|
+
padding-left: var(--spacer-20);
|
|
4311
|
+
border-left: 1px solid var(--border-neutral-l1);
|
|
4312
|
+
margin-left: 7px;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
/* Tree line guides */
|
|
4316
|
+
.ds-tree--lined .ds-tree__children {
|
|
4317
|
+
border-left-color: var(--border-neutral-l1);
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
.ds-tree--compact .ds-tree__item {
|
|
4321
|
+
padding: var(--spacer-2) var(--spacer-8);
|
|
4165
4322
|
}
|
package/css/components.css
CHANGED
|
@@ -540,6 +540,24 @@
|
|
|
540
540
|
.ds-input.is-error { border-color: var(--bg-error-default); }
|
|
541
541
|
.ds-input.is-success { border-color: var(--bg-success-default); }
|
|
542
542
|
|
|
543
|
+
/* BUG-003 fix: ensure <select class="ds-input"> matches <input> height/padding */
|
|
544
|
+
select.ds-input,
|
|
545
|
+
.ds-input select {
|
|
546
|
+
height: 28px;
|
|
547
|
+
padding: 0 var(--spacer-24) 0 var(--spacer-12);
|
|
548
|
+
appearance: none;
|
|
549
|
+
-webkit-appearance: none;
|
|
550
|
+
-moz-appearance: none;
|
|
551
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239599A6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'></polyline></svg>");
|
|
552
|
+
background-repeat: no-repeat;
|
|
553
|
+
background-position: right 8px center;
|
|
554
|
+
background-size: 12px;
|
|
555
|
+
cursor: pointer;
|
|
556
|
+
font: inherit;
|
|
557
|
+
color: var(--text-default);
|
|
558
|
+
}
|
|
559
|
+
select.ds-input::-ms-expand { display: none; }
|
|
560
|
+
|
|
543
561
|
.ds-input__status-icon {
|
|
544
562
|
position: absolute;
|
|
545
563
|
right: 12px;
|
|
@@ -980,6 +998,18 @@
|
|
|
980
998
|
}
|
|
981
999
|
.ds-table__pagination { display: flex; align-items: center; gap: var(--spacer-8); }
|
|
982
1000
|
|
|
1001
|
+
/* Table variants (IMP-001) */
|
|
1002
|
+
.ds-table--striped tbody tr:nth-child(even) { background: var(--bg-base-secondary); }
|
|
1003
|
+
.ds-table--hover tbody tr:hover { background: var(--bg-overlay-l1); cursor: default; }
|
|
1004
|
+
.ds-table--compact th,
|
|
1005
|
+
.ds-table--compact td { padding: var(--spacer-6) var(--spacer-8); font-size: var(--body-xs-font-size); }
|
|
1006
|
+
|
|
1007
|
+
/* Table cell utilities */
|
|
1008
|
+
.ds-td--strong { font-weight: 500; color: var(--text-default); }
|
|
1009
|
+
.ds-td--actions { display: flex; gap: var(--spacer-4); align-items: center; }
|
|
1010
|
+
.ds-td--mono { font-family: var(--code-editor-font-family); font-variant-numeric: tabular-nums; }
|
|
1011
|
+
.ds-td--truncate { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1012
|
+
|
|
983
1013
|
/* ── Tabs ──────────────────────────────────────────────────── */
|
|
984
1014
|
/* ===== Tabs ===== */
|
|
985
1015
|
.ds-tabs { display: flex; gap: var(--spacer-24); border-bottom: 1px solid var(--border-neutral-l1); }
|
|
@@ -1311,6 +1341,45 @@
|
|
|
1311
1341
|
margin-top: var(--spacer-16);
|
|
1312
1342
|
}
|
|
1313
1343
|
|
|
1344
|
+
/* IMP-004: Flat aliases — use these without BEM __ nesting */
|
|
1345
|
+
.ds-form-group {
|
|
1346
|
+
display: flex;
|
|
1347
|
+
flex-direction: column;
|
|
1348
|
+
gap: var(--spacer-6);
|
|
1349
|
+
margin-bottom: var(--spacer-12);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
.ds-form-label {
|
|
1353
|
+
display: block;
|
|
1354
|
+
font-size: var(--body-sm-font-size);
|
|
1355
|
+
font-weight: var(--font-weight-medium);
|
|
1356
|
+
color: var(--text-default);
|
|
1357
|
+
margin-bottom: var(--spacer-4);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
.ds-form-row {
|
|
1361
|
+
display: grid;
|
|
1362
|
+
grid-template-columns: repeat(2, 1fr);
|
|
1363
|
+
gap: var(--spacer-12);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
.ds-form-row--3 {
|
|
1367
|
+
grid-template-columns: repeat(3, 1fr);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
.ds-form-actions {
|
|
1371
|
+
display: flex;
|
|
1372
|
+
justify-content: flex-end;
|
|
1373
|
+
gap: var(--spacer-8);
|
|
1374
|
+
margin-top: var(--spacer-16);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.ds-form-hint {
|
|
1378
|
+
font-size: var(--body-xs-font-size);
|
|
1379
|
+
color: var(--text-tertiary);
|
|
1380
|
+
margin-top: var(--spacer-2);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1314
1383
|
.ds-radio-group {
|
|
1315
1384
|
display: flex;
|
|
1316
1385
|
gap: var(--spacer-16);
|