endfield-vision 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -9
- package/README.ru.md +31 -9
- package/dist/components/CommandPalette.d.ts +24 -1
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +22 -10
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/DataTable.d.ts +38 -1
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/DataTable.js +135 -25
- package/dist/components/DataTable.js.map +1 -1
- package/dist/components/Modal.d.ts +26 -0
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/Modal.js +92 -0
- package/dist/components/Modal.js.map +1 -1
- package/dist/components/Toast.d.ts +3 -0
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +5 -1
- package/dist/components/Toast.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/accent-preset.d.ts +40 -0
- package/dist/lib/accent-preset.d.ts.map +1 -0
- package/dist/lib/accent-preset.js +71 -0
- package/dist/lib/accent-preset.js.map +1 -0
- package/dist/lib/i18n-messages.d.ts +7 -0
- package/dist/lib/i18n-messages.d.ts.map +1 -1
- package/dist/lib/i18n-messages.js +10 -2
- package/dist/lib/i18n-messages.js.map +1 -1
- package/dist/lib/theme-script.d.ts +10 -4
- package/dist/lib/theme-script.d.ts.map +1 -1
- package/dist/lib/theme-script.js +8 -3
- package/dist/lib/theme-script.js.map +1 -1
- package/dist/lib/theme.d.ts +10 -6
- package/dist/lib/theme.d.ts.map +1 -1
- package/dist/lib/theme.js +1 -1
- package/dist/lib/theme.js.map +1 -1
- package/dist/styles/accents.css +6 -6
- package/dist/styles/components/data.css +120 -0
- package/dist/styles/components/navigation.css +6 -0
- package/dist/styles/components/overlay.css +43 -0
- package/dist/styles/shell.css +2 -0
- package/dist/styles/tokens.css +27 -27
- package/package.json +1 -1
- package/src/components/CommandPalette.tsx +68 -10
- package/src/components/DataTable.tsx +258 -41
- package/src/components/Modal.tsx +148 -1
- package/src/components/Toast.tsx +21 -1
- package/src/index.ts +4 -0
- package/src/lib/accent-preset.tsx +109 -0
- package/src/lib/i18n-messages.ts +17 -3
- package/src/lib/theme-script.tsx +19 -5
- package/src/lib/theme.ts +13 -8
- package/src/styles/accents.css +6 -6
- package/src/styles/components/data.css +120 -0
- package/src/styles/components/navigation.css +6 -0
- package/src/styles/components/overlay.css +43 -0
- package/src/styles/shell.css +2 -0
- package/src/styles/tokens.css +27 -27
package/dist/lib/theme.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type Accent, type Style, type Theme, type ThemePreference } from './theme-script.js';
|
|
1
|
+
import { type Accent, type AccentName, type Style, type Theme, type ThemePreference } from './theme-script.js';
|
|
2
2
|
/** Тема: 'dark' | 'light' или 'system' - по настройке ОС. */
|
|
3
3
|
export declare function setTheme(pref: ThemePreference, { persist, storageKey }?: {
|
|
4
4
|
persist?: boolean | undefined;
|
|
5
5
|
storageKey?: string | undefined;
|
|
6
6
|
}): void;
|
|
7
|
-
/**
|
|
8
|
-
export declare function setAccent(accent:
|
|
7
|
+
/** Акцент: встроенный пресет (styles/accents.css) или свой (AccentPreset). 'indigo' - базовый, атрибут снимается. */
|
|
8
|
+
export declare function setAccent(accent: AccentName, { persist, storageKey }?: {
|
|
9
9
|
persist?: boolean | undefined;
|
|
10
10
|
storageKey?: string | undefined;
|
|
11
11
|
}): void;
|
|
@@ -14,16 +14,20 @@ export declare function setStyle(style: Style, { persist, storageKey }?: {
|
|
|
14
14
|
persist?: boolean | undefined;
|
|
15
15
|
storageKey?: string | undefined;
|
|
16
16
|
}): void;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Состояние темы. A - имена акцентов приложения: по умолчанию встроенные;
|
|
19
|
+
* со своими пресетами - useTheme<Accent | 'brand'>().
|
|
20
|
+
*/
|
|
21
|
+
export interface ThemeState<A extends string = Accent> {
|
|
18
22
|
/** Действующая тема. */
|
|
19
23
|
theme: Theme;
|
|
20
24
|
/** Выбор пользователя (может быть 'system'). */
|
|
21
25
|
preference: ThemePreference;
|
|
22
|
-
accent:
|
|
26
|
+
accent: A;
|
|
23
27
|
style: Style;
|
|
24
28
|
setTheme: typeof setTheme;
|
|
25
29
|
setAccent: typeof setAccent;
|
|
26
30
|
setStyle: typeof setStyle;
|
|
27
31
|
}
|
|
28
|
-
export declare function useTheme(): ThemeState
|
|
32
|
+
export declare function useTheme<A extends string = Accent>(): ThemeState<A>;
|
|
29
33
|
//# sourceMappingURL=theme.d.ts.map
|
package/dist/lib/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/lib/theme.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAA;AAgDvB,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,OAAc,EAAE,UAA8B,EAAE;;;CAAK,GAAG,IAAI,CAM7G;AAED,
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/lib/theme.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAA;AAgDvB,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,OAAc,EAAE,UAA8B,EAAE;;;CAAK,GAAG,IAAI,CAM7G;AAED,qHAAqH;AACrH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAc,EAAE,UAA+B,EAAE;;;CAAK,GAAG,IAAI,CAM5G;AAED,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,OAAc,EAAE,UAA8B,EAAE;;;CAAK,GAAG,IAAI,CAMpG;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACnD,wBAAwB;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,gDAAgD;IAChD,UAAU,EAAE,eAAe,CAAA;IAC3B,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,OAAO,QAAQ,CAAA;IACzB,SAAS,EAAE,OAAO,SAAS,CAAA;IAC3B,QAAQ,EAAE,OAAO,QAAQ,CAAA;CAC1B;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,CAmBnE"}
|
package/dist/lib/theme.js
CHANGED
|
@@ -48,7 +48,7 @@ export function setTheme(pref, { persist = true, storageKey = THEME_STORAGE_KEY
|
|
|
48
48
|
store(storageKey, pref);
|
|
49
49
|
emit();
|
|
50
50
|
}
|
|
51
|
-
/**
|
|
51
|
+
/** Акцент: встроенный пресет (styles/accents.css) или свой (AccentPreset). 'indigo' - базовый, атрибут снимается. */
|
|
52
52
|
export function setAccent(accent, { persist = true, storageKey = ACCENT_STORAGE_KEY } = {}) {
|
|
53
53
|
const root = document.documentElement;
|
|
54
54
|
if (accent === 'indigo')
|
package/dist/lib/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/lib/theme.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACvD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/lib/theme.ts"],"names":[],"mappings":"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"}
|
package/dist/styles/accents.css
CHANGED
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/*
|
|
118
|
-
* Стиль Slim: те же пресеты, приглушённые под
|
|
118
|
+
* Стиль Slim: те же пресеты, приглушённые под нейтрали стиля.
|
|
119
119
|
* indigo - без атрибута data-accent.
|
|
120
120
|
*/
|
|
121
121
|
:root[data-style='slim']:not([data-accent]) {
|
|
@@ -167,11 +167,11 @@
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
:root[data-style='slim'][data-accent='ink'] {
|
|
170
|
-
--ev-accent-rgb: 200,
|
|
171
|
-
--ev-accent-text: #
|
|
172
|
-
--ev-accent-strong: #
|
|
173
|
-
--ev-accent-strong-hover: #
|
|
174
|
-
--ev-text-on-accent: #
|
|
170
|
+
--ev-accent-rgb: 200, 198, 192;
|
|
171
|
+
--ev-accent-text: #e2e0db;
|
|
172
|
+
--ev-accent-strong: #e9e8e3;
|
|
173
|
+
--ev-accent-strong-hover: #f5f4f0;
|
|
174
|
+
--ev-text-on-accent: #181817;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
:root[data-style='slim'][data-theme='light']:not([data-accent]) {
|
|
@@ -131,6 +131,20 @@
|
|
|
131
131
|
box-shadow: inset 0 1px 0 var(--ev-selected-edge), inset 0 -1px 0 var(--ev-selected-edge);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/* Тон строки (rowTone): тонированный фон, наведение - тинт поверх него. */
|
|
135
|
+
.ev-table tbody tr[data-tone],
|
|
136
|
+
.ev-table-card[data-tone] {
|
|
137
|
+
--ev-tone-row: color-mix(in srgb, var(--ev-tone-soft) 65%, transparent);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.ev-table tbody tr[data-tone] > td {
|
|
141
|
+
background: var(--ev-tone-row);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.ev-table tbody tr[data-tone]:hover > td {
|
|
145
|
+
background: linear-gradient(var(--ev-hover), var(--ev-hover)), var(--ev-tone-row);
|
|
146
|
+
}
|
|
147
|
+
|
|
134
148
|
.ev-table tbody tr[data-selected] td {
|
|
135
149
|
background: var(--ev-selected-bg-subtle);
|
|
136
150
|
}
|
|
@@ -139,6 +153,89 @@
|
|
|
139
153
|
color: var(--ev-text-muted);
|
|
140
154
|
}
|
|
141
155
|
|
|
156
|
+
/* --- Раскрывающиеся строки --- */
|
|
157
|
+
.ev-table .ev-table-expand {
|
|
158
|
+
width: 40px;
|
|
159
|
+
padding-right: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.ev-table-expand-btn {
|
|
163
|
+
display: inline-flex;
|
|
164
|
+
align-items: center;
|
|
165
|
+
justify-content: center;
|
|
166
|
+
width: 24px;
|
|
167
|
+
height: 24px;
|
|
168
|
+
margin: 0 -4px;
|
|
169
|
+
border-radius: var(--ev-radius-xs);
|
|
170
|
+
color: var(--ev-text-muted);
|
|
171
|
+
vertical-align: middle;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.ev-table-expand-btn:hover {
|
|
175
|
+
background: var(--ev-hover);
|
|
176
|
+
color: var(--ev-text);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.ev-table-expand-btn svg {
|
|
180
|
+
transition: transform var(--ev-dur-fast) var(--ev-ease);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.ev-table-expand-btn[aria-expanded='true'] svg {
|
|
184
|
+
transform: rotate(90deg);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ev-table tbody tr[data-expanded]:not([data-tone], [data-selected]) > td {
|
|
188
|
+
background: var(--ev-tint-1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.ev-table tbody tr[data-expanded] > td {
|
|
192
|
+
border-bottom-color: transparent;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ev-table .ev-table-detail-row > td {
|
|
196
|
+
height: auto;
|
|
197
|
+
padding: 0;
|
|
198
|
+
white-space: normal;
|
|
199
|
+
background: var(--ev-tint-1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.ev-table-detail {
|
|
203
|
+
padding: var(--ev-space-2) var(--ev-space-5) var(--ev-space-5);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.ev-card-body-flush .ev-table-detail {
|
|
207
|
+
padding-inline: var(--ev-space-6);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* --- Итоговая строка --- */
|
|
211
|
+
.ev-table tfoot td {
|
|
212
|
+
position: sticky;
|
|
213
|
+
bottom: 0;
|
|
214
|
+
z-index: var(--ev-z-sticky);
|
|
215
|
+
height: 40px;
|
|
216
|
+
background: var(--ev-surface-2);
|
|
217
|
+
border-top: 1px solid var(--ev-border);
|
|
218
|
+
border-bottom: 0;
|
|
219
|
+
font-weight: var(--ev-fw-medium);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
:is(.ev-card, .ev-panel, .ev-modal, .ev-drawer) .ev-table tfoot td {
|
|
223
|
+
background: var(--ev-surface-3);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.ev-card-body-flush .ev-table tfoot td {
|
|
227
|
+
background: var(--ev-surface-2);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* --- Шапка, липнущая к странице (stickyHeader): сдвиг считает DataTable --- */
|
|
231
|
+
.ev-table[data-sticky-page] thead th {
|
|
232
|
+
transform: translateY(var(--ev-thead-shift, 0px));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.ev-table[data-stuck] thead th {
|
|
236
|
+
box-shadow: var(--ev-shadow-sm);
|
|
237
|
+
}
|
|
238
|
+
|
|
142
239
|
.ev-table-select {
|
|
143
240
|
width: 44px;
|
|
144
241
|
padding-right: 0 !important;
|
|
@@ -258,6 +355,29 @@
|
|
|
258
355
|
opacity: 0.7;
|
|
259
356
|
}
|
|
260
357
|
|
|
358
|
+
.ev-table-card[data-tone]:not([data-selected]) {
|
|
359
|
+
background-image: linear-gradient(var(--ev-tone-row), var(--ev-tone-row));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.ev-table-card[data-tone][data-clickable]:not([data-selected]):active {
|
|
363
|
+
background-image: linear-gradient(var(--ev-active), var(--ev-active)), linear-gradient(var(--ev-tone-row), var(--ev-tone-row));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.ev-table-card-head .ev-table-expand-btn {
|
|
367
|
+
flex: 0 0 auto;
|
|
368
|
+
margin: -2px -4px 0 0;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.ev-table-card-detail {
|
|
372
|
+
padding-top: var(--ev-space-3);
|
|
373
|
+
border-top: 1px solid var(--ev-border-soft);
|
|
374
|
+
min-width: 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.ev-table-card-total {
|
|
378
|
+
background: var(--ev-surface-2);
|
|
379
|
+
}
|
|
380
|
+
|
|
261
381
|
.ev-table-card-head {
|
|
262
382
|
display: flex;
|
|
263
383
|
align-items: flex-start;
|
|
@@ -276,6 +276,12 @@
|
|
|
276
276
|
padding: 0;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
.ev-modal-prompt {
|
|
280
|
+
display: flex;
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
gap: var(--ev-space-4);
|
|
283
|
+
}
|
|
284
|
+
|
|
279
285
|
.ev-modal-message {
|
|
280
286
|
color: var(--ev-text-secondary);
|
|
281
287
|
line-height: 1.55;
|
|
@@ -462,6 +468,43 @@
|
|
|
462
468
|
font-weight: var(--ev-fw-semibold);
|
|
463
469
|
}
|
|
464
470
|
|
|
471
|
+
/* Карточка с onClick: заголовок - кнопка, растянутая на карточку; кнопки карточки - поверх неё. */
|
|
472
|
+
.ev-toast-open {
|
|
473
|
+
display: block;
|
|
474
|
+
padding: 0;
|
|
475
|
+
color: inherit;
|
|
476
|
+
text-align: left;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.ev-toast-open::after {
|
|
480
|
+
content: '';
|
|
481
|
+
position: absolute;
|
|
482
|
+
inset: 0;
|
|
483
|
+
border-radius: inherit;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.ev-toast-open:focus-visible {
|
|
487
|
+
outline: none;
|
|
488
|
+
box-shadow: none;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.ev-toast-open:focus-visible::after {
|
|
492
|
+
box-shadow: var(--ev-focus-ring);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.ev-toast[data-clickable] {
|
|
496
|
+
cursor: pointer;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.ev-toast[data-clickable]:hover {
|
|
500
|
+
background-image: linear-gradient(var(--ev-tint-2), var(--ev-tint-2));
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.ev-toast[data-clickable] :is(.ev-toast-action, .ev-toast-actions, .ev-toast-close) {
|
|
504
|
+
position: relative;
|
|
505
|
+
z-index: 1;
|
|
506
|
+
}
|
|
507
|
+
|
|
465
508
|
.ev-toast-desc {
|
|
466
509
|
margin-top: 2px;
|
|
467
510
|
font-size: var(--ev-fs-sm);
|
package/dist/styles/shell.css
CHANGED
package/dist/styles/tokens.css
CHANGED
|
@@ -295,39 +295,39 @@
|
|
|
295
295
|
|
|
296
296
|
/*
|
|
297
297
|
* Стиль Slim («Утончённый»): <html data-style="slim">. Плоский и спокойный:
|
|
298
|
-
*
|
|
298
|
+
* нейтрали с лёгким тёплым оттенком, без свечения, выбранное - нейтральным тоном, подписи без капса.
|
|
299
299
|
* Размеры (высоты контролов, отступы, кегль) те же, что в Default.
|
|
300
300
|
* Правила компонентов - в slim.css (слой ev.styles).
|
|
301
301
|
*
|
|
302
|
-
* Контраст (тёмная): --ev-text-muted 5.
|
|
303
|
-
* --ev-border-control 3.
|
|
302
|
+
* Контраст (тёмная): --ev-text-muted 5.8 к --ev-surface-1, 4.8 к --ev-surface-3;
|
|
303
|
+
* --ev-border-control 3.6 к фону поля. Светлая: --ev-text-muted 5.8 / 4.7, рамка поля 3.4.
|
|
304
304
|
*/
|
|
305
305
|
:root[data-style='slim'] {
|
|
306
|
-
--ev-bg: #
|
|
307
|
-
--ev-surface-1: #
|
|
308
|
-
--ev-surface-2: #
|
|
309
|
-
--ev-surface-3: #
|
|
310
|
-
--ev-surface-input: #
|
|
311
|
-
--ev-surface-overlay: rgba(
|
|
312
|
-
--ev-surface-tooltip: #
|
|
306
|
+
--ev-bg: #181817;
|
|
307
|
+
--ev-surface-1: #20201e;
|
|
308
|
+
--ev-surface-2: #272725;
|
|
309
|
+
--ev-surface-3: #2f2e2c;
|
|
310
|
+
--ev-surface-input: #1b1b1a;
|
|
311
|
+
--ev-surface-overlay: rgba(8, 8, 7, 0.62);
|
|
312
|
+
--ev-surface-tooltip: #363533;
|
|
313
313
|
--ev-surface-nested: var(--ev-surface-2);
|
|
314
314
|
|
|
315
|
-
--ev-tint-1: rgba(255,
|
|
316
|
-
--ev-tint-2: rgba(255,
|
|
317
|
-
--ev-tint-3: rgba(255,
|
|
318
|
-
--ev-tint-4: rgba(255,
|
|
315
|
+
--ev-tint-1: rgba(255, 253, 248, 0.025);
|
|
316
|
+
--ev-tint-2: rgba(255, 253, 248, 0.045);
|
|
317
|
+
--ev-tint-3: rgba(255, 253, 248, 0.07);
|
|
318
|
+
--ev-tint-4: rgba(255, 253, 248, 0.1);
|
|
319
319
|
|
|
320
|
-
--ev-border-soft: rgba(255,
|
|
321
|
-
--ev-border: #
|
|
322
|
-
--ev-border-strong: #
|
|
323
|
-
--ev-border-control: #
|
|
324
|
-
--ev-border-hover: #
|
|
320
|
+
--ev-border-soft: rgba(255, 253, 248, 0.05);
|
|
321
|
+
--ev-border: #2f2f2c;
|
|
322
|
+
--ev-border-strong: #3c3b38;
|
|
323
|
+
--ev-border-control: #74726c;
|
|
324
|
+
--ev-border-hover: #8a8881;
|
|
325
325
|
|
|
326
|
-
--ev-text: #
|
|
327
|
-
--ev-text-secondary: #
|
|
328
|
-
--ev-text-muted: #
|
|
329
|
-
--ev-text-disabled: #
|
|
330
|
-
--ev-text-on-solid: #
|
|
326
|
+
--ev-text: #ecebe8;
|
|
327
|
+
--ev-text-secondary: #c0beb8;
|
|
328
|
+
--ev-text-muted: #9c9a93;
|
|
329
|
+
--ev-text-disabled: #686660;
|
|
330
|
+
--ev-text-on-solid: #181817;
|
|
331
331
|
|
|
332
332
|
--ev-success-rgb: 127, 191, 149;
|
|
333
333
|
--ev-success-strong: #3f7d57;
|
|
@@ -339,9 +339,9 @@
|
|
|
339
339
|
--ev-info-rgb: 134, 174, 214;
|
|
340
340
|
--ev-violet-rgb: 182, 166, 224;
|
|
341
341
|
|
|
342
|
-
--ev-chart-grid: #
|
|
343
|
-
--ev-chart-axis: #
|
|
344
|
-
--ev-chart-crosshair: #
|
|
342
|
+
--ev-chart-grid: #2f2f2c;
|
|
343
|
+
--ev-chart-axis: #3c3b38;
|
|
344
|
+
--ev-chart-crosshair: #74726c;
|
|
345
345
|
|
|
346
346
|
--ev-radius-xs: 4px;
|
|
347
347
|
--ev-radius-sm: 6px;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "endfield-vision",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Endfield Vision - design system for React / Next.js: tokens, dark and light themes, accent presets, accessible components without third-party UI dependencies",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
import { Search, X } from 'lucide-react'
|
|
4
4
|
import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'
|
|
5
5
|
import { cx, normalizeSearch } from '../lib/cx'
|
|
6
|
-
import { useEventCallback, useIsoLayoutEffect } from '../lib/hooks'
|
|
6
|
+
import { useControllable, useEventCallback, useIsoLayoutEffect } from '../lib/hooks'
|
|
7
7
|
import { useMessages } from '../lib/i18n'
|
|
8
8
|
import { Portal, useEscapeLayer, useFocusTrap, useScrollLock } from '../lib/overlay'
|
|
9
9
|
import { Kbd } from './Display'
|
|
10
|
+
import { Highlight } from './Highlight'
|
|
11
|
+
import { Spinner } from './Spinner'
|
|
10
12
|
|
|
11
13
|
/*
|
|
12
14
|
* Палитра команд: окно поиска по командам и разделам (Ctrl/Cmd+K).
|
|
@@ -14,6 +16,10 @@ import { Kbd } from './Display'
|
|
|
14
16
|
* aria-activedescendant, фокус всё время остаётся в поле. Окно - в портале
|
|
15
17
|
* на слое модалок, прижато к верху экрана; Escape закрывает, фокус
|
|
16
18
|
* возвращается на прежний элемент.
|
|
19
|
+
*
|
|
20
|
+
* Поиск с сервера: запрос уходит наружу через onQueryChange, пункты из
|
|
21
|
+
* ответа помечаются alwaysShow (или вся палитра filter={false}) - тогда
|
|
22
|
+
* локальное сопоставление их не отсекает; loading - индикатор ожидания.
|
|
17
23
|
*/
|
|
18
24
|
|
|
19
25
|
export interface CommandItem {
|
|
@@ -28,6 +34,11 @@ export interface CommandItem {
|
|
|
28
34
|
/** Дополнительные слова для поиска (синонимы, коды, английские названия). */
|
|
29
35
|
keywords?: string[]
|
|
30
36
|
disabled?: boolean
|
|
37
|
+
/**
|
|
38
|
+
* Показывать при любом запросе: пункт уже отобран снаружи (результат поиска
|
|
39
|
+
* с сервера, совпадение по ИНН или телефону, которого нет в подписи).
|
|
40
|
+
*/
|
|
41
|
+
alwaysShow?: boolean
|
|
31
42
|
/** Выполнить команду. Палитра закрывается перед вызовом. */
|
|
32
43
|
onSelect: () => void
|
|
33
44
|
}
|
|
@@ -42,6 +53,21 @@ export interface CommandPaletteProps {
|
|
|
42
53
|
open: boolean
|
|
43
54
|
onOpenChange: (open: boolean) => void
|
|
44
55
|
items: CommandItem[]
|
|
56
|
+
/** Текст поиска (управляемо). Без него палитра хранит запрос сама и сбрасывает при открытии. */
|
|
57
|
+
query?: string
|
|
58
|
+
/** Начальный запрос при открытии (неуправляемый режим). */
|
|
59
|
+
defaultQuery?: string
|
|
60
|
+
/** Запрос изменился: поиск с сервера. Задержку (debounce) выдерживает приложение. */
|
|
61
|
+
onQueryChange?: (query: string) => void
|
|
62
|
+
/**
|
|
63
|
+
* Отбирать пункты по запросу (по умолчанию да). false - список показывается
|
|
64
|
+
* как есть: приложение фильтрует само. Для отдельных пунктов - alwaysShow.
|
|
65
|
+
*/
|
|
66
|
+
filter?: boolean
|
|
67
|
+
/** Ждём результатов: индикатор в поле, при пустом списке - «Поиск...». */
|
|
68
|
+
loading?: boolean
|
|
69
|
+
/** Подсветить совпадения с запросом в названии и строковой подсказке. */
|
|
70
|
+
highlight?: boolean
|
|
45
71
|
/** Плейсхолдер поля. По умолчанию - из словаря. */
|
|
46
72
|
placeholder?: string
|
|
47
73
|
/** Текст при пустом результате. По умолчанию - «Ничего не найдено». */
|
|
@@ -66,9 +92,17 @@ export function commandMatches(item: CommandItem, query: string): boolean {
|
|
|
66
92
|
return words.every((w) => hay.includes(w))
|
|
67
93
|
}
|
|
68
94
|
|
|
69
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Отбор команд по запросу (без учёта регистра и «ё/е»), порядок сохраняется.
|
|
97
|
+
* Пункты с alwaysShow остаются при любом запросе.
|
|
98
|
+
*/
|
|
70
99
|
export function filterCommands(items: CommandItem[], query: string): CommandItem[] {
|
|
71
|
-
return items.filter((it) => commandMatches(it, query))
|
|
100
|
+
return items.filter((it) => it.alwaysShow || commandMatches(it, query))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Слова запроса для подсветки совпадений. */
|
|
104
|
+
function queryWords(query: string): string[] {
|
|
105
|
+
return query.split(/\s+/).filter(Boolean)
|
|
72
106
|
}
|
|
73
107
|
|
|
74
108
|
/**
|
|
@@ -155,6 +189,12 @@ function optionDomId(listId: string, index: number) {
|
|
|
155
189
|
function PalettePanel({
|
|
156
190
|
onOpenChange,
|
|
157
191
|
items,
|
|
192
|
+
query: queryProp,
|
|
193
|
+
defaultQuery = '',
|
|
194
|
+
onQueryChange,
|
|
195
|
+
filter = true,
|
|
196
|
+
loading = false,
|
|
197
|
+
highlight = false,
|
|
158
198
|
placeholder,
|
|
159
199
|
emptyText,
|
|
160
200
|
footer,
|
|
@@ -164,8 +204,9 @@ function PalettePanel({
|
|
|
164
204
|
const t = useMessages()
|
|
165
205
|
const listId = useId()
|
|
166
206
|
const ref = useRef<HTMLDivElement | null>(null)
|
|
167
|
-
const [query, setQuery] =
|
|
168
|
-
const groups = useMemo(() => groupCommands(filterCommands(items, query)), [items, query])
|
|
207
|
+
const [query, setQuery] = useControllable(queryProp, defaultQuery, onQueryChange)
|
|
208
|
+
const groups = useMemo(() => groupCommands(filter ? filterCommands(items, query) : items), [items, query, filter])
|
|
209
|
+
const marks = highlight ? queryWords(query) : []
|
|
169
210
|
const flat = useMemo(() => groups.flatMap((g) => g.items), [groups])
|
|
170
211
|
const [activeId, setActiveId] = useState<string | null>(null)
|
|
171
212
|
|
|
@@ -240,7 +281,14 @@ function PalettePanel({
|
|
|
240
281
|
className={cx('ev-cmdk', className)}
|
|
241
282
|
>
|
|
242
283
|
<div className="ev-cmdk-head">
|
|
243
|
-
|
|
284
|
+
{loading ? (
|
|
285
|
+
// Ожидание объявляет строка состояния под списком; индикатор - только для глаз.
|
|
286
|
+
<span className="ev-cmdk-search-icon ev-cmdk-spinner" aria-hidden="true">
|
|
287
|
+
<Spinner size={16} />
|
|
288
|
+
</span>
|
|
289
|
+
) : (
|
|
290
|
+
<Search size={17} className="ev-cmdk-search-icon" aria-hidden="true" />
|
|
291
|
+
)}
|
|
244
292
|
<input
|
|
245
293
|
className="ev-cmdk-input"
|
|
246
294
|
type="text"
|
|
@@ -266,7 +314,13 @@ function PalettePanel({
|
|
|
266
314
|
<X size={16} />
|
|
267
315
|
</button>
|
|
268
316
|
</div>
|
|
269
|
-
<div
|
|
317
|
+
<div
|
|
318
|
+
id={listId}
|
|
319
|
+
role="listbox"
|
|
320
|
+
aria-label={ariaLabel ?? t.commandPalette.label}
|
|
321
|
+
aria-busy={loading || undefined}
|
|
322
|
+
className="ev-cmdk-list"
|
|
323
|
+
>
|
|
270
324
|
{groups.map((g, gi) => {
|
|
271
325
|
const headId = `${listId}-g${gi}`
|
|
272
326
|
const options = g.items.map((it) => (
|
|
@@ -287,8 +341,12 @@ function PalettePanel({
|
|
|
287
341
|
{it.icon}
|
|
288
342
|
</span>
|
|
289
343
|
) : null}
|
|
290
|
-
<span className="ev-cmdk-item-label">{it.label}</span>
|
|
291
|
-
{it.hint ?
|
|
344
|
+
<span className="ev-cmdk-item-label">{marks.length > 0 ? <Highlight text={it.label} query={marks} /> : it.label}</span>
|
|
345
|
+
{it.hint ? (
|
|
346
|
+
<span className="ev-cmdk-item-hint">
|
|
347
|
+
{marks.length > 0 && typeof it.hint === 'string' ? <Highlight text={it.hint} query={marks} /> : it.hint}
|
|
348
|
+
</span>
|
|
349
|
+
) : null}
|
|
292
350
|
</div>
|
|
293
351
|
))
|
|
294
352
|
if (g.group === undefined) {
|
|
@@ -311,7 +369,7 @@ function PalettePanel({
|
|
|
311
369
|
})}
|
|
312
370
|
</div>
|
|
313
371
|
<div className="ev-cmdk-empty" role="status">
|
|
314
|
-
{flat.length === 0 ? (emptyText ?? t.common.nothingFound) : null}
|
|
372
|
+
{flat.length === 0 ? (loading ? t.commandPalette.searching : (emptyText ?? t.common.nothingFound)) : null}
|
|
315
373
|
</div>
|
|
316
374
|
<div className="ev-cmdk-foot">
|
|
317
375
|
<div className="ev-cmdk-foot-left">{footer}</div>
|